Persist multimodal order routes
Build and deploy Docker image / build (push) Successful in 1m2s

This commit is contained in:
Ruslan Bakiev
2026-08-24 21:45:05 +07:00
parent c3464e5f3f
commit f1ecd83e9c
5 changed files with 575 additions and 28 deletions
@@ -0,0 +1,141 @@
-- AlterTable
ALTER TABLE "orders_order" ADD COLUMN "destination_hub_uuid" VARCHAR(100),
ADD COLUMN "source_hub_uuid" VARCHAR(100);
-- CreateTable
CREATE TABLE "orders_quotation_route_stage" (
"id" SERIAL NOT NULL,
"uuid" TEXT NOT NULL,
"quotation_id" INTEGER NOT NULL,
"sequence" INTEGER NOT NULL,
"stage_type" VARCHAR(30) NOT NULL,
"transport_type" VARCHAR(50),
"source_point_uuid" VARCHAR(100),
"source_point_type" VARCHAR(30) NOT NULL,
"source_location_name" VARCHAR(255) NOT NULL,
"source_latitude" DOUBLE PRECISION,
"source_longitude" DOUBLE PRECISION,
"destination_point_uuid" VARCHAR(100),
"destination_point_type" VARCHAR(30) NOT NULL,
"destination_location_name" VARCHAR(255) NOT NULL,
"destination_latitude" DOUBLE PRECISION,
"destination_longitude" DOUBLE PRECISION,
"distance_km" DOUBLE PRECISION,
"travel_time_seconds" INTEGER,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "orders_quotation_route_stage_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "orders_order_route_stage" (
"id" SERIAL NOT NULL,
"uuid" TEXT NOT NULL,
"order_id" INTEGER NOT NULL,
"quotation_route_stage_uuid" VARCHAR(100),
"sequence" INTEGER NOT NULL,
"stage_type" VARCHAR(30) NOT NULL,
"transport_type" VARCHAR(50),
"source_point_uuid" VARCHAR(100),
"source_point_type" VARCHAR(30) NOT NULL,
"source_location_name" VARCHAR(255) NOT NULL,
"source_latitude" DOUBLE PRECISION,
"source_longitude" DOUBLE PRECISION,
"destination_point_uuid" VARCHAR(100),
"destination_point_type" VARCHAR(30) NOT NULL,
"destination_location_name" VARCHAR(255) NOT NULL,
"destination_latitude" DOUBLE PRECISION,
"destination_longitude" DOUBLE PRECISION,
"distance_km" DOUBLE PRECISION,
"travel_time_seconds" INTEGER,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "orders_order_route_stage_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "orders_quotation_route_stage_uuid_key" ON "orders_quotation_route_stage"("uuid");
-- CreateIndex
CREATE INDEX "orders_quotation_route_stage_quotation_id_sequence_idx" ON "orders_quotation_route_stage"("quotation_id", "sequence");
-- CreateIndex
CREATE UNIQUE INDEX "orders_quotation_route_stage_quotation_id_sequence_key" ON "orders_quotation_route_stage"("quotation_id", "sequence");
-- CreateIndex
CREATE UNIQUE INDEX "orders_order_route_stage_uuid_key" ON "orders_order_route_stage"("uuid");
-- CreateIndex
CREATE INDEX "orders_order_route_stage_order_id_sequence_idx" ON "orders_order_route_stage"("order_id", "sequence");
-- CreateIndex
CREATE UNIQUE INDEX "orders_order_route_stage_order_id_sequence_key" ON "orders_order_route_stage"("order_id", "sequence");
-- AddForeignKey
ALTER TABLE "orders_quotation_route_stage" ADD CONSTRAINT "orders_quotation_route_stage_quotation_id_fkey" FOREIGN KEY ("quotation_id") REFERENCES "orders_quotation"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "orders_order_route_stage" ADD CONSTRAINT "orders_order_route_stage_order_id_fkey" FOREIGN KEY ("order_id") REFERENCES "orders_order"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- Backfill immutable quotation route snapshots for existing calculations.
INSERT INTO "orders_quotation_route_stage" (
"uuid", "quotation_id", "sequence", "stage_type", "transport_type",
"source_point_uuid", "source_point_type", "source_location_name", "source_latitude", "source_longitude",
"destination_point_uuid", "destination_point_type", "destination_location_name", "destination_latitude", "destination_longitude",
"distance_km", "updated_at"
)
SELECT
quotation."uuid" || '-first-mile', quotation."id", 1, 'FIRST_MILE', 'AUTO',
quotation."source_location_uuid", 'ADDRESS', COALESCE(quotation."source_location_name", 'Origin'), quotation."source_latitude", quotation."source_longitude",
quotation."source_hub_uuid", 'HUB', COALESCE(quotation."source_hub_uuid", 'Origin hub'), NULL, NULL,
NULL, CURRENT_TIMESTAMP
FROM "orders_quotation" quotation
UNION ALL
SELECT
quotation."uuid" || '-main-haul', quotation."id", 2, 'MAIN_HAUL', COALESCE(quotation."transport_type_code", 'MULTIMODAL'),
quotation."source_hub_uuid", 'HUB', COALESCE(quotation."source_hub_uuid", 'Origin hub'), NULL, NULL,
quotation."destination_hub_uuid", 'HUB', COALESCE(quotation."destination_hub_uuid", 'Destination hub'), NULL, NULL,
quotation."route_distance_km", CURRENT_TIMESTAMP
FROM "orders_quotation" quotation
UNION ALL
SELECT
quotation."uuid" || '-last-mile', quotation."id", 3, 'LAST_MILE', 'AUTO',
quotation."destination_hub_uuid", 'HUB', COALESCE(quotation."destination_hub_uuid", 'Destination hub'), NULL, NULL,
quotation."destination_location_uuid", 'ADDRESS', COALESCE(quotation."destination_location_name", 'Destination'), quotation."destination_latitude", quotation."destination_longitude",
NULL, CURRENT_TIMESTAMP
FROM "orders_quotation" quotation;
UPDATE "orders_order" order_row
SET
"source_hub_uuid" = quotation."source_hub_uuid",
"destination_hub_uuid" = quotation."destination_hub_uuid"
FROM "orders_quotation" quotation
WHERE order_row."quotation_id" = quotation."id";
INSERT INTO "orders_order_route_stage" (
"uuid", "order_id", "quotation_route_stage_uuid", "sequence", "stage_type", "transport_type",
"source_point_uuid", "source_point_type", "source_location_name", "source_latitude", "source_longitude",
"destination_point_uuid", "destination_point_type", "destination_location_name", "destination_latitude", "destination_longitude",
"distance_km", "travel_time_seconds", "updated_at"
)
SELECT
order_row."uuid" || '-stage-' || route_stage."sequence", order_row."id", route_stage."uuid", route_stage."sequence", route_stage."stage_type", route_stage."transport_type",
route_stage."source_point_uuid", route_stage."source_point_type", route_stage."source_location_name", route_stage."source_latitude", route_stage."source_longitude",
route_stage."destination_point_uuid", route_stage."destination_point_type", route_stage."destination_location_name", route_stage."destination_latitude", route_stage."destination_longitude",
route_stage."distance_km", route_stage."travel_time_seconds", CURRENT_TIMESTAMP
FROM "orders_order" order_row
JOIN "orders_quotation_route_stage" route_stage ON route_stage."quotation_id" = order_row."quotation_id";
INSERT INTO "orders_order_route_stage" (
"uuid", "order_id", "sequence", "stage_type", "transport_type",
"source_point_type", "source_location_name", "source_latitude", "source_longitude",
"destination_point_type", "destination_location_name", "destination_latitude", "destination_longitude", "updated_at"
)
SELECT
order_row."uuid" || '-stage-1', order_row."id", 1, 'MAIN_HAUL', 'MULTIMODAL',
'ADDRESS', COALESCE(order_row."source_location_name", 'Origin'), order_row."source_latitude", order_row."source_longitude",
'ADDRESS', COALESCE(order_row."destination_location_name", 'Destination'), order_row."destination_latitude", order_row."destination_longitude", CURRENT_TIMESTAMP
FROM "orders_order" order_row
WHERE order_row."quotation_id" IS NULL;
+62
View File
@@ -95,12 +95,41 @@ model Quotation {
orders Order[]
changes QuotationChange[]
routeStages QuotationRouteStage[]
@@index([teamUuid, status, createdAt])
@@index([teamUuid, sourceCountryCode, destinationCountryCode])
@@map("orders_quotation")
}
model QuotationRouteStage {
id Int @id @default(autoincrement())
uuid String @unique @default(uuid())
quotationId Int @map("quotation_id")
quotation Quotation @relation(fields: [quotationId], references: [id], onDelete: Cascade)
sequence Int
stageType String @map("stage_type") @db.VarChar(30)
transportType String? @map("transport_type") @db.VarChar(50)
sourcePointUuid String? @map("source_point_uuid") @db.VarChar(100)
sourcePointType String @map("source_point_type") @db.VarChar(30)
sourceLocationName String @map("source_location_name") @db.VarChar(255)
sourceLatitude Float? @map("source_latitude")
sourceLongitude Float? @map("source_longitude")
destinationPointUuid String? @map("destination_point_uuid") @db.VarChar(100)
destinationPointType String @map("destination_point_type") @db.VarChar(30)
destinationLocationName String @map("destination_location_name") @db.VarChar(255)
destinationLatitude Float? @map("destination_latitude")
destinationLongitude Float? @map("destination_longitude")
distanceKm Float? @map("distance_km")
travelTimeSeconds Int? @map("travel_time_seconds")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([quotationId, sequence])
@@index([quotationId, sequence])
@@map("orders_quotation_route_stage")
}
model QuotationChange {
id Int @id @default(autoincrement())
uuid String @unique @default(uuid())
@@ -138,6 +167,7 @@ model Order {
exchangeRateLockedAt DateTime? @map("exchange_rate_locked_at")
pricingCountryCode String? @map("pricing_country_code") @db.VarChar(2)
pricingKycProfileUuid String? @map("pricing_kyc_profile_uuid") @db.VarChar(100)
sourceHubUuid String? @map("source_hub_uuid") @db.VarChar(100)
sourceLocationUuid String? @map("source_location_uuid") @db.VarChar(100)
sourceLocationName String? @map("source_location_name") @db.VarChar(255)
sourceCountryCode String? @map("source_country_code") @db.VarChar(10)
@@ -146,6 +176,7 @@ model Order {
destinationLocationUuid String? @map("destination_location_uuid") @db.VarChar(100)
destinationLocationName String? @map("destination_location_name") @db.VarChar(255)
destinationCountryCode String? @map("destination_country_code") @db.VarChar(10)
destinationHubUuid String? @map("destination_hub_uuid") @db.VarChar(100)
destinationLatitude Float? @map("destination_latitude")
destinationLongitude Float? @map("destination_longitude")
etaDays Int? @map("eta_days")
@@ -153,6 +184,37 @@ model Order {
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
routeStages OrderRouteStage[]
@@index([teamUuid, createdAt])
@@map("orders_order")
}
model OrderRouteStage {
id Int @id @default(autoincrement())
uuid String @unique @default(uuid())
orderId Int @map("order_id")
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
quotationRouteStageUuid String? @map("quotation_route_stage_uuid") @db.VarChar(100)
sequence Int
stageType String @map("stage_type") @db.VarChar(30)
transportType String? @map("transport_type") @db.VarChar(50)
sourcePointUuid String? @map("source_point_uuid") @db.VarChar(100)
sourcePointType String @map("source_point_type") @db.VarChar(30)
sourceLocationName String @map("source_location_name") @db.VarChar(255)
sourceLatitude Float? @map("source_latitude")
sourceLongitude Float? @map("source_longitude")
destinationPointUuid String? @map("destination_point_uuid") @db.VarChar(100)
destinationPointType String @map("destination_point_type") @db.VarChar(30)
destinationLocationName String @map("destination_location_name") @db.VarChar(255)
destinationLatitude Float? @map("destination_latitude")
destinationLongitude Float? @map("destination_longitude")
distanceKm Float? @map("distance_km")
travelTimeSeconds Int? @map("travel_time_seconds")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([orderId, sequence])
@@index([orderId, sequence])
@@map("orders_order_route_stage")
}