@fire-spark/core 0.12.3 → 0.12.5
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.ts +1 -0
- package/dist/index.js +104 -15
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -941,6 +941,7 @@ declare const capRedeems: <T extends CapOrder>(order: T) => T & {
|
|
|
941
941
|
id: string;
|
|
942
942
|
parent_uid: string | null;
|
|
943
943
|
parent_id: string | null;
|
|
944
|
+
group_id?: string | undefined;
|
|
944
945
|
name: string;
|
|
945
946
|
image_url?: string | undefined;
|
|
946
947
|
menu_id?: string | undefined;
|
package/dist/index.js
CHANGED
|
@@ -1415,9 +1415,11 @@ const flattenMenuCategories = (categories, categoriesById, options) => {
|
|
|
1415
1415
|
//#endregion
|
|
1416
1416
|
//#region src/productCustomization/fromOrderLines.ts
|
|
1417
1417
|
/** Group slot of a child line: listed directly, or as the variant of a base
|
|
1418
|
-
* listed in one of the parent's modifier groups.
|
|
1419
|
-
|
|
1418
|
+
* listed in one of the parent's modifier groups. With `onlyGroupId` (the
|
|
1419
|
+
* line's declared `group_id`) only that group of this parent is searched. */
|
|
1420
|
+
const matchModifierLine = (lookup, parent, childId, onlyGroupId) => {
|
|
1420
1421
|
const groups = parent.pricing.modifier_group_ids.flatMap((groupId) => {
|
|
1422
|
+
if (onlyGroupId !== void 0 && groupId !== onlyGroupId) return [];
|
|
1421
1423
|
const group = lookup.modifierGroupsById[groupId];
|
|
1422
1424
|
return group ? [group] : [];
|
|
1423
1425
|
});
|
|
@@ -1463,7 +1465,13 @@ const fromOrderLines = (root, lines, lookup) => {
|
|
|
1463
1465
|
const parentProduct = lookup.productsById[parentLine.id];
|
|
1464
1466
|
if (!parentProduct) return;
|
|
1465
1467
|
for (const child of childrenByParent.get(parentLine.uid) ?? []) {
|
|
1466
|
-
const
|
|
1468
|
+
const p = [
|
|
1469
|
+
lookup,
|
|
1470
|
+
parentProduct,
|
|
1471
|
+
child.id,
|
|
1472
|
+
child.group_id
|
|
1473
|
+
];
|
|
1474
|
+
const match = matchModifierLine(...p);
|
|
1467
1475
|
if (!match) continue;
|
|
1468
1476
|
const { groupId, modifierId, selection } = match;
|
|
1469
1477
|
const path = `${pathPrefix}/group/${groupId}/modifier/${modifierId}`;
|
|
@@ -1750,6 +1758,7 @@ const buildLine = (args) => {
|
|
|
1750
1758
|
name: args.name
|
|
1751
1759
|
};
|
|
1752
1760
|
const r4 = {
|
|
1761
|
+
...args.group_id ? { group_id: args.group_id } : {},
|
|
1753
1762
|
...imagePatch,
|
|
1754
1763
|
...catalog
|
|
1755
1764
|
};
|
|
@@ -1835,7 +1844,8 @@ const appendModifierLine = (modifier, groupId, parent, locale) => {
|
|
|
1835
1844
|
const line = buildLine({
|
|
1836
1845
|
...l1,
|
|
1837
1846
|
...l2,
|
|
1838
|
-
...l3
|
|
1847
|
+
...l3,
|
|
1848
|
+
group_id: groupId
|
|
1839
1849
|
});
|
|
1840
1850
|
parent.children.push(line);
|
|
1841
1851
|
if (modifier.product) appendGroupLines(modifier.product.groups, line, locale);
|
|
@@ -3687,7 +3697,8 @@ const computeLineFingerprint = (root, lines) => {
|
|
|
3687
3697
|
const keys = lines.filter((line) => {
|
|
3688
3698
|
return line.parent_uid === parentUid;
|
|
3689
3699
|
}).map((line) => {
|
|
3690
|
-
|
|
3700
|
+
const slot = line.group_id ? `@${line.group_id}` : "";
|
|
3701
|
+
return `${line.id}${slot}x${line.quantity}(${childKeys(line.uid)})`;
|
|
3691
3702
|
});
|
|
3692
3703
|
keys.sort((left, right) => left.localeCompare(right));
|
|
3693
3704
|
return keys.join(",");
|
|
@@ -3934,11 +3945,20 @@ const redemptionTenderInputs = (redeem, providers = /* @__PURE__ */ new Map()) =
|
|
|
3934
3945
|
};
|
|
3935
3946
|
});
|
|
3936
3947
|
};
|
|
3948
|
+
/**
|
|
3949
|
+
* `collect_at` when the caller omits it, same rule as the API place
|
|
3950
|
+
* default (D23): cash and the Fire Spark card terminal are collected in
|
|
3951
|
+
* person (`DOOR`); every other method is charged by the SDK (`DEVICE`).
|
|
3952
|
+
*/
|
|
3953
|
+
const defaultTenderCollectAt = (provider, method) => {
|
|
3954
|
+
return isManualPayment(provider, method) ? "DOOR" : "DEVICE";
|
|
3955
|
+
};
|
|
3937
3956
|
/** The one real tender of the simple flow (`allocation: null`). */
|
|
3938
3957
|
const simpleTenderInput = (payment) => {
|
|
3939
3958
|
if (!payment.type || !payment.provider) return null;
|
|
3940
3959
|
if (!isRealPaymentMethod(payment.type)) return null;
|
|
3941
|
-
const
|
|
3960
|
+
const fallback = defaultTenderCollectAt(payment.provider, payment.type);
|
|
3961
|
+
const collect_at = payment.collect_at ?? fallback;
|
|
3942
3962
|
const t1 = {
|
|
3943
3963
|
method: payment.type,
|
|
3944
3964
|
provider: payment.provider
|
|
@@ -6634,7 +6654,8 @@ const selectionKey = (line, kidsOf, cache) => {
|
|
|
6634
6654
|
return selectionKey(child, kidsOf, cache);
|
|
6635
6655
|
});
|
|
6636
6656
|
nested.sort((left, right) => left.localeCompare(right));
|
|
6637
|
-
const
|
|
6657
|
+
const slot = line.group_id ? `@${line.group_id}` : "";
|
|
6658
|
+
const key = `${line.id}${slot}x${line.quantity}(${nested.join(",")})`;
|
|
6638
6659
|
cache.set(line.uid, key);
|
|
6639
6660
|
return key;
|
|
6640
6661
|
};
|
|
@@ -6721,6 +6742,36 @@ const hasRepeatedProductSibling = (lines, rootUid) => {
|
|
|
6721
6742
|
};
|
|
6722
6743
|
return walk(rootUid);
|
|
6723
6744
|
};
|
|
6745
|
+
/** A line whose product the parent's menu lists in more than one slot, at
|
|
6746
|
+
* any depth. Cart lines carry no group id, so the slot is chosen by
|
|
6747
|
+
* `placeCartLines`; with a single listing the session path is unambiguous. */
|
|
6748
|
+
const hasMultiSlotChild = (lines, rootUid, lookup) => {
|
|
6749
|
+
const kidsOf = /* @__PURE__ */ new Map();
|
|
6750
|
+
for (const line of lines) {
|
|
6751
|
+
if (line.parent_uid == null) continue;
|
|
6752
|
+
const list = kidsOf.get(line.parent_uid) ?? [];
|
|
6753
|
+
list.push(line);
|
|
6754
|
+
kidsOf.set(line.parent_uid, list);
|
|
6755
|
+
}
|
|
6756
|
+
const walk = (line) => {
|
|
6757
|
+
const parent = lookup.productsById[line.id];
|
|
6758
|
+
const groups = parent ? parentGroups(lookup, parent) : [];
|
|
6759
|
+
for (const kid of kidsOf.get(line.uid) ?? []) {
|
|
6760
|
+
const ids = listingsFor(lookup, groups, kid.id).map((row) => slotKey(row.group.id, row.modifierId));
|
|
6761
|
+
if (new Set(ids).size > 1) return true;
|
|
6762
|
+
if (walk(kid)) return true;
|
|
6763
|
+
}
|
|
6764
|
+
return false;
|
|
6765
|
+
};
|
|
6766
|
+
const root = lines.find((line) => line.uid === rootUid);
|
|
6767
|
+
return root ? walk(root) : false;
|
|
6768
|
+
};
|
|
6769
|
+
/** Cart shapes the slot search must place: a repeated sibling product, or
|
|
6770
|
+
* a product listed in several slots. Everything else keeps the session. */
|
|
6771
|
+
const needsSlotPlacement = (lines, rootUid, lookup) => {
|
|
6772
|
+
if (hasRepeatedProductSibling(lines, rootUid)) return true;
|
|
6773
|
+
return hasMultiSlotChild(lines, rootUid, lookup);
|
|
6774
|
+
};
|
|
6724
6775
|
const noteRules = (state, broken) => {
|
|
6725
6776
|
if (broken) state.rulesBroken = true;
|
|
6726
6777
|
};
|
|
@@ -6888,13 +6939,21 @@ const greedyAssignment = (plans) => {
|
|
|
6888
6939
|
overCapacity
|
|
6889
6940
|
};
|
|
6890
6941
|
};
|
|
6942
|
+
/** The groups a line may sit in under this parent: only its declared
|
|
6943
|
+
* `group_id` when it names one, else every group of the parent. A declared id
|
|
6944
|
+
* the parent does not own leaves none, so the line is never placed. */
|
|
6945
|
+
const groupsDeclared = (groups, line) => {
|
|
6946
|
+
if (line.group_id === void 0) return groups;
|
|
6947
|
+
return groups.filter((group) => group.id === line.group_id);
|
|
6948
|
+
};
|
|
6891
6949
|
const planKids = (lookup, groups, byKey, kids, prefix, state) => {
|
|
6892
6950
|
const plans = [];
|
|
6893
6951
|
let previous = "";
|
|
6894
6952
|
for (const child of kids) {
|
|
6895
6953
|
if (pathVisits(prefix, child.id)) continue;
|
|
6896
6954
|
const ordered = lookup.productsById[child.id];
|
|
6897
|
-
const
|
|
6955
|
+
const scope = groupsDeclared(groups, child);
|
|
6956
|
+
const listings = listingsFor(lookup, scope, child.id);
|
|
6898
6957
|
if (!ordered || listings.length === 0) continue;
|
|
6899
6958
|
const listed = [];
|
|
6900
6959
|
for (const item of listings) {
|
|
@@ -7114,14 +7173,17 @@ const emit = (node, parentUid, parentId, locale, out) => {
|
|
|
7114
7173
|
type: "PRODUCT",
|
|
7115
7174
|
uid: randomUUID()
|
|
7116
7175
|
};
|
|
7176
|
+
const id = node.product.id;
|
|
7177
|
+
const groupPatch = node.group ? { group_id: node.group.id } : {};
|
|
7117
7178
|
const r2 = {
|
|
7118
|
-
id
|
|
7179
|
+
id,
|
|
7119
7180
|
parent_uid: parentUid,
|
|
7120
7181
|
parent_id: parentId
|
|
7121
7182
|
};
|
|
7122
7183
|
const r3 = {
|
|
7123
7184
|
name: displayName(node.product.name, locale),
|
|
7124
|
-
quantity: node.quantity
|
|
7185
|
+
quantity: node.quantity,
|
|
7186
|
+
...groupPatch
|
|
7125
7187
|
};
|
|
7126
7188
|
const r4 = {
|
|
7127
7189
|
redeem: [],
|
|
@@ -7312,10 +7374,25 @@ const childrenOf = (lines, parentUid) => {
|
|
|
7312
7374
|
if (byShape !== 0) return byShape;
|
|
7313
7375
|
const bySubtotal = new Big(a.unit_subtotal).cmp(b.unit_subtotal);
|
|
7314
7376
|
if (bySubtotal !== 0) return bySubtotal;
|
|
7315
|
-
|
|
7377
|
+
const byTax = new Big(a.unit_tax_total).cmp(b.unit_tax_total);
|
|
7378
|
+
if (byTax !== 0) return byTax;
|
|
7379
|
+
return (a.group_id ?? "").localeCompare(b.group_id ?? "");
|
|
7316
7380
|
});
|
|
7317
7381
|
return children;
|
|
7318
7382
|
};
|
|
7383
|
+
/** A declared `group_id` that the parent's menu does not back (unknown under
|
|
7384
|
+
* this parent, or it does not hold the product) names the field; a line that
|
|
7385
|
+
* is no modifier of its parent at all keeps the plain code. */
|
|
7386
|
+
const notFoundIssue = (lookup, parent, child) => {
|
|
7387
|
+
const code = "MODIFIER_NOT_FOUND";
|
|
7388
|
+
if (child.group_id === void 0) return { code };
|
|
7389
|
+
if (!matchModifierLine(lookup, parent, child.id)) return { code };
|
|
7390
|
+
return {
|
|
7391
|
+
code,
|
|
7392
|
+
field: "group_id",
|
|
7393
|
+
actual: child.group_id
|
|
7394
|
+
};
|
|
7395
|
+
};
|
|
7319
7396
|
const collectUnmatchedModifiers = (lines, lookup, parentProductId, parentUid, out) => {
|
|
7320
7397
|
const parent = lookup.productsById[parentProductId];
|
|
7321
7398
|
if (!parent) return;
|
|
@@ -7327,9 +7404,14 @@ const collectUnmatchedModifiers = (lines, lookup, parentProductId, parentUid, ou
|
|
|
7327
7404
|
pushLineIssue(out, child.uid, { code: "VARIANT_BASE_NOT_ORDERABLE" });
|
|
7328
7405
|
continue;
|
|
7329
7406
|
}
|
|
7330
|
-
const match = matchModifierLine(
|
|
7407
|
+
const match = matchModifierLine(...[
|
|
7408
|
+
lookup,
|
|
7409
|
+
parent,
|
|
7410
|
+
child.id,
|
|
7411
|
+
child.group_id
|
|
7412
|
+
]);
|
|
7331
7413
|
if (!match) {
|
|
7332
|
-
pushLineIssue(out, child.uid,
|
|
7414
|
+
pushLineIssue(out, child.uid, notFoundIssue(lookup, parent, child));
|
|
7333
7415
|
continue;
|
|
7334
7416
|
}
|
|
7335
7417
|
const base = lookup.productsById[match.modifierId];
|
|
@@ -7472,6 +7554,13 @@ const compareTrees = (actualLines, expectedLines, actualUid, expectedUid, out) =
|
|
|
7472
7554
|
});
|
|
7473
7555
|
return;
|
|
7474
7556
|
}
|
|
7557
|
+
const declared = actual.group_id;
|
|
7558
|
+
if (declared !== void 0 && declared !== expected.group_id) pushLineIssue(out, actual.uid, {
|
|
7559
|
+
code: "STRUCTURE_MISMATCH",
|
|
7560
|
+
field: "group_id",
|
|
7561
|
+
expected: expected.group_id,
|
|
7562
|
+
actual: declared
|
|
7563
|
+
});
|
|
7475
7564
|
if (actual.quantity !== expected.quantity) pushLineIssue(out, actual.uid, {
|
|
7476
7565
|
code: "QUANTITY_MISMATCH",
|
|
7477
7566
|
field: "quantity",
|
|
@@ -7557,7 +7646,7 @@ const validateProductRoot = (root, lines, lookup, locale, out) => {
|
|
|
7557
7646
|
if (!isOnSchedule(product.availability.schedules)) pushLineIssue(out, root.uid, { code: "OUTSIDE_HOURS" });
|
|
7558
7647
|
collectUnmatchedModifiers(lines, lookup, root.id, root.uid, out);
|
|
7559
7648
|
let expected;
|
|
7560
|
-
if (
|
|
7649
|
+
if (needsSlotPlacement(lines, root.uid, lookup)) {
|
|
7561
7650
|
const placed = placeCartLines(root, lines, lookup, locale);
|
|
7562
7651
|
if (placed.rulesBroken) pushLineIssue(out, root.uid, { code: "MODIFIER_RULES_INVALID" });
|
|
7563
7652
|
expected = placed.lines;
|
|
@@ -7889,7 +7978,7 @@ const collectOrderLineDiffs = (input) => {
|
|
|
7889
7978
|
continue;
|
|
7890
7979
|
}
|
|
7891
7980
|
try {
|
|
7892
|
-
if (
|
|
7981
|
+
if (needsSlotPlacement(input.lines, root.uid, lookup)) {
|
|
7893
7982
|
const placed = placeCartLines(root, input.lines, lookup, locale);
|
|
7894
7983
|
const next = placed.rulesBroken ? null : placed.lines;
|
|
7895
7984
|
diffs.push({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fire-spark/core",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.5",
|
|
4
4
|
"description": "Fire Spark headless SDK",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"big.js": "6.2.1",
|
|
21
21
|
"dayjs": "1.11.9",
|
|
22
22
|
"@types/big.js": "6.2.2",
|
|
23
|
-
"@fire-spark/payments": "^0.12.
|
|
24
|
-
"@fire-spark/types": "^0.12.
|
|
23
|
+
"@fire-spark/payments": "^0.12.5",
|
|
24
|
+
"@fire-spark/types": "^0.12.5"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"tsdown": "^0.22.14",
|