This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
import { createHash } from 'node:crypto'
|
||||
import { Prisma } from '@prisma/client'
|
||||
import { prisma } from './db.js'
|
||||
|
||||
interface DemoWorkspaceAccess {
|
||||
teamUuid: string
|
||||
userId: string
|
||||
}
|
||||
|
||||
interface DemoRoute {
|
||||
title: string
|
||||
sourceCountryCode: string
|
||||
sourceLocationName: string
|
||||
sourceLatitude: number
|
||||
sourceLongitude: number
|
||||
destinationCountryCode: string
|
||||
destinationLocationName: string
|
||||
destinationLatitude: number
|
||||
destinationLongitude: number
|
||||
transportTypeCode: string
|
||||
amountUsd: number
|
||||
etaDays: number
|
||||
grossWeightKg: number
|
||||
volumeCbm: number
|
||||
routeDistanceKm: number
|
||||
}
|
||||
|
||||
const demoRoutes: DemoRoute[] = [
|
||||
{
|
||||
title: 'Mombasa → Almaty',
|
||||
sourceCountryCode: 'KE',
|
||||
sourceLocationName: 'Mombasa',
|
||||
sourceLatitude: -4.0435,
|
||||
sourceLongitude: 39.6682,
|
||||
destinationCountryCode: 'KZ',
|
||||
destinationLocationName: 'Almaty',
|
||||
destinationLatitude: 43.2389,
|
||||
destinationLongitude: 76.8897,
|
||||
transportTypeCode: 'MULTIMODAL',
|
||||
amountUsd: 2450,
|
||||
etaDays: 16,
|
||||
grossWeightKg: 18400,
|
||||
volumeCbm: 68,
|
||||
routeDistanceKm: 8240,
|
||||
},
|
||||
{
|
||||
title: 'Casablanca → Moscow',
|
||||
sourceCountryCode: 'MA',
|
||||
sourceLocationName: 'Casablanca',
|
||||
sourceLatitude: 33.5731,
|
||||
sourceLongitude: -7.5898,
|
||||
destinationCountryCode: 'RU',
|
||||
destinationLocationName: 'Moscow',
|
||||
destinationLatitude: 55.7558,
|
||||
destinationLongitude: 37.6173,
|
||||
transportTypeCode: 'MULTIMODAL',
|
||||
amountUsd: 3100,
|
||||
etaDays: 12,
|
||||
grossWeightKg: 12600,
|
||||
volumeCbm: 52,
|
||||
routeDistanceKm: 5060,
|
||||
},
|
||||
{
|
||||
title: 'Nairobi → Dubai',
|
||||
sourceCountryCode: 'KE',
|
||||
sourceLocationName: 'Nairobi',
|
||||
sourceLatitude: -1.2921,
|
||||
sourceLongitude: 36.8219,
|
||||
destinationCountryCode: 'AE',
|
||||
destinationLocationName: 'Dubai',
|
||||
destinationLatitude: 25.2048,
|
||||
destinationLongitude: 55.2708,
|
||||
transportTypeCode: 'AIR',
|
||||
amountUsd: 1850,
|
||||
etaDays: 4,
|
||||
grossWeightKg: 4200,
|
||||
volumeCbm: 18,
|
||||
routeDistanceKm: 3560,
|
||||
},
|
||||
{
|
||||
title: 'Johannesburg → Warsaw',
|
||||
sourceCountryCode: 'ZA',
|
||||
sourceLocationName: 'Johannesburg',
|
||||
sourceLatitude: -26.2041,
|
||||
sourceLongitude: 28.0473,
|
||||
destinationCountryCode: 'PL',
|
||||
destinationLocationName: 'Warsaw',
|
||||
destinationLatitude: 52.2297,
|
||||
destinationLongitude: 21.0122,
|
||||
transportTypeCode: 'AIR',
|
||||
amountUsd: 4200,
|
||||
etaDays: 7,
|
||||
grossWeightKg: 7600,
|
||||
volumeCbm: 31,
|
||||
routeDistanceKm: 8690,
|
||||
},
|
||||
]
|
||||
|
||||
const demoNote = JSON.stringify({ seed: 'empty-team-workspace' })
|
||||
|
||||
function stableUuid(teamUuid: string, entity: string, index: number): string {
|
||||
const hex = createHash('sha256')
|
||||
.update(`${teamUuid}:${entity}:${index}`)
|
||||
.digest('hex')
|
||||
.slice(0, 32)
|
||||
.split('')
|
||||
hex[12] = '4'
|
||||
hex[16] = '8'
|
||||
const value = hex.join('')
|
||||
return `${value.slice(0, 8)}-${value.slice(8, 12)}-${value.slice(12, 16)}-${value.slice(16, 20)}-${value.slice(20)}`
|
||||
}
|
||||
|
||||
export async function ensureDemoWorkspaceData(access: DemoWorkspaceAccess): Promise<void> {
|
||||
const [quotationCount, orderCount] = await Promise.all([
|
||||
prisma.quotation.count({ where: { teamUuid: access.teamUuid } }),
|
||||
prisma.order.count({ where: { teamUuid: access.teamUuid } }),
|
||||
])
|
||||
const needsCalculations = quotationCount === 0
|
||||
const needsOrders = orderCount === 0
|
||||
if (!needsCalculations && !needsOrders) return
|
||||
|
||||
for (const [index, route] of demoRoutes.entries()) {
|
||||
const createsOrder = index < 2
|
||||
if (!needsCalculations && !(needsOrders && createsOrder)) continue
|
||||
|
||||
const tariffUuid = stableUuid(access.teamUuid, 'demo-tariff', index)
|
||||
const tariff = await prisma.tariffReference.upsert({
|
||||
where: { uuid: tariffUuid },
|
||||
create: {
|
||||
uuid: tariffUuid,
|
||||
teamUuid: access.teamUuid,
|
||||
createdByUserId: access.userId,
|
||||
name: route.title,
|
||||
status: 'active',
|
||||
operationCode: 'IMPORT',
|
||||
transportTypeCode: route.transportTypeCode,
|
||||
sourceCountryCode: route.sourceCountryCode,
|
||||
destinationCountryCode: route.destinationCountryCode,
|
||||
amountUsd: new Prisma.Decimal(route.amountUsd),
|
||||
minPriceUsd: new Prisma.Decimal(route.amountUsd),
|
||||
etaDays: route.etaDays,
|
||||
priority: 50 + index,
|
||||
currency: 'USD',
|
||||
notes: demoNote,
|
||||
},
|
||||
update: {
|
||||
teamUuid: access.teamUuid,
|
||||
createdByUserId: access.userId,
|
||||
amountUsd: new Prisma.Decimal(route.amountUsd),
|
||||
minPriceUsd: new Prisma.Decimal(route.amountUsd),
|
||||
etaDays: route.etaDays,
|
||||
notes: demoNote,
|
||||
},
|
||||
})
|
||||
|
||||
const quotationUuid = stableUuid(access.teamUuid, 'demo-quotation', index)
|
||||
const quotation = await prisma.quotation.upsert({
|
||||
where: { uuid: quotationUuid },
|
||||
create: {
|
||||
uuid: quotationUuid,
|
||||
teamUuid: access.teamUuid,
|
||||
createdByUserId: access.userId,
|
||||
title: route.title,
|
||||
status: createsOrder && needsOrders ? 'converted' : 'priced',
|
||||
operationCode: 'IMPORT',
|
||||
incotermsCode: 'DAP',
|
||||
transportTypeCode: route.transportTypeCode,
|
||||
sourceCountryCode: route.sourceCountryCode,
|
||||
sourceLocationName: route.sourceLocationName,
|
||||
sourceLatitude: route.sourceLatitude,
|
||||
sourceLongitude: route.sourceLongitude,
|
||||
destinationCountryCode: route.destinationCountryCode,
|
||||
destinationLocationName: route.destinationLocationName,
|
||||
destinationLatitude: route.destinationLatitude,
|
||||
destinationLongitude: route.destinationLongitude,
|
||||
grossWeightKg: new Prisma.Decimal(route.grossWeightKg),
|
||||
chargeableWeightKg: new Prisma.Decimal(route.grossWeightKg),
|
||||
volumeCbm: new Prisma.Decimal(route.volumeCbm),
|
||||
unitsCount: 1 + index,
|
||||
routeDistanceKm: route.routeDistanceKm,
|
||||
selectedTariffId: tariff.id,
|
||||
tariffMatchSummary: `Demo tariff: ${route.title}`,
|
||||
totalAmount: new Prisma.Decimal(route.amountUsd),
|
||||
currency: 'USD',
|
||||
etaDays: route.etaDays,
|
||||
notes: demoNote,
|
||||
},
|
||||
update: {
|
||||
teamUuid: access.teamUuid,
|
||||
createdByUserId: access.userId,
|
||||
selectedTariffId: tariff.id,
|
||||
totalAmount: new Prisma.Decimal(route.amountUsd),
|
||||
currency: 'USD',
|
||||
etaDays: route.etaDays,
|
||||
notes: demoNote,
|
||||
},
|
||||
})
|
||||
|
||||
if (!needsOrders || !createsOrder) continue
|
||||
await prisma.order.upsert({
|
||||
where: { uuid: stableUuid(access.teamUuid, 'demo-order', index) },
|
||||
create: {
|
||||
uuid: stableUuid(access.teamUuid, 'demo-order', index),
|
||||
teamUuid: access.teamUuid,
|
||||
quotationId: quotation.id,
|
||||
createdByUserId: access.userId,
|
||||
name: route.title,
|
||||
status: index === 0 ? 'in_transit' : 'processing',
|
||||
totalAmount: new Prisma.Decimal(route.amountUsd),
|
||||
currency: 'USD',
|
||||
sourceLocationName: route.sourceLocationName,
|
||||
sourceCountryCode: route.sourceCountryCode,
|
||||
sourceLatitude: route.sourceLatitude,
|
||||
sourceLongitude: route.sourceLongitude,
|
||||
destinationLocationName: route.destinationLocationName,
|
||||
destinationCountryCode: route.destinationCountryCode,
|
||||
destinationLatitude: route.destinationLatitude,
|
||||
destinationLongitude: route.destinationLongitude,
|
||||
etaDays: route.etaDays,
|
||||
notes: demoNote,
|
||||
},
|
||||
update: {
|
||||
teamUuid: access.teamUuid,
|
||||
createdByUserId: access.userId,
|
||||
status: index === 0 ? 'in_transit' : 'processing',
|
||||
totalAmount: new Prisma.Decimal(route.amountUsd),
|
||||
currency: 'USD',
|
||||
notes: demoNote,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user