@voyantjs/products 0.28.3 → 0.29.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/booking-engine/handler.d.ts +8 -0
- package/dist/booking-engine/handler.d.ts.map +1 -1
- package/dist/booking-engine/handler.js +38 -0
- package/dist/catalog-policy-departures.d.ts +52 -0
- package/dist/catalog-policy-departures.d.ts.map +1 -0
- package/dist/catalog-policy-departures.js +169 -0
- package/dist/catalog-policy-destinations.d.ts +41 -0
- package/dist/catalog-policy-destinations.d.ts.map +1 -0
- package/dist/catalog-policy-destinations.js +121 -0
- package/dist/catalog-policy-pricing.d.ts +55 -0
- package/dist/catalog-policy-pricing.d.ts.map +1 -0
- package/dist/catalog-policy-pricing.js +109 -0
- package/dist/catalog-policy-promotions.d.ts +52 -0
- package/dist/catalog-policy-promotions.d.ts.map +1 -0
- package/dist/catalog-policy-promotions.js +270 -0
- package/dist/catalog-policy-taxonomy.d.ts +51 -0
- package/dist/catalog-policy-taxonomy.d.ts.map +1 -0
- package/dist/catalog-policy-taxonomy.js +191 -0
- package/dist/events.d.ts +1 -1
- package/dist/events.d.ts.map +1 -1
- package/dist/routes.d.ts +254 -19
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +73 -5
- package/dist/schema-taxonomy.d.ts +287 -0
- package/dist/schema-taxonomy.d.ts.map +1 -1
- package/dist/schema-taxonomy.js +47 -0
- package/dist/service-catalog-plane-destinations.d.ts +30 -0
- package/dist/service-catalog-plane-destinations.d.ts.map +1 -0
- package/dist/service-catalog-plane-destinations.js +119 -0
- package/dist/service-catalog-plane-taxonomy.d.ts +73 -0
- package/dist/service-catalog-plane-taxonomy.d.ts.map +1 -0
- package/dist/service-catalog-plane-taxonomy.js +242 -0
- package/dist/service-catalog-plane.d.ts +46 -1
- package/dist/service-catalog-plane.d.ts.map +1 -1
- package/dist/service-catalog-plane.js +42 -6
- package/dist/service.d.ts +98 -19
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +142 -1
- package/dist/tasks/brochures.d.ts +1 -1
- package/dist/validation-content.d.ts +38 -0
- package/dist/validation-content.d.ts.map +1 -1
- package/dist/validation-content.js +29 -0
- package/package.json +77 -7
|
@@ -38,6 +38,14 @@ export interface QuickCreateBridgeInput {
|
|
|
38
38
|
personId?: string | null;
|
|
39
39
|
organizationId?: string | null;
|
|
40
40
|
internalNotes?: string | null;
|
|
41
|
+
/**
|
|
42
|
+
* Override the seed sellAmountCents the booking lands at. The owned
|
|
43
|
+
* commit passes this when the catalog booking-engine's promotion hook
|
|
44
|
+
* has discounted the quote — without it, customers would be charged
|
|
45
|
+
* the product's list price even with a successful promotion. Per
|
|
46
|
+
* docs/architecture/promotions-architecture.md §7.1.
|
|
47
|
+
*/
|
|
48
|
+
sellAmountCentsOverride?: number | null;
|
|
41
49
|
travelers?: Array<{
|
|
42
50
|
firstName: string;
|
|
43
51
|
lastName: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/booking-engine/handler.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/booking-engine/handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -233,6 +233,13 @@ export function createProductsBookingHandler(options) {
|
|
|
233
233
|
? t.band
|
|
234
234
|
: "adult",
|
|
235
235
|
}));
|
|
236
|
+
// Promotion-discounted quotes: thread the discounted customer-
|
|
237
|
+
// facing amount into the booking's seed sellAmountCents so
|
|
238
|
+
// checkout / payment see the quoted amount, not the product list
|
|
239
|
+
// price. Inclusive-tax quotes rewrite `base_amount` to net
|
|
240
|
+
// subtotal during tax recompute, so derive the override from the
|
|
241
|
+
// gross breakdown total when an included tax line is present.
|
|
242
|
+
const sellAmountCentsOverride = resolveSellAmountCentsOverride(request.pricing);
|
|
236
243
|
const bridge = await options.quickCreate({
|
|
237
244
|
productId: product.id,
|
|
238
245
|
bookingNumber: generateNumber(),
|
|
@@ -240,6 +247,7 @@ export function createProductsBookingHandler(options) {
|
|
|
240
247
|
organizationId: extractOrganizationId(request.party),
|
|
241
248
|
internalNotes: extractInternalNotes(request.party),
|
|
242
249
|
travelers: travelers.length > 0 ? travelers : undefined,
|
|
250
|
+
sellAmountCentsOverride,
|
|
243
251
|
taxLines: extractTaxLines(request.pricing),
|
|
244
252
|
});
|
|
245
253
|
if (bridge.status !== "ok" || !bridge.bookingId) {
|
|
@@ -406,6 +414,36 @@ function extractTaxLines(pricing) {
|
|
|
406
414
|
}
|
|
407
415
|
return lines.length ? lines : undefined;
|
|
408
416
|
}
|
|
417
|
+
function resolveSellAmountCentsOverride(pricing) {
|
|
418
|
+
if (!pricing)
|
|
419
|
+
return null;
|
|
420
|
+
const breakdown = pricing.breakdown;
|
|
421
|
+
if (hasInclusiveTaxLine(breakdown)) {
|
|
422
|
+
const total = readBreakdownTotal(breakdown);
|
|
423
|
+
if (total != null)
|
|
424
|
+
return total;
|
|
425
|
+
}
|
|
426
|
+
return pricing.base_amount != null ? Math.round(pricing.base_amount) : null;
|
|
427
|
+
}
|
|
428
|
+
function hasInclusiveTaxLine(breakdown) {
|
|
429
|
+
if (!breakdown || typeof breakdown !== "object" || Array.isArray(breakdown))
|
|
430
|
+
return false;
|
|
431
|
+
const taxes = breakdown.taxes;
|
|
432
|
+
if (!Array.isArray(taxes))
|
|
433
|
+
return false;
|
|
434
|
+
return taxes.some((tax) => {
|
|
435
|
+
if (!tax || typeof tax !== "object" || Array.isArray(tax))
|
|
436
|
+
return false;
|
|
437
|
+
const row = tax;
|
|
438
|
+
return row.includedInPrice === true || row.scope === "included";
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
function readBreakdownTotal(breakdown) {
|
|
442
|
+
if (!breakdown || typeof breakdown !== "object" || Array.isArray(breakdown))
|
|
443
|
+
return null;
|
|
444
|
+
const total = breakdown.total;
|
|
445
|
+
return typeof total === "number" && Number.isFinite(total) ? Math.round(total) : null;
|
|
446
|
+
}
|
|
409
447
|
function asFiniteInteger(value) {
|
|
410
448
|
if (typeof value !== "number" || !Number.isFinite(value))
|
|
411
449
|
return null;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog plane field policy for product → departures denormalization.
|
|
3
|
+
*
|
|
4
|
+
* These fields don't live on the `products` table — they're aggregated
|
|
5
|
+
* from `availability_slots` (filtered to `status = 'open'` and future
|
|
6
|
+
* `startsAt`) at index time and projected onto the product search
|
|
7
|
+
* document. See `docs/architecture/catalog-architecture.md` §5.4.
|
|
8
|
+
*
|
|
9
|
+
* Storefront product cards filter and display by departure surface:
|
|
10
|
+
* - "departing in May" (filter: `departureMonths[]` includes "2026-05")
|
|
11
|
+
* - "available this weekend" (filter: `departureDates[]` overlap)
|
|
12
|
+
* - "available now" (filter: `hasUpcomingDeparture:true`)
|
|
13
|
+
* - sort by next departure (`nextDepartureAt` asc)
|
|
14
|
+
* - show capacity badge (`availableUnitsTotal`)
|
|
15
|
+
*
|
|
16
|
+
* Wire this policy into the products registry by composing with
|
|
17
|
+
* `productCatalogPolicy`:
|
|
18
|
+
*
|
|
19
|
+
* const registry = createFieldPolicyRegistry([
|
|
20
|
+
* ...productCatalogPolicy,
|
|
21
|
+
* ...productDeparturesCatalogPolicy,
|
|
22
|
+
* ])
|
|
23
|
+
*
|
|
24
|
+
* and wire `createProductDeparturesProjectionExtension` into
|
|
25
|
+
* `createProductDocumentBuilder` so the values land in the doc.
|
|
26
|
+
*
|
|
27
|
+
* Reindex semantics: every aggregation depends on `now()` — the same
|
|
28
|
+
* product reindexed an hour later will produce slightly different
|
|
29
|
+
* documents because the future window slides. Operators rely on the
|
|
30
|
+
* channel-push reconciler + scheduled refresh to keep these fields warm
|
|
31
|
+
* without storming the indexer on each tick. Per architecture §5.4,
|
|
32
|
+
* `reindex: "facet-affecting"` is the right tier — these fields drive
|
|
33
|
+
* facets but aren't on the merchandisable hot path.
|
|
34
|
+
*
|
|
35
|
+
* Out of scope here:
|
|
36
|
+
* - Sold-out / cancelled / closed slots. The projection only counts
|
|
37
|
+
* `status = 'open'` so storefront filters never surface unavailable
|
|
38
|
+
* departures. A "show sold-out" toggle is a query-time concern.
|
|
39
|
+
* - Per-option splits. Today's projection rolls up to the product;
|
|
40
|
+
* per-option faceting is a follow-up if storefronts need it.
|
|
41
|
+
* - Duration buckets (nights/days). Slots carry these but products
|
|
42
|
+
* with mixed-duration slots can't be summarized in one number.
|
|
43
|
+
*/
|
|
44
|
+
import { type FieldPolicyInput } from "@voyantjs/catalog/contract";
|
|
45
|
+
declare const PRODUCT_DEPARTURES_FIELD_POLICY: FieldPolicyInput[];
|
|
46
|
+
/**
|
|
47
|
+
* Resolved departures policy. Compose with `productCatalogPolicy` when
|
|
48
|
+
* building the products registry.
|
|
49
|
+
*/
|
|
50
|
+
export declare const productDeparturesCatalogPolicy: import("@voyantjs/catalog").FieldPolicy[];
|
|
51
|
+
export { PRODUCT_DEPARTURES_FIELD_POLICY };
|
|
52
|
+
//# sourceMappingURL=catalog-policy-departures.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-policy-departures.d.ts","sourceRoot":"","sources":["../src/catalog-policy-departures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAErF,QAAA,MAAM,+BAA+B,EAAE,gBAAgB,EAyHtD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,8BAA8B,2CAAqD,CAAA;AAEhG,OAAO,EAAE,+BAA+B,EAAE,CAAA"}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog plane field policy for product → departures denormalization.
|
|
3
|
+
*
|
|
4
|
+
* These fields don't live on the `products` table — they're aggregated
|
|
5
|
+
* from `availability_slots` (filtered to `status = 'open'` and future
|
|
6
|
+
* `startsAt`) at index time and projected onto the product search
|
|
7
|
+
* document. See `docs/architecture/catalog-architecture.md` §5.4.
|
|
8
|
+
*
|
|
9
|
+
* Storefront product cards filter and display by departure surface:
|
|
10
|
+
* - "departing in May" (filter: `departureMonths[]` includes "2026-05")
|
|
11
|
+
* - "available this weekend" (filter: `departureDates[]` overlap)
|
|
12
|
+
* - "available now" (filter: `hasUpcomingDeparture:true`)
|
|
13
|
+
* - sort by next departure (`nextDepartureAt` asc)
|
|
14
|
+
* - show capacity badge (`availableUnitsTotal`)
|
|
15
|
+
*
|
|
16
|
+
* Wire this policy into the products registry by composing with
|
|
17
|
+
* `productCatalogPolicy`:
|
|
18
|
+
*
|
|
19
|
+
* const registry = createFieldPolicyRegistry([
|
|
20
|
+
* ...productCatalogPolicy,
|
|
21
|
+
* ...productDeparturesCatalogPolicy,
|
|
22
|
+
* ])
|
|
23
|
+
*
|
|
24
|
+
* and wire `createProductDeparturesProjectionExtension` into
|
|
25
|
+
* `createProductDocumentBuilder` so the values land in the doc.
|
|
26
|
+
*
|
|
27
|
+
* Reindex semantics: every aggregation depends on `now()` — the same
|
|
28
|
+
* product reindexed an hour later will produce slightly different
|
|
29
|
+
* documents because the future window slides. Operators rely on the
|
|
30
|
+
* channel-push reconciler + scheduled refresh to keep these fields warm
|
|
31
|
+
* without storming the indexer on each tick. Per architecture §5.4,
|
|
32
|
+
* `reindex: "facet-affecting"` is the right tier — these fields drive
|
|
33
|
+
* facets but aren't on the merchandisable hot path.
|
|
34
|
+
*
|
|
35
|
+
* Out of scope here:
|
|
36
|
+
* - Sold-out / cancelled / closed slots. The projection only counts
|
|
37
|
+
* `status = 'open'` so storefront filters never surface unavailable
|
|
38
|
+
* departures. A "show sold-out" toggle is a query-time concern.
|
|
39
|
+
* - Per-option splits. Today's projection rolls up to the product;
|
|
40
|
+
* per-option faceting is a follow-up if storefronts need it.
|
|
41
|
+
* - Duration buckets (nights/days). Slots carry these but products
|
|
42
|
+
* with mixed-duration slots can't be summarized in one number.
|
|
43
|
+
*/
|
|
44
|
+
import { defineFieldPolicy } from "@voyantjs/catalog/contract";
|
|
45
|
+
const PRODUCT_DEPARTURES_FIELD_POLICY = [
|
|
46
|
+
// ── Earliest open future departure ──────────────────────────────────────
|
|
47
|
+
// `nextDepartureAt` is the timestamptz for sort order (catalog sort by
|
|
48
|
+
// soonest available). `nextDepartureDate` is the same departure expressed
|
|
49
|
+
// as the slot's local calendar date — what the storefront card renders.
|
|
50
|
+
{
|
|
51
|
+
path: "nextDepartureAt",
|
|
52
|
+
class: "structural",
|
|
53
|
+
merge: "source-only",
|
|
54
|
+
drift: "low",
|
|
55
|
+
reindex: "facet-affecting",
|
|
56
|
+
snapshot: "on-book",
|
|
57
|
+
query: "indexed-column",
|
|
58
|
+
localized: false,
|
|
59
|
+
visibility: ["staff", "customer", "partner"],
|
|
60
|
+
editRole: "none",
|
|
61
|
+
overrideFriction: "none",
|
|
62
|
+
sourceFreshness: "sync",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
path: "nextDepartureDate",
|
|
66
|
+
class: "structural",
|
|
67
|
+
merge: "source-only",
|
|
68
|
+
drift: "low",
|
|
69
|
+
reindex: "facet-affecting",
|
|
70
|
+
snapshot: "on-book",
|
|
71
|
+
query: "indexed-column",
|
|
72
|
+
localized: false,
|
|
73
|
+
visibility: ["staff", "customer", "partner"],
|
|
74
|
+
editRole: "none",
|
|
75
|
+
overrideFriction: "none",
|
|
76
|
+
sourceFreshness: "sync",
|
|
77
|
+
},
|
|
78
|
+
// ── Existence + count facets ─────────────────────────────────────────────
|
|
79
|
+
// `hasUpcomingDeparture` is the cheap "available now" filter. The count
|
|
80
|
+
// lets storefront sort by "lots of options available" without exposing
|
|
81
|
+
// the date list to the query layer.
|
|
82
|
+
{
|
|
83
|
+
path: "hasUpcomingDeparture",
|
|
84
|
+
class: "structural",
|
|
85
|
+
merge: "source-only",
|
|
86
|
+
drift: "low",
|
|
87
|
+
reindex: "facet-affecting",
|
|
88
|
+
snapshot: "on-book",
|
|
89
|
+
query: "indexed-column",
|
|
90
|
+
localized: false,
|
|
91
|
+
visibility: ["staff", "customer", "partner"],
|
|
92
|
+
editRole: "none",
|
|
93
|
+
overrideFriction: "none",
|
|
94
|
+
sourceFreshness: "sync",
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
path: "upcomingDepartureCount",
|
|
98
|
+
class: "structural",
|
|
99
|
+
merge: "source-only",
|
|
100
|
+
drift: "low",
|
|
101
|
+
reindex: "facet-affecting",
|
|
102
|
+
snapshot: "on-book",
|
|
103
|
+
query: "indexed-column",
|
|
104
|
+
localized: false,
|
|
105
|
+
visibility: ["staff", "customer", "partner"],
|
|
106
|
+
editRole: "none",
|
|
107
|
+
overrideFriction: "none",
|
|
108
|
+
sourceFreshness: "sync",
|
|
109
|
+
},
|
|
110
|
+
// ── Calendar-bucket facets ──────────────────────────────────────────────
|
|
111
|
+
// `departureDates[]` powers fine-grained "this weekend" / "next week"
|
|
112
|
+
// filters; capped at 180 days of distinct calendar dates so document
|
|
113
|
+
// size stays bounded for daily-slot products. `departureMonths[]` is
|
|
114
|
+
// the longer-tail facet — 24 months of "YYYY-MM" tokens covers an
|
|
115
|
+
// operator's typical forward-published inventory horizon.
|
|
116
|
+
{
|
|
117
|
+
path: "departureDates[]",
|
|
118
|
+
class: "structural",
|
|
119
|
+
merge: "source-only",
|
|
120
|
+
drift: "low",
|
|
121
|
+
reindex: "facet-affecting",
|
|
122
|
+
snapshot: "on-book",
|
|
123
|
+
query: "indexed-column",
|
|
124
|
+
localized: false,
|
|
125
|
+
visibility: ["staff", "customer", "partner"],
|
|
126
|
+
editRole: "none",
|
|
127
|
+
overrideFriction: "none",
|
|
128
|
+
sourceFreshness: "sync",
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
path: "departureMonths[]",
|
|
132
|
+
class: "structural",
|
|
133
|
+
merge: "source-only",
|
|
134
|
+
drift: "low",
|
|
135
|
+
reindex: "facet-affecting",
|
|
136
|
+
snapshot: "on-book",
|
|
137
|
+
query: "indexed-column",
|
|
138
|
+
localized: false,
|
|
139
|
+
visibility: ["staff", "customer", "partner"],
|
|
140
|
+
editRole: "none",
|
|
141
|
+
overrideFriction: "none",
|
|
142
|
+
sourceFreshness: "sync",
|
|
143
|
+
},
|
|
144
|
+
// ── Capacity ────────────────────────────────────────────────────────────
|
|
145
|
+
// Sum of `remaining_pax` across upcoming open slots. `null` when ANY
|
|
146
|
+
// counted slot is unlimited — unbounded capacity can't be summarized in
|
|
147
|
+
// a number, and emitting a partial sum would mislead the storefront
|
|
148
|
+
// ("3 seats left" when one slot is actually unlimited).
|
|
149
|
+
{
|
|
150
|
+
path: "availableUnitsTotal",
|
|
151
|
+
class: "structural",
|
|
152
|
+
merge: "source-only",
|
|
153
|
+
drift: "low",
|
|
154
|
+
reindex: "facet-affecting",
|
|
155
|
+
snapshot: "on-book",
|
|
156
|
+
query: "indexed-column",
|
|
157
|
+
localized: false,
|
|
158
|
+
visibility: ["staff", "customer", "partner"],
|
|
159
|
+
editRole: "none",
|
|
160
|
+
overrideFriction: "none",
|
|
161
|
+
sourceFreshness: "sync",
|
|
162
|
+
},
|
|
163
|
+
];
|
|
164
|
+
/**
|
|
165
|
+
* Resolved departures policy. Compose with `productCatalogPolicy` when
|
|
166
|
+
* building the products registry.
|
|
167
|
+
*/
|
|
168
|
+
export const productDeparturesCatalogPolicy = defineFieldPolicy(PRODUCT_DEPARTURES_FIELD_POLICY);
|
|
169
|
+
export { PRODUCT_DEPARTURES_FIELD_POLICY };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog plane field policy for product → destination denormalization.
|
|
3
|
+
*
|
|
4
|
+
* These fields don't live on the `products` table — they're joined from
|
|
5
|
+
* `product_destinations` → `destinations` (+ `destination_translations` for
|
|
6
|
+
* locale-aware names) at index time and projected onto the product search
|
|
7
|
+
* document. See `docs/architecture/catalog-architecture.md` §5.4 — the
|
|
8
|
+
* search index is the canonical place for cross-entity denormalization.
|
|
9
|
+
*
|
|
10
|
+
* Storefront product cards filter and display by destinations:
|
|
11
|
+
* - "trips to Italy" (filter: `countries[]` includes "Italy")
|
|
12
|
+
* - "trips in Rome" (filter: `cities[]` includes "Rome")
|
|
13
|
+
* - "Mediterranean cruises" (filter: `regions[]` includes "Mediterranean")
|
|
14
|
+
*
|
|
15
|
+
* Wire this policy into the products registry by composing with
|
|
16
|
+
* `productCatalogPolicy`:
|
|
17
|
+
*
|
|
18
|
+
* const registry = createFieldPolicyRegistry([
|
|
19
|
+
* ...productCatalogPolicy,
|
|
20
|
+
* ...productDestinationsCatalogPolicy,
|
|
21
|
+
* ])
|
|
22
|
+
*
|
|
23
|
+
* and wire `createProductDestinationsProjectionExtension` into
|
|
24
|
+
* `createProductDocumentBuilder` so the values land in the doc.
|
|
25
|
+
*
|
|
26
|
+
* Out of scope here:
|
|
27
|
+
* - Coordinates / geopoints. The `destinations` table has no coordinate
|
|
28
|
+
* columns; product geolocation lives on `product_locations` and will
|
|
29
|
+
* ship as its own policy in a follow-up PR.
|
|
30
|
+
* - Slug fields per locale. Destinations have one canonical slug today;
|
|
31
|
+
* locale-specific slugs are a follow-up if marketing needs them.
|
|
32
|
+
*/
|
|
33
|
+
import { type FieldPolicyInput } from "@voyantjs/catalog/contract";
|
|
34
|
+
declare const PRODUCT_DESTINATIONS_FIELD_POLICY: FieldPolicyInput[];
|
|
35
|
+
/**
|
|
36
|
+
* Resolved destinations policy. Compose with `productCatalogPolicy` when
|
|
37
|
+
* building the products registry.
|
|
38
|
+
*/
|
|
39
|
+
export declare const productDestinationsCatalogPolicy: import("@voyantjs/catalog").FieldPolicy[];
|
|
40
|
+
export { PRODUCT_DESTINATIONS_FIELD_POLICY };
|
|
41
|
+
//# sourceMappingURL=catalog-policy-destinations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-policy-destinations.d.ts","sourceRoot":"","sources":["../src/catalog-policy-destinations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAErF,QAAA,MAAM,iCAAiC,EAAE,gBAAgB,EAmFxD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,gCAAgC,2CAAuD,CAAA;AAEpG,OAAO,EAAE,iCAAiC,EAAE,CAAA"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog plane field policy for product → destination denormalization.
|
|
3
|
+
*
|
|
4
|
+
* These fields don't live on the `products` table — they're joined from
|
|
5
|
+
* `product_destinations` → `destinations` (+ `destination_translations` for
|
|
6
|
+
* locale-aware names) at index time and projected onto the product search
|
|
7
|
+
* document. See `docs/architecture/catalog-architecture.md` §5.4 — the
|
|
8
|
+
* search index is the canonical place for cross-entity denormalization.
|
|
9
|
+
*
|
|
10
|
+
* Storefront product cards filter and display by destinations:
|
|
11
|
+
* - "trips to Italy" (filter: `countries[]` includes "Italy")
|
|
12
|
+
* - "trips in Rome" (filter: `cities[]` includes "Rome")
|
|
13
|
+
* - "Mediterranean cruises" (filter: `regions[]` includes "Mediterranean")
|
|
14
|
+
*
|
|
15
|
+
* Wire this policy into the products registry by composing with
|
|
16
|
+
* `productCatalogPolicy`:
|
|
17
|
+
*
|
|
18
|
+
* const registry = createFieldPolicyRegistry([
|
|
19
|
+
* ...productCatalogPolicy,
|
|
20
|
+
* ...productDestinationsCatalogPolicy,
|
|
21
|
+
* ])
|
|
22
|
+
*
|
|
23
|
+
* and wire `createProductDestinationsProjectionExtension` into
|
|
24
|
+
* `createProductDocumentBuilder` so the values land in the doc.
|
|
25
|
+
*
|
|
26
|
+
* Out of scope here:
|
|
27
|
+
* - Coordinates / geopoints. The `destinations` table has no coordinate
|
|
28
|
+
* columns; product geolocation lives on `product_locations` and will
|
|
29
|
+
* ship as its own policy in a follow-up PR.
|
|
30
|
+
* - Slug fields per locale. Destinations have one canonical slug today;
|
|
31
|
+
* locale-specific slugs are a follow-up if marketing needs them.
|
|
32
|
+
*/
|
|
33
|
+
import { defineFieldPolicy } from "@voyantjs/catalog/contract";
|
|
34
|
+
const PRODUCT_DESTINATIONS_FIELD_POLICY = [
|
|
35
|
+
// ── Locale-aware destination labels ──────────────────────────────────────
|
|
36
|
+
// Sourced from `destination_translations` (falls back to `destinations.slug`
|
|
37
|
+
// when no translation exists for the slice's locale). One array entry per
|
|
38
|
+
// linked destination of the matching `destination_type`.
|
|
39
|
+
{
|
|
40
|
+
path: "regions[]",
|
|
41
|
+
class: "structural",
|
|
42
|
+
merge: "source-only",
|
|
43
|
+
drift: "low",
|
|
44
|
+
reindex: "entry-locale",
|
|
45
|
+
snapshot: "on-book",
|
|
46
|
+
query: "indexed-column",
|
|
47
|
+
localized: true,
|
|
48
|
+
visibility: ["staff", "customer", "partner"],
|
|
49
|
+
editRole: "none",
|
|
50
|
+
overrideFriction: "none",
|
|
51
|
+
sourceFreshness: "sync",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
path: "countries[]",
|
|
55
|
+
class: "structural",
|
|
56
|
+
merge: "source-only",
|
|
57
|
+
drift: "low",
|
|
58
|
+
reindex: "entry-locale",
|
|
59
|
+
snapshot: "on-book",
|
|
60
|
+
query: "indexed-column",
|
|
61
|
+
localized: true,
|
|
62
|
+
visibility: ["staff", "customer", "partner"],
|
|
63
|
+
editRole: "none",
|
|
64
|
+
overrideFriction: "none",
|
|
65
|
+
sourceFreshness: "sync",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
path: "cities[]",
|
|
69
|
+
class: "structural",
|
|
70
|
+
merge: "source-only",
|
|
71
|
+
drift: "low",
|
|
72
|
+
reindex: "entry-locale",
|
|
73
|
+
snapshot: "on-book",
|
|
74
|
+
query: "indexed-column",
|
|
75
|
+
localized: true,
|
|
76
|
+
visibility: ["staff", "customer", "partner"],
|
|
77
|
+
editRole: "none",
|
|
78
|
+
overrideFriction: "none",
|
|
79
|
+
sourceFreshness: "sync",
|
|
80
|
+
},
|
|
81
|
+
// ── Slugs (locale-stable) ────────────────────────────────────────────────
|
|
82
|
+
// Used for category-page links — operators want stable URLs that don't
|
|
83
|
+
// shift when translations are edited. One entry per linked destination.
|
|
84
|
+
{
|
|
85
|
+
path: "destinationSlugs[]",
|
|
86
|
+
class: "structural",
|
|
87
|
+
merge: "source-only",
|
|
88
|
+
drift: "low",
|
|
89
|
+
reindex: "facet-affecting",
|
|
90
|
+
snapshot: "on-book",
|
|
91
|
+
query: "indexed-column",
|
|
92
|
+
localized: false,
|
|
93
|
+
visibility: ["staff", "customer", "partner"],
|
|
94
|
+
editRole: "none",
|
|
95
|
+
overrideFriction: "none",
|
|
96
|
+
sourceFreshness: "sync",
|
|
97
|
+
},
|
|
98
|
+
// ── Destination IDs ──────────────────────────────────────────────────────
|
|
99
|
+
// Useful for filtering by exact destination match (e.g. landing pages
|
|
100
|
+
// pinned to a destination ID rather than a slug).
|
|
101
|
+
{
|
|
102
|
+
path: "destinationIds[]",
|
|
103
|
+
class: "structural",
|
|
104
|
+
merge: "source-only",
|
|
105
|
+
drift: "low",
|
|
106
|
+
reindex: "facet-affecting",
|
|
107
|
+
snapshot: "on-book",
|
|
108
|
+
query: "indexed-column",
|
|
109
|
+
localized: false,
|
|
110
|
+
visibility: ["staff", "customer", "partner"],
|
|
111
|
+
editRole: "none",
|
|
112
|
+
overrideFriction: "none",
|
|
113
|
+
sourceFreshness: "sync",
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
/**
|
|
117
|
+
* Resolved destinations policy. Compose with `productCatalogPolicy` when
|
|
118
|
+
* building the products registry.
|
|
119
|
+
*/
|
|
120
|
+
export const productDestinationsCatalogPolicy = defineFieldPolicy(PRODUCT_DESTINATIONS_FIELD_POLICY);
|
|
121
|
+
export { PRODUCT_DESTINATIONS_FIELD_POLICY };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog plane field policy for product → pricing denormalization.
|
|
3
|
+
*
|
|
4
|
+
* Aggregates a "price from" value across the product's configured
|
|
5
|
+
* default-rule prices so storefront cards can render `from $X` without
|
|
6
|
+
* fanning out to per-option pricing on every render. See
|
|
7
|
+
* `docs/architecture/catalog-architecture.md` §5.4.
|
|
8
|
+
*
|
|
9
|
+
* Storefront product cards filter and display by:
|
|
10
|
+
* - "trips under $1000" (filter: `priceFromAmountCents` <= 100000)
|
|
11
|
+
* - badge "from $X" (display: `priceFromAmountCents` + `priceFromCurrency`)
|
|
12
|
+
* - sort by price ascending (`priceFromAmountCents` asc)
|
|
13
|
+
*
|
|
14
|
+
* Wire this policy into the products registry by composing with
|
|
15
|
+
* `productCatalogPolicy`:
|
|
16
|
+
*
|
|
17
|
+
* const registry = createFieldPolicyRegistry([
|
|
18
|
+
* ...productCatalogPolicy,
|
|
19
|
+
* ...productPricingCatalogPolicy,
|
|
20
|
+
* ])
|
|
21
|
+
*
|
|
22
|
+
* and wire `createProductPricingProjectionExtension` (from
|
|
23
|
+
* `@voyantjs/pricing/service-catalog-plane-pricing`) into
|
|
24
|
+
* `createProductDocumentBuilder` so the values land in the doc.
|
|
25
|
+
*
|
|
26
|
+
* Why a separate field instead of reusing the existing `sellAmountCents`
|
|
27
|
+
* from `productCatalogPolicy`: that path projects the product-row
|
|
28
|
+
* configured default verbatim. Multi-option products often leave
|
|
29
|
+
* `products.sellAmountCents` null and put the real prices on options —
|
|
30
|
+
* this projection MINs across both, giving storefront a value that's
|
|
31
|
+
* always meaningful even for the option-driven case.
|
|
32
|
+
*
|
|
33
|
+
* Out of scope here (deferred):
|
|
34
|
+
* - Schedule-aware rule resolution. The kernel reads `isDefault=true`
|
|
35
|
+
* rule prices only — it does NOT walk seasonal schedules, per-
|
|
36
|
+
* departure overrides, or per-unit occupancy tiers. A "true cheapest
|
|
37
|
+
* bookable price right now" projection requires per-slice rule
|
|
38
|
+
* evaluation with a moving "now" date and is a follow-up.
|
|
39
|
+
* - Per-audience / per-market currency conversion. The currency we
|
|
40
|
+
* emit is `products.sellCurrency`; multi-catalog operators using
|
|
41
|
+
* mixed currencies for the same product will see prices clipped
|
|
42
|
+
* to the rules matching that currency.
|
|
43
|
+
* - `pricing.changed` event surface. Today, edits to option-price
|
|
44
|
+
* rules don't fire any event, so the bridge can only reindex on
|
|
45
|
+
* `product.updated`. Tracked separately.
|
|
46
|
+
*/
|
|
47
|
+
import { type FieldPolicyInput } from "@voyantjs/catalog/contract";
|
|
48
|
+
declare const PRODUCT_PRICING_FIELD_POLICY: FieldPolicyInput[];
|
|
49
|
+
/**
|
|
50
|
+
* Resolved pricing policy. Compose with `productCatalogPolicy` when
|
|
51
|
+
* building the products registry.
|
|
52
|
+
*/
|
|
53
|
+
export declare const productPricingCatalogPolicy: import("@voyantjs/catalog").FieldPolicy[];
|
|
54
|
+
export { PRODUCT_PRICING_FIELD_POLICY };
|
|
55
|
+
//# sourceMappingURL=catalog-policy-pricing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-policy-pricing.d.ts","sourceRoot":"","sources":["../src/catalog-policy-pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAEH,OAAO,EAAqB,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAErF,QAAA,MAAM,4BAA4B,EAAE,gBAAgB,EAuDnD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,2BAA2B,2CAAkD,CAAA;AAE1F,OAAO,EAAE,4BAA4B,EAAE,CAAA"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog plane field policy for product → pricing denormalization.
|
|
3
|
+
*
|
|
4
|
+
* Aggregates a "price from" value across the product's configured
|
|
5
|
+
* default-rule prices so storefront cards can render `from $X` without
|
|
6
|
+
* fanning out to per-option pricing on every render. See
|
|
7
|
+
* `docs/architecture/catalog-architecture.md` §5.4.
|
|
8
|
+
*
|
|
9
|
+
* Storefront product cards filter and display by:
|
|
10
|
+
* - "trips under $1000" (filter: `priceFromAmountCents` <= 100000)
|
|
11
|
+
* - badge "from $X" (display: `priceFromAmountCents` + `priceFromCurrency`)
|
|
12
|
+
* - sort by price ascending (`priceFromAmountCents` asc)
|
|
13
|
+
*
|
|
14
|
+
* Wire this policy into the products registry by composing with
|
|
15
|
+
* `productCatalogPolicy`:
|
|
16
|
+
*
|
|
17
|
+
* const registry = createFieldPolicyRegistry([
|
|
18
|
+
* ...productCatalogPolicy,
|
|
19
|
+
* ...productPricingCatalogPolicy,
|
|
20
|
+
* ])
|
|
21
|
+
*
|
|
22
|
+
* and wire `createProductPricingProjectionExtension` (from
|
|
23
|
+
* `@voyantjs/pricing/service-catalog-plane-pricing`) into
|
|
24
|
+
* `createProductDocumentBuilder` so the values land in the doc.
|
|
25
|
+
*
|
|
26
|
+
* Why a separate field instead of reusing the existing `sellAmountCents`
|
|
27
|
+
* from `productCatalogPolicy`: that path projects the product-row
|
|
28
|
+
* configured default verbatim. Multi-option products often leave
|
|
29
|
+
* `products.sellAmountCents` null and put the real prices on options —
|
|
30
|
+
* this projection MINs across both, giving storefront a value that's
|
|
31
|
+
* always meaningful even for the option-driven case.
|
|
32
|
+
*
|
|
33
|
+
* Out of scope here (deferred):
|
|
34
|
+
* - Schedule-aware rule resolution. The kernel reads `isDefault=true`
|
|
35
|
+
* rule prices only — it does NOT walk seasonal schedules, per-
|
|
36
|
+
* departure overrides, or per-unit occupancy tiers. A "true cheapest
|
|
37
|
+
* bookable price right now" projection requires per-slice rule
|
|
38
|
+
* evaluation with a moving "now" date and is a follow-up.
|
|
39
|
+
* - Per-audience / per-market currency conversion. The currency we
|
|
40
|
+
* emit is `products.sellCurrency`; multi-catalog operators using
|
|
41
|
+
* mixed currencies for the same product will see prices clipped
|
|
42
|
+
* to the rules matching that currency.
|
|
43
|
+
* - `pricing.changed` event surface. Today, edits to option-price
|
|
44
|
+
* rules don't fire any event, so the bridge can only reindex on
|
|
45
|
+
* `product.updated`. Tracked separately.
|
|
46
|
+
*/
|
|
47
|
+
import { defineFieldPolicy } from "@voyantjs/catalog/contract";
|
|
48
|
+
const PRODUCT_PRICING_FIELD_POLICY = [
|
|
49
|
+
// ── Aggregated "price from" amount ───────────────────────────────────────
|
|
50
|
+
// MIN across `products.sellAmountCents` and the active default
|
|
51
|
+
// `optionPriceRules.baseSellAmountCents` (plus option-unit-rule MINs for
|
|
52
|
+
// per-unit-priced options). `null` when no source has a non-null amount.
|
|
53
|
+
{
|
|
54
|
+
path: "priceFromAmountCents",
|
|
55
|
+
class: "structural",
|
|
56
|
+
merge: "source-only",
|
|
57
|
+
drift: "low",
|
|
58
|
+
reindex: "facet-affecting",
|
|
59
|
+
snapshot: "on-book",
|
|
60
|
+
query: "indexed-column",
|
|
61
|
+
localized: false,
|
|
62
|
+
visibility: ["staff", "customer", "partner"],
|
|
63
|
+
editRole: "none",
|
|
64
|
+
overrideFriction: "none",
|
|
65
|
+
sourceFreshness: "sync",
|
|
66
|
+
},
|
|
67
|
+
// ── Currency for the projected amount ────────────────────────────────────
|
|
68
|
+
// `products.sellCurrency`. Stays consistent across all rule sources for
|
|
69
|
+
// the projected product because we filter rule rows to ones matching
|
|
70
|
+
// this currency before MIN'ing.
|
|
71
|
+
{
|
|
72
|
+
path: "priceFromCurrency",
|
|
73
|
+
class: "structural",
|
|
74
|
+
merge: "source-only",
|
|
75
|
+
drift: "low",
|
|
76
|
+
reindex: "facet-affecting",
|
|
77
|
+
snapshot: "on-book",
|
|
78
|
+
query: "indexed-column",
|
|
79
|
+
localized: false,
|
|
80
|
+
visibility: ["staff", "customer", "partner"],
|
|
81
|
+
editRole: "none",
|
|
82
|
+
overrideFriction: "none",
|
|
83
|
+
sourceFreshness: "sync",
|
|
84
|
+
},
|
|
85
|
+
// ── Existence flag ───────────────────────────────────────────────────────
|
|
86
|
+
// `false` when neither the product row nor any active default rule has a
|
|
87
|
+
// configured price. Storefront filters use this for "show only priced
|
|
88
|
+
// products" and to suppress an empty `from` badge.
|
|
89
|
+
{
|
|
90
|
+
path: "hasPricing",
|
|
91
|
+
class: "structural",
|
|
92
|
+
merge: "source-only",
|
|
93
|
+
drift: "low",
|
|
94
|
+
reindex: "facet-affecting",
|
|
95
|
+
snapshot: "on-book",
|
|
96
|
+
query: "indexed-column",
|
|
97
|
+
localized: false,
|
|
98
|
+
visibility: ["staff", "customer", "partner"],
|
|
99
|
+
editRole: "none",
|
|
100
|
+
overrideFriction: "none",
|
|
101
|
+
sourceFreshness: "sync",
|
|
102
|
+
},
|
|
103
|
+
];
|
|
104
|
+
/**
|
|
105
|
+
* Resolved pricing policy. Compose with `productCatalogPolicy` when
|
|
106
|
+
* building the products registry.
|
|
107
|
+
*/
|
|
108
|
+
export const productPricingCatalogPolicy = defineFieldPolicy(PRODUCT_PRICING_FIELD_POLICY);
|
|
109
|
+
export { PRODUCT_PRICING_FIELD_POLICY };
|