@putiikkipalvelu/storefront-sdk 0.2.5 → 0.3.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/index.cjs +185 -165
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +108 -83
- package/dist/index.d.ts +108 -83
- package/dist/index.js +178 -158
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -610,6 +610,138 @@ function createCartResource(fetcher) {
|
|
|
610
610
|
};
|
|
611
611
|
}
|
|
612
612
|
|
|
613
|
+
// src/utils/pricing.ts
|
|
614
|
+
function isSaleActive(startDate, endDate) {
|
|
615
|
+
if (!startDate && !endDate) {
|
|
616
|
+
return true;
|
|
617
|
+
}
|
|
618
|
+
const now = /* @__PURE__ */ new Date();
|
|
619
|
+
const start = startDate ? new Date(startDate) : null;
|
|
620
|
+
const end = endDate ? new Date(endDate) : null;
|
|
621
|
+
if (start && !end) {
|
|
622
|
+
return now >= start;
|
|
623
|
+
}
|
|
624
|
+
if (!start && end) {
|
|
625
|
+
return now <= end;
|
|
626
|
+
}
|
|
627
|
+
if (start && end) {
|
|
628
|
+
return now >= start && now <= end;
|
|
629
|
+
}
|
|
630
|
+
return true;
|
|
631
|
+
}
|
|
632
|
+
function getPriceInfo(product, variation) {
|
|
633
|
+
if (variation) {
|
|
634
|
+
const isOnSale2 = isSaleActive(variation.saleStartDate, variation.saleEndDate) && variation.salePrice !== null;
|
|
635
|
+
const originalPrice2 = variation.price ?? product.price;
|
|
636
|
+
const effectivePrice2 = isOnSale2 ? variation.salePrice ?? originalPrice2 : originalPrice2;
|
|
637
|
+
return {
|
|
638
|
+
effectivePrice: effectivePrice2,
|
|
639
|
+
originalPrice: originalPrice2,
|
|
640
|
+
isOnSale: isOnSale2,
|
|
641
|
+
salePercent: isOnSale2 ? variation.salePercent ?? null : null
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
const isOnSale = isSaleActive(product.saleStartDate, product.saleEndDate) && product.salePrice !== null;
|
|
645
|
+
const originalPrice = product.price;
|
|
646
|
+
const effectivePrice = isOnSale ? product.salePrice ?? originalPrice : originalPrice;
|
|
647
|
+
return {
|
|
648
|
+
effectivePrice,
|
|
649
|
+
originalPrice,
|
|
650
|
+
isOnSale,
|
|
651
|
+
salePercent: isOnSale ? product.salePercent ?? null : null
|
|
652
|
+
};
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// src/utils/cart-calculations.ts
|
|
656
|
+
function calculateCartWithCampaigns(items, campaigns) {
|
|
657
|
+
const buyXPayYCampaign = campaigns.find(
|
|
658
|
+
(c) => c.type === "BUY_X_PAY_Y" && c.isActive
|
|
659
|
+
);
|
|
660
|
+
const originalTotal = items.reduce((total, { product, variation, cartQuantity }) => {
|
|
661
|
+
const priceInfo = getPriceInfo(product, variation);
|
|
662
|
+
return total + priceInfo.effectivePrice * cartQuantity;
|
|
663
|
+
}, 0);
|
|
664
|
+
if (!buyXPayYCampaign?.BuyXPayYCampaign) {
|
|
665
|
+
const calculatedItems2 = items.map((item) => ({
|
|
666
|
+
item,
|
|
667
|
+
paidQuantity: item.cartQuantity,
|
|
668
|
+
freeQuantity: 0,
|
|
669
|
+
totalQuantity: item.cartQuantity
|
|
670
|
+
}));
|
|
671
|
+
return {
|
|
672
|
+
calculatedItems: calculatedItems2,
|
|
673
|
+
cartTotal: originalTotal,
|
|
674
|
+
originalTotal,
|
|
675
|
+
totalSavings: 0
|
|
676
|
+
};
|
|
677
|
+
}
|
|
678
|
+
const { buyQuantity, payQuantity, applicableCategories } = buyXPayYCampaign.BuyXPayYCampaign;
|
|
679
|
+
const applicableCategoryIds = new Set(
|
|
680
|
+
applicableCategories.map((c) => c.id)
|
|
681
|
+
);
|
|
682
|
+
const eligibleUnits = items.flatMap((item) => {
|
|
683
|
+
const { product, variation } = item;
|
|
684
|
+
const itemCategories = product.categories?.map((cat) => cat.id) || [];
|
|
685
|
+
const isEligible = itemCategories.some(
|
|
686
|
+
(id) => applicableCategoryIds.has(id)
|
|
687
|
+
);
|
|
688
|
+
if (isEligible) {
|
|
689
|
+
const priceInfo = getPriceInfo(product, variation);
|
|
690
|
+
return Array.from({ length: item.cartQuantity }, () => ({
|
|
691
|
+
price: priceInfo.effectivePrice,
|
|
692
|
+
productId: product.id,
|
|
693
|
+
variationId: variation?.id,
|
|
694
|
+
originalItem: item
|
|
695
|
+
}));
|
|
696
|
+
}
|
|
697
|
+
return [];
|
|
698
|
+
});
|
|
699
|
+
if (eligibleUnits.length < buyQuantity) {
|
|
700
|
+
const calculatedItems2 = items.map((item) => ({
|
|
701
|
+
item,
|
|
702
|
+
paidQuantity: item.cartQuantity,
|
|
703
|
+
freeQuantity: 0,
|
|
704
|
+
totalQuantity: item.cartQuantity
|
|
705
|
+
}));
|
|
706
|
+
return {
|
|
707
|
+
calculatedItems: calculatedItems2,
|
|
708
|
+
cartTotal: originalTotal,
|
|
709
|
+
originalTotal,
|
|
710
|
+
totalSavings: 0
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
eligibleUnits.sort((a, b) => a.price - b.price);
|
|
714
|
+
const numToMakeFree = buyQuantity - payQuantity;
|
|
715
|
+
const itemsToMakeFree = eligibleUnits.slice(0, numToMakeFree);
|
|
716
|
+
const totalSavings = itemsToMakeFree.reduce(
|
|
717
|
+
(sum, item) => sum + item.price,
|
|
718
|
+
0
|
|
719
|
+
);
|
|
720
|
+
const freeCountMap = /* @__PURE__ */ new Map();
|
|
721
|
+
for (const freebie of itemsToMakeFree) {
|
|
722
|
+
const key = `${freebie.productId}${freebie.variationId ? `_${freebie.variationId}` : ""}`;
|
|
723
|
+
freeCountMap.set(key, (freeCountMap.get(key) || 0) + 1);
|
|
724
|
+
}
|
|
725
|
+
const calculatedItems = items.map((item) => {
|
|
726
|
+
const key = `${item.product.id}${item.variation?.id ? `_${item.variation.id}` : ""}`;
|
|
727
|
+
const freeQuantity = freeCountMap.get(key) || 0;
|
|
728
|
+
const paidQuantity = item.cartQuantity - freeQuantity;
|
|
729
|
+
return {
|
|
730
|
+
item,
|
|
731
|
+
paidQuantity: Math.max(0, paidQuantity),
|
|
732
|
+
freeQuantity,
|
|
733
|
+
totalQuantity: item.cartQuantity
|
|
734
|
+
};
|
|
735
|
+
});
|
|
736
|
+
const cartTotal = originalTotal - totalSavings;
|
|
737
|
+
return {
|
|
738
|
+
calculatedItems,
|
|
739
|
+
cartTotal,
|
|
740
|
+
originalTotal,
|
|
741
|
+
totalSavings
|
|
742
|
+
};
|
|
743
|
+
}
|
|
744
|
+
|
|
613
745
|
// src/resources/shipping.ts
|
|
614
746
|
function calculateCartWeight(items) {
|
|
615
747
|
return items.reduce((total, item) => {
|
|
@@ -617,48 +749,70 @@ function calculateCartWeight(items) {
|
|
|
617
749
|
return total + itemWeight * item.cartQuantity;
|
|
618
750
|
}, 0);
|
|
619
751
|
}
|
|
752
|
+
function calculateCartTotal(items) {
|
|
753
|
+
return items.reduce((total, item) => {
|
|
754
|
+
const itemPrice = item.variation ? item.variation.salePrice ?? item.variation.price : item.product.salePrice ?? item.product.price;
|
|
755
|
+
return total + itemPrice * item.cartQuantity;
|
|
756
|
+
}, 0);
|
|
757
|
+
}
|
|
620
758
|
function createShippingResource(fetcher) {
|
|
621
759
|
return {
|
|
622
760
|
/**
|
|
623
761
|
* Get shipping options for a specific postal code.
|
|
624
|
-
* Returns home delivery
|
|
762
|
+
* Returns pickup points and home delivery options in a unified format.
|
|
763
|
+
*
|
|
764
|
+
* **Pickup points are returned first** as they are more popular in Finland.
|
|
625
765
|
*
|
|
626
766
|
* @param postalCode - Customer's postal code (e.g., "00100")
|
|
627
767
|
* @param options - Fetch options including optional cartItems for weight-based filtering
|
|
628
|
-
* @returns
|
|
768
|
+
* @returns Unified shipping options (pickupPoints sorted by distance, homeDelivery sorted by price)
|
|
629
769
|
*
|
|
630
770
|
* @example
|
|
631
771
|
* ```typescript
|
|
632
|
-
* const {
|
|
633
|
-
*
|
|
634
|
-
* // Show
|
|
635
|
-
*
|
|
636
|
-
* console.log(`${
|
|
772
|
+
* const { pickupPoints, homeDelivery } = await client.shipping.getOptions("00100");
|
|
773
|
+
*
|
|
774
|
+
* // Show pickup points (more popular in Finland)
|
|
775
|
+
* pickupPoints.forEach(point => {
|
|
776
|
+
* console.log(`${point.name} - ${point.carrier}`);
|
|
777
|
+
* console.log(` ${point.address}, ${point.city}`);
|
|
778
|
+
* console.log(` ${(point.distance! / 1000).toFixed(1)} km away`);
|
|
779
|
+
* console.log(` Price: ${point.price / 100}€`);
|
|
637
780
|
* });
|
|
638
781
|
*
|
|
639
|
-
* // Show
|
|
640
|
-
*
|
|
641
|
-
* console.log(`${
|
|
642
|
-
*
|
|
643
|
-
*
|
|
644
|
-
*
|
|
782
|
+
* // Show home delivery options
|
|
783
|
+
* homeDelivery.forEach(option => {
|
|
784
|
+
* console.log(`${option.name}: ${option.price / 100}€`);
|
|
785
|
+
* if (option.estimatedDelivery) {
|
|
786
|
+
* console.log(` Delivery: ${option.estimatedDelivery} days`);
|
|
787
|
+
* }
|
|
645
788
|
* });
|
|
646
789
|
* ```
|
|
647
790
|
*
|
|
648
791
|
* @example Weight-based filtering
|
|
649
792
|
* ```typescript
|
|
650
|
-
* const
|
|
651
|
-
*
|
|
652
|
-
*
|
|
653
|
-
* );
|
|
793
|
+
* const options = await client.shipping.getOptions("00100", {
|
|
794
|
+
* cartItems: cartItems
|
|
795
|
+
* });
|
|
654
796
|
* // Only shows methods that support the cart's total weight
|
|
655
797
|
* ```
|
|
798
|
+
*
|
|
799
|
+
* @example International shipping
|
|
800
|
+
* ```typescript
|
|
801
|
+
* const options = await client.shipping.getOptions("112 22", {
|
|
802
|
+
* country: "SE"
|
|
803
|
+
* });
|
|
804
|
+
* ```
|
|
656
805
|
*/
|
|
657
|
-
async
|
|
806
|
+
async getOptions(postalCode, options) {
|
|
658
807
|
const params = new URLSearchParams();
|
|
659
808
|
if (options?.cartItems?.length) {
|
|
660
809
|
const cartWeight = calculateCartWeight(options.cartItems);
|
|
661
810
|
params.set("cartWeight", cartWeight.toString());
|
|
811
|
+
const cartTotal = options.campaigns ? calculateCartWithCampaigns(options.cartItems, options.campaigns).cartTotal : calculateCartTotal(options.cartItems);
|
|
812
|
+
params.set("cartTotal", cartTotal.toString());
|
|
813
|
+
}
|
|
814
|
+
if (options?.country) {
|
|
815
|
+
params.set("country", options.country);
|
|
662
816
|
}
|
|
663
817
|
const queryString = params.toString();
|
|
664
818
|
const url = `/api/storefront/v1/shipment-methods/${encodeURIComponent(postalCode)}${queryString ? `?${queryString}` : ""}`;
|
|
@@ -666,6 +820,12 @@ function createShippingResource(fetcher) {
|
|
|
666
820
|
method: "GET",
|
|
667
821
|
...options
|
|
668
822
|
});
|
|
823
|
+
},
|
|
824
|
+
/**
|
|
825
|
+
* @deprecated Use getOptions() instead. This method is kept for backwards compatibility.
|
|
826
|
+
*/
|
|
827
|
+
async getWithLocations(postalCode, options) {
|
|
828
|
+
return this.getOptions(postalCode, options);
|
|
669
829
|
}
|
|
670
830
|
};
|
|
671
831
|
}
|
|
@@ -1393,146 +1553,6 @@ function createStorefrontClient(config) {
|
|
|
1393
1553
|
checkout: createCheckoutResource(fetcher)
|
|
1394
1554
|
};
|
|
1395
1555
|
}
|
|
1396
|
-
|
|
1397
|
-
// src/utils/pricing.ts
|
|
1398
|
-
function isSaleActive(startDate, endDate) {
|
|
1399
|
-
if (!startDate && !endDate) {
|
|
1400
|
-
return true;
|
|
1401
|
-
}
|
|
1402
|
-
const now = /* @__PURE__ */ new Date();
|
|
1403
|
-
const start = startDate ? new Date(startDate) : null;
|
|
1404
|
-
const end = endDate ? new Date(endDate) : null;
|
|
1405
|
-
if (start && !end) {
|
|
1406
|
-
return now >= start;
|
|
1407
|
-
}
|
|
1408
|
-
if (!start && end) {
|
|
1409
|
-
return now <= end;
|
|
1410
|
-
}
|
|
1411
|
-
if (start && end) {
|
|
1412
|
-
return now >= start && now <= end;
|
|
1413
|
-
}
|
|
1414
|
-
return true;
|
|
1415
|
-
}
|
|
1416
|
-
function getPriceInfo(product, variation) {
|
|
1417
|
-
if (variation) {
|
|
1418
|
-
const isOnSale2 = isSaleActive(variation.saleStartDate, variation.saleEndDate) && variation.salePrice !== null;
|
|
1419
|
-
const originalPrice2 = variation.price ?? product.price;
|
|
1420
|
-
const effectivePrice2 = isOnSale2 ? variation.salePrice ?? originalPrice2 : originalPrice2;
|
|
1421
|
-
return {
|
|
1422
|
-
effectivePrice: effectivePrice2,
|
|
1423
|
-
originalPrice: originalPrice2,
|
|
1424
|
-
isOnSale: isOnSale2,
|
|
1425
|
-
salePercent: isOnSale2 ? variation.salePercent ?? null : null
|
|
1426
|
-
};
|
|
1427
|
-
}
|
|
1428
|
-
const isOnSale = isSaleActive(product.saleStartDate, product.saleEndDate) && product.salePrice !== null;
|
|
1429
|
-
const originalPrice = product.price;
|
|
1430
|
-
const effectivePrice = isOnSale ? product.salePrice ?? originalPrice : originalPrice;
|
|
1431
|
-
return {
|
|
1432
|
-
effectivePrice,
|
|
1433
|
-
originalPrice,
|
|
1434
|
-
isOnSale,
|
|
1435
|
-
salePercent: isOnSale ? product.salePercent ?? null : null
|
|
1436
|
-
};
|
|
1437
|
-
}
|
|
1438
|
-
|
|
1439
|
-
// src/utils/cart-calculations.ts
|
|
1440
|
-
function calculateCartWithCampaigns(items, campaigns) {
|
|
1441
|
-
const buyXPayYCampaign = campaigns.find(
|
|
1442
|
-
(c) => c.type === "BUY_X_PAY_Y" && c.isActive
|
|
1443
|
-
);
|
|
1444
|
-
const originalTotal = items.reduce((total, { product, variation, cartQuantity }) => {
|
|
1445
|
-
const priceInfo = getPriceInfo(product, variation);
|
|
1446
|
-
return total + priceInfo.effectivePrice * cartQuantity;
|
|
1447
|
-
}, 0);
|
|
1448
|
-
const freeShipping = {
|
|
1449
|
-
isEligible: false,
|
|
1450
|
-
minimumSpend: 0,
|
|
1451
|
-
remainingAmount: 0
|
|
1452
|
-
};
|
|
1453
|
-
if (!buyXPayYCampaign?.BuyXPayYCampaign) {
|
|
1454
|
-
const calculatedItems2 = items.map((item) => ({
|
|
1455
|
-
item,
|
|
1456
|
-
paidQuantity: item.cartQuantity,
|
|
1457
|
-
freeQuantity: 0,
|
|
1458
|
-
totalQuantity: item.cartQuantity
|
|
1459
|
-
}));
|
|
1460
|
-
return {
|
|
1461
|
-
calculatedItems: calculatedItems2,
|
|
1462
|
-
cartTotal: originalTotal,
|
|
1463
|
-
originalTotal,
|
|
1464
|
-
totalSavings: 0,
|
|
1465
|
-
freeShipping
|
|
1466
|
-
};
|
|
1467
|
-
}
|
|
1468
|
-
const { buyQuantity, payQuantity, applicableCategories } = buyXPayYCampaign.BuyXPayYCampaign;
|
|
1469
|
-
const applicableCategoryIds = new Set(
|
|
1470
|
-
applicableCategories.map((c) => c.id)
|
|
1471
|
-
);
|
|
1472
|
-
const eligibleUnits = items.flatMap((item) => {
|
|
1473
|
-
const { product, variation } = item;
|
|
1474
|
-
const itemCategories = product.categories?.map((cat) => cat.id) || [];
|
|
1475
|
-
const isEligible = itemCategories.some(
|
|
1476
|
-
(id) => applicableCategoryIds.has(id)
|
|
1477
|
-
);
|
|
1478
|
-
if (isEligible) {
|
|
1479
|
-
const priceInfo = getPriceInfo(product, variation);
|
|
1480
|
-
return Array.from({ length: item.cartQuantity }, () => ({
|
|
1481
|
-
price: priceInfo.effectivePrice,
|
|
1482
|
-
productId: product.id,
|
|
1483
|
-
variationId: variation?.id,
|
|
1484
|
-
originalItem: item
|
|
1485
|
-
}));
|
|
1486
|
-
}
|
|
1487
|
-
return [];
|
|
1488
|
-
});
|
|
1489
|
-
if (eligibleUnits.length < buyQuantity) {
|
|
1490
|
-
const calculatedItems2 = items.map((item) => ({
|
|
1491
|
-
item,
|
|
1492
|
-
paidQuantity: item.cartQuantity,
|
|
1493
|
-
freeQuantity: 0,
|
|
1494
|
-
totalQuantity: item.cartQuantity
|
|
1495
|
-
}));
|
|
1496
|
-
return {
|
|
1497
|
-
calculatedItems: calculatedItems2,
|
|
1498
|
-
cartTotal: originalTotal,
|
|
1499
|
-
originalTotal,
|
|
1500
|
-
totalSavings: 0,
|
|
1501
|
-
freeShipping
|
|
1502
|
-
};
|
|
1503
|
-
}
|
|
1504
|
-
eligibleUnits.sort((a, b) => a.price - b.price);
|
|
1505
|
-
const numToMakeFree = buyQuantity - payQuantity;
|
|
1506
|
-
const itemsToMakeFree = eligibleUnits.slice(0, numToMakeFree);
|
|
1507
|
-
const totalSavings = itemsToMakeFree.reduce(
|
|
1508
|
-
(sum, item) => sum + item.price,
|
|
1509
|
-
0
|
|
1510
|
-
);
|
|
1511
|
-
const freeCountMap = /* @__PURE__ */ new Map();
|
|
1512
|
-
for (const freebie of itemsToMakeFree) {
|
|
1513
|
-
const key = `${freebie.productId}${freebie.variationId ? `_${freebie.variationId}` : ""}`;
|
|
1514
|
-
freeCountMap.set(key, (freeCountMap.get(key) || 0) + 1);
|
|
1515
|
-
}
|
|
1516
|
-
const calculatedItems = items.map((item) => {
|
|
1517
|
-
const key = `${item.product.id}${item.variation?.id ? `_${item.variation.id}` : ""}`;
|
|
1518
|
-
const freeQuantity = freeCountMap.get(key) || 0;
|
|
1519
|
-
const paidQuantity = item.cartQuantity - freeQuantity;
|
|
1520
|
-
return {
|
|
1521
|
-
item,
|
|
1522
|
-
paidQuantity: Math.max(0, paidQuantity),
|
|
1523
|
-
freeQuantity,
|
|
1524
|
-
totalQuantity: item.cartQuantity
|
|
1525
|
-
};
|
|
1526
|
-
});
|
|
1527
|
-
const cartTotal = originalTotal - totalSavings;
|
|
1528
|
-
return {
|
|
1529
|
-
calculatedItems,
|
|
1530
|
-
cartTotal,
|
|
1531
|
-
originalTotal,
|
|
1532
|
-
totalSavings,
|
|
1533
|
-
freeShipping
|
|
1534
|
-
};
|
|
1535
|
-
}
|
|
1536
1556
|
export {
|
|
1537
1557
|
AuthError,
|
|
1538
1558
|
NotFoundError,
|