@final-commerce/common 2.4.1-staging2.1 → 2.5.0-staging.1
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/index.d.mts +379 -19
- package/dist/index.d.ts +379 -19
- package/dist/index.js +827 -53
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +790 -41
- package/dist/index.mjs.map +1 -1
- package/dist/pos-types/index.d.mts +315 -95
- package/dist/pos-types/index.d.ts +315 -95
- package/dist/pos-types/index.js.map +1 -1
- package/dist/pos-types/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19,14 +19,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
19
19
|
// index.ts
|
|
20
20
|
var index_exports = {};
|
|
21
21
|
__export(index_exports, {
|
|
22
|
-
ADYEN_JOB_TITLE_ASSOCIATION_TYPES: () => ADYEN_JOB_TITLE_ASSOCIATION_TYPES,
|
|
23
|
-
ADYEN_LEGAL_ENTITY_STATE_PROVINCE_COUNTRIES: () => ADYEN_LEGAL_ENTITY_STATE_PROVINCE_COUNTRIES,
|
|
24
|
-
ADYEN_NO_TAX_NUMBER_ABSENT_COUNTRIES: () => ADYEN_NO_TAX_NUMBER_ABSENT_COUNTRIES,
|
|
25
22
|
ADYEN_ROLLOUT_COUNTRY_CODES: () => ADYEN_ROLLOUT_COUNTRY_CODES,
|
|
26
|
-
ADYEN_STORE_STATE_PROVINCE_COUNTRIES: () => ADYEN_STORE_STATE_PROVINCE_COUNTRIES,
|
|
27
|
-
ADYEN_TAX_NUMBER_FORMATS: () => ADYEN_TAX_NUMBER_FORMATS,
|
|
28
|
-
ADYEN_TAX_NUMBER_MIN_LENGTH: () => ADYEN_TAX_NUMBER_MIN_LENGTH,
|
|
29
23
|
AttributeType: () => AttributeType,
|
|
24
|
+
BookingRatePeriod: () => BookingRatePeriod,
|
|
25
|
+
BookingResourceKind: () => BookingResourceKind,
|
|
26
|
+
BookingResourceStatus: () => BookingResourceStatus,
|
|
27
|
+
BookingRulesError: () => BookingRulesError,
|
|
28
|
+
BookingType: () => BookingType,
|
|
30
29
|
CONDITION_OPERATORS: () => CONDITION_OPERATORS,
|
|
31
30
|
COUNTRY_CURRENCIES: () => COUNTRY_CURRENCIES,
|
|
32
31
|
CURRENCY_CONFIG: () => CURRENCY_CONFIG,
|
|
@@ -37,6 +36,7 @@ __export(index_exports, {
|
|
|
37
36
|
DEFAULT_CONFIG: () => DEFAULT_CONFIG,
|
|
38
37
|
DEFAULT_CROSS_AXIS_RULES: () => DEFAULT_CROSS_AXIS_RULES,
|
|
39
38
|
DEFAULT_DISPLAY_STATE_MAP: () => DEFAULT_DISPLAY_STATE_MAP,
|
|
39
|
+
DEFAULT_HOLD_MINUTES: () => DEFAULT_HOLD_MINUTES,
|
|
40
40
|
DEFAULT_RESOLVED_CONFIG: () => DEFAULT_RESOLVED_CONFIG,
|
|
41
41
|
DEFAULT_UNIT_ID: () => DEFAULT_UNIT_ID,
|
|
42
42
|
DualWriteStrategy: () => DualWriteStrategy,
|
|
@@ -80,8 +80,10 @@ __export(index_exports, {
|
|
|
80
80
|
REPORT_NEGATE_PATHS: () => REPORT_NEGATE_PATHS,
|
|
81
81
|
ReceiptSendChannel: () => ReceiptSendChannel,
|
|
82
82
|
ReceiptType: () => ReceiptType,
|
|
83
|
+
ReservationStatus: () => ReservationStatus,
|
|
83
84
|
ResidualPaymentMethod: () => ResidualPaymentMethod,
|
|
84
85
|
ResidualStatus: () => ResidualStatus,
|
|
86
|
+
ResourceAvailabilityState: () => ResourceAvailabilityState,
|
|
85
87
|
STATE_SCHEMA: () => STATE_SCHEMA,
|
|
86
88
|
STRIPE_SUPPORTED_COUNTRIES: () => STRIPE_SUPPORTED_COUNTRIES,
|
|
87
89
|
SYSTEM_FAMILIES: () => SYSTEM_FAMILIES,
|
|
@@ -95,23 +97,29 @@ __export(index_exports, {
|
|
|
95
97
|
TopMetericsSort: () => TopMetericsSort,
|
|
96
98
|
UserTypes: () => UserTypes,
|
|
97
99
|
addAmounts: () => addAmounts,
|
|
98
|
-
adyenLegalEntityRequiresStateOrProvince: () => adyenLegalEntityRequiresStateOrProvince,
|
|
99
|
-
adyenRequiresJobTitle: () => adyenRequiresJobTitle,
|
|
100
|
-
adyenStoreRequiresStateOrProvince: () => adyenStoreRequiresStateOrProvince,
|
|
101
|
-
adyenSupportsTaxNumberAbsent: () => adyenSupportsTaxNumberAbsent,
|
|
102
|
-
adyenTaxNumberFormat: () => adyenTaxNumberFormat,
|
|
103
100
|
amountToString: () => amountToString,
|
|
101
|
+
ancestorChain: () => ancestorChain,
|
|
104
102
|
assertUnitSane: () => assertUnitSane,
|
|
105
103
|
availableIn: () => availableIn,
|
|
106
104
|
baseFor: () => baseFor,
|
|
107
105
|
baseFulfillmentDefinitions: () => baseFulfillmentDefinitions,
|
|
108
106
|
baseOf: () => baseOf,
|
|
109
107
|
basePaymentDefinitions: () => basePaymentDefinitions,
|
|
108
|
+
buildAvailability: () => buildAvailability,
|
|
109
|
+
buildGrid: () => buildGrid,
|
|
110
110
|
buildOrderContext: () => buildOrderContext,
|
|
111
111
|
buildPosPresetConfig: () => buildPosPresetConfig,
|
|
112
112
|
buildResolvedConfig: () => buildResolvedConfig,
|
|
113
113
|
calculatePercentage: () => calculatePercentage,
|
|
114
114
|
canTransition: () => canTransition,
|
|
115
|
+
cheapestCompositeItem: () => cheapestCompositeItem,
|
|
116
|
+
cheapestCompositePrice: () => cheapestCompositePrice,
|
|
117
|
+
compositeItemCost: () => compositeItemCost,
|
|
118
|
+
compositeItemUnavailable: () => compositeItemUnavailable,
|
|
119
|
+
compositeMakeable: () => compositeMakeable,
|
|
120
|
+
compositeModifierMismatches: () => compositeModifierMismatches,
|
|
121
|
+
compositeReservationMismatches: () => compositeReservationMismatches,
|
|
122
|
+
compositeVariantInStock: () => compositeVariantInStock,
|
|
115
123
|
conditionSummary: () => conditionSummary,
|
|
116
124
|
convertFixedFeeToLocalCurrency: () => convertFixedFeeToLocalCurrency,
|
|
117
125
|
createAmount: () => createAmount,
|
|
@@ -146,8 +154,11 @@ __export(index_exports, {
|
|
|
146
154
|
getPricingRegionFromCountry: () => getPricingRegionFromCountry,
|
|
147
155
|
getSettlementTotal: () => getSettlementTotal,
|
|
148
156
|
getTotalCollected: () => getTotalCollected,
|
|
157
|
+
hasSellableChoice: () => hasSellableChoice,
|
|
158
|
+
holdExpiresAt: () => holdExpiresAt,
|
|
149
159
|
inferStatesFromLegacyStatus: () => inferStatesFromLegacyStatus,
|
|
150
160
|
isAdyenRolloutCountry: () => isAdyenRolloutCountry,
|
|
161
|
+
isChoiceAvailableAtOutlet: () => isChoiceAvailableAtOutlet,
|
|
151
162
|
isConditionOperator: () => isConditionOperator,
|
|
152
163
|
isFulfillmentState: () => isFulfillmentState,
|
|
153
164
|
isPaymentState: () => isPaymentState,
|
|
@@ -158,26 +169,40 @@ __export(index_exports, {
|
|
|
158
169
|
mapToLegacyStatus: () => mapToLegacyStatus,
|
|
159
170
|
maxPrecisionFor: () => maxPrecisionFor,
|
|
160
171
|
mergeFragment: () => mergeFragment,
|
|
172
|
+
modifiersSellable: () => modifiersSellable,
|
|
161
173
|
multiplyAmount: () => multiplyAmount,
|
|
162
174
|
normalizeMongoIdString: () => normalizeMongoIdString,
|
|
175
|
+
occupancyIn: () => occupancyIn,
|
|
163
176
|
parseAmountToMinorUnits: () => parseAmountToMinorUnits,
|
|
164
177
|
parseCurrencyCode: () => parseCurrencyCode,
|
|
165
178
|
parseStripeCurrencyCode: () => parseStripeCurrencyCode,
|
|
179
|
+
planWindow: () => planWindow,
|
|
180
|
+
poolDemand: () => poolDemand,
|
|
181
|
+
poolOf: () => poolOf,
|
|
182
|
+
poolShortfall: () => poolShortfall,
|
|
183
|
+
poolStockAt: () => poolStockAt,
|
|
184
|
+
presentAt: () => presentAt,
|
|
166
185
|
removeFragment: () => removeFragment,
|
|
167
186
|
resolveFamily: () => resolveFamily,
|
|
187
|
+
resolveModifiersForProduct: () => resolveModifiersForProduct,
|
|
168
188
|
resolveTemplate: () => resolveTemplate,
|
|
169
189
|
resolveUnit: () => resolveUnit,
|
|
170
190
|
roundToPrecision: () => roundToPrecision,
|
|
171
191
|
sameFamily: () => sameFamily,
|
|
172
192
|
setOrderState: () => setOrderState,
|
|
193
|
+
shopDayKey: () => shopDayKey,
|
|
194
|
+
shopDayRange: () => shopDayRange,
|
|
173
195
|
signReportForDisplay: () => signReportForDisplay,
|
|
196
|
+
slotsForWindow: () => slotsForWindow,
|
|
174
197
|
stringifyMinorUnits: () => stringifyMinorUnits,
|
|
175
198
|
subtractAmounts: () => subtractAmounts,
|
|
176
199
|
toBase: () => toBase,
|
|
177
200
|
toMinorUnits: () => toMinorUnits,
|
|
178
201
|
validateConfig: () => validateConfig,
|
|
179
202
|
validateFragmentCompatibility: () => validateFragmentCompatibility,
|
|
180
|
-
violatesFinancialInvariant: () => violatesFinancialInvariant
|
|
203
|
+
violatesFinancialInvariant: () => violatesFinancialInvariant,
|
|
204
|
+
windowEndsAt: () => windowEndsAt,
|
|
205
|
+
withinPresence: () => withinPresence
|
|
181
206
|
});
|
|
182
207
|
module.exports = __toCommonJS(index_exports);
|
|
183
208
|
|
|
@@ -605,6 +630,8 @@ var StripeCurrencyCode = /* @__PURE__ */ ((StripeCurrencyCode2) => {
|
|
|
605
630
|
var ProductType = /* @__PURE__ */ ((ProductType2) => {
|
|
606
631
|
ProductType2["SIMPLE"] = "simple";
|
|
607
632
|
ProductType2["VARIABLE"] = "variable";
|
|
633
|
+
ProductType2["BOOKING"] = "booking";
|
|
634
|
+
ProductType2["COMPOSITE"] = "composite";
|
|
608
635
|
return ProductType2;
|
|
609
636
|
})(ProductType || {});
|
|
610
637
|
var ProductStatus = /* @__PURE__ */ ((ProductStatus2) => {
|
|
@@ -622,6 +649,50 @@ var PaymentProcessor = /* @__PURE__ */ ((PaymentProcessor2) => {
|
|
|
622
649
|
return PaymentProcessor2;
|
|
623
650
|
})(PaymentProcessor || {});
|
|
624
651
|
|
|
652
|
+
// enums/booking.enum.ts
|
|
653
|
+
var BookingType = /* @__PURE__ */ ((BookingType3) => {
|
|
654
|
+
BookingType3["RENTAL"] = "rental";
|
|
655
|
+
BookingType3["APPOINTMENT"] = "appointment";
|
|
656
|
+
BookingType3["OVERNIGHT"] = "overnight";
|
|
657
|
+
BookingType3["GROUP"] = "group";
|
|
658
|
+
return BookingType3;
|
|
659
|
+
})(BookingType || {});
|
|
660
|
+
var BookingRatePeriod = /* @__PURE__ */ ((BookingRatePeriod2) => {
|
|
661
|
+
BookingRatePeriod2["SLOT"] = "slot";
|
|
662
|
+
BookingRatePeriod2["DAY"] = "day";
|
|
663
|
+
BookingRatePeriod2["NIGHT"] = "night";
|
|
664
|
+
BookingRatePeriod2["WEEK"] = "week";
|
|
665
|
+
BookingRatePeriod2["MONTH"] = "month";
|
|
666
|
+
return BookingRatePeriod2;
|
|
667
|
+
})(BookingRatePeriod || {});
|
|
668
|
+
var BookingResourceKind = /* @__PURE__ */ ((BookingResourceKind2) => {
|
|
669
|
+
BookingResourceKind2["ASSET"] = "asset";
|
|
670
|
+
BookingResourceKind2["ROOM"] = "room";
|
|
671
|
+
BookingResourceKind2["PROPERTY"] = "property";
|
|
672
|
+
BookingResourceKind2["SPACE"] = "space";
|
|
673
|
+
BookingResourceKind2["STAFF"] = "staff";
|
|
674
|
+
BookingResourceKind2["TABLE"] = "table";
|
|
675
|
+
return BookingResourceKind2;
|
|
676
|
+
})(BookingResourceKind || {});
|
|
677
|
+
var ReservationStatus = /* @__PURE__ */ ((ReservationStatus2) => {
|
|
678
|
+
ReservationStatus2["HELD"] = "held";
|
|
679
|
+
ReservationStatus2["CONFIRMED"] = "confirmed";
|
|
680
|
+
ReservationStatus2["CANCELLED"] = "cancelled";
|
|
681
|
+
ReservationStatus2["EXPIRED"] = "expired";
|
|
682
|
+
return ReservationStatus2;
|
|
683
|
+
})(ReservationStatus || {});
|
|
684
|
+
var BookingResourceStatus = /* @__PURE__ */ ((BookingResourceStatus2) => {
|
|
685
|
+
BookingResourceStatus2["ACTIVE"] = "active";
|
|
686
|
+
BookingResourceStatus2["INACTIVE"] = "inactive";
|
|
687
|
+
return BookingResourceStatus2;
|
|
688
|
+
})(BookingResourceStatus || {});
|
|
689
|
+
var ResourceAvailabilityState = /* @__PURE__ */ ((ResourceAvailabilityState2) => {
|
|
690
|
+
ResourceAvailabilityState2["AVAILABLE"] = "available";
|
|
691
|
+
ResourceAvailabilityState2["FULLY_BOOKED"] = "fullyBooked";
|
|
692
|
+
ResourceAvailabilityState2["NO_HOURS_IN_RANGE"] = "noHoursInRange";
|
|
693
|
+
return ResourceAvailabilityState2;
|
|
694
|
+
})(ResourceAvailabilityState || {});
|
|
695
|
+
|
|
625
696
|
// utils/currency.util.ts
|
|
626
697
|
var CURRENCY_CONFIG = {
|
|
627
698
|
// Major currencies with 2 decimal places
|
|
@@ -1491,6 +1562,309 @@ function normalizeMongoIdString(value) {
|
|
|
1491
1562
|
return null;
|
|
1492
1563
|
}
|
|
1493
1564
|
|
|
1565
|
+
// utils/composite-price.util.ts
|
|
1566
|
+
var compositeItemCost = (item) => item.extraCharge * item.quantity;
|
|
1567
|
+
function cheapestCompositeItem(items) {
|
|
1568
|
+
let cheapest;
|
|
1569
|
+
items.forEach((item, index) => {
|
|
1570
|
+
if (!item.available) return;
|
|
1571
|
+
if (cheapest === void 0 || compositeItemCost(item) < compositeItemCost(items[cheapest])) cheapest = index;
|
|
1572
|
+
});
|
|
1573
|
+
return cheapest;
|
|
1574
|
+
}
|
|
1575
|
+
function cheapestCompositePrice(parts) {
|
|
1576
|
+
let total = 0;
|
|
1577
|
+
for (const part of parts) {
|
|
1578
|
+
if (part.min === 0) continue;
|
|
1579
|
+
const index = cheapestCompositeItem(part.items) ?? cheapestCompositeItem(part.items.map((item) => ({ ...item, available: true })));
|
|
1580
|
+
if (index === void 0) return void 0;
|
|
1581
|
+
total += part.min * compositeItemCost(part.items[index]);
|
|
1582
|
+
}
|
|
1583
|
+
return total;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1586
|
+
// utils/modifier-resolution.util.ts
|
|
1587
|
+
function ancestorChain(categoryId, categoriesById) {
|
|
1588
|
+
const chain = [];
|
|
1589
|
+
const seen = /* @__PURE__ */ new Set([categoryId]);
|
|
1590
|
+
let current = categoriesById.get(categoryId)?.parentId ?? void 0;
|
|
1591
|
+
while (current && !seen.has(current)) {
|
|
1592
|
+
chain.push(current);
|
|
1593
|
+
seen.add(current);
|
|
1594
|
+
current = categoriesById.get(current)?.parentId ?? void 0;
|
|
1595
|
+
}
|
|
1596
|
+
return chain;
|
|
1597
|
+
}
|
|
1598
|
+
function clampRule(rule) {
|
|
1599
|
+
if (rule.min != null && rule.max != null && rule.min > rule.max) {
|
|
1600
|
+
return { ...rule, min: rule.max };
|
|
1601
|
+
}
|
|
1602
|
+
return rule;
|
|
1603
|
+
}
|
|
1604
|
+
function mergeRules(a, b) {
|
|
1605
|
+
const required = a.required || b.required;
|
|
1606
|
+
const min = a.min == null ? b.min : b.min == null ? a.min : Math.max(a.min, b.min);
|
|
1607
|
+
const max = a.max == null ? b.max : b.max == null ? a.max : Math.min(a.max, b.max);
|
|
1608
|
+
return clampRule({ required, min, max, sortOrder: Math.min(a.sortOrder, b.sortOrder) });
|
|
1609
|
+
}
|
|
1610
|
+
function toRule(row) {
|
|
1611
|
+
const required = row.required ?? false;
|
|
1612
|
+
return clampRule({
|
|
1613
|
+
required,
|
|
1614
|
+
// `required` is the gate: a stale min left on a placement that went optional is
|
|
1615
|
+
// ignored. A cleared min/max stays the explicit null it arrived as — nothing
|
|
1616
|
+
// downstream distinguishes null from absent.
|
|
1617
|
+
min: required ? row.min : void 0,
|
|
1618
|
+
max: row.max,
|
|
1619
|
+
sortOrder: row.sortOrder ?? 0
|
|
1620
|
+
});
|
|
1621
|
+
}
|
|
1622
|
+
function toResolvedChoices(modifier) {
|
|
1623
|
+
return (modifier.choices ?? []).map((choice, index) => ({
|
|
1624
|
+
_id: String(choice._id),
|
|
1625
|
+
name: choice.name,
|
|
1626
|
+
price: choice.price ?? 0,
|
|
1627
|
+
isDefault: choice.isDefault,
|
|
1628
|
+
defaultQuantity: choice.defaultQuantity,
|
|
1629
|
+
unavailableOutletIds: choice.unavailableOutletIds?.map(String),
|
|
1630
|
+
sortOrder: choice.sortOrder ?? index
|
|
1631
|
+
})).sort((a, b) => a.sortOrder - b.sortOrder);
|
|
1632
|
+
}
|
|
1633
|
+
function resolveModifiersForProduct(inputs) {
|
|
1634
|
+
const categoriesById = new Map(
|
|
1635
|
+
inputs.categories.filter((category) => !category.isDeleted).map((category) => [String(category._id), category])
|
|
1636
|
+
);
|
|
1637
|
+
const modifiersById = new Map(
|
|
1638
|
+
inputs.modifiers.filter((modifier) => !modifier.isDeleted).map((modifier) => [String(modifier._id), modifier])
|
|
1639
|
+
);
|
|
1640
|
+
const directCategories = new Set(inputs.categoryIds.map(String));
|
|
1641
|
+
const inheritedCategories = /* @__PURE__ */ new Set();
|
|
1642
|
+
for (const categoryId of directCategories) {
|
|
1643
|
+
for (const ancestor of ancestorChain(categoryId, categoriesById)) {
|
|
1644
|
+
if (!directCategories.has(ancestor)) inheritedCategories.add(ancestor);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
const rules = /* @__PURE__ */ new Map();
|
|
1648
|
+
for (const placement of inputs.categoryModifiers) {
|
|
1649
|
+
if (placement.isDeleted) continue;
|
|
1650
|
+
const categoryId = String(placement.categoryId);
|
|
1651
|
+
const precedence = directCategories.has(categoryId) ? 0 : inheritedCategories.has(categoryId) ? 1 : -1;
|
|
1652
|
+
if (precedence === -1) continue;
|
|
1653
|
+
const modifierId = String(placement.modifierId);
|
|
1654
|
+
if (!modifiersById.has(modifierId)) continue;
|
|
1655
|
+
const incoming = toRule(placement);
|
|
1656
|
+
const existing = rules.get(modifierId);
|
|
1657
|
+
if (!existing || precedence < existing.precedence) {
|
|
1658
|
+
rules.set(modifierId, { precedence, rule: incoming });
|
|
1659
|
+
} else if (precedence === existing.precedence) {
|
|
1660
|
+
rules.set(modifierId, { precedence, rule: mergeRules(existing.rule, incoming) });
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
const resolved = [];
|
|
1664
|
+
for (const [modifierId, { rule }] of rules) {
|
|
1665
|
+
const modifier = modifiersById.get(modifierId);
|
|
1666
|
+
if (!modifier) continue;
|
|
1667
|
+
const required = rule.required;
|
|
1668
|
+
resolved.push({
|
|
1669
|
+
_id: modifierId,
|
|
1670
|
+
name: modifier.name,
|
|
1671
|
+
selectionType: modifier.selectionType,
|
|
1672
|
+
allowQuantity: modifier.allowQuantity,
|
|
1673
|
+
required,
|
|
1674
|
+
// single-selection is implicitly capped at 1 — min/max are never carried.
|
|
1675
|
+
min: modifier.selectionType === "single" ? void 0 : rule.min,
|
|
1676
|
+
max: modifier.selectionType === "single" ? void 0 : rule.max,
|
|
1677
|
+
sortOrder: rule.sortOrder,
|
|
1678
|
+
choices: toResolvedChoices(modifier)
|
|
1679
|
+
});
|
|
1680
|
+
}
|
|
1681
|
+
return resolved.sort((a, b) => a.sortOrder - b.sortOrder || a.name.localeCompare(b.name));
|
|
1682
|
+
}
|
|
1683
|
+
function isChoiceAvailableAtOutlet(choice, outletId) {
|
|
1684
|
+
return !(choice.unavailableOutletIds ?? []).includes(outletId);
|
|
1685
|
+
}
|
|
1686
|
+
function hasSellableChoice(modifier, outletId) {
|
|
1687
|
+
return modifier.choices.some((choice) => isChoiceAvailableAtOutlet(choice, outletId));
|
|
1688
|
+
}
|
|
1689
|
+
var modifiersSellable = (modifiers, outletId) => modifiers.every((modifier) => !modifier.required || hasSellableChoice(modifier, outletId));
|
|
1690
|
+
|
|
1691
|
+
// utils/composite-availability.util.ts
|
|
1692
|
+
function poolStockAt(rows, outletId) {
|
|
1693
|
+
if (!rows.some((row) => row.manageStock === true)) return null;
|
|
1694
|
+
return Math.max(0, rows.find((row) => String(row.outletId) === outletId)?.quantity ?? 0);
|
|
1695
|
+
}
|
|
1696
|
+
function compositeVariantInStock(variantId, quantity, outlet) {
|
|
1697
|
+
const shelf = outlet.shelves.get(variantId);
|
|
1698
|
+
if (!shelf || shelf.unresolved) return false;
|
|
1699
|
+
const onHand = outlet.poolStock.get(shelf.pool);
|
|
1700
|
+
if (onHand === void 0) return false;
|
|
1701
|
+
if (onHand === null || shelf.backorder) return true;
|
|
1702
|
+
return onHand >= (shelf.unit ? toBase(quantity, shelf.unit) : quantity);
|
|
1703
|
+
}
|
|
1704
|
+
function compositeItemUnavailable(item, rows) {
|
|
1705
|
+
const { outlet } = rows;
|
|
1706
|
+
const sellableHere = (productId2) => !outlet || !outlet.hiddenProductIds.has(productId2) && !outlet.unsellableProductIds.has(productId2);
|
|
1707
|
+
if (item.categoryId) {
|
|
1708
|
+
const variants = rows.categoryVariants.get(String(item.categoryId));
|
|
1709
|
+
if (!variants) return "deleted";
|
|
1710
|
+
const offered = variants.filter((variantId2) => sellableHere(rows.variantProducts.get(variantId2) ?? ""));
|
|
1711
|
+
if (!offered.length) return "empty";
|
|
1712
|
+
if (!outlet) return null;
|
|
1713
|
+
return offered.some((variantId2) => compositeVariantInStock(variantId2, item.quantity, outlet)) ? null : "out_of_stock";
|
|
1714
|
+
}
|
|
1715
|
+
const variantId = String(item.variantId);
|
|
1716
|
+
const productId = rows.variantProducts.get(variantId);
|
|
1717
|
+
if (!productId || !rows.productStatuses.has(productId)) return "deleted";
|
|
1718
|
+
if (rows.productStatuses.get(productId) !== "active" /* ACTIVE */) return "inactive";
|
|
1719
|
+
if (!outlet) return null;
|
|
1720
|
+
if (outlet.hiddenProductIds.has(productId)) return "hidden";
|
|
1721
|
+
if (outlet.unsellableProductIds.has(productId)) return "empty";
|
|
1722
|
+
if (rows.bookableProductIds.has(productId)) {
|
|
1723
|
+
if (!outlet.bookableSeats) return "by_date";
|
|
1724
|
+
return (outlet.bookableSeats.get(productId) ?? 0) >= item.quantity ? null : "fully_booked";
|
|
1725
|
+
}
|
|
1726
|
+
return compositeVariantInStock(variantId, item.quantity, outlet) ? null : "out_of_stock";
|
|
1727
|
+
}
|
|
1728
|
+
function compositeMakeable(parts, rows) {
|
|
1729
|
+
const { outlet } = rows;
|
|
1730
|
+
if (!outlet) throw new Error("compositeMakeable counts at one outlet: rows.outlet is required");
|
|
1731
|
+
const required = parts.map((part, partIndex) => ({ ...part, partIndex })).filter((part) => part.min > 0);
|
|
1732
|
+
const isBookable = (variantId) => rows.bookableProductIds.has(rows.variantProducts.get(String(variantId)) ?? "");
|
|
1733
|
+
if (required.some((part) => part.items.some((item) => item.variantId && isBookable(item.variantId))))
|
|
1734
|
+
return { byDate: true };
|
|
1735
|
+
const optionsOf = (item) => (item.categoryId ? rows.categoryVariants.get(String(item.categoryId)) ?? [] : [String(item.variantId)]).flatMap(
|
|
1736
|
+
(variantId) => {
|
|
1737
|
+
const reason = compositeItemUnavailable({ variantId, quantity: item.quantity }, rows);
|
|
1738
|
+
const shelf = outlet.shelves.get(variantId);
|
|
1739
|
+
if (reason && reason !== "out_of_stock" || !shelf) return [];
|
|
1740
|
+
const stock = outlet.poolStock.get(shelf.pool);
|
|
1741
|
+
const onHand = shelf.unresolved || stock === void 0 ? 0 : stock === null || shelf.backorder ? null : stock;
|
|
1742
|
+
const perPick = shelf.unit ? toBase(item.quantity, shelf.unit) : item.quantity;
|
|
1743
|
+
return [{ itemId: item.id, pool: shelf.pool, perPick, onHand }];
|
|
1744
|
+
}
|
|
1745
|
+
);
|
|
1746
|
+
const counted = required.map((part) => ({ ...part, options: part.items.flatMap(optionsOf) }));
|
|
1747
|
+
const order = [...counted].sort((a, b) => Number(a.options.length !== 1) - Number(b.options.length !== 1));
|
|
1748
|
+
const picksLeft = (option, reserved) => option.onHand === null ? Infinity : Math.max(0, Math.floor((option.onHand - (reserved.get(option.pool) ?? 0)) / option.perPick));
|
|
1749
|
+
const shortAt = (n) => {
|
|
1750
|
+
const reserved = /* @__PURE__ */ new Map();
|
|
1751
|
+
for (const part of order) {
|
|
1752
|
+
let wanted = part.min * n;
|
|
1753
|
+
const ranked = [...part.options].sort((a, b) => picksLeft(b, reserved) - picksLeft(a, reserved));
|
|
1754
|
+
for (const option of ranked) {
|
|
1755
|
+
if (wanted <= 0) break;
|
|
1756
|
+
const taken = Math.min(wanted, picksLeft(option, reserved));
|
|
1757
|
+
if (option.onHand !== null)
|
|
1758
|
+
reserved.set(option.pool, (reserved.get(option.pool) ?? 0) + taken * option.perPick);
|
|
1759
|
+
wanted -= taken;
|
|
1760
|
+
}
|
|
1761
|
+
if (wanted > 0) return part.partIndex;
|
|
1762
|
+
}
|
|
1763
|
+
return void 0;
|
|
1764
|
+
};
|
|
1765
|
+
const whyRows = [];
|
|
1766
|
+
const rowPools = /* @__PURE__ */ new Map();
|
|
1767
|
+
const makes = (has, uses) => has === null ? null : Math.floor(has / uses);
|
|
1768
|
+
for (const part of counted) {
|
|
1769
|
+
const [option] = part.options;
|
|
1770
|
+
if (part.options.length === 1) {
|
|
1771
|
+
const uses = option.perPick * part.min;
|
|
1772
|
+
const row = whyRows.find((candidate) => rowPools.get(candidate) === option.pool);
|
|
1773
|
+
if (!row) {
|
|
1774
|
+
const created = { itemIds: [option.itemId], uses, has: option.onHand, makes: makes(option.onHand, uses) };
|
|
1775
|
+
rowPools.set(created, option.pool);
|
|
1776
|
+
whyRows.push(created);
|
|
1777
|
+
continue;
|
|
1778
|
+
}
|
|
1779
|
+
row.itemIds.push(option.itemId);
|
|
1780
|
+
row.uses += uses;
|
|
1781
|
+
if (option.onHand === null) row.has = null;
|
|
1782
|
+
row.makes = makes(row.has, row.uses);
|
|
1783
|
+
continue;
|
|
1784
|
+
}
|
|
1785
|
+
const perPool = /* @__PURE__ */ new Map();
|
|
1786
|
+
for (const candidate of part.options)
|
|
1787
|
+
perPool.set(candidate.pool, Math.max(perPool.get(candidate.pool) ?? 0, picksLeft(candidate, /* @__PURE__ */ new Map())));
|
|
1788
|
+
const total = [...perPool.values()].reduce((sum, picks) => sum + picks, 0);
|
|
1789
|
+
const has = total === Infinity ? null : total;
|
|
1790
|
+
whyRows.push({
|
|
1791
|
+
itemIds: part.items.map((item) => item.id),
|
|
1792
|
+
partIndex: part.partIndex,
|
|
1793
|
+
uses: part.min,
|
|
1794
|
+
has,
|
|
1795
|
+
makes: makes(has, part.min)
|
|
1796
|
+
});
|
|
1797
|
+
}
|
|
1798
|
+
if (counted.every((part) => part.options.some((option) => option.onHand === null)))
|
|
1799
|
+
return { count: null, rows: whyRows };
|
|
1800
|
+
const ceiling = Math.min(
|
|
1801
|
+
...counted.filter((part) => !part.options.some((option) => option.onHand === null)).map(
|
|
1802
|
+
(part) => Math.floor(part.options.reduce((sum, option) => sum + picksLeft(option, /* @__PURE__ */ new Map()), 0) / part.min)
|
|
1803
|
+
)
|
|
1804
|
+
);
|
|
1805
|
+
let [low, high] = [0, ceiling];
|
|
1806
|
+
while (low < high) {
|
|
1807
|
+
const mid = Math.ceil((low + high) / 2);
|
|
1808
|
+
if (shortAt(mid) === void 0) low = mid;
|
|
1809
|
+
else high = mid - 1;
|
|
1810
|
+
}
|
|
1811
|
+
const short = shortAt(low + 1);
|
|
1812
|
+
const shortPart = counted.find((part) => part.partIndex === short);
|
|
1813
|
+
const limitedBy = whyRows.findIndex(
|
|
1814
|
+
(row) => shortPart?.options.length === 1 ? row.partIndex === void 0 && row.itemIds.includes(shortPart.options[0].itemId) : row.partIndex === short
|
|
1815
|
+
);
|
|
1816
|
+
return { count: low, rows: whyRows, ...limitedBy >= 0 ? { limitedBy } : {} };
|
|
1817
|
+
}
|
|
1818
|
+
var poolOf = (line) => line.stockVariantId || line.variantId;
|
|
1819
|
+
function poolDemand(lines) {
|
|
1820
|
+
const demand = /* @__PURE__ */ new Map();
|
|
1821
|
+
const add = (line, times) => demand.set(
|
|
1822
|
+
poolOf(line),
|
|
1823
|
+
(demand.get(poolOf(line)) ?? 0) + (line.unit ? toBase(line.quantity * times, line.unit) : line.quantity * times)
|
|
1824
|
+
);
|
|
1825
|
+
for (const line of lines) {
|
|
1826
|
+
if (line.components) for (const component of line.components) add(component, line.quantity);
|
|
1827
|
+
else add(line, 1);
|
|
1828
|
+
}
|
|
1829
|
+
return demand;
|
|
1830
|
+
}
|
|
1831
|
+
function poolShortfall(demand, poolStock, backordered = /* @__PURE__ */ new Set()) {
|
|
1832
|
+
for (const [poolId, wanted] of demand) {
|
|
1833
|
+
const available = poolStock.get(poolId);
|
|
1834
|
+
if (available === null || available === void 0 || backordered.has(poolId)) continue;
|
|
1835
|
+
if (wanted > available) return { poolId, available, wanted };
|
|
1836
|
+
}
|
|
1837
|
+
return null;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
// utils/composite-reservation.util.ts
|
|
1841
|
+
function compositeModifierMismatches(lineItems) {
|
|
1842
|
+
return lineItems.flatMap(
|
|
1843
|
+
(line) => line.components?.length ? (line.modifiers ?? []).flatMap(
|
|
1844
|
+
(modifier) => modifier.componentIndex !== void 0 && line.components[modifier.componentIndex] !== void 0 ? [] : [
|
|
1845
|
+
`Modifier ${modifier.modifierName ?? "?"} on composite line ${line.internalId ?? "?"} names no component (componentIndex ${modifier.componentIndex}) \u2014 a composite has no modifiers of its own`
|
|
1846
|
+
]
|
|
1847
|
+
) : []
|
|
1848
|
+
);
|
|
1849
|
+
}
|
|
1850
|
+
function compositeReservationMismatches(order) {
|
|
1851
|
+
return (order.reservations ?? []).flatMap((reservation) => {
|
|
1852
|
+
if (reservation.lineItemInternalId === void 0) return [];
|
|
1853
|
+
const name = `Booking ${String(reservation.bookingId ?? "?")}`;
|
|
1854
|
+
const line = order.lineItems?.find((candidate) => candidate.internalId === reservation.lineItemInternalId);
|
|
1855
|
+
if (!line) return [`${name} names line ${reservation.lineItemInternalId}, which is not on the order`];
|
|
1856
|
+
const component = reservation.componentIndex === void 0 ? void 0 : line.components?.[reservation.componentIndex];
|
|
1857
|
+
if (!component) return [`${name} names no component ${reservation.componentIndex} of line ${line.internalId}`];
|
|
1858
|
+
if (String(component.productId) !== String(reservation.productId))
|
|
1859
|
+
return [
|
|
1860
|
+
`${name} is for ${String(reservation.productId)}, but that component sold ${String(component.productId)}`
|
|
1861
|
+
];
|
|
1862
|
+
if (reservation.price !== 0 || reservation.total !== 0)
|
|
1863
|
+
return [`${name} carries money (${reservation.price}/${reservation.total}); its component already does`];
|
|
1864
|
+
return [];
|
|
1865
|
+
});
|
|
1866
|
+
}
|
|
1867
|
+
|
|
1494
1868
|
// units/family-code.ts
|
|
1495
1869
|
var MAX_SLUG_LENGTH = 32;
|
|
1496
1870
|
var FALLBACK_SLUG = "family";
|
|
@@ -1833,6 +2207,15 @@ function sumRefundQuantities(refunds) {
|
|
|
1833
2207
|
}
|
|
1834
2208
|
return t;
|
|
1835
2209
|
}
|
|
2210
|
+
var asCount = (value) => typeof value === "number" && Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
2211
|
+
function countsOf(row) {
|
|
2212
|
+
const quantity = asCount(row.quantity);
|
|
2213
|
+
return {
|
|
2214
|
+
quantity,
|
|
2215
|
+
fulfilled: Math.min(asCount(row.fulfilledQuantity), quantity),
|
|
2216
|
+
returned: Math.min(asCount(row.returnedQuantity), quantity)
|
|
2217
|
+
};
|
|
2218
|
+
}
|
|
1836
2219
|
function buildOrderContext(order, extras) {
|
|
1837
2220
|
const o = order ?? {};
|
|
1838
2221
|
const total = typeof o.total === "number" && Number.isFinite(o.total) ? o.total : 0;
|
|
@@ -1840,6 +2223,7 @@ function buildOrderContext(order, extras) {
|
|
|
1840
2223
|
const paymentMethods = o.paymentMethods ?? [];
|
|
1841
2224
|
const refunds = o.refunds ?? o.refund ?? [];
|
|
1842
2225
|
const lineItems = o.lineItems ?? [];
|
|
2226
|
+
const reservations = o.reservations ?? [];
|
|
1843
2227
|
const totalPaid = sumNumbers(paymentMethods);
|
|
1844
2228
|
const totalRefunded = sumRefundQuantities(refunds);
|
|
1845
2229
|
const isFullyPaid = total > 0 ? balance <= 0 : totalPaid > 0 && balance <= 0;
|
|
@@ -1847,13 +2231,11 @@ function buildOrderContext(order, extras) {
|
|
|
1847
2231
|
let itemCount = 0;
|
|
1848
2232
|
let fulfilledItemCount = 0;
|
|
1849
2233
|
let returnedItemCount = 0;
|
|
1850
|
-
for (const
|
|
1851
|
-
const
|
|
1852
|
-
itemCount +=
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
const rq = typeof li.returnedQuantity === "number" && Number.isFinite(li.returnedQuantity) ? Math.max(0, li.returnedQuantity) : 0;
|
|
1856
|
-
returnedItemCount += Math.min(rq, q);
|
|
2234
|
+
for (const row of [...lineItems, ...reservations]) {
|
|
2235
|
+
const { quantity, fulfilled, returned } = countsOf(row);
|
|
2236
|
+
itemCount += quantity;
|
|
2237
|
+
fulfilledItemCount += fulfilled;
|
|
2238
|
+
returnedItemCount += returned;
|
|
1857
2239
|
}
|
|
1858
2240
|
const isFullyReturned = itemCount > 0 ? returnedItemCount >= itemCount : returnedItemCount > 0;
|
|
1859
2241
|
const hasPartialReturns = returnedItemCount > 0 && !isFullyReturned;
|
|
@@ -1863,7 +2245,8 @@ function buildOrderContext(order, extras) {
|
|
|
1863
2245
|
balance,
|
|
1864
2246
|
paymentMethods,
|
|
1865
2247
|
refunds,
|
|
1866
|
-
lineItems
|
|
2248
|
+
lineItems,
|
|
2249
|
+
reservations
|
|
1867
2250
|
},
|
|
1868
2251
|
computed: {
|
|
1869
2252
|
balance,
|
|
@@ -2943,44 +3326,409 @@ var ORDER_STATE_EVENTS = {
|
|
|
2943
3326
|
configUpdated: "config-updated"
|
|
2944
3327
|
};
|
|
2945
3328
|
|
|
2946
|
-
//
|
|
2947
|
-
var
|
|
2948
|
-
|
|
2949
|
-
|
|
3329
|
+
// booking/types.ts
|
|
3330
|
+
var BookingRulesError = class extends Error {
|
|
3331
|
+
constructor(message) {
|
|
3332
|
+
super(message);
|
|
3333
|
+
this.name = "BookingRulesError";
|
|
3334
|
+
}
|
|
3335
|
+
};
|
|
3336
|
+
|
|
3337
|
+
// booking/zoned-time.ts
|
|
3338
|
+
var MINUTE = 6e4;
|
|
3339
|
+
var formatters = /* @__PURE__ */ new Map();
|
|
3340
|
+
var formatterFor = (timeZone) => {
|
|
3341
|
+
const existing = formatters.get(timeZone);
|
|
3342
|
+
if (existing) return existing;
|
|
3343
|
+
let created;
|
|
3344
|
+
try {
|
|
3345
|
+
created = new Intl.DateTimeFormat("en-US", {
|
|
3346
|
+
timeZone,
|
|
3347
|
+
hour12: false,
|
|
3348
|
+
year: "numeric",
|
|
3349
|
+
month: "2-digit",
|
|
3350
|
+
day: "2-digit",
|
|
3351
|
+
hour: "2-digit",
|
|
3352
|
+
minute: "2-digit",
|
|
3353
|
+
second: "2-digit",
|
|
3354
|
+
weekday: "short"
|
|
3355
|
+
});
|
|
3356
|
+
} catch {
|
|
3357
|
+
throw new BookingRulesError(`Booking rules: "${timeZone}" is not a known time zone`);
|
|
3358
|
+
}
|
|
3359
|
+
formatters.set(timeZone, created);
|
|
3360
|
+
return created;
|
|
3361
|
+
};
|
|
3362
|
+
var WEEKDAYS = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
|
3363
|
+
function zonedParts(instant, timeZone) {
|
|
3364
|
+
const parts = {};
|
|
3365
|
+
for (const { type, value } of formatterFor(timeZone).formatToParts(instant)) parts[type] = value;
|
|
3366
|
+
const hour = Number(parts.hour) % 24;
|
|
3367
|
+
return {
|
|
3368
|
+
year: Number(parts.year),
|
|
3369
|
+
month: Number(parts.month),
|
|
3370
|
+
day: Number(parts.day),
|
|
3371
|
+
hour,
|
|
3372
|
+
minute: Number(parts.minute),
|
|
3373
|
+
second: Number(parts.second),
|
|
3374
|
+
weekday: WEEKDAYS.indexOf(parts.weekday)
|
|
3375
|
+
};
|
|
3376
|
+
}
|
|
3377
|
+
function offsetAt(instant, timeZone) {
|
|
3378
|
+
const { year, month, day, hour, minute, second } = zonedParts(instant, timeZone);
|
|
3379
|
+
return Date.UTC(year, month - 1, day, hour, minute, second) - Math.floor(instant.getTime() / 1e3) * 1e3;
|
|
3380
|
+
}
|
|
3381
|
+
function instantFromLocal(year, month, day, minutes, timeZone) {
|
|
3382
|
+
const naive = Date.UTC(year, month - 1, day) + minutes * MINUTE;
|
|
3383
|
+
const firstGuess = naive - offsetAt(new Date(naive), timeZone);
|
|
3384
|
+
return new Date(naive - offsetAt(new Date(firstGuess), timeZone));
|
|
3385
|
+
}
|
|
3386
|
+
function startOfZonedDay(instant, timeZone) {
|
|
3387
|
+
const { year, month, day } = zonedParts(instant, timeZone);
|
|
3388
|
+
return instantFromLocal(year, month, day, 0, timeZone);
|
|
3389
|
+
}
|
|
3390
|
+
function nextZonedDay(dayStart, timeZone) {
|
|
3391
|
+
const { year, month, day } = zonedParts(dayStart, timeZone);
|
|
3392
|
+
return instantFromLocal(year, month, day + 1, 0, timeZone);
|
|
2950
3393
|
}
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
return
|
|
3394
|
+
function atZonedMinute(dayStart, minutes, timeZone) {
|
|
3395
|
+
const { year, month, day } = zonedParts(dayStart, timeZone);
|
|
3396
|
+
return instantFromLocal(year, month, day, minutes, timeZone);
|
|
3397
|
+
}
|
|
3398
|
+
|
|
3399
|
+
// booking/grid.ts
|
|
3400
|
+
var MINUTE2 = 6e4;
|
|
3401
|
+
var MAX_RANGE_DAYS = 366;
|
|
3402
|
+
var asTime = (value, field) => {
|
|
3403
|
+
if (value == null) return void 0;
|
|
3404
|
+
const time = new Date(value).getTime();
|
|
3405
|
+
if (Number.isNaN(time)) throw new BookingRulesError(`Booking rules: ${field} is not a date, got "${String(value)}"`);
|
|
3406
|
+
return time;
|
|
3407
|
+
};
|
|
3408
|
+
function parseHhMm(value, field) {
|
|
3409
|
+
const [hours, minutes] = value.split(":").map(Number);
|
|
3410
|
+
if (!Number.isInteger(hours) || !Number.isInteger(minutes)) {
|
|
3411
|
+
throw new BookingRulesError(`Booking rules: ${field} must be "HH:mm", got "${value}"`);
|
|
3412
|
+
}
|
|
3413
|
+
return hours * 60 + minutes;
|
|
3414
|
+
}
|
|
3415
|
+
function windowEndsAt(rule, now) {
|
|
3416
|
+
const { maxAdvanceDays, bookableTo } = rule.window;
|
|
3417
|
+
const ends = Math.min(
|
|
3418
|
+
maxAdvanceDays ? now.getTime() + maxAdvanceDays * 1440 * MINUTE2 : Number.POSITIVE_INFINITY,
|
|
3419
|
+
asTime(bookableTo, "window.bookableTo") ?? Number.POSITIVE_INFINITY
|
|
3420
|
+
);
|
|
3421
|
+
return Number.isFinite(ends) ? new Date(ends) : null;
|
|
3422
|
+
}
|
|
3423
|
+
function periodSlot(dayStart, timeZone, rule, openMinute, closeMinute) {
|
|
3424
|
+
const { ratePeriod, slot, checkInTime, checkOutTime } = rule;
|
|
3425
|
+
const at = (minutes) => atZonedMinute(dayStart, minutes, timeZone);
|
|
3426
|
+
if (ratePeriod === "night" /* NIGHT */) {
|
|
3427
|
+
if (!checkInTime || !checkOutTime) {
|
|
3428
|
+
throw new BookingRulesError("Overnight booking rules need both checkInTime and checkOutTime");
|
|
3429
|
+
}
|
|
3430
|
+
const checkIn = parseHhMm(checkInTime, "checkInTime");
|
|
3431
|
+
const checkOut = parseHhMm(checkOutTime, "checkOutTime");
|
|
3432
|
+
return {
|
|
3433
|
+
startAt: at(checkIn),
|
|
3434
|
+
endAt: at(1440 + checkOut),
|
|
3435
|
+
// Housekeeping sits between check-out and the next check-in: it costs no night.
|
|
3436
|
+
bufferEndAt: at(1440 + checkIn),
|
|
3437
|
+
canStart: true
|
|
3438
|
+
};
|
|
3439
|
+
}
|
|
3440
|
+
const from = ratePeriod === "day" /* DAY */ ? openMinute ?? 0 : 0;
|
|
3441
|
+
const to = ratePeriod === "day" /* DAY */ ? closeMinute ?? 1440 : 1440;
|
|
3442
|
+
return {
|
|
3443
|
+
startAt: at(from),
|
|
3444
|
+
endAt: at(to),
|
|
3445
|
+
bufferEndAt: at(to + (slot.bufferMinutes ?? 0)),
|
|
3446
|
+
canStart: true
|
|
3447
|
+
};
|
|
2954
3448
|
}
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
3449
|
+
function freeGaps(openAt, closeAt, busy) {
|
|
3450
|
+
const inside = busy.map(({ startAt, bufferEndAt }) => ({ from: +startAt, to: +bufferEndAt })).filter(({ from, to }) => to > openAt && from < closeAt).sort((first, second) => first.from - second.from);
|
|
3451
|
+
const gaps = [];
|
|
3452
|
+
let cursor = openAt;
|
|
3453
|
+
for (const { from, to } of inside) {
|
|
3454
|
+
if (from > cursor) gaps.push({ from: cursor, to: from, endsAtBooking: true });
|
|
3455
|
+
cursor = Math.max(cursor, to);
|
|
3456
|
+
if (cursor >= closeAt) break;
|
|
3457
|
+
}
|
|
3458
|
+
if (cursor < closeAt) gaps.push({ from: cursor, to: closeAt, endsAtBooking: false });
|
|
3459
|
+
return gaps;
|
|
3460
|
+
}
|
|
3461
|
+
function buildGrid(rule, timeZone, from, to, now, busy = []) {
|
|
3462
|
+
if (to.getTime() - from.getTime() > MAX_RANGE_DAYS * 1440 * MINUTE2) {
|
|
3463
|
+
throw new BookingRulesError(`A booking range may span at most ${MAX_RANGE_DAYS} days`);
|
|
3464
|
+
}
|
|
3465
|
+
const { availability, slot, window, ratePeriod } = rule;
|
|
3466
|
+
const periodMode = ratePeriod !== "slot" /* SLOT */;
|
|
3467
|
+
const weeklyHours = availability.weeklyHours ?? [];
|
|
3468
|
+
const notBefore = Math.max(
|
|
3469
|
+
now.getTime() + (window.minNoticeMinutes ?? 0) * MINUTE2,
|
|
3470
|
+
asTime(window.bookableFrom, "window.bookableFrom") ?? 0,
|
|
3471
|
+
asTime(availability.availableFrom, "availability.availableFrom") ?? 0
|
|
3472
|
+
);
|
|
3473
|
+
const notAfter = windowEndsAt(rule, now)?.getTime() ?? Number.POSITIVE_INFINITY;
|
|
3474
|
+
const blocked = (availability.offMarket ?? []).map(({ from: blockFrom, to: blockTo }) => ({
|
|
3475
|
+
from: asTime(blockFrom, "availability.offMarket.from"),
|
|
3476
|
+
to: asTime(blockTo, "availability.offMarket.to")
|
|
3477
|
+
}));
|
|
3478
|
+
const arrivalDays = availability.arrivalDays;
|
|
3479
|
+
const step = slot.lengthMinutes + (slot.bufferMinutes ?? 0);
|
|
3480
|
+
const slots = [];
|
|
3481
|
+
const lastDay = startOfZonedDay(to, timeZone).getTime();
|
|
3482
|
+
let dayStart = startOfZonedDay(from, timeZone);
|
|
3483
|
+
while (dayStart.getTime() <= lastDay) {
|
|
3484
|
+
const weekday = zonedParts(dayStart, timeZone).weekday;
|
|
3485
|
+
const rows = weeklyHours.filter((entry) => entry.weekday === weekday);
|
|
3486
|
+
if (periodMode) {
|
|
3487
|
+
const openToday = weeklyHours.length === 0 || rows.length > 0;
|
|
3488
|
+
if (openToday) {
|
|
3489
|
+
const built = periodSlot(dayStart, timeZone, rule, rows[0]?.openMinute, rows[0]?.closeMinute);
|
|
3490
|
+
slots.push({ ...built, canStart: !arrivalDays?.length || arrivalDays.includes(weekday) });
|
|
3491
|
+
}
|
|
3492
|
+
} else {
|
|
3493
|
+
for (const row of rows) {
|
|
3494
|
+
const openAt = +atZonedMinute(dayStart, row.openMinute, timeZone);
|
|
3495
|
+
const closeAt = +atZonedMinute(dayStart, row.closeMinute, timeZone);
|
|
3496
|
+
for (const gap of freeGaps(openAt, closeAt, busy)) {
|
|
3497
|
+
const mustFit = (gap.endsAtBooking ? step : slot.lengthMinutes) * MINUTE2;
|
|
3498
|
+
for (let start = gap.from; start + mustFit <= gap.to; start += step * MINUTE2) {
|
|
3499
|
+
slots.push({
|
|
3500
|
+
startAt: new Date(start),
|
|
3501
|
+
endAt: new Date(start + slot.lengthMinutes * MINUTE2),
|
|
3502
|
+
bufferEndAt: new Date(start + step * MINUTE2),
|
|
3503
|
+
canStart: true
|
|
3504
|
+
});
|
|
3505
|
+
}
|
|
3506
|
+
}
|
|
3507
|
+
}
|
|
3508
|
+
}
|
|
3509
|
+
dayStart = nextZonedDay(dayStart, timeZone);
|
|
3510
|
+
}
|
|
3511
|
+
const askedFrom = from.getTime();
|
|
3512
|
+
const askedTo = to.getTime();
|
|
3513
|
+
return slots.filter(({ startAt, bufferEndAt }) => {
|
|
3514
|
+
const start = startAt.getTime();
|
|
3515
|
+
if (start < askedFrom || start >= askedTo) return false;
|
|
3516
|
+
if (start < notBefore || start > notAfter) return false;
|
|
3517
|
+
return !blocked.some(
|
|
3518
|
+
({ from: blockFrom, to: blockTo }) => start < blockTo && bufferEndAt.getTime() > blockFrom
|
|
3519
|
+
);
|
|
3520
|
+
}).sort((first, second) => +first.startAt - +second.startAt);
|
|
3521
|
+
}
|
|
3522
|
+
function slotsForWindow(grid, startAt, endAt) {
|
|
3523
|
+
const startIndex = grid.findIndex((entry) => entry.startAt.getTime() === startAt.getTime());
|
|
3524
|
+
if (startIndex < 0) {
|
|
3525
|
+
throw new BookingRulesError(`${startAt.toISOString()} is not a bookable slot start for these rules`);
|
|
3526
|
+
}
|
|
3527
|
+
if (!grid[startIndex].canStart) {
|
|
3528
|
+
throw new BookingRulesError(`${startAt.toISOString()} is not an arrival day for these rules`);
|
|
3529
|
+
}
|
|
3530
|
+
const covered = [];
|
|
3531
|
+
for (let index = startIndex; index < grid.length; index++) {
|
|
3532
|
+
const entry = grid[index];
|
|
3533
|
+
const previous = covered[covered.length - 1];
|
|
3534
|
+
if (previous && entry.startAt.getTime() !== previous.bufferEndAt.getTime()) break;
|
|
3535
|
+
covered.push(entry);
|
|
3536
|
+
if (entry.endAt.getTime() === endAt.getTime()) return covered;
|
|
3537
|
+
if (entry.endAt.getTime() > endAt.getTime()) break;
|
|
3538
|
+
}
|
|
3539
|
+
throw new BookingRulesError(
|
|
3540
|
+
`${startAt.toISOString()} \u2192 ${endAt.toISOString()} does not line up with the bookable grid`
|
|
3541
|
+
);
|
|
2958
3542
|
}
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
3543
|
+
|
|
3544
|
+
// booking/availability.ts
|
|
3545
|
+
var withinPresence = (slot, timeZone, presence) => {
|
|
3546
|
+
if (!presence?.length) return true;
|
|
3547
|
+
const dayStart = startOfZonedDay(slot.startAt, timeZone);
|
|
3548
|
+
const weekday = zonedParts(dayStart, timeZone).weekday;
|
|
3549
|
+
return presence.some(
|
|
3550
|
+
(shift) => shift.weekday === weekday && slot.startAt.getTime() >= atZonedMinute(dayStart, shift.openMinute, timeZone).getTime() && slot.endAt.getTime() <= atZonedMinute(dayStart, shift.closeMinute, timeZone).getTime()
|
|
3551
|
+
);
|
|
3552
|
+
};
|
|
3553
|
+
var overlaps = (entry, startAt, bufferEndAt) => entry.startAt.getTime() < bufferEndAt.getTime() && entry.bufferEndAt.getTime() > startAt.getTime();
|
|
3554
|
+
function occupancyIn(occupied, productId, startAt, bufferEndAt, shared) {
|
|
3555
|
+
const clashing = occupied.filter((entry) => overlaps(entry, startAt, bufferEndAt));
|
|
3556
|
+
const foreign = shared ? void 0 : clashing.find((entry) => entry.productId !== productId);
|
|
3557
|
+
return {
|
|
3558
|
+
taken: clashing.filter((entry) => shared || entry.productId === productId).reduce((sum, entry) => sum + entry.qty, 0),
|
|
3559
|
+
foreignProductId: foreign?.productId
|
|
3560
|
+
};
|
|
2962
3561
|
}
|
|
2963
|
-
var
|
|
2964
|
-
|
|
3562
|
+
var stateFor = (hasShift, offerable, free) => {
|
|
3563
|
+
if (offerable === 0) {
|
|
3564
|
+
return hasShift() ? "fullyBooked" /* FULLY_BOOKED */ : "noHoursInRange" /* NO_HOURS_IN_RANGE */;
|
|
3565
|
+
}
|
|
3566
|
+
return free === 0 ? "fullyBooked" /* FULLY_BOOKED */ : "available" /* AVAILABLE */;
|
|
2965
3567
|
};
|
|
2966
|
-
function
|
|
2967
|
-
|
|
3568
|
+
function shopDayKey(instant, timeZone) {
|
|
3569
|
+
const { year, month, day } = zonedParts(instant, timeZone);
|
|
3570
|
+
const pad = (value) => String(value).padStart(2, "0");
|
|
3571
|
+
return `${year}-${pad(month)}-${pad(day)}`;
|
|
3572
|
+
}
|
|
3573
|
+
function shopDayRange(fromDayKey, count, timeZone) {
|
|
3574
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(fromDayKey ?? "");
|
|
3575
|
+
if (!match) {
|
|
3576
|
+
throw new BookingRulesError(`Booking rules: "${fromDayKey}" is not a shop day (YYYY-MM-DD)`);
|
|
3577
|
+
}
|
|
3578
|
+
if (!Number.isInteger(count) || count < 1) {
|
|
3579
|
+
throw new BookingRulesError(`Booking rules: "${count}" is not a number of days`);
|
|
3580
|
+
}
|
|
3581
|
+
const [, year, month, day] = match.map(Number);
|
|
3582
|
+
const from = instantFromLocal(year, month, day, 0, timeZone);
|
|
3583
|
+
if (shopDayKey(from, timeZone) !== fromDayKey) {
|
|
3584
|
+
throw new BookingRulesError(`Booking rules: "${fromDayKey}" is not a real day`);
|
|
3585
|
+
}
|
|
3586
|
+
return { from, to: instantFromLocal(year, month, day + count, 0, timeZone) };
|
|
3587
|
+
}
|
|
3588
|
+
function buildAvailability({
|
|
3589
|
+
productId,
|
|
3590
|
+
bookingRulesId,
|
|
3591
|
+
bookingType,
|
|
3592
|
+
rule,
|
|
3593
|
+
resources,
|
|
3594
|
+
occupied,
|
|
3595
|
+
from,
|
|
3596
|
+
to,
|
|
3597
|
+
now
|
|
3598
|
+
}) {
|
|
3599
|
+
const shared = rule.slot.sharedAcrossProducts ?? false;
|
|
3600
|
+
const bookableUntil = windowEndsAt(rule, now);
|
|
3601
|
+
const header = {
|
|
3602
|
+
productId,
|
|
3603
|
+
bookingRulesId,
|
|
3604
|
+
bookingType,
|
|
3605
|
+
ratePeriod: rule.ratePeriod,
|
|
3606
|
+
// Passed through for the UI to label: a group slot under minimumToRun may not run.
|
|
3607
|
+
minimumToRun: rule.slot.minimumToRun,
|
|
3608
|
+
minStay: rule.slot.minStay,
|
|
3609
|
+
maxStay: rule.slot.maxStay,
|
|
3610
|
+
// Why a day can come back empty. Past this instant the rule refuses everything, so the UI
|
|
3611
|
+
// can say "beyond the booking window" where it would otherwise claim "nothing free".
|
|
3612
|
+
bookableUntil,
|
|
3613
|
+
// The comparison itself, not just the boundary: deciding whether a day lies past the
|
|
3614
|
+
// window is a rule, and a UI that re-derives it owns a copy of that rule — which is how
|
|
3615
|
+
// the same empty grid ends up explained one way on the till and another in a flow.
|
|
3616
|
+
beyondWindow: !!bookableUntil && from.getTime() > bookableUntil.getTime()
|
|
3617
|
+
};
|
|
3618
|
+
const byResource = /* @__PURE__ */ new Map();
|
|
3619
|
+
for (const entry of occupied) {
|
|
3620
|
+
byResource.set(entry.resourceId, [...byResource.get(entry.resourceId) ?? [], entry]);
|
|
3621
|
+
}
|
|
3622
|
+
const grids = resources.map((resource) => {
|
|
3623
|
+
const mine = byResource.get(resource.id) ?? [];
|
|
3624
|
+
const busy = (resource.seats ?? 1) === 1 ? mine : [];
|
|
3625
|
+
const slots2 = buildGrid(rule, resource.timeZone, from, to, now, busy).filter(
|
|
3626
|
+
(slot) => withinPresence(slot, resource.timeZone, resource.presence)
|
|
3627
|
+
);
|
|
3628
|
+
return { resource, slots: slots2 };
|
|
3629
|
+
});
|
|
3630
|
+
const byInstant = /* @__PURE__ */ new Map();
|
|
3631
|
+
const freeSlotsPerResource = /* @__PURE__ */ new Map();
|
|
3632
|
+
for (const { resource, slots: slots2 } of grids) {
|
|
3633
|
+
const capacity = resource.seats ?? 1;
|
|
3634
|
+
const mine = byResource.get(resource.id) ?? [];
|
|
3635
|
+
for (const slot of slots2) {
|
|
3636
|
+
const { taken, foreignProductId } = occupancyIn(mine, productId, slot.startAt, slot.bufferEndAt, shared);
|
|
3637
|
+
const free = foreignProductId ? 0 : Math.max(capacity - taken, 0);
|
|
3638
|
+
const entry = byInstant.get(+slot.startAt) ?? {
|
|
3639
|
+
...slot,
|
|
3640
|
+
capacity: 0,
|
|
3641
|
+
booked: 0,
|
|
3642
|
+
free: 0,
|
|
3643
|
+
resources: [],
|
|
3644
|
+
dayKey: shopDayKey(slot.startAt, resource.timeZone)
|
|
3645
|
+
};
|
|
3646
|
+
entry.capacity += capacity;
|
|
3647
|
+
entry.booked += foreignProductId ? capacity : taken;
|
|
3648
|
+
entry.free += free;
|
|
3649
|
+
entry.canStart = entry.canStart || slot.canStart;
|
|
3650
|
+
entry.resources.push({ resourceId: resource.id, name: resource.name, capacity, booked: taken, free });
|
|
3651
|
+
if (free > 0) freeSlotsPerResource.set(resource.id, (freeSlotsPerResource.get(resource.id) ?? 0) + 1);
|
|
3652
|
+
byInstant.set(+slot.startAt, entry);
|
|
3653
|
+
}
|
|
3654
|
+
}
|
|
3655
|
+
const inWindow = grids.map(({ resource, slots: slots2 }) => {
|
|
3656
|
+
const free = freeSlotsPerResource.get(resource.id) ?? 0;
|
|
3657
|
+
return {
|
|
3658
|
+
resourceId: resource.id,
|
|
3659
|
+
name: resource.name,
|
|
3660
|
+
slots: slots2.length,
|
|
3661
|
+
free,
|
|
3662
|
+
// Lazily: the shift grid is a second walk, and only an empty answer needs it.
|
|
3663
|
+
state: stateFor(
|
|
3664
|
+
() => buildGrid(rule, resource.timeZone, from, to, now).filter(
|
|
3665
|
+
(slot) => withinPresence(slot, resource.timeZone, resource.presence)
|
|
3666
|
+
).length > 0,
|
|
3667
|
+
slots2.length,
|
|
3668
|
+
free
|
|
3669
|
+
)
|
|
3670
|
+
};
|
|
3671
|
+
});
|
|
3672
|
+
const slots = [...byInstant.values()].sort((first, second) => +first.startAt - +second.startAt);
|
|
3673
|
+
return {
|
|
3674
|
+
...header,
|
|
3675
|
+
resources: inWindow,
|
|
3676
|
+
slots,
|
|
3677
|
+
/**
|
|
3678
|
+
* The clock every instant above reads on. Returned rather than assumed: without it a caller
|
|
3679
|
+
* has to fetch the zone from somewhere else and hope it is the same one the grid used.
|
|
3680
|
+
*/
|
|
3681
|
+
timeZone: resources[0]?.timeZone ?? null,
|
|
3682
|
+
/** The shop days this answer covers, in order — what a day picker lists. */
|
|
3683
|
+
days: [...new Set(slots.map((slot) => slot.dayKey))]
|
|
3684
|
+
};
|
|
3685
|
+
}
|
|
3686
|
+
function presentAt(resources, rows, outletId) {
|
|
3687
|
+
const byResource = /* @__PURE__ */ new Map();
|
|
3688
|
+
for (const row of rows) {
|
|
3689
|
+
byResource.set(row.resourceId, [...byResource.get(row.resourceId) ?? [], row]);
|
|
3690
|
+
}
|
|
3691
|
+
return resources.flatMap((resource) => {
|
|
3692
|
+
const own = byResource.get(resource.id) ?? [];
|
|
3693
|
+
if (own.length === 0 || !outletId) return [{ resource }];
|
|
3694
|
+
const here = own.find((row) => row.outletId === outletId);
|
|
3695
|
+
return here ? [{ resource, presence: here.weeklyHours }] : [];
|
|
3696
|
+
});
|
|
3697
|
+
}
|
|
3698
|
+
|
|
3699
|
+
// booking/plan.ts
|
|
3700
|
+
var DEFAULT_HOLD_MINUTES = 10;
|
|
3701
|
+
function planWindow({ rule, timeZone, presence, startAt, endAt, now, busy = [] }) {
|
|
3702
|
+
const grid = buildGrid(rule, timeZone, startAt, endAt, now, busy).filter(
|
|
3703
|
+
(slot) => withinPresence(slot, timeZone, presence)
|
|
3704
|
+
);
|
|
3705
|
+
const slots = slotsForWindow(grid, startAt, endAt);
|
|
3706
|
+
const { minStay, maxStay } = rule.slot;
|
|
3707
|
+
if (minStay && slots.length < minStay) {
|
|
3708
|
+
throw new BookingRulesError(`These rules ask for at least ${minStay} period(s), got ${slots.length}`);
|
|
3709
|
+
}
|
|
3710
|
+
if (maxStay && slots.length > maxStay) {
|
|
3711
|
+
throw new BookingRulesError(`These rules allow at most ${maxStay} period(s), got ${slots.length}`);
|
|
3712
|
+
}
|
|
3713
|
+
const last = slots[slots.length - 1];
|
|
3714
|
+
return { slots, endAt: last.endAt, bufferEndAt: last.bufferEndAt };
|
|
2968
3715
|
}
|
|
2969
|
-
var
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
3716
|
+
var holdExpiresAt = (rule, now) => new Date(now.getTime() + (rule.window.holdMinutes ?? DEFAULT_HOLD_MINUTES) * 6e4);
|
|
3717
|
+
|
|
3718
|
+
// constants/adyen.constants.ts
|
|
3719
|
+
var ADYEN_ROLLOUT_COUNTRY_CODES = /* @__PURE__ */ new Set(["CA"]);
|
|
3720
|
+
function isAdyenRolloutCountry(alpha2) {
|
|
3721
|
+
return ADYEN_ROLLOUT_COUNTRY_CODES.has(alpha2);
|
|
2973
3722
|
}
|
|
2974
3723
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2975
3724
|
0 && (module.exports = {
|
|
2976
|
-
ADYEN_JOB_TITLE_ASSOCIATION_TYPES,
|
|
2977
|
-
ADYEN_LEGAL_ENTITY_STATE_PROVINCE_COUNTRIES,
|
|
2978
|
-
ADYEN_NO_TAX_NUMBER_ABSENT_COUNTRIES,
|
|
2979
3725
|
ADYEN_ROLLOUT_COUNTRY_CODES,
|
|
2980
|
-
ADYEN_STORE_STATE_PROVINCE_COUNTRIES,
|
|
2981
|
-
ADYEN_TAX_NUMBER_FORMATS,
|
|
2982
|
-
ADYEN_TAX_NUMBER_MIN_LENGTH,
|
|
2983
3726
|
AttributeType,
|
|
3727
|
+
BookingRatePeriod,
|
|
3728
|
+
BookingResourceKind,
|
|
3729
|
+
BookingResourceStatus,
|
|
3730
|
+
BookingRulesError,
|
|
3731
|
+
BookingType,
|
|
2984
3732
|
CONDITION_OPERATORS,
|
|
2985
3733
|
COUNTRY_CURRENCIES,
|
|
2986
3734
|
CURRENCY_CONFIG,
|
|
@@ -2991,6 +3739,7 @@ function adyenRequiresJobTitle(associationType) {
|
|
|
2991
3739
|
DEFAULT_CONFIG,
|
|
2992
3740
|
DEFAULT_CROSS_AXIS_RULES,
|
|
2993
3741
|
DEFAULT_DISPLAY_STATE_MAP,
|
|
3742
|
+
DEFAULT_HOLD_MINUTES,
|
|
2994
3743
|
DEFAULT_RESOLVED_CONFIG,
|
|
2995
3744
|
DEFAULT_UNIT_ID,
|
|
2996
3745
|
DualWriteStrategy,
|
|
@@ -3034,8 +3783,10 @@ function adyenRequiresJobTitle(associationType) {
|
|
|
3034
3783
|
REPORT_NEGATE_PATHS,
|
|
3035
3784
|
ReceiptSendChannel,
|
|
3036
3785
|
ReceiptType,
|
|
3786
|
+
ReservationStatus,
|
|
3037
3787
|
ResidualPaymentMethod,
|
|
3038
3788
|
ResidualStatus,
|
|
3789
|
+
ResourceAvailabilityState,
|
|
3039
3790
|
STATE_SCHEMA,
|
|
3040
3791
|
STRIPE_SUPPORTED_COUNTRIES,
|
|
3041
3792
|
SYSTEM_FAMILIES,
|
|
@@ -3049,23 +3800,29 @@ function adyenRequiresJobTitle(associationType) {
|
|
|
3049
3800
|
TopMetericsSort,
|
|
3050
3801
|
UserTypes,
|
|
3051
3802
|
addAmounts,
|
|
3052
|
-
adyenLegalEntityRequiresStateOrProvince,
|
|
3053
|
-
adyenRequiresJobTitle,
|
|
3054
|
-
adyenStoreRequiresStateOrProvince,
|
|
3055
|
-
adyenSupportsTaxNumberAbsent,
|
|
3056
|
-
adyenTaxNumberFormat,
|
|
3057
3803
|
amountToString,
|
|
3804
|
+
ancestorChain,
|
|
3058
3805
|
assertUnitSane,
|
|
3059
3806
|
availableIn,
|
|
3060
3807
|
baseFor,
|
|
3061
3808
|
baseFulfillmentDefinitions,
|
|
3062
3809
|
baseOf,
|
|
3063
3810
|
basePaymentDefinitions,
|
|
3811
|
+
buildAvailability,
|
|
3812
|
+
buildGrid,
|
|
3064
3813
|
buildOrderContext,
|
|
3065
3814
|
buildPosPresetConfig,
|
|
3066
3815
|
buildResolvedConfig,
|
|
3067
3816
|
calculatePercentage,
|
|
3068
3817
|
canTransition,
|
|
3818
|
+
cheapestCompositeItem,
|
|
3819
|
+
cheapestCompositePrice,
|
|
3820
|
+
compositeItemCost,
|
|
3821
|
+
compositeItemUnavailable,
|
|
3822
|
+
compositeMakeable,
|
|
3823
|
+
compositeModifierMismatches,
|
|
3824
|
+
compositeReservationMismatches,
|
|
3825
|
+
compositeVariantInStock,
|
|
3069
3826
|
conditionSummary,
|
|
3070
3827
|
convertFixedFeeToLocalCurrency,
|
|
3071
3828
|
createAmount,
|
|
@@ -3100,8 +3857,11 @@ function adyenRequiresJobTitle(associationType) {
|
|
|
3100
3857
|
getPricingRegionFromCountry,
|
|
3101
3858
|
getSettlementTotal,
|
|
3102
3859
|
getTotalCollected,
|
|
3860
|
+
hasSellableChoice,
|
|
3861
|
+
holdExpiresAt,
|
|
3103
3862
|
inferStatesFromLegacyStatus,
|
|
3104
3863
|
isAdyenRolloutCountry,
|
|
3864
|
+
isChoiceAvailableAtOutlet,
|
|
3105
3865
|
isConditionOperator,
|
|
3106
3866
|
isFulfillmentState,
|
|
3107
3867
|
isPaymentState,
|
|
@@ -3112,25 +3872,39 @@ function adyenRequiresJobTitle(associationType) {
|
|
|
3112
3872
|
mapToLegacyStatus,
|
|
3113
3873
|
maxPrecisionFor,
|
|
3114
3874
|
mergeFragment,
|
|
3875
|
+
modifiersSellable,
|
|
3115
3876
|
multiplyAmount,
|
|
3116
3877
|
normalizeMongoIdString,
|
|
3878
|
+
occupancyIn,
|
|
3117
3879
|
parseAmountToMinorUnits,
|
|
3118
3880
|
parseCurrencyCode,
|
|
3119
3881
|
parseStripeCurrencyCode,
|
|
3882
|
+
planWindow,
|
|
3883
|
+
poolDemand,
|
|
3884
|
+
poolOf,
|
|
3885
|
+
poolShortfall,
|
|
3886
|
+
poolStockAt,
|
|
3887
|
+
presentAt,
|
|
3120
3888
|
removeFragment,
|
|
3121
3889
|
resolveFamily,
|
|
3890
|
+
resolveModifiersForProduct,
|
|
3122
3891
|
resolveTemplate,
|
|
3123
3892
|
resolveUnit,
|
|
3124
3893
|
roundToPrecision,
|
|
3125
3894
|
sameFamily,
|
|
3126
3895
|
setOrderState,
|
|
3896
|
+
shopDayKey,
|
|
3897
|
+
shopDayRange,
|
|
3127
3898
|
signReportForDisplay,
|
|
3899
|
+
slotsForWindow,
|
|
3128
3900
|
stringifyMinorUnits,
|
|
3129
3901
|
subtractAmounts,
|
|
3130
3902
|
toBase,
|
|
3131
3903
|
toMinorUnits,
|
|
3132
3904
|
validateConfig,
|
|
3133
3905
|
validateFragmentCompatibility,
|
|
3134
|
-
violatesFinancialInvariant
|
|
3906
|
+
violatesFinancialInvariant,
|
|
3907
|
+
windowEndsAt,
|
|
3908
|
+
withinPresence
|
|
3135
3909
|
});
|
|
3136
3910
|
//# sourceMappingURL=index.js.map
|