@misiki/gocommerce-connector 0.11.0 → 0.12.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/README.md +3 -0
- package/dist/{index-90wdO5MM.d.cts → index-Bu4bVBBm.d.cts} +393 -5
- package/dist/{index-90wdO5MM.d.ts → index-Bu4bVBBm.d.ts} +393 -5
- package/dist/index.cjs +178 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +176 -4
- package/dist/index.js.map +1 -1
- package/dist/services/index.cjs +175 -3
- package/dist/services/index.cjs.map +1 -1
- package/dist/services/index.d.cts +1 -1
- package/dist/services/index.d.ts +1 -1
- package/dist/services/index.js +175 -3
- package/dist/services/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -765,7 +765,12 @@ function toCartLine(l, extra = {}) {
|
|
|
765
765
|
variantTitle: l.variant_label ?? "",
|
|
766
766
|
qty: l.quantity,
|
|
767
767
|
price: toMajor(l.unit_price),
|
|
768
|
-
|
|
768
|
+
// The variant's compare-at price, where the shop set one above what the
|
|
769
|
+
// line costs: what the basket's "you save" is measured from.
|
|
770
|
+
mrp: l.compare_at_price && l.compare_at_price.amount_minor > l.unit_price.amount_minor ? toMajor(l.compare_at_price) : toMajor(l.unit_price),
|
|
771
|
+
/** The add-on this line was bought as (D133), or null on an ordinary line. */
|
|
772
|
+
addOnId: l.add_on_id ? str(l.add_on_id) : null,
|
|
773
|
+
addOnFor: l.add_on_for ? str(l.add_on_for) : null,
|
|
769
774
|
subtotal: toMajor(l.total),
|
|
770
775
|
total: toMajor(l.total),
|
|
771
776
|
inStock: l.in_stock,
|
|
@@ -999,6 +1004,45 @@ function toUser(c) {
|
|
|
999
1004
|
};
|
|
1000
1005
|
}
|
|
1001
1006
|
var priceOf = (m) => m ? toMajor(m) : 0;
|
|
1007
|
+
function toAddOn(a) {
|
|
1008
|
+
return {
|
|
1009
|
+
id: str(a.id),
|
|
1010
|
+
productId: str(a.item.product_id),
|
|
1011
|
+
variantId: str(a.variant_id),
|
|
1012
|
+
slug: a.item.slug,
|
|
1013
|
+
title: a.item.title,
|
|
1014
|
+
variantTitle: a.item.variant_label ?? "",
|
|
1015
|
+
thumbnail: mediaUrl(a.item.image_url ?? null),
|
|
1016
|
+
price: toMajor(a.offer_price ?? a.price),
|
|
1017
|
+
regularPrice: toMajor(a.price),
|
|
1018
|
+
hasOffer: !!a.offer_price && a.offer_price.amount_minor < a.price.amount_minor,
|
|
1019
|
+
inStock: a.item.in_stock
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
function toCartOffer(o, currency) {
|
|
1023
|
+
const isPercent = o.kind === "percentage";
|
|
1024
|
+
return {
|
|
1025
|
+
code: o.code,
|
|
1026
|
+
title: o.title,
|
|
1027
|
+
isPercent,
|
|
1028
|
+
freeShipping: o.kind === "free_shipping",
|
|
1029
|
+
/** The percentage for a percentage code, the amount for a fixed one. */
|
|
1030
|
+
value: isPercent ? (o.value_bp ?? 0) / 100 : minorToMajor(o.value_minor ?? 0, currency),
|
|
1031
|
+
minAmount: o.min_subtotal_minor ? minorToMajor(o.min_subtotal_minor, currency) : null,
|
|
1032
|
+
applies: o.applies,
|
|
1033
|
+
amount: o.amount ? toMajor(o.amount) : null,
|
|
1034
|
+
remaining: o.remaining ? toMajor(o.remaining) : null,
|
|
1035
|
+
reason: o.reason ?? ""
|
|
1036
|
+
};
|
|
1037
|
+
}
|
|
1038
|
+
function toFreeShipping(f) {
|
|
1039
|
+
return {
|
|
1040
|
+
qualifies: f.qualifies,
|
|
1041
|
+
threshold: f.threshold ? toMajor(f.threshold) : null,
|
|
1042
|
+
remaining: f.remaining ? toMajor(f.remaining) : null,
|
|
1043
|
+
subtotal: toMajor(f.subtotal)
|
|
1044
|
+
};
|
|
1045
|
+
}
|
|
1002
1046
|
|
|
1003
1047
|
// src/services/facts.ts
|
|
1004
1048
|
var StoreFacts = class extends BaseService {
|
|
@@ -1309,6 +1353,36 @@ var ProductService = class extends CatalogService {
|
|
|
1309
1353
|
if (!category) return this.list({ page, limit });
|
|
1310
1354
|
return this.list({ page, limit, categories: category.slug });
|
|
1311
1355
|
}
|
|
1356
|
+
/**
|
|
1357
|
+
* What the shop offers with a product, ticked in its buy box (D133): each
|
|
1358
|
+
* add-on at the price ticking it adds. Only add-ons that can be bought
|
|
1359
|
+
* arrive; an engine without the route offers none.
|
|
1360
|
+
*/
|
|
1361
|
+
async listAddOns({ product }) {
|
|
1362
|
+
const p = await this.findProduct(String(product));
|
|
1363
|
+
try {
|
|
1364
|
+
return (await this.data("/api/add-ons", { query: { product_id: p.id } }) ?? []).map(toAddOn);
|
|
1365
|
+
} catch (err) {
|
|
1366
|
+
if (err instanceof GoCommerceError && err.status === 404) return [];
|
|
1367
|
+
throw err;
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
/**
|
|
1371
|
+
* "You may also like": the products the shop chose for this one, at their
|
|
1372
|
+
* own prices (D133). Curated only, and empty when none were chosen: the
|
|
1373
|
+
* related products already fill in from the category, and the page should
|
|
1374
|
+
* not draw the same fill twice.
|
|
1375
|
+
*/
|
|
1376
|
+
async listCrossSells({ product, limit }) {
|
|
1377
|
+
const p = await this.findProduct(String(product));
|
|
1378
|
+
try {
|
|
1379
|
+
const rows = await this.data("/api/cross-sells", { query: { product_id: p.id, limit } }) ?? [];
|
|
1380
|
+
return rows.map((r) => toProduct(r));
|
|
1381
|
+
} catch (err) {
|
|
1382
|
+
if (err instanceof GoCommerceError && err.status === 404) return [];
|
|
1383
|
+
throw err;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1312
1386
|
async relatedTo(slug, limit) {
|
|
1313
1387
|
const size = Math.min(100, Math.max(1, Number(limit) || PAGE_SIZE));
|
|
1314
1388
|
const p = await this.findProduct(slug);
|
|
@@ -1648,6 +1722,88 @@ var CartService = class extends BaseService {
|
|
|
1648
1722
|
throw err;
|
|
1649
1723
|
}
|
|
1650
1724
|
}
|
|
1725
|
+
/**
|
|
1726
|
+
* Adds an add-on from a product's "Complete the set" (D133) at its offer
|
|
1727
|
+
* price. The product it is offered with has to be in the bag already, so
|
|
1728
|
+
* this is called after adding it; the engine refuses one too many with the
|
|
1729
|
+
* sentence the shopper is shown.
|
|
1730
|
+
*/
|
|
1731
|
+
async addAddOn({ cartId, addOnId, qty = 1 }) {
|
|
1732
|
+
const id2 = clean(cartId) ?? storedCartId();
|
|
1733
|
+
if (!id2) throw new GoCommerceError("Add the product to your bag first.", 409);
|
|
1734
|
+
return this.present(
|
|
1735
|
+
await this.data(`/api/carts/${encodeURIComponent(id2)}/line-items`, {
|
|
1736
|
+
method: "POST",
|
|
1737
|
+
body: { add_on_id: Number(addOnId), quantity: Number(qty) }
|
|
1738
|
+
})
|
|
1739
|
+
);
|
|
1740
|
+
}
|
|
1741
|
+
/**
|
|
1742
|
+
* The codes the shop chose to show (D133), each with what it takes off this
|
|
1743
|
+
* bag or how much more the bag needs. None without a bag.
|
|
1744
|
+
*/
|
|
1745
|
+
async getOffers({ cartId } = {}) {
|
|
1746
|
+
const id2 = clean(cartId) ?? storedCartId();
|
|
1747
|
+
if (!id2) return [];
|
|
1748
|
+
try {
|
|
1749
|
+
const rows = await this.data(`/api/carts/${encodeURIComponent(id2)}/offers`) ?? [];
|
|
1750
|
+
const currency = await this.currency();
|
|
1751
|
+
return rows.map((o) => toCartOffer(o, o.amount?.currency ?? o.remaining?.currency ?? currency));
|
|
1752
|
+
} catch (err) {
|
|
1753
|
+
if (err instanceof GoCommerceError && err.status === 404) return [];
|
|
1754
|
+
throw err;
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
/**
|
|
1758
|
+
* How far the bag is from free delivery (D133), read from the store's own
|
|
1759
|
+
* rates for the country (the store's own when none is given). Null when
|
|
1760
|
+
* the engine cannot say: a bar with a made-up figure is worse than none.
|
|
1761
|
+
*/
|
|
1762
|
+
async getFreeShipping({ cartId, country, state } = {}) {
|
|
1763
|
+
const id2 = clean(cartId) ?? storedCartId();
|
|
1764
|
+
if (!id2) return null;
|
|
1765
|
+
const where = country ?? cartExtras(id2).shippingAddress?.country ?? void 0;
|
|
1766
|
+
try {
|
|
1767
|
+
return toFreeShipping(
|
|
1768
|
+
await this.data(`/api/carts/${encodeURIComponent(id2)}/free-shipping`, {
|
|
1769
|
+
query: { country: where || void 0, state: state || void 0 }
|
|
1770
|
+
})
|
|
1771
|
+
);
|
|
1772
|
+
} catch (err) {
|
|
1773
|
+
if (err instanceof GoCommerceError && err.status === 404) return null;
|
|
1774
|
+
throw err;
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
/**
|
|
1778
|
+
* "You may be interested in" (D133): what the bag's products suggest, less
|
|
1779
|
+
* what it holds; with nothing curated, the first product's related
|
|
1780
|
+
* products, still less what it holds.
|
|
1781
|
+
*/
|
|
1782
|
+
async listCrossSells({ cartId, limit = 12 } = {}) {
|
|
1783
|
+
const id2 = clean(cartId) ?? storedCartId();
|
|
1784
|
+
if (!id2) return [];
|
|
1785
|
+
let curated = [];
|
|
1786
|
+
try {
|
|
1787
|
+
curated = await this.data(`/api/carts/${encodeURIComponent(id2)}/cross-sells`, { query: { limit } }) ?? [];
|
|
1788
|
+
} catch (err) {
|
|
1789
|
+
if (!(err instanceof GoCommerceError) || err.status !== 404) throw err;
|
|
1790
|
+
}
|
|
1791
|
+
if (curated.length) return curated.map((p) => toProduct(p));
|
|
1792
|
+
let cart;
|
|
1793
|
+
try {
|
|
1794
|
+
cart = await this.data(`/api/carts/${encodeURIComponent(id2)}`);
|
|
1795
|
+
} catch {
|
|
1796
|
+
return [];
|
|
1797
|
+
}
|
|
1798
|
+
const held = new Set((cart.line_items ?? []).map((l) => String(l.product_id)));
|
|
1799
|
+
const first = cart.line_items?.[0];
|
|
1800
|
+
if (!first) return [];
|
|
1801
|
+
const related = await new ProductService(this._fetch).listRelatedProducts({
|
|
1802
|
+
product: String(first.product_id),
|
|
1803
|
+
limit: limit + held.size
|
|
1804
|
+
});
|
|
1805
|
+
return related.data.filter((p) => !held.has(String(p.id))).slice(0, limit);
|
|
1806
|
+
}
|
|
1651
1807
|
/** `qty` is the new total; 0 takes the line out. */
|
|
1652
1808
|
async updateCart({
|
|
1653
1809
|
cartId,
|
|
@@ -2081,7 +2237,20 @@ var paymentMethodService = new PaymentMethodService();
|
|
|
2081
2237
|
// src/services/coupon-service.ts
|
|
2082
2238
|
var CouponService = class extends BaseService {
|
|
2083
2239
|
async listCoupons(_args = {}) {
|
|
2084
|
-
|
|
2240
|
+
const offers = await new CartService(this._fetch).getOffers().catch(() => []);
|
|
2241
|
+
if (!offers.length) return emptyPage();
|
|
2242
|
+
const data = offers.map((o) => ({
|
|
2243
|
+
id: o.code,
|
|
2244
|
+
code: o.code,
|
|
2245
|
+
title: o.title,
|
|
2246
|
+
isPercent: o.isPercent,
|
|
2247
|
+
amount: o.value,
|
|
2248
|
+
minAmount: o.minAmount,
|
|
2249
|
+
description: o.applies ? o.title : o.remaining !== null ? `${o.title}. Add ${o.remaining} more to use this.` : o.reason || o.title,
|
|
2250
|
+
applies: o.applies,
|
|
2251
|
+
remaining: o.remaining
|
|
2252
|
+
}));
|
|
2253
|
+
return { data, count: data.length, pageSize: data.length, noOfPage: 1, page: 1 };
|
|
2085
2254
|
}
|
|
2086
2255
|
};
|
|
2087
2256
|
var couponService = new CouponService();
|
|
@@ -2828,7 +2997,10 @@ var StoreService = class extends BaseService {
|
|
|
2828
2997
|
},
|
|
2829
2998
|
// The footer's sign-up box posts to ext/newsletter, and the theme editor's footer
|
|
2830
2999
|
// switch (D131) can only show it while that is on.
|
|
2831
|
-
newsletter: { ...basePlugins.newsletter, ...flag(plugins.has("newsletter")) }
|
|
3000
|
+
newsletter: { ...basePlugins.newsletter, ...flag(plugins.has("newsletter")) },
|
|
3001
|
+
// Discount codes are core: every GoCommerce store takes them, so
|
|
3002
|
+
// the code box is shown whatever the static record says.
|
|
3003
|
+
isDiscountCoupons: { ...basePlugins.isDiscountCoupons, active: true }
|
|
2832
3004
|
},
|
|
2833
3005
|
...menus?.length ? { menu: menus } : {},
|
|
2834
3006
|
...deliverable(base, ships),
|
|
@@ -3656,12 +3828,15 @@ exports.stateService = stateService;
|
|
|
3656
3828
|
exports.staticStore = staticStore;
|
|
3657
3829
|
exports.storeForHost = storeForHost;
|
|
3658
3830
|
exports.storeService = storeService;
|
|
3831
|
+
exports.toAddOn = toAddOn;
|
|
3659
3832
|
exports.toCart = toCart;
|
|
3660
3833
|
exports.toCartLine = toCartLine;
|
|
3834
|
+
exports.toCartOffer = toCartOffer;
|
|
3661
3835
|
exports.toCategory = toCategory;
|
|
3662
3836
|
exports.toCmsPage = toCmsPage;
|
|
3663
3837
|
exports.toCollection = toCollection;
|
|
3664
3838
|
exports.toEngineAddress = toEngineAddress;
|
|
3839
|
+
exports.toFreeShipping = toFreeShipping;
|
|
3665
3840
|
exports.toIdentityAddress = toIdentityAddress;
|
|
3666
3841
|
exports.toMajor = toMajor;
|
|
3667
3842
|
exports.toMinor = toMinor;
|