diff --git a/api/queries/storefront.js b/api/queries/storefront.js index a446080..f71260f 100644 --- a/api/queries/storefront.js +++ b/api/queries/storefront.js @@ -86,6 +86,16 @@ const productViewOptionFieldsFragment = gql` } `; +/** The fields we retrieve from a ProductViewLink. */ +const productViewLinkFieldsFragment = gql` + fragment ProductViewLinkFields on ProductViewLink { + linkTypes + product { + sku + } + } +`; + /** The base fields we retrieve from any Product. */ const productViewBaseFieldsFragment = gql` fragment ProductViewBaseFields on ProductView { @@ -130,6 +140,9 @@ const GET_PRODUCT_DETAILS = gql` ...ProductViewPriceRangeFields } } + links { + ...ProductViewLinkFields + } } } @@ -140,6 +153,7 @@ const GET_PRODUCT_DETAILS = gql` ${productViewPriceRangeFieldsFragment} ${productViewOptionFieldsFragment} ${productViewOptionValueFieldsFragment} + ${productViewLinkFieldsFragment} `; module.exports = { diff --git a/transformers/product.js b/transformers/product.js index 46d27b0..3cee181 100644 --- a/transformers/product.js +++ b/transformers/product.js @@ -73,6 +73,56 @@ const transformCustomAttributes = attributes => { return acoAttributes; }; +/** + * Builds a variant reference ID. + * + * @param {string} masterSku - The master SKU + * @param {string} variantCode - The variant code + * @param {string | number} variantValue - The variant value + * @returns {string} The variant reference ID + */ +function buildVariantReferenceId(masterSku, variantCode, variantValue) { + return `${masterSku}-${variantCode}-${variantValue.toString()}`; +} + +/** + * Transforms variationAttributes and masterSku to configurations format + * + * @param {string} masterSku - The master SKU + * @param {Array} variationAttributes - The variation attributes array + * @returns {Array} Array of configuration objects + */ +function transformVariantAttributes(masterSku, variationAttributes) { + if (!Array.isArray(variationAttributes)) return []; + return variationAttributes.map(attr => ({ + attributeCode: attr.id, + label: attr.name, + type: 'CONFIGURABLE', + values: Array.isArray(attr.values) + ? attr.values.map(v => ({ + variantReferenceId: buildVariantReferenceId(masterSku, attr.id, v.value), + label: v.name, + })) + : [], + })); +} + +/** + * Transforms variationValues to ACO attribute format + * + * @param {string} masterSku - The master SKU + * @param {object} variationValues - The variation values object + * @returns {Array} Array of ACO attribute objects + */ +function transformVariantValues(masterSku, variationValues) { + if (!variationValues || typeof variationValues !== 'object') return []; + return Object.entries(variationValues).map(([key, value]) => ({ + code: key, + values: [value.toString()], + variantReferenceId: buildVariantReferenceId(masterSku, key, value), + })); +} + /** * Transforms a Salesforce product to an ACO product. * @@ -116,11 +166,27 @@ const transformProduct = product => { ...transformCustomAttributes(product.customAttributes), ], images: transformImages(product.images), - // TODO: Add links - // TODO: Add configurable product support // TODO: Add bundle product support }; + //add configurations + if (product.type === 'MASTER') { + acoProduct.configurations = transformVariantAttributes(product.id, product.variationAttributes); + } + + if (product.type === 'VARIANT') { + const masterSku = product.master.id; + acoProduct.links = [ + { + type: 'variant_of', + sku: masterSku, + }, + ]; + + //attributes + acoProduct.attributes.push(...transformVariantValues(masterSku, product.variationValues)); + } + // @ts-ignore return acoProduct; }; diff --git a/types/salesforce.d.ts b/types/salesforce.d.ts index 0d199c9..43957f7 100644 --- a/types/salesforce.d.ts +++ b/types/salesforce.d.ts @@ -51,6 +51,19 @@ declare interface SalesforceProduct { customAttributes: SalesforceProductCustomAttributes[]; creationDate: string; lastModified: string; + type: + | 'SIMPLE' + | 'MASTER' + | 'VARIANT' + | 'VARIATION_GROUP' + | 'BUNDLE' + | 'BUNDLED' + | 'PRODUCT_SET' + | 'PRODUCT_SET_PRODUCT'; + variationAttributes: SalesforceProductVariationAttribute[]; + variants?: SalesforceProductVariant[]; + variationValues?: SalesforceProductVariationValues; + master?: SalesforceProductMaster; } declare interface SalesforceProductPrice { @@ -125,3 +138,29 @@ declare interface SalesforceTrackedChanges { isDeleted: boolean; lastModified: string; } + +declare interface SalesforceProductVariationAttribute { + id: string; + attributeId: string; + name: string; + values: SalesforceProductVariationAttributeValue[]; +} + +declare interface SalesforceProductVariationAttributeValue { + description: string; + name: string; + value: string; +} + +declare interface SalesforceProductVariant { + productId: string; + variationValues: SalesforceProductVariationValues; +} + +declare interface SalesforceProductVariationValues { + [key: string]: unknown; +} + +declare interface SalesforceProductMaster { + id: string; +}