57 lines
2.4 KiB
TypeScript
57 lines
2.4 KiB
TypeScript
import { prisma } from '../lib/prisma'
|
|
|
|
interface DriverInfo {
|
|
dateOfBirth?: Date | null
|
|
licenseIssuedAt?: Date | null
|
|
}
|
|
|
|
export async function applyPricingRules(
|
|
companyId: string,
|
|
customerId: string,
|
|
additionalDrivers: DriverInfo[],
|
|
dailyRate: number,
|
|
totalDays: number
|
|
): Promise<{ applied: any[]; total: number }> {
|
|
const rules = await prisma.pricingRule.findMany({ where: { companyId, isActive: true } })
|
|
const customer = await prisma.customer.findUniqueOrThrow({ where: { id: customerId } })
|
|
const allDrivers: DriverInfo[] = [customer, ...additionalDrivers]
|
|
const applied: any[] = []
|
|
const baseAmount = dailyRate * totalDays
|
|
|
|
for (const driver of allDrivers) {
|
|
for (const rule of rules) {
|
|
const driverAge = driver.dateOfBirth
|
|
? Math.floor((Date.now() - driver.dateOfBirth.getTime()) / (365.25 * 24 * 60 * 60 * 1000))
|
|
: null
|
|
const licenseYears = driver.licenseIssuedAt
|
|
? Math.floor((Date.now() - driver.licenseIssuedAt.getTime()) / (365.25 * 24 * 60 * 60 * 1000))
|
|
: null
|
|
|
|
let conditionMet = false
|
|
if (rule.condition === 'AGE_LESS_THAN' && driverAge !== null) conditionMet = driverAge < rule.conditionValue
|
|
else if (rule.condition === 'AGE_GREATER_THAN' && driverAge !== null) conditionMet = driverAge > rule.conditionValue
|
|
else if (rule.condition === 'LICENSE_YEARS_LESS_THAN' && licenseYears !== null) conditionMet = licenseYears < rule.conditionValue
|
|
else if (rule.condition === 'LICENSE_YEARS_GREATER_THAN' && licenseYears !== null) conditionMet = licenseYears > rule.conditionValue
|
|
|
|
if (!conditionMet) continue
|
|
|
|
let amount = 0
|
|
if (rule.adjustmentType === 'PERCENTAGE') amount = Math.round(baseAmount * rule.adjustmentValue / 100)
|
|
else if (rule.adjustmentType === 'FLAT_PER_DAY') amount = rule.adjustmentValue * totalDays
|
|
else amount = rule.adjustmentValue
|
|
|
|
if (rule.type === 'DISCOUNT') amount = -amount
|
|
applied.push({ ruleId: rule.id, name: rule.name, type: rule.type, amount })
|
|
}
|
|
}
|
|
|
|
// Deduplicate: each rule applied once even if multiple drivers qualify
|
|
const deduped = applied.reduce((acc: any[], item) => {
|
|
if (!acc.find((a) => a.ruleId === item.ruleId)) acc.push(item)
|
|
return acc
|
|
}, [])
|
|
|
|
const total = deduped.reduce((s: number, r: any) => s + r.amount, 0)
|
|
return { applied: deduped, total }
|
|
}
|