Skip to content

Commit e7afdcd

Browse files
committed
Merge branch 'main' into image-roles
2 parents 135a140 + 3384046 commit e7afdcd

File tree

10 files changed

+212
-47
lines changed

10 files changed

+212
-47
lines changed

CHANGELOG.md

+15
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
# [1.5.0](https://github.com/adobe-rnd/helix-commerce-api/compare/v1.4.1...v1.5.0) (2024-11-05)
2+
3+
4+
### Bug Fixes
5+
6+
* date parsing ([cebc0bc](https://github.com/adobe-rnd/helix-commerce-api/commit/cebc0bce7c9655e3b96ab328c9cd2998ac48fa68))
7+
* fix variants check ([d986afa](https://github.com/adobe-rnd/helix-commerce-api/commit/d986afa5f68775622af148cb3cec3ca110cdf73d))
8+
* support priceValidUntil in simple products ([3f79d8d](https://github.com/adobe-rnd/helix-commerce-api/commit/3f79d8d8a3cbf7c3dd39bfb19e31138d5eb36f6d))
9+
* test ([f484693](https://github.com/adobe-rnd/helix-commerce-api/commit/f484693165cab9e9d4ef21fbe29d3f4682ff1fa1))
10+
11+
12+
### Features
13+
14+
* add support for ListPrice and priceValidUntil in JSON-LD ([f91bbae](https://github.com/adobe-rnd/helix-commerce-api/commit/f91bbaea681b9d687ac4e0e01b2f8e3aae201b2f))
15+
116
## [1.4.1](https://github.com/adobe-rnd/helix-commerce-api/compare/v1.4.0...v1.4.1) (2024-11-05)
217

318

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "helix-commerce-api",
3-
"version": "1.4.1",
3+
"version": "1.5.0",
44
"private": true,
55
"description": "API for markup content and a commerce graphql commerce proxy",
66
"main": "src/index.js",

src/content/queries/cs-product.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*/
1212

1313
import { forceImagesHTTPS } from '../../utils/http.js';
14-
import { gql } from '../../utils/product.js';
14+
import { gql, parseSpecialToDate } from '../../utils/product.js';
1515

1616
/**
1717
* @param {any} productData
@@ -90,6 +90,11 @@ export const adapter = (productData) => {
9090
} : null,
9191
};
9292

93+
const specialToDate = parseSpecialToDate(product);
94+
if (specialToDate) {
95+
product.specialToDate = specialToDate;
96+
}
97+
9398
return product;
9499
};
95100

src/content/queries/cs-variants.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*/
1212

1313
import { forceImagesHTTPS } from '../../utils/http.js';
14-
import { gql } from '../../utils/product.js';
14+
import { gql, parseSpecialToDate } from '../../utils/product.js';
1515

1616
/**
1717
* @param {any} variants
@@ -49,6 +49,12 @@ export const adapter = (config, variants) => variants.map(({ selections, product
4949
},
5050
selections: selections ?? [],
5151
};
52+
53+
const specialToDate = parseSpecialToDate(product);
54+
if (specialToDate) {
55+
variant.specialToDate = specialToDate;
56+
}
57+
5258
if (config.attributeOverrides?.variant) {
5359
Object.entries(config.attributeOverrides.variant).forEach(([key, value]) => {
5460
variant[key] = product.attributes?.find((attr) => attr.name === value)?.value;

src/templates/html/HTMLTemplate.js

+8
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,10 @@ ${HTMLTemplate.metaProperty('product:price.currency', product.prices.final.curre
272272
* @returns {string}
273273
*/
274274
renderProductVariants() {
275+
if (!this.variants) {
276+
return '';
277+
}
278+
275279
return /* html */ `\
276280
<div class="product-variants">
277281
${this.variants.map((v) => /* html */`\
@@ -292,6 +296,10 @@ ${HTMLTemplate.metaProperty('product:price.currency', product.prices.final.curre
292296
* @returns {string}
293297
*/
294298
renderProductVariantsAttributes() {
299+
if (!this.variants) {
300+
return '';
301+
}
302+
295303
return /* html */ `\
296304
<div class="variant-attributes">
297305
${this.variants?.map((v) => /* html */`\

src/templates/json/JSONTemplate.js

+55-31
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13+
/* eslint-disable class-methods-use-this */
14+
1315
import { findProductImage, pruneUndefined } from '../../utils/product.js';
1416

1517
export class JSONTemplate {
@@ -80,6 +82,58 @@ export class JSONTemplate {
8082
};
8183
}
8284

85+
renderOffers() {
86+
const image = this.product.images?.[0]?.url
87+
?? findProductImage(this.product, this.variants)?.url;
88+
const configurableProduct = this.variants?.length > 0;
89+
const offers = configurableProduct ? this.variants : [this.product];
90+
return {
91+
offers: [
92+
...offers.map((v) => {
93+
const offerUrl = this.constructProductURL(configurableProduct ? v : undefined);
94+
const { prices: variantPrices } = v;
95+
const finalPrice = variantPrices?.final?.amount;
96+
const regularPrice = variantPrices?.regular?.amount;
97+
const offer = {
98+
'@type': 'Offer',
99+
sku: v.sku,
100+
url: offerUrl,
101+
image: v.images?.[0]?.url ?? image,
102+
availability: v.inStock ? 'InStock' : 'OutOfStock',
103+
price: finalPrice,
104+
priceCurrency: variantPrices.final?.currency,
105+
};
106+
107+
if (finalPrice < regularPrice) {
108+
offer.priceSpecification = this.renderOffersPriceSpecification(v);
109+
}
110+
111+
if (v.gtin) {
112+
offer.gtin = v.gtin;
113+
}
114+
115+
if (v.specialToDate) {
116+
offer.priceValidUntil = v.specialToDate;
117+
}
118+
119+
return offer;
120+
}).filter(Boolean),
121+
],
122+
};
123+
}
124+
125+
renderOffersPriceSpecification(variant) {
126+
const { prices } = variant;
127+
const { regular } = prices;
128+
const { amount, currency } = regular;
129+
return {
130+
'@type': 'UnitPriceSpecification',
131+
priceType: 'https://schema.org/ListPrice',
132+
price: amount,
133+
priceCurrency: currency,
134+
};
135+
}
136+
83137
render() {
84138
const {
85139
sku,
@@ -88,8 +142,6 @@ export class JSONTemplate {
88142
images,
89143
reviewCount,
90144
ratingValue,
91-
inStock,
92-
prices,
93145
} = this.product;
94146

95147
const productUrl = this.constructProductURL();
@@ -103,35 +155,7 @@ export class JSONTemplate {
103155
description: metaDescription,
104156
image,
105157
productID: sku,
106-
offers: [
107-
prices ? ({
108-
'@type': 'Offer',
109-
sku,
110-
url: productUrl,
111-
image,
112-
availability: inStock ? 'InStock' : 'OutOfStock',
113-
price: prices?.final?.amount,
114-
priceCurrency: prices?.final?.currency,
115-
}) : undefined,
116-
...this.variants.map((v) => {
117-
const offerUrl = this.constructProductURL(v);
118-
const offer = {
119-
'@type': 'Offer',
120-
sku: v.sku,
121-
url: offerUrl,
122-
image: v.images?.[0]?.url ?? image,
123-
availability: v.inStock ? 'InStock' : 'OutOfStock',
124-
price: v.prices?.final?.amount,
125-
priceCurrency: v.prices?.final?.currency,
126-
};
127-
128-
if (v.gtin) {
129-
offer.gtin = v.gtin;
130-
}
131-
132-
return offer;
133-
}).filter(Boolean),
134-
],
158+
...this.renderOffers(),
135159
...(this.renderBrand() ?? {}),
136160
...(typeof reviewCount === 'number'
137161
&& typeof ratingValue === 'number'

src/types.d.ts

+2
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ declare global {
8989
urlKey?: string;
9090
externalId?: string;
9191
variants?: Variant[]; // variants exist on products in helix commerce but not on magento
92+
specialToDate?: string;
9293

9394
// not handled currently:
9495
externalParentId?: string;
@@ -109,6 +110,7 @@ declare global {
109110
selections: string[];
110111
attributes: Attribute[];
111112
externalId: string;
113+
specialToDate?: string;
112114
gtin?: string;
113115
}
114116

src/utils/product.js

+13
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,16 @@ export function matchConfigPath(config, path) {
9595
console.warn('No match found for path:', path);
9696
return null;
9797
}
98+
99+
export function parseSpecialToDate(product) {
100+
const specialToDate = product.attributes?.find((attr) => attr.name === 'special_to_date')?.value;
101+
if (specialToDate) {
102+
const today = new Date();
103+
const specialPriceToDate = new Date(specialToDate);
104+
if (specialPriceToDate.getTime() >= today.getTime()) {
105+
const [date] = specialToDate.split(' ');
106+
return date;
107+
}
108+
}
109+
return undefined;
110+
}

0 commit comments

Comments
 (0)