feat: Equipment-System, Buchungsbearbeitung, Kundenadresse, LexOffice-Fix
- Vintage Modell hinzugefuegt - Equipment Multi-Select (Neue Buchung + Bearbeitung) - Kundenadresse in Formularen - Bearbeiten-Seite fuer Buchungen - Abbau-Zeiten in Formularen und Uebersicht - Vertrag PDF nur bei Privatkunden - LexOffice Kontakt-Erstellung Fix (BUSINESS) - Zurueck-Pfeil auf Touren-Seite
This commit is contained in:
@@ -0,0 +1,432 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "UserRole" AS ENUM ('ADMIN', 'DRIVER');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "BookingStatus" AS ENUM ('RESERVED', 'CONFIRMED', 'READY_FOR_ASSIGNMENT', 'OPEN_FOR_DRIVERS', 'ASSIGNED', 'COMPLETED', 'CANCELLED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PhotoboxStatus" AS ENUM ('AVAILABLE', 'IN_USE', 'MAINTENANCE', 'DAMAGED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PhotoboxModel" AS ENUM ('VINTAGE_SMILE', 'VINTAGE_PHOTOS', 'NOSTALGIE', 'MAGIC_MIRROR');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "InvoiceType" AS ENUM ('PRIVATE', 'BUSINESS');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "EquipmentType" AS ENUM ('PRINTER', 'CARPET', 'VIP_BARRIER', 'ACCESSORIES_KIT', 'PRINTER_PAPER', 'TRIPOD', 'OTHER');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "EquipmentStatus" AS ENUM ('AVAILABLE', 'IN_USE', 'MAINTENANCE', 'DAMAGED', 'RESERVED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "TourStatus" AS ENUM ('PLANNED', 'IN_PROGRESS', 'COMPLETED', 'CANCELLED');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"password" TEXT NOT NULL,
|
||||
"role" "UserRole" NOT NULL DEFAULT 'DRIVER',
|
||||
"phoneNumber" TEXT,
|
||||
"vehiclePlate" TEXT,
|
||||
"vehicleModel" TEXT,
|
||||
"active" BOOLEAN NOT NULL DEFAULT true,
|
||||
"available" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Location" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"city" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"websiteUrl" TEXT NOT NULL,
|
||||
"contactEmail" TEXT NOT NULL,
|
||||
"active" BOOLEAN NOT NULL DEFAULT true,
|
||||
"warehouseAddress" TEXT,
|
||||
"warehouseZip" TEXT,
|
||||
"warehouseCity" TEXT,
|
||||
"imapHost" TEXT,
|
||||
"imapPort" INTEGER,
|
||||
"imapUser" TEXT,
|
||||
"imapPassword" TEXT,
|
||||
"imapSecure" BOOLEAN NOT NULL DEFAULT true,
|
||||
"smtpHost" TEXT,
|
||||
"smtpPort" INTEGER,
|
||||
"smtpUser" TEXT,
|
||||
"smtpPassword" TEXT,
|
||||
"smtpSecure" BOOLEAN NOT NULL DEFAULT true,
|
||||
"emailSyncEnabled" BOOLEAN NOT NULL DEFAULT false,
|
||||
"lastEmailSync" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Location_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PriceConfig" (
|
||||
"id" TEXT NOT NULL,
|
||||
"locationId" TEXT NOT NULL,
|
||||
"model" "PhotoboxModel" NOT NULL,
|
||||
"basePrice" DOUBLE PRECISION NOT NULL,
|
||||
"kmFlatRate" DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
"kmFlatRateUpTo" INTEGER NOT NULL DEFAULT 15,
|
||||
"pricePerKm" DOUBLE PRECISION NOT NULL DEFAULT 0,
|
||||
"kmMultiplier" INTEGER NOT NULL DEFAULT 4,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "PriceConfig_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Photobox" (
|
||||
"id" TEXT NOT NULL,
|
||||
"locationId" TEXT NOT NULL,
|
||||
"model" "PhotoboxModel" NOT NULL,
|
||||
"serialNumber" TEXT NOT NULL,
|
||||
"status" "PhotoboxStatus" NOT NULL DEFAULT 'AVAILABLE',
|
||||
"active" BOOLEAN NOT NULL DEFAULT true,
|
||||
"description" TEXT,
|
||||
"purchaseDate" TIMESTAMP(3),
|
||||
"lastMaintenance" TIMESTAMP(3),
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Photobox_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Booking" (
|
||||
"id" TEXT NOT NULL,
|
||||
"bookingNumber" TEXT NOT NULL,
|
||||
"locationId" TEXT NOT NULL,
|
||||
"photoboxId" TEXT,
|
||||
"status" "BookingStatus" NOT NULL DEFAULT 'RESERVED',
|
||||
"customerName" TEXT NOT NULL,
|
||||
"customerEmail" TEXT NOT NULL,
|
||||
"customerPhone" TEXT NOT NULL,
|
||||
"customerAddress" TEXT,
|
||||
"customerCity" TEXT,
|
||||
"customerZip" TEXT,
|
||||
"invoiceType" "InvoiceType" NOT NULL DEFAULT 'PRIVATE',
|
||||
"companyName" TEXT,
|
||||
"eventDate" TIMESTAMP(3) NOT NULL,
|
||||
"eventAddress" TEXT NOT NULL,
|
||||
"eventCity" TEXT NOT NULL,
|
||||
"eventZip" TEXT NOT NULL,
|
||||
"eventLocation" TEXT,
|
||||
"setupTimeStart" TIMESTAMP(3) NOT NULL,
|
||||
"setupTimeLatest" TIMESTAMP(3) NOT NULL,
|
||||
"dismantleTimeEarliest" TIMESTAMP(3),
|
||||
"dismantleTimeLatest" TIMESTAMP(3),
|
||||
"distance" DOUBLE PRECISION,
|
||||
"calculatedPrice" DOUBLE PRECISION,
|
||||
"contractSigned" BOOLEAN NOT NULL DEFAULT false,
|
||||
"contractSignedAt" TIMESTAMP(3),
|
||||
"contractGenerated" BOOLEAN NOT NULL DEFAULT false,
|
||||
"contractGeneratedAt" TIMESTAMP(3),
|
||||
"contractSentAt" TIMESTAMP(3),
|
||||
"contractSignedOnline" BOOLEAN NOT NULL DEFAULT false,
|
||||
"contractPdfUrl" TEXT,
|
||||
"contractSignatureData" TEXT,
|
||||
"contractSignedBy" TEXT,
|
||||
"contractSignedIp" TEXT,
|
||||
"contractUploadedBy" TEXT,
|
||||
"lexofficeOfferId" TEXT,
|
||||
"lexofficeInvoiceId" TEXT,
|
||||
"lexofficeContactId" TEXT,
|
||||
"lexofficeConfirmationId" TEXT,
|
||||
"confirmationSentAt" TIMESTAMP(3),
|
||||
"aiParsed" BOOLEAN NOT NULL DEFAULT false,
|
||||
"aiResponseDraft" TEXT,
|
||||
"aiProcessedAt" TIMESTAMP(3),
|
||||
"readyForAssignment" BOOLEAN NOT NULL DEFAULT false,
|
||||
"openForDrivers" BOOLEAN NOT NULL DEFAULT false,
|
||||
"calendarEventId" TEXT,
|
||||
"calendarSynced" BOOLEAN NOT NULL DEFAULT false,
|
||||
"calendarSyncedAt" TIMESTAMP(3),
|
||||
"tourId" TEXT,
|
||||
"notes" TEXT,
|
||||
"internalNotes" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Booking_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SetupWindow" (
|
||||
"id" TEXT NOT NULL,
|
||||
"bookingId" TEXT NOT NULL,
|
||||
"setupDate" TIMESTAMP(3) NOT NULL,
|
||||
"setupTimeStart" TIMESTAMP(3) NOT NULL,
|
||||
"setupTimeEnd" TIMESTAMP(3) NOT NULL,
|
||||
"preferred" BOOLEAN NOT NULL DEFAULT false,
|
||||
"selected" BOOLEAN NOT NULL DEFAULT false,
|
||||
"notes" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "SetupWindow_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Tour" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tourDate" TIMESTAMP(3) NOT NULL,
|
||||
"tourNumber" TEXT NOT NULL,
|
||||
"driverId" TEXT,
|
||||
"routeOptimized" JSONB,
|
||||
"totalDistance" DOUBLE PRECISION,
|
||||
"estimatedDuration" INTEGER,
|
||||
"status" "TourStatus" NOT NULL DEFAULT 'PLANNED',
|
||||
"startedAt" TIMESTAMP(3),
|
||||
"completedAt" TIMESTAMP(3),
|
||||
"notes" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Tour_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Notification" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT,
|
||||
"type" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"message" TEXT NOT NULL,
|
||||
"read" BOOLEAN NOT NULL DEFAULT false,
|
||||
"metadata" JSONB,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "Notification_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Email" (
|
||||
"id" TEXT NOT NULL,
|
||||
"locationSlug" TEXT,
|
||||
"from" TEXT NOT NULL,
|
||||
"to" TEXT NOT NULL,
|
||||
"subject" TEXT NOT NULL,
|
||||
"textBody" TEXT,
|
||||
"htmlBody" TEXT,
|
||||
"messageId" TEXT,
|
||||
"inReplyTo" TEXT,
|
||||
"bookingId" TEXT,
|
||||
"parsed" BOOLEAN NOT NULL DEFAULT false,
|
||||
"parsedData" JSONB,
|
||||
"direction" TEXT NOT NULL DEFAULT 'INBOUND',
|
||||
"receivedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "Email_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Project" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"active" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Project_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Equipment" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"type" "EquipmentType" NOT NULL,
|
||||
"brand" TEXT,
|
||||
"model" TEXT,
|
||||
"serialNumber" TEXT,
|
||||
"quantity" INTEGER NOT NULL DEFAULT 1,
|
||||
"status" "EquipmentStatus" NOT NULL DEFAULT 'AVAILABLE',
|
||||
"locationId" TEXT,
|
||||
"projectId" TEXT,
|
||||
"notes" TEXT,
|
||||
"purchaseDate" TIMESTAMP(3),
|
||||
"purchasePrice" DECIMAL(65,30),
|
||||
"minStockLevel" INTEGER,
|
||||
"currentStock" INTEGER,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Equipment_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "BookingEquipment" (
|
||||
"id" TEXT NOT NULL,
|
||||
"bookingId" TEXT NOT NULL,
|
||||
"equipmentId" TEXT NOT NULL,
|
||||
"quantity" INTEGER NOT NULL DEFAULT 1,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "BookingEquipment_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "DriverAvailability" (
|
||||
"id" TEXT NOT NULL,
|
||||
"bookingId" TEXT NOT NULL,
|
||||
"driverId" TEXT NOT NULL,
|
||||
"available" BOOLEAN NOT NULL DEFAULT true,
|
||||
"message" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "DriverAvailability_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Location_slug_key" ON "Location"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Location_slug_idx" ON "Location"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "PriceConfig_locationId_model_key" ON "PriceConfig"("locationId", "model");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Photobox_serialNumber_key" ON "Photobox"("serialNumber");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Photobox_locationId_model_idx" ON "Photobox"("locationId", "model");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Photobox_status_idx" ON "Photobox"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Booking_bookingNumber_key" ON "Booking"("bookingNumber");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Booking_eventDate_idx" ON "Booking"("eventDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Booking_status_idx" ON "Booking"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Booking_locationId_idx" ON "Booking"("locationId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SetupWindow_bookingId_idx" ON "SetupWindow"("bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "SetupWindow_setupDate_idx" ON "SetupWindow"("setupDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Tour_tourNumber_key" ON "Tour"("tourNumber");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Tour_tourDate_idx" ON "Tour"("tourDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Tour_driverId_idx" ON "Tour"("driverId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Tour_status_idx" ON "Tour"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Notification_userId_read_idx" ON "Notification"("userId", "read");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Email_messageId_key" ON "Email"("messageId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Email_locationSlug_idx" ON "Email"("locationSlug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Email_bookingId_idx" ON "Email"("bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Email_receivedAt_idx" ON "Email"("receivedAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Equipment_serialNumber_key" ON "Equipment"("serialNumber");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Equipment_type_idx" ON "Equipment"("type");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Equipment_status_idx" ON "Equipment"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Equipment_locationId_idx" ON "Equipment"("locationId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "BookingEquipment_bookingId_idx" ON "BookingEquipment"("bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "BookingEquipment_equipmentId_idx" ON "BookingEquipment"("equipmentId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "BookingEquipment_bookingId_equipmentId_key" ON "BookingEquipment"("bookingId", "equipmentId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "DriverAvailability_bookingId_idx" ON "DriverAvailability"("bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "DriverAvailability_driverId_idx" ON "DriverAvailability"("driverId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "DriverAvailability_bookingId_driverId_key" ON "DriverAvailability"("bookingId", "driverId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "PriceConfig" ADD CONSTRAINT "PriceConfig_locationId_fkey" FOREIGN KEY ("locationId") REFERENCES "Location"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Photobox" ADD CONSTRAINT "Photobox_locationId_fkey" FOREIGN KEY ("locationId") REFERENCES "Location"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Booking" ADD CONSTRAINT "Booking_locationId_fkey" FOREIGN KEY ("locationId") REFERENCES "Location"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Booking" ADD CONSTRAINT "Booking_photoboxId_fkey" FOREIGN KEY ("photoboxId") REFERENCES "Photobox"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Booking" ADD CONSTRAINT "Booking_tourId_fkey" FOREIGN KEY ("tourId") REFERENCES "Tour"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "SetupWindow" ADD CONSTRAINT "SetupWindow_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Tour" ADD CONSTRAINT "Tour_driverId_fkey" FOREIGN KEY ("driverId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Notification" ADD CONSTRAINT "Notification_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Email" ADD CONSTRAINT "Email_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Equipment" ADD CONSTRAINT "Equipment_locationId_fkey" FOREIGN KEY ("locationId") REFERENCES "Location"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Equipment" ADD CONSTRAINT "Equipment_projectId_fkey" FOREIGN KEY ("projectId") REFERENCES "Project"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "BookingEquipment" ADD CONSTRAINT "BookingEquipment_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "BookingEquipment" ADD CONSTRAINT "BookingEquipment_equipmentId_fkey" FOREIGN KEY ("equipmentId") REFERENCES "Equipment"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "DriverAvailability" ADD CONSTRAINT "DriverAvailability_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "DriverAvailability" ADD CONSTRAINT "DriverAvailability_driverId_fkey" FOREIGN KEY ("driverId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,12 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "Booking" ADD COLUMN "withPrintFlat" BOOLEAN NOT NULL DEFAULT true;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Equipment" ADD COLUMN "lexofficeArticleId" TEXT,
|
||||
ADD COLUMN "price" DOUBLE PRECISION;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "PriceConfig" ADD COLUMN "lexofficeArticleId" TEXT,
|
||||
ADD COLUMN "lexofficeArticleIdWithFlat" TEXT,
|
||||
ADD COLUMN "lexofficeKmExtraArticleId" TEXT,
|
||||
ADD COLUMN "lexofficeKmFlatArticleId" TEXT;
|
||||
@@ -0,0 +1,94 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "StopStatus" AS ENUM ('PENDING', 'EN_ROUTE', 'ARRIVED', 'SETUP_STARTED', 'SETUP_COMPLETE', 'PICKUP_STARTED', 'PICKUP_COMPLETE', 'SKIPPED', 'ISSUE');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PhotoType" AS ENUM ('SETUP_BEFORE', 'SETUP_AFTER', 'PICKUP_BEFORE', 'PICKUP_AFTER', 'ISSUE', 'OTHER');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "TourStop" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tourId" TEXT NOT NULL,
|
||||
"bookingId" TEXT NOT NULL,
|
||||
"stopOrder" INTEGER NOT NULL,
|
||||
"stopType" TEXT NOT NULL DEFAULT 'DELIVERY',
|
||||
"status" "StopStatus" NOT NULL DEFAULT 'PENDING',
|
||||
"arrivedAt" TIMESTAMP(3),
|
||||
"setupStartedAt" TIMESTAMP(3),
|
||||
"setupCompleteAt" TIMESTAMP(3),
|
||||
"pickupStartedAt" TIMESTAMP(3),
|
||||
"pickupCompleteAt" TIMESTAMP(3),
|
||||
"arrivalLatitude" DOUBLE PRECISION,
|
||||
"arrivalLongitude" DOUBLE PRECISION,
|
||||
"notes" TEXT,
|
||||
"issueDescription" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "TourStop_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "DriverLocation" (
|
||||
"id" TEXT NOT NULL,
|
||||
"driverId" TEXT NOT NULL,
|
||||
"latitude" DOUBLE PRECISION NOT NULL,
|
||||
"longitude" DOUBLE PRECISION NOT NULL,
|
||||
"accuracy" DOUBLE PRECISION,
|
||||
"heading" DOUBLE PRECISION,
|
||||
"speed" DOUBLE PRECISION,
|
||||
"tourId" TEXT,
|
||||
"currentStopId" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "DriverLocation_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "DeliveryPhoto" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tourStopId" TEXT NOT NULL,
|
||||
"photoType" "PhotoType" NOT NULL,
|
||||
"fileName" TEXT NOT NULL,
|
||||
"filePath" TEXT NOT NULL,
|
||||
"fileSize" INTEGER,
|
||||
"mimeType" TEXT,
|
||||
"latitude" DOUBLE PRECISION,
|
||||
"longitude" DOUBLE PRECISION,
|
||||
"caption" TEXT,
|
||||
"uploadedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "DeliveryPhoto_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TourStop_tourId_stopOrder_idx" ON "TourStop"("tourId", "stopOrder");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "TourStop_status_idx" ON "TourStop"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "TourStop_tourId_bookingId_key" ON "TourStop"("tourId", "bookingId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "DriverLocation_driverId_createdAt_idx" ON "DriverLocation"("driverId", "createdAt");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "DriverLocation_tourId_idx" ON "DriverLocation"("tourId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "DeliveryPhoto_tourStopId_idx" ON "DeliveryPhoto"("tourStopId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "DeliveryPhoto_photoType_idx" ON "DeliveryPhoto"("photoType");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TourStop" ADD CONSTRAINT "TourStop_tourId_fkey" FOREIGN KEY ("tourId") REFERENCES "Tour"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "TourStop" ADD CONSTRAINT "TourStop_bookingId_fkey" FOREIGN KEY ("bookingId") REFERENCES "Booking"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "DriverLocation" ADD CONSTRAINT "DriverLocation_driverId_fkey" FOREIGN KEY ("driverId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "DeliveryPhoto" ADD CONSTRAINT "DeliveryPhoto_tourStopId_fkey" FOREIGN KEY ("tourStopId") REFERENCES "TourStop"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
3
prisma/migrations/migration_lock.toml
Normal file
3
prisma/migrations/migration_lock.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (i.e. Git)
|
||||
provider = "postgresql"
|
||||
@@ -34,6 +34,7 @@ enum PhotoboxModel {
|
||||
VINTAGE_PHOTOS
|
||||
NOSTALGIE
|
||||
MAGIC_MIRROR
|
||||
VINTAGE
|
||||
}
|
||||
|
||||
enum InvoiceType {
|
||||
@@ -74,6 +75,7 @@ model User {
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
driverTours Tour[]
|
||||
driverLocations DriverLocation[]
|
||||
notifications Notification[]
|
||||
driverAvailability DriverAvailability[]
|
||||
}
|
||||
@@ -87,6 +89,10 @@ model Location {
|
||||
contactEmail String
|
||||
active Boolean @default(true)
|
||||
|
||||
warehouseAddress String?
|
||||
warehouseZip String?
|
||||
warehouseCity String?
|
||||
|
||||
imapHost String?
|
||||
imapPort Int?
|
||||
imapUser String?
|
||||
@@ -120,8 +126,16 @@ model PriceConfig {
|
||||
|
||||
model PhotoboxModel
|
||||
basePrice Float
|
||||
pricePerKm Float
|
||||
includedKm Int @default(0)
|
||||
|
||||
kmFlatRate Float @default(0)
|
||||
kmFlatRateUpTo Int @default(15)
|
||||
pricePerKm Float @default(0)
|
||||
kmMultiplier Int @default(4)
|
||||
|
||||
lexofficeArticleId String?
|
||||
lexofficeArticleIdWithFlat String?
|
||||
lexofficeKmFlatArticleId String?
|
||||
lexofficeKmExtraArticleId String?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
@@ -185,6 +199,8 @@ model Booking {
|
||||
dismantleTimeEarliest DateTime?
|
||||
dismantleTimeLatest DateTime?
|
||||
|
||||
withPrintFlat Boolean @default(true)
|
||||
|
||||
distance Float?
|
||||
calculatedPrice Float?
|
||||
|
||||
@@ -223,6 +239,7 @@ model Booking {
|
||||
|
||||
tourId String?
|
||||
tour Tour? @relation(fields: [tourId], references: [id])
|
||||
tourStops TourStop[]
|
||||
|
||||
notes String?
|
||||
internalNotes String?
|
||||
@@ -267,6 +284,27 @@ enum TourStatus {
|
||||
CANCELLED
|
||||
}
|
||||
|
||||
enum StopStatus {
|
||||
PENDING // Noch nicht erreicht
|
||||
EN_ROUTE // Fahrer ist unterwegs
|
||||
ARRIVED // Fahrer ist angekommen
|
||||
SETUP_STARTED // Aufbau begonnen
|
||||
SETUP_COMPLETE // Aufbau abgeschlossen
|
||||
PICKUP_STARTED // Abbau/Abholung begonnen
|
||||
PICKUP_COMPLETE // Abholung abgeschlossen
|
||||
SKIPPED // Übersprungen
|
||||
ISSUE // Problem aufgetreten
|
||||
}
|
||||
|
||||
enum PhotoType {
|
||||
SETUP_BEFORE // Vor dem Aufbau
|
||||
SETUP_AFTER // Nach dem Aufbau
|
||||
PICKUP_BEFORE // Vor dem Abbau
|
||||
PICKUP_AFTER // Nach dem Abbau
|
||||
ISSUE // Problem-Dokumentation
|
||||
OTHER // Sonstiges
|
||||
}
|
||||
|
||||
model Tour {
|
||||
id String @id @default(cuid())
|
||||
tourDate DateTime
|
||||
@@ -276,6 +314,7 @@ model Tour {
|
||||
driver User? @relation(fields: [driverId], references: [id])
|
||||
|
||||
bookings Booking[]
|
||||
tourStops TourStop[]
|
||||
|
||||
routeOptimized Json?
|
||||
totalDistance Float?
|
||||
@@ -295,6 +334,93 @@ model Tour {
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
model TourStop {
|
||||
id String @id @default(cuid())
|
||||
tourId String
|
||||
tour Tour @relation(fields: [tourId], references: [id], onDelete: Cascade)
|
||||
|
||||
bookingId String
|
||||
booking Booking @relation(fields: [bookingId], references: [id])
|
||||
|
||||
stopOrder Int // Reihenfolge der Stopps (1, 2, 3, ...)
|
||||
stopType String @default("DELIVERY") // DELIVERY, PICKUP, BOTH
|
||||
|
||||
status StopStatus @default(PENDING)
|
||||
|
||||
// Timestamps für jeden Status
|
||||
arrivedAt DateTime?
|
||||
setupStartedAt DateTime?
|
||||
setupCompleteAt DateTime?
|
||||
pickupStartedAt DateTime?
|
||||
pickupCompleteAt DateTime?
|
||||
|
||||
// Optional: GPS-Position bei Ankunft
|
||||
arrivalLatitude Float?
|
||||
arrivalLongitude Float?
|
||||
|
||||
// Notizen vom Fahrer
|
||||
notes String? @db.Text
|
||||
issueDescription String? @db.Text
|
||||
|
||||
photos DeliveryPhoto[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([tourId, bookingId])
|
||||
@@index([tourId, stopOrder])
|
||||
@@index([status])
|
||||
}
|
||||
|
||||
model DriverLocation {
|
||||
id String @id @default(cuid())
|
||||
|
||||
driverId String
|
||||
driver User @relation(fields: [driverId], references: [id], onDelete: Cascade)
|
||||
|
||||
latitude Float
|
||||
longitude Float
|
||||
accuracy Float? // GPS-Genauigkeit in Metern
|
||||
heading Float? // Richtung in Grad (0-360)
|
||||
speed Float? // Geschwindigkeit in km/h
|
||||
|
||||
tourId String?
|
||||
|
||||
// Optional: Welcher Stopp ist aktuell?
|
||||
currentStopId String?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([driverId, createdAt])
|
||||
@@index([tourId])
|
||||
}
|
||||
|
||||
model DeliveryPhoto {
|
||||
id String @id @default(cuid())
|
||||
|
||||
tourStopId String
|
||||
tourStop TourStop @relation(fields: [tourStopId], references: [id], onDelete: Cascade)
|
||||
|
||||
photoType PhotoType
|
||||
|
||||
// Dateispeicherung (z.B. /uploads/photos/...)
|
||||
fileName String
|
||||
filePath String
|
||||
fileSize Int?
|
||||
mimeType String?
|
||||
|
||||
// Optional: GPS-Position wo das Foto aufgenommen wurde
|
||||
latitude Float?
|
||||
longitude Float?
|
||||
|
||||
caption String? @db.Text
|
||||
|
||||
uploadedAt DateTime @default(now())
|
||||
|
||||
@@index([tourStopId])
|
||||
@@index([photoType])
|
||||
}
|
||||
|
||||
model Notification {
|
||||
id String @id @default(cuid())
|
||||
userId String?
|
||||
@@ -372,6 +498,9 @@ model Equipment {
|
||||
notes String?
|
||||
purchaseDate DateTime?
|
||||
purchasePrice Decimal?
|
||||
price Float?
|
||||
|
||||
lexofficeArticleId String?
|
||||
|
||||
minStockLevel Int?
|
||||
currentStock Int?
|
||||
|
||||
@@ -54,6 +54,9 @@ async function main() {
|
||||
slug: 'luebeck',
|
||||
websiteUrl: 'https://fotobox-luebeck.de',
|
||||
contactEmail: 'info@fotobox-luebeck.de',
|
||||
warehouseAddress: 'Wahmstraße 83',
|
||||
warehouseZip: '23552',
|
||||
warehouseCity: 'Lübeck',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -66,6 +69,9 @@ async function main() {
|
||||
slug: 'hamburg',
|
||||
websiteUrl: 'https://hamburg-fotobox.de',
|
||||
contactEmail: 'info@hamburg-fotobox.de',
|
||||
warehouseAddress: 'Wahmstraße 83',
|
||||
warehouseZip: '23552',
|
||||
warehouseCity: 'Lübeck',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -78,6 +84,9 @@ async function main() {
|
||||
slug: 'kiel',
|
||||
websiteUrl: 'https://fotobox-kiel.de',
|
||||
contactEmail: 'info@fotobox-kiel.de',
|
||||
warehouseAddress: 'Wahmstraße 83',
|
||||
warehouseZip: '23552',
|
||||
warehouseCity: 'Lübeck',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -90,6 +99,9 @@ async function main() {
|
||||
slug: 'berlin',
|
||||
websiteUrl: 'https://fotobox-potsdam.de',
|
||||
contactEmail: 'info@fotobox-potsdam.de',
|
||||
warehouseAddress: 'Wahmstraße 83',
|
||||
warehouseZip: '23552',
|
||||
warehouseCity: 'Lübeck',
|
||||
},
|
||||
});
|
||||
|
||||
@@ -102,35 +114,38 @@ async function main() {
|
||||
slug: 'rostock',
|
||||
websiteUrl: 'https://fotobox-rostock.de',
|
||||
contactEmail: 'info@fotobox-rostock.de',
|
||||
warehouseAddress: 'Wahmstraße 83',
|
||||
warehouseZip: '23552',
|
||||
warehouseCity: 'Lübeck',
|
||||
},
|
||||
});
|
||||
|
||||
await prisma.priceConfig.createMany({
|
||||
data: [
|
||||
{ locationId: luebeck.id, model: 'VINTAGE_SMILE', basePrice: 399, pricePerKm: 0.8, includedKm: 30 },
|
||||
{ locationId: luebeck.id, model: 'VINTAGE_PHOTOS', basePrice: 449, pricePerKm: 0.8, includedKm: 30 },
|
||||
{ locationId: luebeck.id, model: 'NOSTALGIE', basePrice: 499, pricePerKm: 0.8, includedKm: 30 },
|
||||
{ locationId: luebeck.id, model: 'MAGIC_MIRROR', basePrice: 599, pricePerKm: 0.8, includedKm: 30 },
|
||||
{ locationId: luebeck.id, model: 'VINTAGE_SMILE', basePrice: 399, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: luebeck.id, model: 'VINTAGE_PHOTOS', basePrice: 449, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: luebeck.id, model: 'NOSTALGIE', basePrice: 499, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: luebeck.id, model: 'MAGIC_MIRROR', basePrice: 599, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
|
||||
{ locationId: hamburg.id, model: 'VINTAGE_SMILE', basePrice: 419, pricePerKm: 0.9, includedKm: 25 },
|
||||
{ locationId: hamburg.id, model: 'VINTAGE_PHOTOS', basePrice: 469, pricePerKm: 0.9, includedKm: 25 },
|
||||
{ locationId: hamburg.id, model: 'NOSTALGIE', basePrice: 519, pricePerKm: 0.9, includedKm: 25 },
|
||||
{ locationId: hamburg.id, model: 'MAGIC_MIRROR', basePrice: 619, pricePerKm: 0.9, includedKm: 25 },
|
||||
{ locationId: hamburg.id, model: 'VINTAGE_SMILE', basePrice: 419, kmFlatRate: 100, kmFlatRateUpTo: 60, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: hamburg.id, model: 'VINTAGE_PHOTOS', basePrice: 469, kmFlatRate: 100, kmFlatRateUpTo: 60, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: hamburg.id, model: 'NOSTALGIE', basePrice: 519, kmFlatRate: 100, kmFlatRateUpTo: 60, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: hamburg.id, model: 'MAGIC_MIRROR', basePrice: 619, kmFlatRate: 100, kmFlatRateUpTo: 60, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
|
||||
{ locationId: kiel.id, model: 'VINTAGE_SMILE', basePrice: 389, pricePerKm: 0.75, includedKm: 35 },
|
||||
{ locationId: kiel.id, model: 'VINTAGE_PHOTOS', basePrice: 439, pricePerKm: 0.75, includedKm: 35 },
|
||||
{ locationId: kiel.id, model: 'NOSTALGIE', basePrice: 489, pricePerKm: 0.75, includedKm: 35 },
|
||||
{ locationId: kiel.id, model: 'MAGIC_MIRROR', basePrice: 589, pricePerKm: 0.75, includedKm: 35 },
|
||||
{ locationId: kiel.id, model: 'VINTAGE_SMILE', basePrice: 389, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: kiel.id, model: 'VINTAGE_PHOTOS', basePrice: 439, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: kiel.id, model: 'NOSTALGIE', basePrice: 489, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: kiel.id, model: 'MAGIC_MIRROR', basePrice: 589, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
|
||||
{ locationId: berlin.id, model: 'VINTAGE_SMILE', basePrice: 409, pricePerKm: 0.85, includedKm: 30 },
|
||||
{ locationId: berlin.id, model: 'VINTAGE_PHOTOS', basePrice: 459, pricePerKm: 0.85, includedKm: 30 },
|
||||
{ locationId: berlin.id, model: 'NOSTALGIE', basePrice: 509, pricePerKm: 0.85, includedKm: 30 },
|
||||
{ locationId: berlin.id, model: 'MAGIC_MIRROR', basePrice: 609, pricePerKm: 0.85, includedKm: 30 },
|
||||
{ locationId: berlin.id, model: 'VINTAGE_SMILE', basePrice: 409, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: berlin.id, model: 'VINTAGE_PHOTOS', basePrice: 459, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: berlin.id, model: 'NOSTALGIE', basePrice: 509, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: berlin.id, model: 'MAGIC_MIRROR', basePrice: 609, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
|
||||
{ locationId: rostock.id, model: 'VINTAGE_SMILE', basePrice: 379, pricePerKm: 0.75, includedKm: 35 },
|
||||
{ locationId: rostock.id, model: 'VINTAGE_PHOTOS', basePrice: 429, pricePerKm: 0.75, includedKm: 35 },
|
||||
{ locationId: rostock.id, model: 'NOSTALGIE', basePrice: 479, pricePerKm: 0.75, includedKm: 35 },
|
||||
{ locationId: rostock.id, model: 'MAGIC_MIRROR', basePrice: 579, pricePerKm: 0.75, includedKm: 35 },
|
||||
{ locationId: rostock.id, model: 'VINTAGE_SMILE', basePrice: 379, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: rostock.id, model: 'VINTAGE_PHOTOS', basePrice: 429, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: rostock.id, model: 'NOSTALGIE', basePrice: 479, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
{ locationId: rostock.id, model: 'MAGIC_MIRROR', basePrice: 579, kmFlatRate: 60, kmFlatRateUpTo: 15, pricePerKm: 0.40, kmMultiplier: 4 },
|
||||
],
|
||||
skipDuplicates: true,
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user