Files
carmanagement/apps/api/src/modules/carplace/carplace.repo.ts
T
root a010ad6811
Build & Push / Build & Push Docker Image (push) Failing after 3m46s
apply security fix
2026-07-19 22:22:33 -04:00

244 lines
9.2 KiB
TypeScript

import { prisma } from '../../lib/prisma'
export async function findPublicOffers() {
return prisma.offer.findMany({
where: { isPublic: true, isActive: true, validFrom: { lte: new Date() }, validUntil: { gte: new Date() } },
include: { company: { include: { brand: { select: { displayName: true, logoUrl: true, subdomain: true, primaryColor: true } } } } },
orderBy: [{ isFeatured: 'desc' }, { createdAt: 'desc' }],
take: 50,
})
}
export async function findCitiesFromCompanies() {
return prisma.company.findMany({
where: {
status: { in: ['ACTIVE', 'TRIALING'] },
brand: { isListedOnCarplace: true, publicCity: { not: null } },
},
select: { brand: { select: { publicCity: true } } },
})
}
export async function findListedCompanies(where: any, skip: number, take: number) {
return prisma.company.findMany({
where,
include: {
brand: { select: { displayName: true, logoUrl: true, subdomain: true, publicCity: true, publicCountry: true, carplaceRating: true, primaryColor: true } },
_count: { select: { vehicles: { where: { isPublished: true, status: 'AVAILABLE' } } } },
},
skip,
take,
})
}
export async function findPublishedVehicles(where: any) {
return prisma.vehicle.findMany({
where,
include: {
company: { include: { brand: { select: { displayName: true, logoUrl: true, subdomain: true, carplaceRating: true, primaryColor: true } } } },
},
orderBy: { dailyRate: 'asc' },
})
}
export async function findVehicleForCarplace(vehicleId: string, companySlug: string) {
return prisma.vehicle.findFirst({
where: { id: vehicleId, isPublished: true, status: 'AVAILABLE', company: { status: { in: ['ACTIVE', 'TRIALING'] }, OR: [{ slug: companySlug }, { brand: { subdomain: companySlug } }] } },
include: { company: { include: { brand: true } } },
})
}
export async function findVehicleForCarplaceById(vehicleId: string) {
return prisma.vehicle.findFirst({
where: {
id: vehicleId,
isPublished: true,
status: 'AVAILABLE',
company: { status: { in: ['ACTIVE', 'TRIALING'] }, brand: { isListedOnCarplace: true } },
},
include: { company: { include: { brand: true } } },
})
}
export async function upsertCarplaceCustomer(companyId: string, data: {
email: string
firstName: string
lastName: string
phone?: string
dateOfBirth?: string
nationality?: string
identityDocumentNumber?: string
fullAddress?: string
driverLicense?: string
licenseExpiry?: string
licenseIssuedAt?: string
licenseCountry?: string
licenseCategory?: string
internationalLicenseNumber?: string
}) {
const existing = await prisma.customer.findUnique({
where: { companyId_email: { companyId, email: data.email } },
select: { id: true, address: true },
})
// Only patch the address JSON with fields that were actually provided
const prevAddress = (existing?.address && typeof existing.address === 'object' && !Array.isArray(existing.address))
? existing.address as Record<string, unknown>
: {}
const hasAddressPatch = data.fullAddress || data.identityDocumentNumber || data.internationalLicenseNumber !== undefined
const address = hasAddressPatch
? {
...prevAddress,
...(data.fullAddress ? { fullAddress: data.fullAddress } : {}),
...(data.identityDocumentNumber ? { identityDocumentNumber: data.identityDocumentNumber } : {}),
...(data.internationalLicenseNumber !== undefined ? { internationalLicenseNumber: data.internationalLicenseNumber ?? null } : {}),
}
: undefined
const payload = {
firstName: data.firstName,
lastName: data.lastName,
email: data.email,
...(data.phone ? { phone: data.phone } : {}),
...(data.driverLicense ? { driverLicense: data.driverLicense, licenseNumber: data.driverLicense } : {}),
...(data.dateOfBirth ? { dateOfBirth: new Date(data.dateOfBirth) } : {}),
...(data.nationality ? { nationality: data.nationality } : {}),
...(address !== undefined ? { address } : {}),
...(data.licenseExpiry ? { licenseExpiry: new Date(data.licenseExpiry) } : {}),
...(data.licenseIssuedAt ? { licenseIssuedAt: new Date(data.licenseIssuedAt) } : {}),
...(data.licenseCountry ? { licenseCountry: data.licenseCountry } : {}),
...(data.licenseCategory ? { licenseCategory: data.licenseCategory } : {}),
}
if (!existing) {
return prisma.customer.create({ data: { companyId, ...payload } })
}
return prisma.customer.update({ where: { id: existing.id }, data: payload })
}
export async function createCarplaceReservation(data: {
companyId: string; vehicleId: string; customerId: string
startDate: Date; endDate: Date; pickupLocation?: string | null; returnLocation?: string | null
dailyRate: number; totalDays: number; totalAmount: number; notes?: string; bookingReference?: string
}) {
return prisma.reservation.create({
data: { ...data, source: 'CARPLACE', status: 'DRAFT' },
})
}
export async function createCarplaceFunnelEvent(data: {
eventName: string
companySlug: string
vehicleId: string
renterId?: string | null
sessionId?: string
path?: string
metadata?: Record<string, string | number | boolean | null>
}) {
const vehicle = await prisma.vehicle.findFirst({
where: {
id: data.vehicleId,
isPublished: true,
company: { status: { in: ['ACTIVE', 'TRIALING'] }, OR: [{ slug: data.companySlug }, { brand: { subdomain: data.companySlug } }] },
status: 'AVAILABLE',
},
select: { companyId: true },
})
return prisma.carplaceFunnelEvent.create({
data: {
eventName: data.eventName,
companyId: vehicle?.companyId ?? null,
companySlug: data.companySlug,
vehicleId: data.vehicleId,
renterId: data.renterId ?? null,
sessionId: data.sessionId,
path: data.path,
metadata: (data.metadata ?? {}) as any,
},
})
}
export async function findCompanyPage(slug: string) {
return prisma.company.findFirst({
where: { status: { in: ['ACTIVE', 'TRIALING'] }, OR: [{ slug }, { brand: { subdomain: slug } }] },
include: {
brand: true,
vehicles: { where: { isPublished: true, status: 'AVAILABLE' }, orderBy: { createdAt: 'desc' } },
offers: { where: { isPublic: true, isActive: true, validUntil: { gte: new Date() } }, orderBy: { isFeatured: 'desc' } },
},
})
}
export async function findCompanyBySlug(slug: string) {
return prisma.company.findFirstOrThrow({ where: { status: { in: ['ACTIVE', 'TRIALING'] }, OR: [{ slug }, { brand: { subdomain: slug } }] } })
}
export async function findCompanyReviews(companyId: string) {
return prisma.review.findMany({
where: { companyId, isPublished: true },
include: { renter: { select: { firstName: true, lastName: true } } },
orderBy: { createdAt: 'desc' },
take: 50,
})
}
export async function findCompanyVehicles(companyId: string) {
return prisma.vehicle.findMany({
where: { companyId, isPublished: true, status: 'AVAILABLE' },
orderBy: { createdAt: 'desc' },
})
}
export async function findVehicleById(slug: string, vehicleId: string) {
const company = await prisma.company.findFirstOrThrow({ where: { status: { in: ['ACTIVE', 'TRIALING'] }, OR: [{ slug }, { brand: { subdomain: slug } }] } })
return prisma.vehicle.findFirstOrThrow({
where: { id: vehicleId, companyId: company.id, isPublished: true, status: 'AVAILABLE' },
include: { company: { include: { brand: true } } },
})
}
export async function findCompanyOffers(companyId: string) {
return prisma.offer.findMany({
where: { companyId, isPublic: true, isActive: true, validFrom: { lte: new Date() }, validUntil: { gte: new Date() } },
orderBy: [{ isFeatured: 'desc' }, { createdAt: 'desc' }],
})
}
export async function findReservationByReviewToken(token: string) {
return prisma.reservation.findUnique({
where: { reviewToken: token },
include: {
vehicle: { select: { make: true, model: true, year: true, photos: true } },
company: { include: { brand: { select: { displayName: true, logoUrl: true } } } },
review: { select: { id: true } },
},
})
}
export async function findReservationForReviewSubmit(token: string) {
return prisma.reservation.findUnique({
where: { reviewToken: token },
include: { review: { select: { id: true } } },
})
}
export async function createReview(data: {
reservationId: string; companyId: string; renterId?: string | null
overallRating: number; vehicleRating?: number; serviceRating?: number; comment?: string
}) {
return prisma.review.create({
data: { ...data, renterId: data.renterId ?? undefined, isPublished: true },
})
}
export async function invalidateReviewToken(reservationId: string) {
return prisma.reservation.update({ where: { id: reservationId }, data: { reviewToken: null } })
}
export async function findOfferByCode(code: string) {
return prisma.offer.findFirst({
where: { promoCode: code, isActive: true, validFrom: { lte: new Date() }, validUntil: { gte: new Date() } },
})
}