@voyantjs/legal 0.9.0 → 0.10.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.
@@ -88,9 +88,9 @@ export declare function createContractsAdminRoutes(options?: ContractsRouteOptio
88
88
  scope: "customer" | "partner" | "supplier" | "other" | "channel";
89
89
  slug: string;
90
90
  description: string | null;
91
- language: string;
92
91
  active: boolean;
93
92
  body: string;
93
+ language: string;
94
94
  variableSchema: import("hono/utils/types").JSONValue;
95
95
  currentVersionId: string | null;
96
96
  } | null;
@@ -531,11 +531,11 @@ export declare function createContractsAdminRoutes(options?: ContractsRouteOptio
531
531
  scope: "customer" | "partner" | "supplier" | "other" | "channel";
532
532
  organizationId: string | null;
533
533
  status: "executed" | "void" | "draft" | "issued" | "sent" | "signed" | "expired";
534
+ bookingId: string | null;
534
535
  language: string;
535
536
  variables: import("hono/utils/types").JSONValue;
536
537
  personId: string | null;
537
538
  supplierId: string | null;
538
- bookingId: string | null;
539
539
  orderId: string | null;
540
540
  title: string;
541
541
  templateVersionId: string | null;
@@ -886,12 +886,12 @@ export declare function createContractsAdminRoutes(options?: ContractsRouteOptio
886
886
  createdAt: string;
887
887
  ipAddress: string | null;
888
888
  userAgent: string | null;
889
+ provider: string | null;
889
890
  personId: string | null;
890
891
  signerName: string;
891
892
  signerEmail: string | null;
892
893
  signerRole: string | null;
893
894
  method: "other" | "manual" | "electronic" | "docusign";
894
- provider: string | null;
895
895
  externalReference: string | null;
896
896
  signatureData: string | null;
897
897
  contractId: string;
@@ -1479,9 +1479,9 @@ export declare const contractsAdminRoutes: import("hono/hono-base").HonoBase<Env
1479
1479
  scope: "customer" | "partner" | "supplier" | "other" | "channel";
1480
1480
  slug: string;
1481
1481
  description: string | null;
1482
- language: string;
1483
1482
  active: boolean;
1484
1483
  body: string;
1484
+ language: string;
1485
1485
  variableSchema: import("hono/utils/types").JSONValue;
1486
1486
  currentVersionId: string | null;
1487
1487
  } | null;
@@ -1922,11 +1922,11 @@ export declare const contractsAdminRoutes: import("hono/hono-base").HonoBase<Env
1922
1922
  scope: "customer" | "partner" | "supplier" | "other" | "channel";
1923
1923
  organizationId: string | null;
1924
1924
  status: "executed" | "void" | "draft" | "issued" | "sent" | "signed" | "expired";
1925
+ bookingId: string | null;
1925
1926
  language: string;
1926
1927
  variables: import("hono/utils/types").JSONValue;
1927
1928
  personId: string | null;
1928
1929
  supplierId: string | null;
1929
- bookingId: string | null;
1930
1930
  orderId: string | null;
1931
1931
  title: string;
1932
1932
  templateVersionId: string | null;
@@ -2277,12 +2277,12 @@ export declare const contractsAdminRoutes: import("hono/hono-base").HonoBase<Env
2277
2277
  createdAt: string;
2278
2278
  ipAddress: string | null;
2279
2279
  userAgent: string | null;
2280
+ provider: string | null;
2280
2281
  personId: string | null;
2281
2282
  signerName: string;
2282
2283
  signerEmail: string | null;
2283
2284
  signerRole: string | null;
2284
2285
  method: "other" | "manual" | "electronic" | "docusign";
2285
- provider: string | null;
2286
2286
  externalReference: string | null;
2287
2287
  signatureData: string | null;
2288
2288
  contractId: string;
@@ -2947,12 +2947,12 @@ export declare function createContractsPublicRoutes(): import("hono/hono-base").
2947
2947
  createdAt: string;
2948
2948
  ipAddress: string | null;
2949
2949
  userAgent: string | null;
2950
+ provider: string | null;
2950
2951
  personId: string | null;
2951
2952
  signerName: string;
2952
2953
  signerEmail: string | null;
2953
2954
  signerRole: string | null;
2954
2955
  method: "other" | "manual" | "electronic" | "docusign";
2955
- provider: string | null;
2956
2956
  externalReference: string | null;
2957
2957
  signatureData: string | null;
2958
2958
  contractId: string;
@@ -3113,12 +3113,12 @@ export declare const contractsPublicRoutes: import("hono/hono-base").HonoBase<En
3113
3113
  createdAt: string;
3114
3114
  ipAddress: string | null;
3115
3115
  userAgent: string | null;
3116
+ provider: string | null;
3116
3117
  personId: string | null;
3117
3118
  signerName: string;
3118
3119
  signerEmail: string | null;
3119
3120
  signerRole: string | null;
3120
3121
  method: "other" | "manual" | "electronic" | "docusign";
3121
- provider: string | null;
3122
3122
  externalReference: string | null;
3123
3123
  signatureData: string | null;
3124
3124
  contractId: string;
@@ -69,11 +69,11 @@ export declare const contractRecordsService: {
69
69
  scope: "customer" | "partner" | "supplier" | "other" | "channel";
70
70
  organizationId: string | null;
71
71
  status: "executed" | "void" | "draft" | "issued" | "sent" | "signed" | "expired";
72
+ bookingId: string | null;
72
73
  language: string;
73
74
  variables: unknown;
74
75
  personId: string | null;
75
76
  supplierId: string | null;
76
- bookingId: string | null;
77
77
  orderId: string | null;
78
78
  title: string;
79
79
  templateVersionId: string | null;
@@ -801,12 +801,12 @@ export declare const contractRecordsService: {
801
801
  createdAt: Date;
802
802
  ipAddress: string | null;
803
803
  userAgent: string | null;
804
+ provider: string | null;
804
805
  personId: string | null;
805
806
  signerName: string;
806
807
  signerEmail: string | null;
807
808
  signerRole: string | null;
808
809
  method: "other" | "manual" | "electronic" | "docusign";
809
- provider: string | null;
810
810
  externalReference: string | null;
811
811
  signatureData: string | null;
812
812
  contractId: string;
@@ -78,9 +78,9 @@ export declare const contractTemplatesService: {
78
78
  scope: "customer" | "partner" | "supplier" | "other" | "channel";
79
79
  slug: string;
80
80
  description: string | null;
81
- language: string;
82
81
  active: boolean;
83
82
  body: string;
83
+ language: string;
84
84
  variableSchema: unknown;
85
85
  currentVersionId: string | null;
86
86
  } | null>;
@@ -81,11 +81,11 @@ export declare const contractsService: {
81
81
  scope: "customer" | "partner" | "supplier" | "other" | "channel";
82
82
  organizationId: string | null;
83
83
  status: "executed" | "void" | "draft" | "issued" | "sent" | "signed" | "expired";
84
+ bookingId: string | null;
84
85
  language: string;
85
86
  variables: unknown;
86
87
  personId: string | null;
87
88
  supplierId: string | null;
88
- bookingId: string | null;
89
89
  orderId: string | null;
90
90
  title: string;
91
91
  templateVersionId: string | null;
@@ -813,12 +813,12 @@ export declare const contractsService: {
813
813
  createdAt: Date;
814
814
  ipAddress: string | null;
815
815
  userAgent: string | null;
816
+ provider: string | null;
816
817
  personId: string | null;
817
818
  signerName: string;
818
819
  signerEmail: string | null;
819
820
  signerRole: string | null;
820
821
  method: "other" | "manual" | "electronic" | "docusign";
821
- provider: string | null;
822
822
  externalReference: string | null;
823
823
  signatureData: string | null;
824
824
  contractId: string;
@@ -1400,9 +1400,9 @@ export declare const contractsService: {
1400
1400
  scope: "customer" | "partner" | "supplier" | "other" | "channel";
1401
1401
  slug: string;
1402
1402
  description: string | null;
1403
- language: string;
1404
1403
  active: boolean;
1405
1404
  body: string;
1405
+ language: string;
1406
1406
  variableSchema: unknown;
1407
1407
  currentVersionId: string | null;
1408
1408
  } | null>;
@@ -10,7 +10,7 @@ export declare const policiesLinkable: {
10
10
  };
11
11
  export type { NewPolicy, NewPolicyAcceptance, NewPolicyAssignment, NewPolicyRule, NewPolicyVersion, Policy, PolicyAcceptance, PolicyAssignment, PolicyRule, PolicyVersion, } from "./schema.js";
12
12
  export { policies, policyAcceptances, policyAssignments, policyRules, policyVersions, } from "./schema.js";
13
- export type { CancellationResult, CancellationRule } from "./service.js";
14
- export { evaluateCancellationPolicy, policiesService } from "./service.js";
13
+ export type { CancellationResult, CancellationRule, CancellationSegment, SegmentedCancellationInput, SegmentedCancellationResult, } from "./service.js";
14
+ export { evaluateCancellationPolicy, evaluateSegmentedCancellation, policiesService, } from "./service.js";
15
15
  export { evaluateCancellationInputSchema, insertPolicyAcceptanceSchema, insertPolicyAssignmentSchema, insertPolicyRuleSchema, insertPolicySchema, insertPolicyVersionSchema, policyAcceptanceListQuerySchema, policyAcceptanceMethodSchema, policyAssignmentListQuerySchema, policyAssignmentScopeSchema, policyKindSchema, policyListQuerySchema, policyRefundTypeSchema, policyRuleTypeSchema, policyVersionStatusSchema, resolvePolicyInputSchema, updatePolicyAssignmentSchema, updatePolicyRuleSchema, updatePolicySchema, updatePolicyVersionSchema, } from "./validation.js";
16
16
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/policies/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAExD,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAE5E,eAAO,MAAM,cAAc,EAAE,kBAK5B,CAAA;AAED,eAAO,MAAM,qBAAqB,EAAE,kBAKnC,CAAA;AAED,eAAO,MAAM,wBAAwB,EAAE,kBAKtC,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;CAI5B,CAAA;AAED,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,MAAM,EACN,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,aAAa,GACd,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,cAAc,GACf,MAAM,aAAa,CAAA;AACpB,YAAY,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAA;AACxE,OAAO,EAAE,0BAA0B,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAC1E,OAAO,EACL,+BAA+B,EAC/B,4BAA4B,EAC5B,4BAA4B,EAC5B,sBAAsB,EACtB,kBAAkB,EAClB,yBAAyB,EACzB,+BAA+B,EAC/B,4BAA4B,EAC5B,+BAA+B,EAC/B,2BAA2B,EAC3B,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,yBAAyB,EACzB,wBAAwB,EACxB,4BAA4B,EAC5B,sBAAsB,EACtB,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/policies/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAA;AAExD,YAAY,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAE5E,eAAO,MAAM,cAAc,EAAE,kBAK5B,CAAA;AAED,eAAO,MAAM,qBAAqB,EAAE,kBAKnC,CAAA;AAED,eAAO,MAAM,wBAAwB,EAAE,kBAKtC,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;CAI5B,CAAA;AAED,YAAY,EACV,SAAS,EACT,mBAAmB,EACnB,mBAAmB,EACnB,aAAa,EACb,gBAAgB,EAChB,MAAM,EACN,gBAAgB,EAChB,gBAAgB,EAChB,UAAU,EACV,aAAa,GACd,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,QAAQ,EACR,iBAAiB,EACjB,iBAAiB,EACjB,WAAW,EACX,cAAc,GACf,MAAM,aAAa,CAAA;AACpB,YAAY,EACV,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,0BAA0B,EAC1B,2BAA2B,GAC5B,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,0BAA0B,EAC1B,6BAA6B,EAC7B,eAAe,GAChB,MAAM,cAAc,CAAA;AACrB,OAAO,EACL,+BAA+B,EAC/B,4BAA4B,EAC5B,4BAA4B,EAC5B,sBAAsB,EACtB,kBAAkB,EAClB,yBAAyB,EACzB,+BAA+B,EAC/B,4BAA4B,EAC5B,+BAA+B,EAC/B,2BAA2B,EAC3B,gBAAgB,EAChB,qBAAqB,EACrB,sBAAsB,EACtB,oBAAoB,EACpB,yBAAyB,EACzB,wBAAwB,EACxB,4BAA4B,EAC5B,sBAAsB,EACtB,kBAAkB,EAClB,yBAAyB,GAC1B,MAAM,iBAAiB,CAAA"}
@@ -22,5 +22,5 @@ export const policiesLinkable = {
22
22
  policyAcceptance: policyAcceptanceLinkable,
23
23
  };
24
24
  export { policies, policyAcceptances, policyAssignments, policyRules, policyVersions, } from "./schema.js";
25
- export { evaluateCancellationPolicy, policiesService } from "./service.js";
25
+ export { evaluateCancellationPolicy, evaluateSegmentedCancellation, policiesService, } from "./service.js";
26
26
  export { evaluateCancellationInputSchema, insertPolicyAcceptanceSchema, insertPolicyAssignmentSchema, insertPolicyRuleSchema, insertPolicySchema, insertPolicyVersionSchema, policyAcceptanceListQuerySchema, policyAcceptanceMethodSchema, policyAssignmentListQuerySchema, policyAssignmentScopeSchema, policyKindSchema, policyListQuerySchema, policyRefundTypeSchema, policyRuleTypeSchema, policyVersionStatusSchema, resolvePolicyInputSchema, updatePolicyAssignmentSchema, updatePolicyRuleSchema, updatePolicySchema, updatePolicyVersionSchema, } from "./validation.js";
@@ -666,8 +666,8 @@ export declare const policiesAdminRoutes: import("hono/hono-base").HonoBase<Env,
666
666
  createdAt: string;
667
667
  ipAddress: string | null;
668
668
  userAgent: string | null;
669
- personId: string | null;
670
669
  bookingId: string | null;
670
+ personId: string | null;
671
671
  orderId: string | null;
672
672
  method: "signature" | "implicit" | "explicit_checkbox";
673
673
  acceptedAt: string;
@@ -888,8 +888,8 @@ export declare const policiesPublicRoutes: import("hono/hono-base").HonoBase<Env
888
888
  createdAt: string;
889
889
  ipAddress: string | null;
890
890
  userAgent: string | null;
891
- personId: string | null;
892
891
  bookingId: string | null;
892
+ personId: string | null;
893
893
  orderId: string | null;
894
894
  method: "signature" | "implicit" | "explicit_checkbox";
895
895
  acceptedAt: string;
@@ -1,5 +1,5 @@
1
1
  import type { PostgresJsDatabase } from "drizzle-orm/postgres-js";
2
- import { type CreatePolicyAcceptanceInput, type CreatePolicyAssignmentInput, type CreatePolicyInput, type CreatePolicyRuleInput, type CreatePolicyVersionInput, type EvaluateCancellationInput, type PolicyAcceptanceListQuery, type PolicyAssignmentListQuery, type PolicyListQuery, type ResolvePolicyInput, type UpdatePolicyAssignmentInput, type UpdatePolicyInput, type UpdatePolicyRuleInput, type UpdatePolicyVersionInput } from "./service-shared.js";
2
+ import { type CreatePolicyAcceptanceInput, type CreatePolicyAssignmentInput, type CreatePolicyInput, type CreatePolicyRuleInput, type CreatePolicyVersionInput, type EvaluateCancellationInput, type PolicyAcceptanceListQuery, type PolicyAssignmentListQuery, type PolicyListQuery, type ResolvePolicyInput, type SegmentedCancellationResult, type UpdatePolicyAssignmentInput, type UpdatePolicyInput, type UpdatePolicyRuleInput, type UpdatePolicyVersionInput } from "./service-shared.js";
3
3
  export declare const policiesCoreService: {
4
4
  listPolicies(db: PostgresJsDatabase, query: PolicyListQuery): Promise<{
5
5
  data: {
@@ -1256,6 +1256,27 @@ export declare const policiesCoreService: {
1256
1256
  }[];
1257
1257
  } | null>;
1258
1258
  evaluateCancellation(db: PostgresJsDatabase, policyId: string, input: EvaluateCancellationInput): Promise<import("./service-shared.js").CancellationResult | null>;
1259
+ /**
1260
+ * DB variant of {@link evaluateSegmentedCancellation} that resolves
1261
+ * each segment's rules from a `policyId`. Use this for multi-segment
1262
+ * cancellations where each line item may carry a different
1263
+ * cancellation policy (e.g. mid-stay room change with mixed
1264
+ * flexible/non-refundable rate plans).
1265
+ *
1266
+ * Segments referencing a missing or version-less policy are passed
1267
+ * through with empty `rules`, which produces a zero refund — surfaces
1268
+ * as a per-segment `appliedRule: null` for ops triage rather than
1269
+ * throwing on the whole cancellation.
1270
+ */
1271
+ evaluateMultiPolicyCancellation(db: PostgresJsDatabase, segments: Array<{
1272
+ id?: string;
1273
+ label?: string;
1274
+ policyId: string;
1275
+ totalCents: number;
1276
+ }>, input: {
1277
+ daysBeforeDeparture: number;
1278
+ currency?: string;
1279
+ }): Promise<SegmentedCancellationResult>;
1259
1280
  listPolicyAcceptances(db: PostgresJsDatabase, query: PolicyAcceptanceListQuery): Promise<{
1260
1281
  data: {
1261
1282
  id: string;
@@ -1282,8 +1303,8 @@ export declare const policiesCoreService: {
1282
1303
  createdAt: Date;
1283
1304
  ipAddress: string | null;
1284
1305
  userAgent: string | null;
1285
- personId: string | null;
1286
1306
  bookingId: string | null;
1307
+ personId: string | null;
1287
1308
  orderId: string | null;
1288
1309
  method: "signature" | "implicit" | "explicit_checkbox";
1289
1310
  acceptedAt: Date;
@@ -1 +1 @@
1
- {"version":3,"file":"service-core.d.ts","sourceRoot":"","sources":["../../src/policies/service-core.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service-core.d.ts","sourceRoot":"","sources":["../../src/policies/service-core.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { and, desc, eq, gte, ilike, lte, or, sql } from "drizzle-orm";
2
2
  import { policies, policyAcceptances, policyAssignments, policyRules, policyVersions, } from "./schema.js";
3
- import { evaluateCancellationPolicy, paginate, toDateString, } from "./service-shared.js";
3
+ import { evaluateCancellationPolicy, evaluateSegmentedCancellation, paginate, toDateString, } from "./service-shared.js";
4
4
  export const policiesCoreService = {
5
5
  async listPolicies(db, query) {
6
6
  const conditions = [];
@@ -316,6 +316,55 @@ export const policiesCoreService = {
316
316
  }));
317
317
  return evaluateCancellationPolicy(mapped, input);
318
318
  },
319
+ /**
320
+ * DB variant of {@link evaluateSegmentedCancellation} that resolves
321
+ * each segment's rules from a `policyId`. Use this for multi-segment
322
+ * cancellations where each line item may carry a different
323
+ * cancellation policy (e.g. mid-stay room change with mixed
324
+ * flexible/non-refundable rate plans).
325
+ *
326
+ * Segments referencing a missing or version-less policy are passed
327
+ * through with empty `rules`, which produces a zero refund — surfaces
328
+ * as a per-segment `appliedRule: null` for ops triage rather than
329
+ * throwing on the whole cancellation.
330
+ */
331
+ async evaluateMultiPolicyCancellation(db, segments, input) {
332
+ const policyIds = [...new Set(segments.map((segment) => segment.policyId))];
333
+ const rulesByPolicyId = new Map();
334
+ for (const policyId of policyIds) {
335
+ const [policy] = await db
336
+ .select({ id: policies.id, currentVersionId: policies.currentVersionId })
337
+ .from(policies)
338
+ .where(eq(policies.id, policyId))
339
+ .limit(1);
340
+ if (!policy?.currentVersionId) {
341
+ rulesByPolicyId.set(policyId, []);
342
+ continue;
343
+ }
344
+ const rules = await db
345
+ .select()
346
+ .from(policyRules)
347
+ .where(eq(policyRules.policyVersionId, policy.currentVersionId));
348
+ rulesByPolicyId.set(policyId, rules.map((r) => ({
349
+ id: r.id,
350
+ daysBeforeDeparture: r.daysBeforeDeparture,
351
+ refundPercent: r.refundPercent,
352
+ refundType: r.refundType,
353
+ flatAmountCents: r.flatAmountCents,
354
+ label: r.label,
355
+ })));
356
+ }
357
+ return evaluateSegmentedCancellation({
358
+ daysBeforeDeparture: input.daysBeforeDeparture,
359
+ currency: input.currency,
360
+ segments: segments.map((segment) => ({
361
+ id: segment.id,
362
+ label: segment.label,
363
+ totalCents: segment.totalCents,
364
+ rules: rulesByPolicyId.get(segment.policyId) ?? [],
365
+ })),
366
+ });
367
+ },
319
368
  async listPolicyAcceptances(db, query) {
320
369
  const conditions = [];
321
370
  if (query.policyVersionId)
@@ -39,5 +39,62 @@ export type CancellationResult = {
39
39
  appliedRule: CancellationRule | null;
40
40
  };
41
41
  export declare function evaluateCancellationPolicy(rules: CancellationRule[], input: EvaluateCancellationInput): CancellationResult;
42
+ /**
43
+ * One revenue line in a multi-segment cancellation. Each segment carries
44
+ * its own rule set + own amount; segments that share a policy still need
45
+ * to be passed in separately so the per-segment refund tracks the
46
+ * specific line item.
47
+ */
48
+ export type CancellationSegment = {
49
+ /** Optional caller-supplied id — typically the booking_item id. */
50
+ id?: string;
51
+ /** Optional human-readable label (e.g. "Deluxe room, 3 nights"). */
52
+ label?: string;
53
+ rules: CancellationRule[];
54
+ totalCents: number;
55
+ };
56
+ export type SegmentedCancellationInput = {
57
+ daysBeforeDeparture: number;
58
+ currency?: string;
59
+ segments: CancellationSegment[];
60
+ };
61
+ export type SegmentedCancellationResult = {
62
+ /** Σ(segments.totalCents). */
63
+ totalCents: number;
64
+ /** Σ(per-segment refundCents). */
65
+ refundCents: number;
66
+ /** Aggregate refund as basis points: refundCents / totalCents × 10000. */
67
+ refundPercent: number;
68
+ /**
69
+ * "mixed" when the segments resolve to different refundTypes (e.g. one
70
+ * segment is `cash` and another is `none`). When all non-zero
71
+ * segments resolve to the same refundType, that value is preserved.
72
+ * "none" when every segment resolves to 0 refund.
73
+ */
74
+ refundType: "cash" | "credit" | "cash_or_credit" | "none" | "mixed";
75
+ segments: Array<{
76
+ id?: string;
77
+ label?: string;
78
+ totalCents: number;
79
+ result: CancellationResult;
80
+ }>;
81
+ };
82
+ /**
83
+ * Evaluate a multi-segment cancellation. Each segment runs through
84
+ * {@link evaluateCancellationPolicy} with the shared
85
+ * `daysBeforeDeparture`; per-segment refunds are summed and a coarse
86
+ * `refundType` is computed for the aggregate.
87
+ *
88
+ * Use case: hotel bookings with mid-stay room changes where each
89
+ * `stay_booking_items.ratePlanId` carries a different
90
+ * `cancellationPolicyId` (e.g. flexible Deluxe + non-refundable Suite).
91
+ * The customer cancels and we owe a partial refund — the flexible
92
+ * portion's refundCents + 0 from the non-refundable portion.
93
+ *
94
+ * Pure: no I/O. Caller resolves rules from policy IDs first (see
95
+ * {@link policiesService.evaluateMultiPolicyCancellation} for the DB
96
+ * variant).
97
+ */
98
+ export declare function evaluateSegmentedCancellation(input: SegmentedCancellationInput): SegmentedCancellationResult;
42
99
  export declare const _unused: typeof inArray;
43
100
  //# sourceMappingURL=service-shared.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"service-shared.d.ts","sourceRoot":"","sources":["../../src/policies/service-shared.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service-shared.d.ts","sourceRoot":"","sources":["../../src/policies/service-shared.ts"],"names":[],"mappings":"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"}
@@ -27,4 +27,55 @@ export function evaluateCancellationPolicy(rules, input) {
27
27
  const refundCents = applied.flatAmountCents ?? percentageRefundCents;
28
28
  return { refundPercent, refundCents, refundType, appliedRule: applied };
29
29
  }
30
+ /**
31
+ * Evaluate a multi-segment cancellation. Each segment runs through
32
+ * {@link evaluateCancellationPolicy} with the shared
33
+ * `daysBeforeDeparture`; per-segment refunds are summed and a coarse
34
+ * `refundType` is computed for the aggregate.
35
+ *
36
+ * Use case: hotel bookings with mid-stay room changes where each
37
+ * `stay_booking_items.ratePlanId` carries a different
38
+ * `cancellationPolicyId` (e.g. flexible Deluxe + non-refundable Suite).
39
+ * The customer cancels and we owe a partial refund — the flexible
40
+ * portion's refundCents + 0 from the non-refundable portion.
41
+ *
42
+ * Pure: no I/O. Caller resolves rules from policy IDs first (see
43
+ * {@link policiesService.evaluateMultiPolicyCancellation} for the DB
44
+ * variant).
45
+ */
46
+ export function evaluateSegmentedCancellation(input) {
47
+ const totalCents = input.segments.reduce((sum, segment) => sum + segment.totalCents, 0);
48
+ const segmentResults = input.segments.map((segment) => ({
49
+ id: segment.id,
50
+ label: segment.label,
51
+ totalCents: segment.totalCents,
52
+ result: evaluateCancellationPolicy(segment.rules, {
53
+ daysBeforeDeparture: input.daysBeforeDeparture,
54
+ totalCents: segment.totalCents,
55
+ currency: input.currency,
56
+ }),
57
+ }));
58
+ const refundCents = segmentResults.reduce((sum, segment) => sum + segment.result.refundCents, 0);
59
+ const refundPercent = totalCents > 0 ? Math.floor((refundCents * 10000) / totalCents) : 0;
60
+ const nonZeroTypes = new Set(segmentResults
61
+ .filter((segment) => segment.result.refundCents > 0)
62
+ .map((segment) => segment.result.refundType));
63
+ let refundType;
64
+ if (nonZeroTypes.size === 0) {
65
+ refundType = "none";
66
+ }
67
+ else if (nonZeroTypes.size === 1) {
68
+ refundType = [...nonZeroTypes][0];
69
+ }
70
+ else {
71
+ refundType = "mixed";
72
+ }
73
+ return {
74
+ totalCents,
75
+ refundCents,
76
+ refundPercent,
77
+ refundType,
78
+ segments: segmentResults,
79
+ };
80
+ }
30
81
  export const _unused = inArray;
@@ -1,5 +1,5 @@
1
- import { _unused, type CancellationResult, type CancellationRule, evaluateCancellationPolicy } from "./service-shared.js";
2
- export { _unused, type CancellationResult, type CancellationRule, evaluateCancellationPolicy };
1
+ import { _unused, type CancellationResult, type CancellationRule, type CancellationSegment, evaluateCancellationPolicy, evaluateSegmentedCancellation, type SegmentedCancellationInput, type SegmentedCancellationResult } from "./service-shared.js";
2
+ export { _unused, type CancellationResult, type CancellationRule, type CancellationSegment, evaluateCancellationPolicy, evaluateSegmentedCancellation, type SegmentedCancellationInput, type SegmentedCancellationResult, };
3
3
  export declare const policiesService: {
4
4
  listPolicies(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, query: import("./service-shared.js").PolicyListQuery): Promise<{
5
5
  data: {
@@ -1256,6 +1256,15 @@ export declare const policiesService: {
1256
1256
  }[];
1257
1257
  } | null>;
1258
1258
  evaluateCancellation(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, policyId: string, input: import("./service-shared.js").EvaluateCancellationInput): Promise<CancellationResult | null>;
1259
+ evaluateMultiPolicyCancellation(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, segments: Array<{
1260
+ id?: string;
1261
+ label?: string;
1262
+ policyId: string;
1263
+ totalCents: number;
1264
+ }>, input: {
1265
+ daysBeforeDeparture: number;
1266
+ currency?: string;
1267
+ }): Promise<SegmentedCancellationResult>;
1259
1268
  listPolicyAcceptances(db: import("drizzle-orm/postgres-js").PostgresJsDatabase, query: import("./service-shared.js").PolicyAcceptanceListQuery): Promise<{
1260
1269
  data: {
1261
1270
  id: string;
@@ -1282,8 +1291,8 @@ export declare const policiesService: {
1282
1291
  createdAt: Date;
1283
1292
  ipAddress: string | null;
1284
1293
  userAgent: string | null;
1285
- personId: string | null;
1286
1294
  bookingId: string | null;
1295
+ personId: string | null;
1287
1296
  orderId: string | null;
1288
1297
  method: "signature" | "implicit" | "explicit_checkbox";
1289
1298
  acceptedAt: Date;
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/policies/service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,OAAO,EACP,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,0BAA0B,EAC3B,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,0BAA0B,EAAE,CAAA;AAE9F,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAE3B,CAAA"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/policies/service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,OAAO,EACP,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,0BAA0B,EAC1B,6BAA6B,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,EACjC,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EACL,OAAO,EACP,KAAK,kBAAkB,EACvB,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,0BAA0B,EAC1B,6BAA6B,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,2BAA2B,GACjC,CAAA;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAGo8b,CAAC;aAAoB,CAAC;;;;;gBAAmH,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CADzmc,CAAA"}
@@ -1,6 +1,6 @@
1
1
  import { policiesCoreService } from "./service-core.js";
2
- import { _unused, evaluateCancellationPolicy, } from "./service-shared.js";
3
- export { _unused, evaluateCancellationPolicy };
2
+ import { _unused, evaluateCancellationPolicy, evaluateSegmentedCancellation, } from "./service-shared.js";
3
+ export { _unused, evaluateCancellationPolicy, evaluateSegmentedCancellation, };
4
4
  export const policiesService = {
5
5
  ...policiesCoreService,
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voyantjs/legal",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "license": "FSL-1.1-Apache-2.0",
5
5
  "type": "module",
6
6
  "exports": {
@@ -53,14 +53,14 @@
53
53
  "drizzle-orm": "^0.45.2",
54
54
  "hono": "^4.12.10",
55
55
  "zod": "^4.3.6",
56
- "@voyantjs/bookings": "0.9.0",
57
- "@voyantjs/core": "0.9.0",
58
- "@voyantjs/crm": "0.9.0",
59
- "@voyantjs/db": "0.9.0",
60
- "@voyantjs/hono": "0.9.0",
61
- "@voyantjs/suppliers": "0.9.0",
62
- "@voyantjs/utils": "0.9.0",
63
- "@voyantjs/voyant-storage": "0.9.0"
56
+ "@voyantjs/core": "0.10.0",
57
+ "@voyantjs/crm": "0.10.0",
58
+ "@voyantjs/db": "0.10.0",
59
+ "@voyantjs/hono": "0.10.0",
60
+ "@voyantjs/suppliers": "0.10.0",
61
+ "@voyantjs/utils": "0.10.0",
62
+ "@voyantjs/voyant-storage": "0.10.0",
63
+ "@voyantjs/bookings": "0.10.0"
64
64
  },
65
65
  "devDependencies": {
66
66
  "typescript": "^6.0.2",