add pricing feature

This commit is contained in:
root
2026-06-02 01:15:04 -04:00
parent 05d7b1bf8c
commit 0df950f2b1
18 changed files with 2364 additions and 29 deletions
@@ -77,6 +77,22 @@ describe('Vehicles API', () => {
expect(res.body.data.dropoffLocations).toEqual(['Rabat Downtown'])
})
it('creates a vehicle without a daily rate and defaults it to zero', async () => {
const res = await request(app)
.post('/api/v1/vehicles')
.set(authHeader(token))
.send({
make: 'Nissan',
model: 'Micra',
year: 2024,
licensePlate: `ZERO-${Date.now()}`,
category: 'ECONOMY',
})
expect(res.status).toBe(201)
expect(res.body.data.dailyRate).toBe(0)
})
it('returns 400 for missing required fields', async () => {
const res = await request(app)
.post('/api/v1/vehicles')
@@ -228,4 +244,101 @@ describe('Vehicles API', () => {
expect(res.status).toBe(404)
})
})
describe('Vehicle pricing management', () => {
it('returns a default pricing configuration for a vehicle', async () => {
const vehicle = await createVehicle(companyId, { dailyRate: 6250 })
const res = await request(app)
.get(`/api/v1/vehicles/${vehicle.id}/pricing`)
.set(authHeader(token))
expect(res.status).toBe(200)
expect(res.body.data.configuration.baseDailyRate).toBe(6250)
expect(res.body.data.configuration.pricingMode).toBe('MANUAL')
expect(Array.isArray(res.body.data.preview.next14Days)).toBe(true)
expect(res.body.data.preview.next14Days.length).toBe(14)
})
it('updates vehicle pricing configuration and syncs the vehicle daily rate', async () => {
const vehicle = await createVehicle(companyId, { dailyRate: 5000 })
const res = await request(app)
.put(`/api/v1/vehicles/${vehicle.id}/pricing`)
.set(authHeader(token))
.send({
pricingMode: 'AUTOMATIC',
baseDailyRate: 6400,
weeklyRate: 39900,
weekendRate: 7200,
holidayRate: null,
monthlyRate: 118000,
longTermDailyRate: 5600,
minimumDailyRate: 5900,
maximumDailyRate: 8600,
maxDailyPriceMovementPct: 12,
automaticPricingEnabled: true,
approvalRequired: true,
note: 'Summer setup',
})
expect(res.status).toBe(200)
expect(res.body.data.configuration.pricingMode).toBe('AUTOMATIC')
expect(res.body.data.configuration.baseDailyRate).toBe(6400)
expect(res.body.data.history[0].note).toBe('Summer setup')
const updatedVehicle = await prisma.vehicle.findUniqueOrThrow({ where: { id: vehicle.id } })
expect(updatedVehicle.dailyRate).toBe(6400)
})
it('creates, updates, and deletes pricing rules', async () => {
const vehicle = await createVehicle(companyId, { dailyRate: 5400 })
const createRes = await request(app)
.post(`/api/v1/vehicles/${vehicle.id}/pricing/rules`)
.set(authHeader(token))
.send({
name: 'Summer high season',
ruleType: 'SEASONAL',
startDate: '2026-07-01',
endDate: '2026-08-31',
dailyRate: 7800,
weeklyRate: 46900,
weekendRate: null,
monthlyRate: null,
minDailyRate: null,
maxDailyRate: null,
automaticAdjustmentPct: null,
priceAdjustment: null,
isActive: true,
sortOrder: 30,
})
expect(createRes.status).toBe(201)
expect(createRes.body.data.rules.length).toBe(1)
const createdRule = createRes.body.data.rules[0]
const updateRes = await request(app)
.patch(`/api/v1/vehicles/${vehicle.id}/pricing/rules/${createdRule.id}`)
.set(authHeader(token))
.send({
dailyRate: 8100,
weeklyRate: 48900,
sortOrder: 40,
})
expect(updateRes.status).toBe(200)
const updatedRule = updateRes.body.data.rules.find((rule: any) => rule.id === createdRule.id)
expect(updatedRule.dailyRate).toBe(8100)
expect(updatedRule.weeklyRate).toBe(48900)
const deleteRes = await request(app)
.delete(`/api/v1/vehicles/${vehicle.id}/pricing/rules/${createdRule.id}`)
.set(authHeader(token))
expect(deleteRes.status).toBe(200)
expect(deleteRes.body.data.rules).toHaveLength(0)
expect(deleteRes.body.data.history.length).toBeGreaterThanOrEqual(1)
})
})
})
+3
View File
@@ -32,6 +32,9 @@ const delegates = [
'offerVehicle',
'offer',
'vehicleCalendarBlock',
'vehiclePriceHistory',
'vehiclePricingRule',
'vehiclePricingConfiguration',
'maintenanceLog',
'vehicle',
'employee',