fix production issue

This commit is contained in:
root
2026-05-10 19:55:57 -04:00
parent a224d7704a
commit 2d28947b92
17 changed files with 107 additions and 81 deletions
+6 -6
View File
@@ -487,7 +487,7 @@ router.patch('/companies/:id', requireAdminAuth, requireAdminRole('SUPPORT'), as
currentPeriodEnd: parseOptionalDate(body.subscription.currentPeriodEnd),
cancelledAt: parseOptionalDate(body.subscription.cancelledAt),
cancelAtPeriodEnd: body.subscription.cancelAtPeriodEnd ?? false,
},
} as any,
})
}
@@ -502,7 +502,7 @@ router.patch('/companies/:id', requireAdminAuth, requireAdminRole('SUPPORT'), as
subdomain: body.brand.subdomain ?? currentCompany.slug,
paymentMethodsEnabled: before.brand?.paymentMethodsEnabled ?? [],
...body.brand,
},
} as any,
})
}
@@ -513,7 +513,7 @@ router.patch('/companies/:id', requireAdminAuth, requireAdminRole('SUPPORT'), as
create: {
companyId: req.params.id,
...body.contractSettings,
},
} as any,
})
}
@@ -524,7 +524,7 @@ router.patch('/companies/:id', requireAdminAuth, requireAdminRole('SUPPORT'), as
create: {
companyId: req.params.id,
...body.accountingSettings,
},
} as any,
})
}
@@ -721,7 +721,7 @@ router.patch('/admins/:id/permissions', requireAdminAuth, requireAdminRole('SUPE
adminUserId: req.params.id,
resource: permission.resource,
actions: permission.actions,
})),
})) as any,
}),
])
const admin = await prisma.adminUser.findUniqueOrThrow({
@@ -762,7 +762,7 @@ router.get('/billing', requireAdminAuth, requireAdminRole('FINANCE'), async (req
prisma.subscription.count({ where }),
])
const activeStatuses = ['ACTIVE', 'TRIALING']
const activeStatuses = ['ACTIVE', 'TRIALING'] as any[]
const allActive = await prisma.subscription.findMany({
where: { status: { in: activeStatuses } },
select: { plan: true, billingPeriod: true, currency: true },
+1 -1
View File
@@ -217,7 +217,7 @@ router.patch('/me', async (req, res, next) => {
const body = companySchema.parse(req.body)
const company = await prisma.company.update({
where: { id: req.companyId },
data: body,
data: body as any,
})
res.json({ data: company })
} catch (err) { next(err) }
+2 -2
View File
@@ -59,7 +59,7 @@ router.post('/', async (req, res, next) => {
dateOfBirth: body.dateOfBirth ? new Date(body.dateOfBirth) : null,
licenseExpiry: body.licenseExpiry ? new Date(body.licenseExpiry) : null,
licenseIssuedAt: body.licenseIssuedAt ? new Date(body.licenseIssuedAt) : null,
},
} as any,
})
if (body.licenseExpiry) {
await validateAndFlagLicense(customer.id).catch(() => null)
@@ -81,7 +81,7 @@ router.get('/:id', async (req, res, next) => {
router.patch('/:id', async (req, res, next) => {
try {
const body = customerSchema.partial().parse(req.body)
const updated = await prisma.customer.updateMany({ where: { id: req.params.id, companyId: req.companyId }, data: { ...body, dateOfBirth: body.dateOfBirth ? new Date(body.dateOfBirth) : undefined, licenseExpiry: body.licenseExpiry ? new Date(body.licenseExpiry) : undefined, licenseIssuedAt: body.licenseIssuedAt ? new Date(body.licenseIssuedAt) : undefined } })
const updated = await prisma.customer.updateMany({ where: { id: req.params.id, companyId: req.companyId }, data: { ...body, dateOfBirth: body.dateOfBirth ? new Date(body.dateOfBirth) : undefined, licenseExpiry: body.licenseExpiry ? new Date(body.licenseExpiry) : undefined, licenseIssuedAt: body.licenseIssuedAt ? new Date(body.licenseIssuedAt) : undefined } as any })
if (updated.count === 0) return res.status(404).json({ error: 'not_found', message: 'Customer not found', statusCode: 404 })
if (body.licenseExpiry) await validateAndFlagLicense(req.params.id).catch(() => null)
const customer = await prisma.customer.findUniqueOrThrow({ where: { id: req.params.id } })
+1 -1
View File
@@ -190,7 +190,7 @@ router.post('/reservations/:id/capture-paypal', async (req, res, next) => {
where: { paypalCaptureId: paypalOrderId, companyId: req.companyId },
})
const capture = await paypal.captureOrder(paypalOrderId)
const capture = await paypal.captureOrder(paypalOrderId) as Record<string, any>
const captureId = capture.purchase_units?.[0]?.payments?.captures?.[0]?.id ?? paypalOrderId
const updated = await prisma.rentalPayment.update({
+1 -1
View File
@@ -156,7 +156,7 @@ router.post('/', async (req, res, next) => {
}
const baseAmount = vehicle.dailyRate * totalDays
const { applied, total: pricingTotal } = await applyPricingRules(req.companyId, body.customerId, body.additionalDrivers, vehicle.dailyRate, totalDays)
const { applied, total: pricingTotal } = await applyPricingRules(req.companyId, body.customerId, body.additionalDrivers as any[], vehicle.dailyRate, totalDays)
const totalAmount = baseAmount - discountAmount + pricingTotal + body.depositAmount
const reservation = await prisma.reservation.create({
+2 -2
View File
@@ -291,7 +291,7 @@ router.post('/:slug/book', async (req, res, next) => {
const { applied, total: pricingRulesTotal } = await applyPricingRules(
company.id,
customer.id,
body.additionalDrivers,
body.additionalDrivers as any[],
vehicle.dailyRate,
totalDays,
)
@@ -484,7 +484,7 @@ router.post('/:slug/booking/:id/capture-paypal', async (req, res, next) => {
where: { paypalCaptureId: paypalOrderId, companyId: company.id },
})
const capture = await paypal.captureOrder(paypalOrderId)
const capture = await paypal.captureOrder(paypalOrderId) as Record<string, any>
const captureId = capture.purchase_units?.[0]?.payments?.captures?.[0]?.id ?? paypalOrderId
await prisma.rentalPayment.update({
+1 -1
View File
@@ -101,7 +101,7 @@ router.post('/capture-paypal', requireCompanyAuth, requireTenant, async (req, re
include: { subscription: true },
})
const capture = await paypal.captureOrder(paypalOrderId)
const capture = await paypal.captureOrder(paypalOrderId) as Record<string, any>
const captureId = capture.purchase_units?.[0]?.payments?.captures?.[0]?.id ?? paypalOrderId
await prisma.subscriptionInvoice.update({
@@ -1,5 +1,6 @@
import { AdditionalDriverCharge } from '@rentaldrivego/database'
import { prisma } from '../lib/prisma'
type AdditionalDriverCharge = 'PER_DAY' | 'FLAT' | 'FREE'
import { validateLicense } from './licenseValidationService'
export interface AdditionalDriverInput {
+8 -8
View File
@@ -50,15 +50,15 @@ export async function createCheckout(params: AmanPayCreateParams): Promise<AmanP
})
if (!res.ok) {
const err = await res.json().catch(() => ({}))
throw new Error(`AmanPay checkout failed: ${err?.message ?? res.statusText}`)
const err = await res.json().catch(() => ({})) as Record<string, unknown>
throw new Error(`AmanPay checkout failed: ${(err?.message as string) ?? res.statusText}`)
}
const json = await res.json()
const json = await res.json() as Record<string, unknown>
return {
transactionId: json.transaction_id ?? json.id,
checkoutUrl: json.checkout_url ?? json.payment_url,
status: json.status ?? 'PENDING',
transactionId: (json.transaction_id ?? json.id) as string,
checkoutUrl: (json.checkout_url ?? json.payment_url) as string,
status: (json.status ?? 'PENDING') as string,
}
}
@@ -77,8 +77,8 @@ export async function refundTransaction(transactionId: string, amount: number, r
body: JSON.stringify({ amount, reason }),
})
if (!res.ok) {
const err = await res.json().catch(() => ({}))
throw new Error(`AmanPay refund failed: ${err?.message ?? res.statusText}`)
const err = await res.json().catch(() => ({})) as Record<string, unknown>
throw new Error(`AmanPay refund failed: ${(err?.message as string) ?? res.statusText}`)
}
return res.json()
}
+24 -22
View File
@@ -2,7 +2,9 @@ import { execFile } from 'child_process'
import { promisify } from 'util'
import * as fs from 'fs/promises'
import * as path from 'path'
import { prisma } from '../lib/prisma'
import { prisma as _prisma } from '../lib/prisma'
const db = _prisma as any
const execFileAsync = promisify(execFile)
let composeCommand: 'docker-compose' | 'docker' | null = null
@@ -72,12 +74,12 @@ async function composeFilesExist(): Promise<boolean> {
}
async function rebuildServicesFromDatabase(): Promise<ServicesMap> {
const records = await prisma.companyContainer.findMany({
const records = await db.companyContainer.findMany({
include: { company: { select: { slug: true } } },
})
return Object.fromEntries(
records.map((record) => [
records.map((record: any) => [
serviceName(record.company.slug),
{
companyId: record.companyId,
@@ -225,7 +227,7 @@ function mapDockerError(err: unknown) {
}
async function setContainerError(companyId: string, message: string): Promise<void> {
await prisma.companyContainer.update({
await db.companyContainer.update({
where: { companyId },
data: { status: 'ERROR', errorMessage: message },
}).catch(() => null)
@@ -239,7 +241,7 @@ async function runContainerAction(
preStatus?: Exclude<ServiceStatus, 'ERROR'>,
): Promise<void> {
if (preStatus) {
await prisma.companyContainer.update({ where: { companyId }, data: { status: preStatus, errorMessage: null } })
await db.companyContainer.update({ where: { companyId }, data: { status: preStatus, errorMessage: null } })
}
try {
@@ -248,7 +250,7 @@ async function runContainerAction(
? ['up', '-d', '--no-recreate', serviceName(slug)]
: [command, serviceName(slug)]
await compose(...args)
await prisma.companyContainer.update({
await db.companyContainer.update({
where: { companyId },
data: { status: successStatus, errorMessage: null },
})
@@ -260,7 +262,7 @@ async function runContainerAction(
}
async function allocatePort(): Promise<number> {
const last = await prisma.companyContainer.findFirst({
const last = await db.companyContainer.findFirst({
orderBy: { port: 'desc' },
select: { port: true },
})
@@ -304,7 +306,7 @@ export async function createCompanyContainer(company: {
const name = serviceName(company.slug)
const port = await allocatePort()
const record = await prisma.companyContainer.create({
const record = await db.companyContainer.create({
data: {
companyId: company.id,
containerName: containerName(company.slug),
@@ -322,12 +324,12 @@ export async function createCompanyContainer(company: {
await compose('up', '-d', '--no-recreate', name)
const dockerId = await getDockerServiceId(company.slug)
await prisma.companyContainer.update({
await db.companyContainer.update({
where: { id: record.id },
data: { dockerId, status: 'RUNNING' },
})
} catch (err) {
await prisma.companyContainer.update({
await db.companyContainer.update({
where: { id: record.id },
data: {
status: 'ERROR',
@@ -339,7 +341,7 @@ export async function createCompanyContainer(company: {
}
export async function startCompanyContainer(companyId: string): Promise<void> {
const record = await prisma.companyContainer.findUniqueOrThrow({
const record = await db.companyContainer.findUniqueOrThrow({
where: { companyId },
include: { company: { select: { slug: true } } },
})
@@ -348,7 +350,7 @@ export async function startCompanyContainer(companyId: string): Promise<void> {
}
export async function stopCompanyContainer(companyId: string): Promise<void> {
const record = await prisma.companyContainer.findUniqueOrThrow({
const record = await db.companyContainer.findUniqueOrThrow({
where: { companyId },
include: { company: { select: { slug: true } } },
})
@@ -357,7 +359,7 @@ export async function stopCompanyContainer(companyId: string): Promise<void> {
}
export async function restartCompanyContainer(companyId: string): Promise<void> {
const record = await prisma.companyContainer.findUniqueOrThrow({
const record = await db.companyContainer.findUniqueOrThrow({
where: { companyId },
include: { company: { select: { slug: true } } },
})
@@ -366,13 +368,13 @@ export async function restartCompanyContainer(companyId: string): Promise<void>
}
export async function removeCompanyContainer(companyId: string): Promise<void> {
const record = await prisma.companyContainer.findUniqueOrThrow({
const record = await db.companyContainer.findUniqueOrThrow({
where: { companyId },
include: { company: { select: { slug: true } } },
})
const name = serviceName(record.company.slug)
await prisma.companyContainer.update({ where: { companyId }, data: { status: 'REMOVING' } })
await db.companyContainer.update({ where: { companyId }, data: { status: 'REMOVING' } })
try {
await compose('stop', name)
@@ -386,7 +388,7 @@ export async function removeCompanyContainer(companyId: string): Promise<void> {
delete services[name]
await writeServices(services)
await prisma.companyContainer.delete({ where: { companyId } })
await db.companyContainer.delete({ where: { companyId } })
}
export async function redeployCompanyContainer(company: {
@@ -396,11 +398,11 @@ export async function redeployCompanyContainer(company: {
}): Promise<void> {
const name = serviceName(company.slug)
const existing = await prisma.companyContainer.findUnique({ where: { companyId: company.id } })
const existing = await db.companyContainer.findUnique({ where: { companyId: company.id } })
if (existing) {
try { await compose('stop', name) } catch { /* ok */ }
try { await compose('rm', '-f', name) } catch { /* ok */ }
await prisma.companyContainer.delete({ where: { companyId: company.id } })
await db.companyContainer.delete({ where: { companyId: company.id } })
}
// Remove from compose file too, then recreate
@@ -412,7 +414,7 @@ export async function redeployCompanyContainer(company: {
}
export async function getContainerLogs(companyId: string, tail = 150): Promise<string> {
const record = await prisma.companyContainer.findUniqueOrThrow({
const record = await db.companyContainer.findUniqueOrThrow({
where: { companyId },
include: { company: { select: { slug: true } } },
})
@@ -431,7 +433,7 @@ export async function getContainerLogs(companyId: string, tail = 150): Promise<s
}
export async function syncContainerStatuses(): Promise<void> {
const records = await prisma.companyContainer.findMany({
const records = await db.companyContainer.findMany({
where: { status: { notIn: ['PENDING', 'CREATING', 'REMOVING'] } },
include: { company: { select: { slug: true } } },
})
@@ -451,13 +453,13 @@ export async function syncContainerStatuses(): Promise<void> {
const stateByService = Object.fromEntries(rows.map((r) => [r.Service, r.State]))
await Promise.allSettled(
records.map(async (rec) => {
records.map(async (rec: any) => {
const name = serviceName(rec.company.slug)
const dockerState = stateByService[name]
const status = dockerState ? mapDockerState(dockerState) : 'STOPPED'
if (rec.status !== status) {
await prisma.companyContainer.update({ where: { id: rec.id }, data: { status } })
await db.companyContainer.update({ where: { id: rec.id }, data: { status } })
}
}),
)
+2 -2
View File
@@ -135,7 +135,7 @@ export async function sendNotification(opts: SendNotificationOptions) {
type: opts.type,
title: opts.title,
body: opts.body,
data: opts.data ?? {},
data: (opts.data ?? {}) as any,
channel,
status: 'PENDING',
companyId: opts.companyId ?? null,
@@ -181,7 +181,7 @@ export async function sendNotification(opts: SendNotificationOptions) {
: process.env.MAIL_REPLY_TO_ADDRESS
: undefined,
})
providerMessageId = info.messageId
providerMessageId = info.messageId ?? null
success = true
} else {
throw new Error('No email provider is configured')
+9 -9
View File
@@ -19,8 +19,8 @@ async function getAccessToken(): Promise<string> {
})
if (!res.ok) throw new Error('PayPal: failed to obtain access token')
const json = await res.json()
cachedToken = { token: json.access_token, expiresAt: Date.now() + json.expires_in * 1000 }
const json = await res.json() as Record<string, unknown>
cachedToken = { token: json.access_token as string, expiresAt: Date.now() + (json.expires_in as number) * 1000 }
return cachedToken.token
}
@@ -35,10 +35,10 @@ async function ppFetch(path: string, init?: RequestInit) {
},
})
if (!res.ok) {
const err = await res.json().catch(() => ({}))
throw new Error(`PayPal ${path} failed: ${err?.message ?? res.statusText}`)
const err = await res.json().catch(() => ({})) as Record<string, unknown>
throw new Error(`PayPal ${path} failed: ${(err?.message as string) ?? res.statusText}`)
}
return res.json()
return res.json() as Promise<Record<string, unknown>>
}
export interface PayPalCreateOrderParams {
@@ -80,11 +80,11 @@ export async function createOrder(params: PayPalCreateOrderParams): Promise<PayP
}),
})
const approveLink = json.links?.find((l: { rel: string; href: string }) => l.rel === 'approve')
const approveLink = (json.links as Array<{ rel: string; href: string }> | undefined)?.find((l) => l.rel === 'approve')
return {
orderId: json.id,
orderId: json.id as string,
approveUrl: approveLink?.href ?? '',
status: json.status,
status: json.status as string,
}
}
@@ -116,7 +116,7 @@ export async function verifyWebhookEvent(headers: Record<string, string | undefi
webhook_event: JSON.parse(rawBody),
}),
})
return json.verification_status === 'SUCCESS'
return (json as Record<string, unknown>).verification_status === 'SUCCESS'
} catch {
return false
}