import type { PostgresJsDatabase } from "drizzle-orm/postgres-js"; import type { z } from "zod"; import { type Quote, type QuoteVersion, type QuoteVersionLine } from "../schema.js"; import type { acceptQuoteVersionSchema, applyTripSnapshotToQuoteVersionSchema, declineQuoteVersionSchema, expireQuoteVersionsSchema, insertQuoteVersionLineSchema, insertQuoteVersionSchema, quoteVersionListQuerySchema, sendQuoteVersionSchema, updateQuoteVersionLineSchema, updateQuoteVersionSchema } from "../validation.js"; type QuoteVersionListQuery = z.infer; type CreateQuoteVersionInput = z.infer; type UpdateQuoteVersionInput = z.infer; type CreateQuoteVersionLineInput = z.infer; type UpdateQuoteVersionLineInput = z.infer; type ApplyTripSnapshotToQuoteVersionInput = z.infer; type SendQuoteVersionInput = z.infer; type AcceptQuoteVersionInput = z.infer; type DeclineQuoteVersionInput = z.infer; type ExpireQuoteVersionsInput = z.infer; export interface QuoteVersionProposalReadModel { quote: Quote; quoteVersion: QuoteVersion; lines: QuoteVersionLine[]; } export interface AcceptQuoteVersionResult { quote: Quote; quoteVersion: QuoteVersion; closedQuoteVersions: QuoteVersion[]; } export declare class QuoteVersionConflictError extends Error { constructor(message: string); } export declare class QuoteVersionParentNotFoundError extends Error { constructor(quoteId: string); } export declare function resolveQuoteVersionSnapshotCurrency(quoteCurrency: string | null | undefined, productCurrencies: ReadonlyArray): string; export declare const quoteVersionsService: { listQuoteVersions(db: PostgresJsDatabase, query: QuoteVersionListQuery): Promise>; getQuoteVersionById(db: PostgresJsDatabase, id: string): Promise<{ id: string; quoteId: string; label: string | null; status: "draft" | "sent" | "accepted" | "declined" | "superseded" | "expired"; supersedesId: string | null; tripSnapshotId: string | null; validUntil: string | null; currency: string; subtotalAmountCents: number; taxAmountCents: number; totalAmountCents: number; notes: string | null; sentAt: Date | null; viewedAt: Date | null; decidedAt: Date | null; createdAt: Date; updatedAt: Date; archivedAt: Date | null; } | null>; getQuoteVersionProposal(db: PostgresJsDatabase, id: string): Promise; createQuoteVersion(db: PostgresJsDatabase, data: CreateQuoteVersionInput): Promise<{ quoteId: string; createdAt: Date; updatedAt: Date; status: "draft" | "sent" | "accepted" | "declined" | "superseded" | "expired"; id: string; label: string | null; currency: string; supersedesId: string | null; tripSnapshotId: string | null; validUntil: string | null; subtotalAmountCents: number; taxAmountCents: number; totalAmountCents: number; notes: string | null; sentAt: Date | null; viewedAt: Date | null; decidedAt: Date | null; archivedAt: Date | null; } | undefined>; /** * Snapshot the quote's CURRENT line items into a new version ("save a * proposal"). Copies `quoteProducts` → `quoteVersionLines` with the computed * total, links `supersedesId` to the prior current version, and supersedes * every still-live (draft/sent) version so exactly one version is current. * Returns `null` if the quote doesn't exist. */ createVersionSnapshotFromQuote(db: PostgresJsDatabase, quoteId: string): Promise<{ quoteId: string; createdAt: Date; updatedAt: Date; status: "draft" | "sent" | "accepted" | "declined" | "superseded" | "expired"; id: string; label: string | null; currency: string; supersedesId: string | null; tripSnapshotId: string | null; validUntil: string | null; subtotalAmountCents: number; taxAmountCents: number; totalAmountCents: number; notes: string | null; sentAt: Date | null; viewedAt: Date | null; decidedAt: Date | null; archivedAt: Date | null; } | null>; updateQuoteVersion(db: PostgresJsDatabase, id: string, data: UpdateQuoteVersionInput): Promise<{ id: string; quoteId: string; label: string | null; status: "draft" | "sent" | "accepted" | "declined" | "superseded" | "expired"; supersedesId: string | null; tripSnapshotId: string | null; validUntil: string | null; currency: string; subtotalAmountCents: number; taxAmountCents: number; totalAmountCents: number; notes: string | null; sentAt: Date | null; viewedAt: Date | null; decidedAt: Date | null; createdAt: Date; updatedAt: Date; archivedAt: Date | null; } | null>; /** * Set a version's validity date. Narrow on purpose — the generic update * schema carries insert defaults (status/totals) that would otherwise be * written, so validity gets its own path. */ setQuoteVersionValidUntil(db: PostgresJsDatabase, id: string, validUntil: string | null): Promise<{ id: string; quoteId: string; label: string | null; status: "draft" | "sent" | "accepted" | "declined" | "superseded" | "expired"; supersedesId: string | null; tripSnapshotId: string | null; validUntil: string | null; currency: string; subtotalAmountCents: number; taxAmountCents: number; totalAmountCents: number; notes: string | null; sentAt: Date | null; viewedAt: Date | null; decidedAt: Date | null; createdAt: Date; updatedAt: Date; archivedAt: Date | null; } | null>; deleteQuoteVersion(db: PostgresJsDatabase, id: string): Promise<{ id: string; } | null>; applyTripSnapshotToQuoteVersion(db: PostgresJsDatabase, id: string, data: ApplyTripSnapshotToQuoteVersionInput): Promise<{ quoteVersion: { id: string; quoteId: string; label: string | null; status: "draft" | "sent" | "accepted" | "declined" | "superseded" | "expired"; supersedesId: string | null; tripSnapshotId: string | null; validUntil: string | null; currency: string; subtotalAmountCents: number; taxAmountCents: number; totalAmountCents: number; notes: string | null; sentAt: Date | null; viewedAt: Date | null; decidedAt: Date | null; createdAt: Date; updatedAt: Date; archivedAt: Date | null; }; lines: { quoteVersionId: string; createdAt: Date; updatedAt: Date; description: string; id: string; productId: string | null; supplierServiceId: string | null; quantity: number; unitPriceAmountCents: number; currency: string; totalAmountCents: number; }[]; } | null>; sendQuoteVersion(db: PostgresJsDatabase, id: string, data?: SendQuoteVersionInput): Promise<{ id: string; quoteId: string; label: string | null; status: "draft" | "sent" | "accepted" | "declined" | "superseded" | "expired"; supersedesId: string | null; tripSnapshotId: string | null; validUntil: string | null; currency: string; subtotalAmountCents: number; taxAmountCents: number; totalAmountCents: number; notes: string | null; sentAt: Date | null; viewedAt: Date | null; decidedAt: Date | null; createdAt: Date; updatedAt: Date; archivedAt: Date | null; } | null>; markQuoteVersionViewed(db: PostgresJsDatabase, id: string): Promise<{ id: string; quoteId: string; label: string | null; status: "draft" | "sent" | "accepted" | "declined" | "superseded" | "expired"; supersedesId: string | null; tripSnapshotId: string | null; validUntil: string | null; currency: string; subtotalAmountCents: number; taxAmountCents: number; totalAmountCents: number; notes: string | null; sentAt: Date | null; viewedAt: Date | null; decidedAt: Date | null; createdAt: Date; updatedAt: Date; archivedAt: Date | null; } | null>; acceptQuoteVersion(db: PostgresJsDatabase, id: string, _data?: AcceptQuoteVersionInput): Promise; declineQuoteVersion(db: PostgresJsDatabase, id: string, _data?: DeclineQuoteVersionInput): Promise<{ id: string; quoteId: string; label: string | null; status: "draft" | "sent" | "accepted" | "declined" | "superseded" | "expired"; supersedesId: string | null; tripSnapshotId: string | null; validUntil: string | null; currency: string; subtotalAmountCents: number; taxAmountCents: number; totalAmountCents: number; notes: string | null; sentAt: Date | null; viewedAt: Date | null; decidedAt: Date | null; createdAt: Date; updatedAt: Date; archivedAt: Date | null; } | null>; expireQuoteVersionIfPastValidUntil(db: PostgresJsDatabase, id: string, nowValue?: Date | string): Promise<{ id: string; quoteId: string; label: string | null; status: "draft" | "sent" | "accepted" | "declined" | "superseded" | "expired"; supersedesId: string | null; tripSnapshotId: string | null; validUntil: string | null; currency: string; subtotalAmountCents: number; taxAmountCents: number; totalAmountCents: number; notes: string | null; sentAt: Date | null; viewedAt: Date | null; decidedAt: Date | null; createdAt: Date; updatedAt: Date; archivedAt: Date | null; } | null>; expireQuoteVersions(db: PostgresJsDatabase, data?: ExpireQuoteVersionsInput): Promise<{ id: string; quoteId: string; label: string | null; status: "draft" | "sent" | "accepted" | "declined" | "superseded" | "expired"; supersedesId: string | null; tripSnapshotId: string | null; validUntil: string | null; currency: string; subtotalAmountCents: number; taxAmountCents: number; totalAmountCents: number; notes: string | null; sentAt: Date | null; viewedAt: Date | null; decidedAt: Date | null; createdAt: Date; updatedAt: Date; archivedAt: Date | null; }[]>; listQuoteVersionLines(db: PostgresJsDatabase, quoteVersionId: string): Omit; quoteVersionId: import("drizzle-orm/pg-core").PgColumn<{ name: string; tableName: "quote_version_lines"; dataType: "string"; columnType: "PgText"; data: string; driverParam: string; notNull: true; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: [string, ...string[]]; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; productId: import("drizzle-orm/pg-core").PgColumn<{ name: "product_id"; tableName: "quote_version_lines"; dataType: "string"; columnType: "PgText"; data: string; driverParam: string; notNull: false; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: [string, ...string[]]; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; supplierServiceId: import("drizzle-orm/pg-core").PgColumn<{ name: "supplier_service_id"; tableName: "quote_version_lines"; dataType: "string"; columnType: "PgText"; data: string; driverParam: string; notNull: false; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: [string, ...string[]]; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; description: import("drizzle-orm/pg-core").PgColumn<{ name: "description"; tableName: "quote_version_lines"; dataType: "string"; columnType: "PgText"; data: string; driverParam: string; notNull: true; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: [string, ...string[]]; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; quantity: import("drizzle-orm/pg-core").PgColumn<{ name: "quantity"; tableName: "quote_version_lines"; dataType: "number"; columnType: "PgInteger"; data: number; driverParam: string | number; notNull: true; hasDefault: true; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; unitPriceAmountCents: import("drizzle-orm/pg-core").PgColumn<{ name: "unit_price_amount_cents"; tableName: "quote_version_lines"; dataType: "number"; columnType: "PgInteger"; data: number; driverParam: string | number; notNull: true; hasDefault: true; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; totalAmountCents: import("drizzle-orm/pg-core").PgColumn<{ name: "total_amount_cents"; tableName: "quote_version_lines"; dataType: "number"; columnType: "PgInteger"; data: number; driverParam: string | number; notNull: true; hasDefault: true; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; currency: import("drizzle-orm/pg-core").PgColumn<{ name: "currency"; tableName: "quote_version_lines"; dataType: "string"; columnType: "PgText"; data: string; driverParam: string; notNull: true; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: [string, ...string[]]; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; createdAt: import("drizzle-orm/pg-core").PgColumn<{ name: "created_at"; tableName: "quote_version_lines"; dataType: "date"; columnType: "PgTimestamp"; data: Date; driverParam: string; notNull: true; hasDefault: true; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; updatedAt: import("drizzle-orm/pg-core").PgColumn<{ name: "updated_at"; tableName: "quote_version_lines"; dataType: "date"; columnType: "PgTimestamp"; data: Date; driverParam: string; notNull: true; hasDefault: true; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; }, "single", Record<"quote_version_lines", "not-null">, false, "where" | "orderBy", { id: string; quoteVersionId: string; productId: string | null; supplierServiceId: string | null; description: string; quantity: number; unitPriceAmountCents: number; totalAmountCents: number; currency: string; createdAt: Date; updatedAt: Date; }[], { id: import("drizzle-orm/pg-core").PgColumn<{ name: string; tableName: "quote_version_lines"; dataType: "string"; columnType: "PgText"; data: string; driverParam: string; notNull: true; hasDefault: true; isPrimaryKey: true; isAutoincrement: false; hasRuntimeDefault: true; enumValues: [string, ...string[]]; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; quoteVersionId: import("drizzle-orm/pg-core").PgColumn<{ name: string; tableName: "quote_version_lines"; dataType: "string"; columnType: "PgText"; data: string; driverParam: string; notNull: true; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: [string, ...string[]]; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; productId: import("drizzle-orm/pg-core").PgColumn<{ name: "product_id"; tableName: "quote_version_lines"; dataType: "string"; columnType: "PgText"; data: string; driverParam: string; notNull: false; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: [string, ...string[]]; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; supplierServiceId: import("drizzle-orm/pg-core").PgColumn<{ name: "supplier_service_id"; tableName: "quote_version_lines"; dataType: "string"; columnType: "PgText"; data: string; driverParam: string; notNull: false; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: [string, ...string[]]; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; description: import("drizzle-orm/pg-core").PgColumn<{ name: "description"; tableName: "quote_version_lines"; dataType: "string"; columnType: "PgText"; data: string; driverParam: string; notNull: true; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: [string, ...string[]]; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; quantity: import("drizzle-orm/pg-core").PgColumn<{ name: "quantity"; tableName: "quote_version_lines"; dataType: "number"; columnType: "PgInteger"; data: number; driverParam: string | number; notNull: true; hasDefault: true; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; unitPriceAmountCents: import("drizzle-orm/pg-core").PgColumn<{ name: "unit_price_amount_cents"; tableName: "quote_version_lines"; dataType: "number"; columnType: "PgInteger"; data: number; driverParam: string | number; notNull: true; hasDefault: true; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; totalAmountCents: import("drizzle-orm/pg-core").PgColumn<{ name: "total_amount_cents"; tableName: "quote_version_lines"; dataType: "number"; columnType: "PgInteger"; data: number; driverParam: string | number; notNull: true; hasDefault: true; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; currency: import("drizzle-orm/pg-core").PgColumn<{ name: "currency"; tableName: "quote_version_lines"; dataType: "string"; columnType: "PgText"; data: string; driverParam: string; notNull: true; hasDefault: false; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: [string, ...string[]]; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; createdAt: import("drizzle-orm/pg-core").PgColumn<{ name: "created_at"; tableName: "quote_version_lines"; dataType: "date"; columnType: "PgTimestamp"; data: Date; driverParam: string; notNull: true; hasDefault: true; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; updatedAt: import("drizzle-orm/pg-core").PgColumn<{ name: "updated_at"; tableName: "quote_version_lines"; dataType: "date"; columnType: "PgTimestamp"; data: Date; driverParam: string; notNull: true; hasDefault: true; isPrimaryKey: false; isAutoincrement: false; hasRuntimeDefault: false; enumValues: undefined; baseColumn: never; identity: undefined; generated: undefined; }, {}, {}>; }>, "where" | "orderBy">; createQuoteVersionLine(db: PostgresJsDatabase, quoteVersionId: string, data: CreateQuoteVersionLineInput): Promise<{ quoteVersionId: string; createdAt: Date; updatedAt: Date; description: string; id: string; productId: string | null; supplierServiceId: string | null; quantity: number; unitPriceAmountCents: number; currency: string; totalAmountCents: number; } | null | undefined>; updateQuoteVersionLine(db: PostgresJsDatabase, id: string, data: UpdateQuoteVersionLineInput): Promise<{ id: string; quoteVersionId: string; productId: string | null; supplierServiceId: string | null; description: string; quantity: number; unitPriceAmountCents: number; totalAmountCents: number; currency: string; createdAt: Date; updatedAt: Date; } | null>; deleteQuoteVersionLine(db: PostgresJsDatabase, id: string): Promise<{ id: string; } | null>; }; export {};