@voyantjs/legal 0.6.9 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contracts/service-auto-generate.d.ts +129 -0
- package/dist/contracts/service-auto-generate.d.ts.map +1 -0
- package/dist/contracts/service-auto-generate.js +122 -0
- package/dist/contracts/service-series.d.ts +20 -0
- package/dist/contracts/service-series.d.ts.map +1 -1
- package/dist/contracts/service-series.js +16 -1
- package/dist/contracts/service-templates.d.ts +18 -0
- package/dist/contracts/service-templates.d.ts.map +1 -1
- package/dist/contracts/service-templates.js +12 -0
- package/dist/contracts/service.d.ts +28 -0
- package/dist/contracts/service.d.ts.map +1 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -1
- package/dist/policies/routes.d.ts +8 -8
- package/dist/policies/schema.d.ts +1 -1
- package/dist/policies/service-core.d.ts +8 -8
- package/dist/policies/service.d.ts +8 -8
- package/dist/policies/validation.d.ts +3 -3
- package/package.json +9 -8
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { bookingsService } from "@voyantjs/bookings";
|
|
2
|
+
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
3
|
+
import type { ContractDocumentGenerator } from "./service-documents.js";
|
|
4
|
+
/**
|
|
5
|
+
* Event shape emitted by `@voyantjs/bookings` on confirm. Duplicated here so
|
|
6
|
+
* legal doesn't have to import the bookings service just for the interface —
|
|
7
|
+
* the concrete `bookingsService` lookup happens inside the handler.
|
|
8
|
+
*/
|
|
9
|
+
export interface BookingConfirmedLikeEvent {
|
|
10
|
+
bookingId: string;
|
|
11
|
+
bookingNumber: string;
|
|
12
|
+
actorId: string | null;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Variables passed to the contract template at render time. Consumers can
|
|
16
|
+
* augment via `resolveVariables`; the built-in resolver supplies the fields
|
|
17
|
+
* the default contract template expects.
|
|
18
|
+
*/
|
|
19
|
+
export interface DefaultContractVariables {
|
|
20
|
+
contract: {
|
|
21
|
+
issuedAt: string;
|
|
22
|
+
date: string;
|
|
23
|
+
};
|
|
24
|
+
booking: {
|
|
25
|
+
id: string;
|
|
26
|
+
number: string;
|
|
27
|
+
status: string;
|
|
28
|
+
currency: string | null;
|
|
29
|
+
startDate: string | null;
|
|
30
|
+
endDate: string | null;
|
|
31
|
+
pax: number | null;
|
|
32
|
+
internalNotes: string | null;
|
|
33
|
+
totalAmountCents: number | null;
|
|
34
|
+
};
|
|
35
|
+
travelers: Array<{
|
|
36
|
+
id: string;
|
|
37
|
+
firstName: string;
|
|
38
|
+
lastName: string;
|
|
39
|
+
email: string | null;
|
|
40
|
+
phone: string | null;
|
|
41
|
+
isPrimary: boolean;
|
|
42
|
+
participantType: string;
|
|
43
|
+
}>;
|
|
44
|
+
leadTraveler: {
|
|
45
|
+
id: string;
|
|
46
|
+
firstName: string;
|
|
47
|
+
lastName: string;
|
|
48
|
+
email: string | null;
|
|
49
|
+
phone: string | null;
|
|
50
|
+
} | null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Hook point so consumers can extend (or replace) the template variables.
|
|
54
|
+
* Receives the default payload plus the raw booking/travelers so the
|
|
55
|
+
* consumer can fold in product/person/etc. lookups without re-fetching.
|
|
56
|
+
*/
|
|
57
|
+
export type ResolveContractVariablesFn = (context: {
|
|
58
|
+
db: PostgresJsDatabase;
|
|
59
|
+
booking: NonNullable<Awaited<ReturnType<typeof bookingsService.getBookingById>>>;
|
|
60
|
+
travelers: Awaited<ReturnType<typeof bookingsService.listTravelers>>;
|
|
61
|
+
defaults: DefaultContractVariables;
|
|
62
|
+
}) => Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
63
|
+
export interface AutoGenerateContractOptions {
|
|
64
|
+
enabled?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Slug of the contract template to use. The contract is created against
|
|
67
|
+
* that template's `currentVersionId`. If the template has no current
|
|
68
|
+
* version, the handler logs + bails.
|
|
69
|
+
*/
|
|
70
|
+
templateSlug: string;
|
|
71
|
+
/**
|
|
72
|
+
* Scope the contract defaults to when creating. Matches
|
|
73
|
+
* `contractScopeEnum`; the default `"customer"` is right for the common
|
|
74
|
+
* operator-issues-to-traveler case.
|
|
75
|
+
*/
|
|
76
|
+
scope?: "customer" | "supplier" | "partner" | "channel" | "other";
|
|
77
|
+
/**
|
|
78
|
+
* When set, the contract tries to allocate a number from the matching
|
|
79
|
+
* active series on issuance. Without it, the contract issues unnumbered.
|
|
80
|
+
*/
|
|
81
|
+
seriesName?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Language code written onto the contract row. Used by the PDF
|
|
84
|
+
* renderer to pick the right locale for date/currency filters.
|
|
85
|
+
*/
|
|
86
|
+
language?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Optional variable extender — see `ResolveContractVariablesFn`.
|
|
89
|
+
*/
|
|
90
|
+
resolveVariables?: ResolveContractVariablesFn;
|
|
91
|
+
}
|
|
92
|
+
export interface AutoGenerateContractRuntime {
|
|
93
|
+
generator: ContractDocumentGenerator;
|
|
94
|
+
eventBus?: import("@voyantjs/core").EventBus;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Core auto-generate handler. Fire this from a `booking.confirmed` subscriber.
|
|
98
|
+
* On success, the booking now has an issued contract with an attachment
|
|
99
|
+
* (the PDF / storage object produced by the configured generator) and a
|
|
100
|
+
* `contract.document.generated` event has been emitted post-commit.
|
|
101
|
+
*
|
|
102
|
+
* Failure modes (all surfaced via the returned status):
|
|
103
|
+
* - `template_not_found` — no active template matches the slug
|
|
104
|
+
* - `template_version_missing` — template exists but has no published version
|
|
105
|
+
* - `booking_not_found` — booking disappeared between confirm + fire
|
|
106
|
+
* - `contract_create_failed` — insert returned null
|
|
107
|
+
* - `document_<…>` — pass-through of generateContractDocument statuses
|
|
108
|
+
*
|
|
109
|
+
* Callers (the subscriber wrapper) log these and move on — per the EventBus
|
|
110
|
+
* contract, handler throws are swallowed anyway; returning a discriminated
|
|
111
|
+
* status keeps tests honest.
|
|
112
|
+
*/
|
|
113
|
+
export declare function autoGenerateContractForBooking(db: PostgresJsDatabase, event: BookingConfirmedLikeEvent, options: AutoGenerateContractOptions, runtime: AutoGenerateContractRuntime): Promise<{
|
|
114
|
+
status: "ok";
|
|
115
|
+
contractId: string;
|
|
116
|
+
attachmentId: string;
|
|
117
|
+
} | {
|
|
118
|
+
status: "template_not_found";
|
|
119
|
+
} | {
|
|
120
|
+
status: "template_version_missing";
|
|
121
|
+
} | {
|
|
122
|
+
status: "booking_not_found";
|
|
123
|
+
} | {
|
|
124
|
+
status: "contract_create_failed";
|
|
125
|
+
} | {
|
|
126
|
+
status: "document_failed";
|
|
127
|
+
reason: string;
|
|
128
|
+
}>;
|
|
129
|
+
//# sourceMappingURL=service-auto-generate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-auto-generate.d.ts","sourceRoot":"","sources":["../../src/contracts/service-auto-generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { bookingsService } from "@voyantjs/bookings";
|
|
2
|
+
import { contractRecordsService } from "./service-contracts.js";
|
|
3
|
+
import { contractDocumentsService } from "./service-documents.js";
|
|
4
|
+
import { contractSeriesService } from "./service-series.js";
|
|
5
|
+
import { contractTemplatesService } from "./service-templates.js";
|
|
6
|
+
/**
|
|
7
|
+
* Core auto-generate handler. Fire this from a `booking.confirmed` subscriber.
|
|
8
|
+
* On success, the booking now has an issued contract with an attachment
|
|
9
|
+
* (the PDF / storage object produced by the configured generator) and a
|
|
10
|
+
* `contract.document.generated` event has been emitted post-commit.
|
|
11
|
+
*
|
|
12
|
+
* Failure modes (all surfaced via the returned status):
|
|
13
|
+
* - `template_not_found` — no active template matches the slug
|
|
14
|
+
* - `template_version_missing` — template exists but has no published version
|
|
15
|
+
* - `booking_not_found` — booking disappeared between confirm + fire
|
|
16
|
+
* - `contract_create_failed` — insert returned null
|
|
17
|
+
* - `document_<…>` — pass-through of generateContractDocument statuses
|
|
18
|
+
*
|
|
19
|
+
* Callers (the subscriber wrapper) log these and move on — per the EventBus
|
|
20
|
+
* contract, handler throws are swallowed anyway; returning a discriminated
|
|
21
|
+
* status keeps tests honest.
|
|
22
|
+
*/
|
|
23
|
+
export async function autoGenerateContractForBooking(db, event, options, runtime) {
|
|
24
|
+
// Resolve the template + its current version. Consumers configure the slug
|
|
25
|
+
// once at module bootstrap; we look up on every fire so template body
|
|
26
|
+
// edits are picked up without restart.
|
|
27
|
+
const template = await contractTemplatesService.findTemplateBySlug(db, options.templateSlug);
|
|
28
|
+
if (!template) {
|
|
29
|
+
return { status: "template_not_found" };
|
|
30
|
+
}
|
|
31
|
+
if (!template.currentVersionId) {
|
|
32
|
+
return { status: "template_version_missing" };
|
|
33
|
+
}
|
|
34
|
+
const booking = await bookingsService.getBookingById(db, event.bookingId);
|
|
35
|
+
if (!booking) {
|
|
36
|
+
return { status: "booking_not_found" };
|
|
37
|
+
}
|
|
38
|
+
const travelers = await bookingsService.listTravelers(db, event.bookingId);
|
|
39
|
+
const leadTraveler = travelers.find((t) => t.isPrimary) ??
|
|
40
|
+
travelers.find((t) => t.participantType === "traveler") ??
|
|
41
|
+
travelers[0] ??
|
|
42
|
+
null;
|
|
43
|
+
const now = new Date();
|
|
44
|
+
const defaults = {
|
|
45
|
+
contract: {
|
|
46
|
+
issuedAt: now.toISOString(),
|
|
47
|
+
date: now.toISOString().slice(0, 10),
|
|
48
|
+
},
|
|
49
|
+
booking: {
|
|
50
|
+
id: booking.id,
|
|
51
|
+
number: booking.bookingNumber,
|
|
52
|
+
status: booking.status,
|
|
53
|
+
currency: booking.sellCurrency ?? null,
|
|
54
|
+
startDate: booking.startDate,
|
|
55
|
+
endDate: booking.endDate,
|
|
56
|
+
pax: booking.pax,
|
|
57
|
+
internalNotes: booking.internalNotes,
|
|
58
|
+
totalAmountCents: booking.sellAmountCents ?? null,
|
|
59
|
+
},
|
|
60
|
+
travelers: travelers.map((t) => ({
|
|
61
|
+
id: t.id,
|
|
62
|
+
firstName: t.firstName,
|
|
63
|
+
lastName: t.lastName,
|
|
64
|
+
email: t.email,
|
|
65
|
+
phone: t.phone,
|
|
66
|
+
isPrimary: t.isPrimary,
|
|
67
|
+
participantType: t.participantType,
|
|
68
|
+
})),
|
|
69
|
+
leadTraveler: leadTraveler
|
|
70
|
+
? {
|
|
71
|
+
id: leadTraveler.id,
|
|
72
|
+
firstName: leadTraveler.firstName,
|
|
73
|
+
lastName: leadTraveler.lastName,
|
|
74
|
+
email: leadTraveler.email,
|
|
75
|
+
phone: leadTraveler.phone,
|
|
76
|
+
}
|
|
77
|
+
: null,
|
|
78
|
+
};
|
|
79
|
+
const variables = options.resolveVariables
|
|
80
|
+
? await options.resolveVariables({ db, booking, travelers, defaults })
|
|
81
|
+
: defaults;
|
|
82
|
+
// Resolve a series id if the consumer gave a name — failure to find is
|
|
83
|
+
// non-fatal since a contract can issue without a number (some operators
|
|
84
|
+
// use templates as standalone records and number externally).
|
|
85
|
+
let seriesId = null;
|
|
86
|
+
if (options.seriesName) {
|
|
87
|
+
const series = await contractSeriesService.findSeriesByName(db, options.seriesName);
|
|
88
|
+
seriesId = series?.id ?? null;
|
|
89
|
+
}
|
|
90
|
+
const contract = await contractRecordsService.createContract(db, {
|
|
91
|
+
scope: options.scope ?? "customer",
|
|
92
|
+
status: "draft",
|
|
93
|
+
title: `${template.name} — ${booking.bookingNumber}`,
|
|
94
|
+
templateVersionId: template.currentVersionId,
|
|
95
|
+
seriesId,
|
|
96
|
+
bookingId: event.bookingId,
|
|
97
|
+
personId: booking.personId ?? null,
|
|
98
|
+
organizationId: booking.organizationId ?? null,
|
|
99
|
+
language: options.language ?? template.language ?? "en",
|
|
100
|
+
variables,
|
|
101
|
+
metadata: {
|
|
102
|
+
autoGenerated: true,
|
|
103
|
+
trigger: "booking.confirmed",
|
|
104
|
+
triggerActorId: event.actorId,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
if (!contract) {
|
|
108
|
+
return { status: "contract_create_failed" };
|
|
109
|
+
}
|
|
110
|
+
const result = await contractDocumentsService.generateContractDocument(db, contract.id, {
|
|
111
|
+
issueIfDraft: true,
|
|
112
|
+
replaceExisting: true,
|
|
113
|
+
kind: "document",
|
|
114
|
+
}, {
|
|
115
|
+
generator: runtime.generator,
|
|
116
|
+
eventBus: runtime.eventBus,
|
|
117
|
+
});
|
|
118
|
+
if (result.status === "generated") {
|
|
119
|
+
return { status: "ok", contractId: contract.id, attachmentId: result.attachment.id };
|
|
120
|
+
}
|
|
121
|
+
return { status: "document_failed", reason: result.status };
|
|
122
|
+
}
|
|
@@ -29,6 +29,26 @@ export declare const contractSeriesService: {
|
|
|
29
29
|
createdAt: Date;
|
|
30
30
|
updatedAt: Date;
|
|
31
31
|
} | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Find the most-recently-updated active series matching a name. Used by
|
|
34
|
+
* the auto-generate subscriber so consumers can pin a named series
|
|
35
|
+
* (`"2026 Customer"`) in config and let operators rename the row via
|
|
36
|
+
* the admin UI without breaking the wiring.
|
|
37
|
+
*/
|
|
38
|
+
findSeriesByName(db: PostgresJsDatabase, name: string): Promise<{
|
|
39
|
+
id: string;
|
|
40
|
+
name: string;
|
|
41
|
+
prefix: string;
|
|
42
|
+
separator: string;
|
|
43
|
+
padLength: number;
|
|
44
|
+
currentSequence: number;
|
|
45
|
+
resetStrategy: "never" | "annual" | "monthly";
|
|
46
|
+
resetAt: Date | null;
|
|
47
|
+
scope: "customer" | "partner" | "supplier" | "other" | "channel";
|
|
48
|
+
active: boolean;
|
|
49
|
+
createdAt: Date;
|
|
50
|
+
updatedAt: Date;
|
|
51
|
+
} | null>;
|
|
32
52
|
createSeries(db: PostgresJsDatabase, data: CreateContractNumberSeriesInput): Promise<{
|
|
33
53
|
id: string;
|
|
34
54
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-series.d.ts","sourceRoot":"","sources":["../../src/contracts/service-series.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAGjE,OAAO,KAAK,EACV,+BAA+B,EAC/B,+BAA+B,EAChC,MAAM,qBAAqB,CAAA;AAE5B,eAAO,MAAM,qBAAqB;mBACX,kBAAkB;;;;;;;;;;;;;;sBAGf,kBAAkB,MAAM,MAAM;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"service-series.d.ts","sourceRoot":"","sources":["../../src/contracts/service-series.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAGjE,OAAO,KAAK,EACV,+BAA+B,EAC/B,+BAA+B,EAChC,MAAM,qBAAqB,CAAA;AAE5B,eAAO,MAAM,qBAAqB;mBACX,kBAAkB;;;;;;;;;;;;;;sBAGf,kBAAkB,MAAM,MAAM;;;;;;;;;;;;;;IAQtD;;;;;OAKG;yBACwB,kBAAkB,QAAQ,MAAM;;;;;;;;;;;;;;qBASpC,kBAAkB,QAAQ,+BAA+B;;;;;;;;;;;;;;qBAIzD,kBAAkB,MAAM,MAAM,QAAQ,+BAA+B;;;;;;;;;;;;;;qBAQrE,kBAAkB,MAAM,MAAM;;;CAOtD,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { desc, eq } from "drizzle-orm";
|
|
1
|
+
import { and, desc, eq } from "drizzle-orm";
|
|
2
2
|
import { contractNumberSeries } from "./schema.js";
|
|
3
3
|
export const contractSeriesService = {
|
|
4
4
|
async listSeries(db) {
|
|
@@ -12,6 +12,21 @@ export const contractSeriesService = {
|
|
|
12
12
|
.limit(1);
|
|
13
13
|
return row ?? null;
|
|
14
14
|
},
|
|
15
|
+
/**
|
|
16
|
+
* Find the most-recently-updated active series matching a name. Used by
|
|
17
|
+
* the auto-generate subscriber so consumers can pin a named series
|
|
18
|
+
* (`"2026 Customer"`) in config and let operators rename the row via
|
|
19
|
+
* the admin UI without breaking the wiring.
|
|
20
|
+
*/
|
|
21
|
+
async findSeriesByName(db, name) {
|
|
22
|
+
const [row] = await db
|
|
23
|
+
.select()
|
|
24
|
+
.from(contractNumberSeries)
|
|
25
|
+
.where(and(eq(contractNumberSeries.name, name), eq(contractNumberSeries.active, true)))
|
|
26
|
+
.orderBy(desc(contractNumberSeries.updatedAt))
|
|
27
|
+
.limit(1);
|
|
28
|
+
return row ?? null;
|
|
29
|
+
},
|
|
15
30
|
async createSeries(db, data) {
|
|
16
31
|
const [row] = await db.insert(contractNumberSeries).values(data).returning();
|
|
17
32
|
return row ?? null;
|
|
@@ -34,6 +34,24 @@ export declare const contractTemplatesService: {
|
|
|
34
34
|
createdAt: Date;
|
|
35
35
|
updatedAt: Date;
|
|
36
36
|
} | null>;
|
|
37
|
+
/**
|
|
38
|
+
* Slug lookup, used by the auto-generate subscriber. Slug is unique so the
|
|
39
|
+
* result is either the row or null — no disambiguation needed.
|
|
40
|
+
*/
|
|
41
|
+
findTemplateBySlug(db: PostgresJsDatabase, slug: string): Promise<{
|
|
42
|
+
id: string;
|
|
43
|
+
name: string;
|
|
44
|
+
slug: string;
|
|
45
|
+
scope: "customer" | "partner" | "supplier" | "other" | "channel";
|
|
46
|
+
language: string;
|
|
47
|
+
description: string | null;
|
|
48
|
+
body: string;
|
|
49
|
+
variableSchema: unknown;
|
|
50
|
+
currentVersionId: string | null;
|
|
51
|
+
active: boolean;
|
|
52
|
+
createdAt: Date;
|
|
53
|
+
updatedAt: Date;
|
|
54
|
+
} | null>;
|
|
37
55
|
getDefaultTemplate(db: PostgresJsDatabase, query: {
|
|
38
56
|
scope: "customer" | "supplier" | "partner" | "channel" | "other";
|
|
39
57
|
language?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service-templates.d.ts","sourceRoot":"","sources":["../../src/contracts/service-templates.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAGjE,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EAChC,KAAK,kCAAkC,EAEvC,KAAK,mBAAmB,EAExB,KAAK,2BAA2B,EACjC,MAAM,qBAAqB,CAAA;AAE5B,eAAO,MAAM,wBAAwB;sBACX,kBAAkB,SAAS,yBAAyB;;;;;;;;;;;;;;;;;;;wBA6BlD,kBAAkB,MAAM,MAAM;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"service-templates.d.ts","sourceRoot":"","sources":["../../src/contracts/service-templates.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAGjE,OAAO,EACL,KAAK,yBAAyB,EAC9B,KAAK,2BAA2B,EAChC,KAAK,kCAAkC,EAEvC,KAAK,mBAAmB,EAExB,KAAK,2BAA2B,EACjC,MAAM,qBAAqB,CAAA;AAE5B,eAAO,MAAM,wBAAwB;sBACX,kBAAkB,SAAS,yBAAyB;;;;;;;;;;;;;;;;;;;wBA6BlD,kBAAkB,MAAM,MAAM;;;;;;;;;;;;;;IAQxD;;;OAGG;2BAC0B,kBAAkB,QAAQ,MAAM;;;;;;;;;;;;;;2BASvD,kBAAkB,SACf;QACL,KAAK,EAAE,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;QAChE,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;KAC7B;;;;;;;;;;;;;;uBAgCsB,kBAAkB,QAAQ,2BAA2B;;;;;;;;;;;;;;uBAIrD,kBAAkB,MAAM,MAAM,QAAQ,2BAA2B;;;;;;;;;;;;;;uBAQjE,kBAAkB,MAAM,MAAM;;;6BAO9B,kBAAkB,cAAc,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+BAO9B,kBAAkB,MAAM,MAAM;;;;;;;;;;8BASzD,kBAAkB,cACV,MAAM,QACZ,kCAAkC;;;;;;;;;;yBAkCrB,mBAAmB,GAAG,MAAM;CAIlD,CAAA"}
|
|
@@ -31,6 +31,18 @@ export const contractTemplatesService = {
|
|
|
31
31
|
.limit(1);
|
|
32
32
|
return row ?? null;
|
|
33
33
|
},
|
|
34
|
+
/**
|
|
35
|
+
* Slug lookup, used by the auto-generate subscriber. Slug is unique so the
|
|
36
|
+
* result is either the row or null — no disambiguation needed.
|
|
37
|
+
*/
|
|
38
|
+
async findTemplateBySlug(db, slug) {
|
|
39
|
+
const [row] = await db
|
|
40
|
+
.select()
|
|
41
|
+
.from(contractTemplates)
|
|
42
|
+
.where(eq(contractTemplates.slug, slug))
|
|
43
|
+
.limit(1);
|
|
44
|
+
return row ?? null;
|
|
45
|
+
},
|
|
34
46
|
async getDefaultTemplate(db, query) {
|
|
35
47
|
const rows = await db
|
|
36
48
|
.select()
|
|
@@ -1282,6 +1282,20 @@ export declare const contractsService: {
|
|
|
1282
1282
|
createdAt: Date;
|
|
1283
1283
|
updatedAt: Date;
|
|
1284
1284
|
} | null>;
|
|
1285
|
+
findSeriesByName(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, name: string): Promise<{
|
|
1286
|
+
id: string;
|
|
1287
|
+
name: string;
|
|
1288
|
+
prefix: string;
|
|
1289
|
+
separator: string;
|
|
1290
|
+
padLength: number;
|
|
1291
|
+
currentSequence: number;
|
|
1292
|
+
resetStrategy: "never" | "annual" | "monthly";
|
|
1293
|
+
resetAt: Date | null;
|
|
1294
|
+
scope: "customer" | "partner" | "supplier" | "other" | "channel";
|
|
1295
|
+
active: boolean;
|
|
1296
|
+
createdAt: Date;
|
|
1297
|
+
updatedAt: Date;
|
|
1298
|
+
} | null>;
|
|
1285
1299
|
createSeries(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, data: import("./service-shared.js").CreateContractNumberSeriesInput): Promise<{
|
|
1286
1300
|
id: string;
|
|
1287
1301
|
name: string;
|
|
@@ -1346,6 +1360,20 @@ export declare const contractsService: {
|
|
|
1346
1360
|
createdAt: Date;
|
|
1347
1361
|
updatedAt: Date;
|
|
1348
1362
|
} | null>;
|
|
1363
|
+
findTemplateBySlug(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, slug: string): Promise<{
|
|
1364
|
+
id: string;
|
|
1365
|
+
name: string;
|
|
1366
|
+
slug: string;
|
|
1367
|
+
scope: "customer" | "partner" | "supplier" | "other" | "channel";
|
|
1368
|
+
language: string;
|
|
1369
|
+
description: string | null;
|
|
1370
|
+
body: string;
|
|
1371
|
+
variableSchema: unknown;
|
|
1372
|
+
currentVersionId: string | null;
|
|
1373
|
+
active: boolean;
|
|
1374
|
+
createdAt: Date;
|
|
1375
|
+
updatedAt: Date;
|
|
1376
|
+
} | null>;
|
|
1349
1377
|
getDefaultTemplate(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, query: {
|
|
1350
1378
|
scope: "customer" | "supplier" | "partner" | "channel" | "other";
|
|
1351
1379
|
language?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/contracts/service.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,yBAAyB,EAC1B,MAAM,qBAAqB,CAAA;AAG5B,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,yBAAyB,EAAE,CAAA;AAE5E,eAAO,MAAM,gBAAgB;;mBAMy1S,CAAC
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/contracts/service.ts"],"names":[],"mappings":"AAGA,OAAO,EACL,sBAAsB,EACtB,cAAc,EACd,yBAAyB,EAC1B,MAAM,qBAAqB,CAAA;AAG5B,OAAO,EAAE,sBAAsB,EAAE,cAAc,EAAE,yBAAyB,EAAE,CAAA;AAE5E,eAAO,MAAM,gBAAgB;;mBAMy1S,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gBAA9rP,CAAC;yBAAgC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAD1tD,CAAA"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Module } from "@voyantjs/core";
|
|
2
2
|
import type { HonoModule } from "@voyantjs/hono/module";
|
|
3
|
+
import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
|
|
3
4
|
import { type ContractsRouteOptions } from "./contracts/routes.js";
|
|
5
|
+
import { type AutoGenerateContractOptions } from "./contracts/service-auto-generate.js";
|
|
4
6
|
export declare const legalLinkable: {
|
|
5
7
|
policy: import("@voyantjs/core").LinkableDefinition;
|
|
6
8
|
policyVersion: import("@voyantjs/core").LinkableDefinition;
|
|
@@ -9,10 +11,27 @@ export declare const legalLinkable: {
|
|
|
9
11
|
contractTemplate: import("@voyantjs/core").LinkableDefinition;
|
|
10
12
|
};
|
|
11
13
|
export declare const legalModule: Module;
|
|
12
|
-
export
|
|
14
|
+
export interface CreateLegalHonoModuleOptions extends ContractsRouteOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Required when `autoGenerateContractOnConfirmed.enabled` is true. The
|
|
17
|
+
* `booking.confirmed` subscriber fires outside request scope, so it
|
|
18
|
+
* needs its own db handle from runtime bindings.
|
|
19
|
+
*/
|
|
20
|
+
resolveDb?: (bindings: Record<string, unknown>) => PostgresJsDatabase;
|
|
21
|
+
/**
|
|
22
|
+
* Opt-in auto-generate on `booking.confirmed`. When enabled + a
|
|
23
|
+
* `templateSlug` is supplied + a `documentGenerator` is resolvable, every
|
|
24
|
+
* booking.confirmed event creates a contract against the template's
|
|
25
|
+
* current version and generates its attachment via the configured
|
|
26
|
+
* generator (R2-backed PDF, etc.).
|
|
27
|
+
*/
|
|
28
|
+
autoGenerateContractOnConfirmed?: AutoGenerateContractOptions;
|
|
29
|
+
}
|
|
30
|
+
export declare function createLegalHonoModule(options?: CreateLegalHonoModuleOptions): HonoModule;
|
|
13
31
|
export declare const legalHonoModule: HonoModule;
|
|
14
32
|
export * from "./contracts/index.js";
|
|
15
33
|
export { buildContractsRouteRuntime, CONTRACTS_ROUTE_RUNTIME_CONTAINER_KEY, type ContractsRouteRuntime, } from "./contracts/route-runtime.js";
|
|
16
34
|
export type { ContractsRouteOptions } from "./contracts/routes.js";
|
|
35
|
+
export { type AutoGenerateContractOptions, type AutoGenerateContractRuntime, autoGenerateContractForBooking, type BookingConfirmedLikeEvent, type DefaultContractVariables, type ResolveContractVariablesFn, } from "./contracts/service-auto-generate.js";
|
|
17
36
|
export * from "./policies/index.js";
|
|
18
37
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAA;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AACvD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAA;AAOjE,OAAO,EACL,KAAK,qBAAqB,EAG3B,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EACL,KAAK,2BAA2B,EAEjC,MAAM,sCAAsC,CAAA;AAI7C,eAAO,MAAM,aAAa;;;;;;CAGzB,CAAA;AAED,eAAO,MAAM,WAAW,EAAE,MAGzB,CAAA;AAED,MAAM,WAAW,4BAA6B,SAAQ,qBAAqB;IACzE;;;;OAIG;IACH,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,kBAAkB,CAAA;IACrE;;;;;;OAMG;IACH,+BAA+B,CAAC,EAAE,2BAA2B,CAAA;CAC9D;AAED,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,4BAAiC,GAAG,UAAU,CAsE5F;AAED,eAAO,MAAM,eAAe,EAAE,UAAoC,CAAA;AAElE,cAAc,sBAAsB,CAAA;AACpC,OAAO,EACL,0BAA0B,EAC1B,qCAAqC,EACrC,KAAK,qBAAqB,GAC3B,MAAM,8BAA8B,CAAA;AACrC,YAAY,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAClE,OAAO,EACL,KAAK,2BAA2B,EAChC,KAAK,2BAA2B,EAChC,8BAA8B,EAC9B,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,GAChC,MAAM,sCAAsC,CAAA;AAC7C,cAAc,qBAAqB,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import { Hono } from "hono";
|
|
|
2
2
|
import { contractsLinkable } from "./contracts/index.js";
|
|
3
3
|
import { buildContractsRouteRuntime, CONTRACTS_ROUTE_RUNTIME_CONTAINER_KEY, } from "./contracts/route-runtime.js";
|
|
4
4
|
import { createContractsAdminRoutes, createContractsPublicRoutes, } from "./contracts/routes.js";
|
|
5
|
+
import { autoGenerateContractForBooking, } from "./contracts/service-auto-generate.js";
|
|
5
6
|
import { policiesLinkable } from "./policies/index.js";
|
|
6
7
|
import { policiesAdminRoutes, policiesPublicRoutes } from "./policies/routes.js";
|
|
7
8
|
export const legalLinkable = {
|
|
@@ -21,8 +22,42 @@ export function createLegalHonoModule(options = {}) {
|
|
|
21
22
|
.route("/policies", policiesPublicRoutes);
|
|
22
23
|
const module = {
|
|
23
24
|
...legalModule,
|
|
24
|
-
bootstrap: ({ bindings, container }) => {
|
|
25
|
+
bootstrap: ({ bindings, container, eventBus }) => {
|
|
25
26
|
container.register(CONTRACTS_ROUTE_RUNTIME_CONTAINER_KEY, buildContractsRouteRuntime(bindings, options));
|
|
27
|
+
// Auto-generate wiring — opt-in. Mirrors the notifications
|
|
28
|
+
// autoConfirmAndDispatch subscriber pattern. Both fire on the same
|
|
29
|
+
// booking.confirmed event; legal's handler just needs to run first
|
|
30
|
+
// so the contract attachment exists before notifications looks it
|
|
31
|
+
// up via listLegalBookingDocuments. Module-registration order in the
|
|
32
|
+
// template controls this.
|
|
33
|
+
const auto = options.autoGenerateContractOnConfirmed;
|
|
34
|
+
if (auto?.enabled && options.resolveDb) {
|
|
35
|
+
const resolveDb = options.resolveDb;
|
|
36
|
+
const runtime = buildContractsRouteRuntime(bindings, options);
|
|
37
|
+
if (!runtime.documentGenerator) {
|
|
38
|
+
// Mis-configuration — don't silently drop contracts. Log and
|
|
39
|
+
// skip; the template operator will notice on the first confirm.
|
|
40
|
+
console.error("[legal] autoGenerateContractOnConfirmed.enabled=true but no documentGenerator resolved; skipping subscriber.");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const generator = runtime.documentGenerator;
|
|
44
|
+
eventBus.subscribe("booking.confirmed", async (event) => {
|
|
45
|
+
try {
|
|
46
|
+
const db = resolveDb(bindings);
|
|
47
|
+
const result = await autoGenerateContractForBooking(db, event.data, auto, {
|
|
48
|
+
generator,
|
|
49
|
+
eventBus,
|
|
50
|
+
});
|
|
51
|
+
if (result.status !== "ok") {
|
|
52
|
+
console.error(`[legal] auto-generate contract skipped for booking ${event.data.bookingId}: ${result.status}`);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
57
|
+
console.error(`[legal] auto-generate contract failed for booking ${event.data.bookingId}: ${message}`);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
26
61
|
},
|
|
27
62
|
};
|
|
28
63
|
return {
|
|
@@ -34,4 +69,5 @@ export function createLegalHonoModule(options = {}) {
|
|
|
34
69
|
export const legalHonoModule = createLegalHonoModule();
|
|
35
70
|
export * from "./contracts/index.js";
|
|
36
71
|
export { buildContractsRouteRuntime, CONTRACTS_ROUTE_RUNTIME_CONTAINER_KEY, } from "./contracts/route-runtime.js";
|
|
72
|
+
export { autoGenerateContractForBooking, } from "./contracts/service-auto-generate.js";
|
|
37
73
|
export * from "./policies/index.js";
|
|
@@ -114,7 +114,7 @@ export declare const policiesAdminRoutes: import("hono/hono-base").HonoBase<Env,
|
|
|
114
114
|
label: string | null;
|
|
115
115
|
daysBeforeDeparture: number | null;
|
|
116
116
|
refundPercent: number | null;
|
|
117
|
-
refundType: "
|
|
117
|
+
refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
|
|
118
118
|
flatAmountCents: number | null;
|
|
119
119
|
currency: string | null;
|
|
120
120
|
validFrom: string | null;
|
|
@@ -380,7 +380,7 @@ export declare const policiesAdminRoutes: import("hono/hono-base").HonoBase<Env,
|
|
|
380
380
|
label: string | null;
|
|
381
381
|
daysBeforeDeparture: number | null;
|
|
382
382
|
refundPercent: number | null;
|
|
383
|
-
refundType: "
|
|
383
|
+
refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
|
|
384
384
|
flatAmountCents: number | null;
|
|
385
385
|
currency: string | null;
|
|
386
386
|
validFrom: string | null;
|
|
@@ -429,7 +429,7 @@ export declare const policiesAdminRoutes: import("hono/hono-base").HonoBase<Env,
|
|
|
429
429
|
ruleType: "custom" | "window" | "percentage" | "flat_amount" | "date_range";
|
|
430
430
|
daysBeforeDeparture: number | null;
|
|
431
431
|
refundPercent: number | null;
|
|
432
|
-
refundType: "
|
|
432
|
+
refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
|
|
433
433
|
flatAmountCents: number | null;
|
|
434
434
|
};
|
|
435
435
|
};
|
|
@@ -464,7 +464,7 @@ export declare const policiesAdminRoutes: import("hono/hono-base").HonoBase<Env,
|
|
|
464
464
|
label: string | null;
|
|
465
465
|
daysBeforeDeparture: number | null;
|
|
466
466
|
refundPercent: number | null;
|
|
467
|
-
refundType: "
|
|
467
|
+
refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
|
|
468
468
|
flatAmountCents: number | null;
|
|
469
469
|
currency: string | null;
|
|
470
470
|
validFrom: string | null;
|
|
@@ -670,9 +670,9 @@ export declare const policiesAdminRoutes: import("hono/hono-base").HonoBase<Env,
|
|
|
670
670
|
bookingId: string | null;
|
|
671
671
|
orderId: string | null;
|
|
672
672
|
method: "signature" | "implicit" | "explicit_checkbox";
|
|
673
|
-
policyVersionId: string;
|
|
674
|
-
offerId: string | null;
|
|
675
673
|
acceptedAt: string;
|
|
674
|
+
offerId: string | null;
|
|
675
|
+
policyVersionId: string;
|
|
676
676
|
acceptedBy: string | null;
|
|
677
677
|
} | null;
|
|
678
678
|
};
|
|
@@ -892,9 +892,9 @@ export declare const policiesPublicRoutes: import("hono/hono-base").HonoBase<Env
|
|
|
892
892
|
bookingId: string | null;
|
|
893
893
|
orderId: string | null;
|
|
894
894
|
method: "signature" | "implicit" | "explicit_checkbox";
|
|
895
|
-
policyVersionId: string;
|
|
896
|
-
offerId: string | null;
|
|
897
895
|
acceptedAt: string;
|
|
896
|
+
offerId: string | null;
|
|
897
|
+
policyVersionId: string;
|
|
898
898
|
acceptedBy: string | null;
|
|
899
899
|
} | null;
|
|
900
900
|
};
|
|
@@ -507,7 +507,7 @@ export declare const policyRules: import("drizzle-orm/pg-core").PgTableWithColum
|
|
|
507
507
|
tableName: "policy_rules";
|
|
508
508
|
dataType: "string";
|
|
509
509
|
columnType: "PgEnumColumn";
|
|
510
|
-
data: "
|
|
510
|
+
data: "none" | "cash" | "credit" | "cash_or_credit";
|
|
511
511
|
driverParam: string;
|
|
512
512
|
notNull: false;
|
|
513
513
|
hasDefault: false;
|
|
@@ -680,7 +680,7 @@ export declare const policiesCoreService: {
|
|
|
680
680
|
tableName: "policy_rules";
|
|
681
681
|
dataType: "string";
|
|
682
682
|
columnType: "PgEnumColumn";
|
|
683
|
-
data: "
|
|
683
|
+
data: "none" | "cash" | "credit" | "cash_or_credit";
|
|
684
684
|
driverParam: string;
|
|
685
685
|
notNull: false;
|
|
686
686
|
hasDefault: false;
|
|
@@ -835,7 +835,7 @@ export declare const policiesCoreService: {
|
|
|
835
835
|
label: string | null;
|
|
836
836
|
daysBeforeDeparture: number | null;
|
|
837
837
|
refundPercent: number | null;
|
|
838
|
-
refundType: "
|
|
838
|
+
refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
|
|
839
839
|
flatAmountCents: number | null;
|
|
840
840
|
currency: string | null;
|
|
841
841
|
validFrom: string | null;
|
|
@@ -952,7 +952,7 @@ export declare const policiesCoreService: {
|
|
|
952
952
|
tableName: "policy_rules";
|
|
953
953
|
dataType: "string";
|
|
954
954
|
columnType: "PgEnumColumn";
|
|
955
|
-
data: "
|
|
955
|
+
data: "none" | "cash" | "credit" | "cash_or_credit";
|
|
956
956
|
driverParam: string;
|
|
957
957
|
notNull: false;
|
|
958
958
|
hasDefault: false;
|
|
@@ -1115,7 +1115,7 @@ export declare const policiesCoreService: {
|
|
|
1115
1115
|
ruleType: "custom" | "window" | "percentage" | "flat_amount" | "date_range";
|
|
1116
1116
|
daysBeforeDeparture: number | null;
|
|
1117
1117
|
refundPercent: number | null;
|
|
1118
|
-
refundType: "
|
|
1118
|
+
refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
|
|
1119
1119
|
flatAmountCents: number | null;
|
|
1120
1120
|
} | null>;
|
|
1121
1121
|
updatePolicyRule(db: PostgresJsDatabase, ruleId: string, data: UpdatePolicyRuleInput): Promise<{
|
|
@@ -1125,7 +1125,7 @@ export declare const policiesCoreService: {
|
|
|
1125
1125
|
label: string | null;
|
|
1126
1126
|
daysBeforeDeparture: number | null;
|
|
1127
1127
|
refundPercent: number | null;
|
|
1128
|
-
refundType: "
|
|
1128
|
+
refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
|
|
1129
1129
|
flatAmountCents: number | null;
|
|
1130
1130
|
currency: string | null;
|
|
1131
1131
|
validFrom: string | null;
|
|
@@ -1244,7 +1244,7 @@ export declare const policiesCoreService: {
|
|
|
1244
1244
|
label: string | null;
|
|
1245
1245
|
daysBeforeDeparture: number | null;
|
|
1246
1246
|
refundPercent: number | null;
|
|
1247
|
-
refundType: "
|
|
1247
|
+
refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
|
|
1248
1248
|
flatAmountCents: number | null;
|
|
1249
1249
|
currency: string | null;
|
|
1250
1250
|
validFrom: string | null;
|
|
@@ -1286,9 +1286,9 @@ export declare const policiesCoreService: {
|
|
|
1286
1286
|
bookingId: string | null;
|
|
1287
1287
|
orderId: string | null;
|
|
1288
1288
|
method: "signature" | "implicit" | "explicit_checkbox";
|
|
1289
|
-
policyVersionId: string;
|
|
1290
|
-
offerId: string | null;
|
|
1291
1289
|
acceptedAt: Date;
|
|
1290
|
+
offerId: string | null;
|
|
1291
|
+
policyVersionId: string;
|
|
1292
1292
|
acceptedBy: string | null;
|
|
1293
1293
|
} | null>;
|
|
1294
1294
|
};
|
|
@@ -680,7 +680,7 @@ export declare const policiesService: {
|
|
|
680
680
|
tableName: "policy_rules";
|
|
681
681
|
dataType: "string";
|
|
682
682
|
columnType: "PgEnumColumn";
|
|
683
|
-
data: "
|
|
683
|
+
data: "none" | "cash" | "credit" | "cash_or_credit";
|
|
684
684
|
driverParam: string;
|
|
685
685
|
notNull: false;
|
|
686
686
|
hasDefault: false;
|
|
@@ -835,7 +835,7 @@ export declare const policiesService: {
|
|
|
835
835
|
label: string | null;
|
|
836
836
|
daysBeforeDeparture: number | null;
|
|
837
837
|
refundPercent: number | null;
|
|
838
|
-
refundType: "
|
|
838
|
+
refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
|
|
839
839
|
flatAmountCents: number | null;
|
|
840
840
|
currency: string | null;
|
|
841
841
|
validFrom: string | null;
|
|
@@ -952,7 +952,7 @@ export declare const policiesService: {
|
|
|
952
952
|
tableName: "policy_rules";
|
|
953
953
|
dataType: "string";
|
|
954
954
|
columnType: "PgEnumColumn";
|
|
955
|
-
data: "
|
|
955
|
+
data: "none" | "cash" | "credit" | "cash_or_credit";
|
|
956
956
|
driverParam: string;
|
|
957
957
|
notNull: false;
|
|
958
958
|
hasDefault: false;
|
|
@@ -1115,7 +1115,7 @@ export declare const policiesService: {
|
|
|
1115
1115
|
ruleType: "custom" | "window" | "percentage" | "flat_amount" | "date_range";
|
|
1116
1116
|
daysBeforeDeparture: number | null;
|
|
1117
1117
|
refundPercent: number | null;
|
|
1118
|
-
refundType: "
|
|
1118
|
+
refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
|
|
1119
1119
|
flatAmountCents: number | null;
|
|
1120
1120
|
} | null>;
|
|
1121
1121
|
updatePolicyRule(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, ruleId: string, data: import("./service-shared.js").UpdatePolicyRuleInput): Promise<{
|
|
@@ -1125,7 +1125,7 @@ export declare const policiesService: {
|
|
|
1125
1125
|
label: string | null;
|
|
1126
1126
|
daysBeforeDeparture: number | null;
|
|
1127
1127
|
refundPercent: number | null;
|
|
1128
|
-
refundType: "
|
|
1128
|
+
refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
|
|
1129
1129
|
flatAmountCents: number | null;
|
|
1130
1130
|
currency: string | null;
|
|
1131
1131
|
validFrom: string | null;
|
|
@@ -1244,7 +1244,7 @@ export declare const policiesService: {
|
|
|
1244
1244
|
label: string | null;
|
|
1245
1245
|
daysBeforeDeparture: number | null;
|
|
1246
1246
|
refundPercent: number | null;
|
|
1247
|
-
refundType: "
|
|
1247
|
+
refundType: "none" | "cash" | "credit" | "cash_or_credit" | null;
|
|
1248
1248
|
flatAmountCents: number | null;
|
|
1249
1249
|
currency: string | null;
|
|
1250
1250
|
validFrom: string | null;
|
|
@@ -1286,9 +1286,9 @@ export declare const policiesService: {
|
|
|
1286
1286
|
bookingId: string | null;
|
|
1287
1287
|
orderId: string | null;
|
|
1288
1288
|
method: "signature" | "implicit" | "explicit_checkbox";
|
|
1289
|
-
policyVersionId: string;
|
|
1290
|
-
offerId: string | null;
|
|
1291
1289
|
acceptedAt: Date;
|
|
1290
|
+
offerId: string | null;
|
|
1291
|
+
policyVersionId: string;
|
|
1292
1292
|
acceptedBy: string | null;
|
|
1293
1293
|
} | null>;
|
|
1294
1294
|
};
|
|
@@ -22,10 +22,10 @@ export declare const policyRuleTypeSchema: z.ZodEnum<{
|
|
|
22
22
|
date_range: "date_range";
|
|
23
23
|
}>;
|
|
24
24
|
export declare const policyRefundTypeSchema: z.ZodEnum<{
|
|
25
|
+
none: "none";
|
|
25
26
|
cash: "cash";
|
|
26
27
|
credit: "credit";
|
|
27
28
|
cash_or_credit: "cash_or_credit";
|
|
28
|
-
none: "none";
|
|
29
29
|
}>;
|
|
30
30
|
export declare const policyAssignmentScopeSchema: z.ZodEnum<{
|
|
31
31
|
supplier: "supplier";
|
|
@@ -114,10 +114,10 @@ export declare const insertPolicyRuleSchema: z.ZodObject<{
|
|
|
114
114
|
daysBeforeDeparture: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
|
|
115
115
|
refundPercent: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
|
|
116
116
|
refundType: z.ZodNullable<z.ZodOptional<z.ZodEnum<{
|
|
117
|
+
none: "none";
|
|
117
118
|
cash: "cash";
|
|
118
119
|
credit: "credit";
|
|
119
120
|
cash_or_credit: "cash_or_credit";
|
|
120
|
-
none: "none";
|
|
121
121
|
}>>>;
|
|
122
122
|
flatAmountCents: z.ZodNullable<z.ZodOptional<z.ZodNumber>>;
|
|
123
123
|
currency: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
@@ -138,10 +138,10 @@ export declare const updatePolicyRuleSchema: z.ZodObject<{
|
|
|
138
138
|
daysBeforeDeparture: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodNumber>>>;
|
|
139
139
|
refundPercent: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodNumber>>>;
|
|
140
140
|
refundType: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodEnum<{
|
|
141
|
+
none: "none";
|
|
141
142
|
cash: "cash";
|
|
142
143
|
credit: "credit";
|
|
143
144
|
cash_or_credit: "cash_or_credit";
|
|
144
|
-
none: "none";
|
|
145
145
|
}>>>>;
|
|
146
146
|
flatAmountCents: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodNumber>>>;
|
|
147
147
|
currency: z.ZodOptional<z.ZodNullable<z.ZodOptional<z.ZodString>>>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyantjs/legal",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"license": "FSL-1.1-Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -53,13 +53,14 @@
|
|
|
53
53
|
"drizzle-orm": "^0.45.2",
|
|
54
54
|
"hono": "^4.12.10",
|
|
55
55
|
"zod": "^4.3.6",
|
|
56
|
-
"@voyantjs/
|
|
57
|
-
"@voyantjs/
|
|
58
|
-
"@voyantjs/
|
|
59
|
-
"@voyantjs/
|
|
60
|
-
"@voyantjs/
|
|
61
|
-
"@voyantjs/
|
|
62
|
-
"@voyantjs/
|
|
56
|
+
"@voyantjs/bookings": "0.8.0",
|
|
57
|
+
"@voyantjs/core": "0.8.0",
|
|
58
|
+
"@voyantjs/crm": "0.8.0",
|
|
59
|
+
"@voyantjs/db": "0.8.0",
|
|
60
|
+
"@voyantjs/hono": "0.8.0",
|
|
61
|
+
"@voyantjs/suppliers": "0.8.0",
|
|
62
|
+
"@voyantjs/utils": "0.8.0",
|
|
63
|
+
"@voyantjs/voyant-storage": "0.8.0"
|
|
63
64
|
},
|
|
64
65
|
"devDependencies": {
|
|
65
66
|
"typescript": "^6.0.2",
|