Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v0.56.2 #1052

Merged
merged 8 commits into from
May 23, 2024
2 changes: 1 addition & 1 deletion .github/workflows/patchGenerate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,6 @@ jobs:

- name: Create PR
run: |
gh pr create --title "Patch file ${{ matrix.framework }}/${{ env.version }}" --body "" --repo "https://github.com/searchspring/snapfu-patches" --base "main" --head "patch-generate-${{ matrix.framework }}-${{ env.version }}" --project "Snap Beta" --reviewer "searchspring/snap-team"
gh pr create --title "Patch file ${{ matrix.framework }}/${{ env.version }}" --body "" --repo "https://github.com/searchspring/snapfu-patches" --base "main" --head "patch-generate-${{ matrix.framework }}-${{ env.version }}" --project "Snap" --reviewer "searchspring/snap-team"
env:
GITHUB_TOKEN: ${{ secrets.MACHINE_ACTION_WORKFLOW_PAT }}
67 changes: 67 additions & 0 deletions packages/snap-platforms/bigcommerce/groovy/ss_variants.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
Snap variants script for BigCommerce

Generates a JSON string with format:
ss_variants = [
{
attributes: { ... },
mappings: { core: { ... } },
options: {
[optionName]: { value: '', ... }
}
}
]

Each object (variant) in the array represents a variation of the product and each of the `options` should reflect that configuration.
When using this in Snap any properties found in `mappings.core` and `attributes` will be "masked" when the variant is selected.
See Snap documentation for more details.

*/

import groovy.json.JsonOutput
import groovy.json.JsonSlurper
import org.apache.commons.lang.StringUtils

def slurper = new JsonSlurper()
def ss_variants = []

if (Objects.nonNull(doc?.child_sku_options) && !StringUtils.isEmpty(doc?.child_sku_options)) {
def sku_options = slurper.parseText(doc.child_sku_options as String)
if(Objects.nonNull(sku_options) && !(sku_options as List).isEmpty()){
sku_options.each { sku_option ->
def sku = [:]
def mappings = [:]
def core = [:]
def attributes = [:]
def option_data = [:]
def options = [:]

core.put("imageUrl" , sku_option?.image_url)
core.put("url", doc.url)
core.put("uid" ,sku_option.child_sku)
mappings.put("core", core)
sku.put("mappings",mappings)

if(Objects.nonNull(sku_option?.inventory_level)){
attributes.put("available", sku_option?.inventory_level > 0)
}

if(Objects.nonNull(sku_option?.option) && !StringUtils.isEmpty(sku_option?.option) && Objects.nonNull(sku_option?.value) && !StringUtils.isEmpty(sku_option?.value)){
attributes.put("title", sku_option?.option + " / " + sku_option?.value)

}
sku.put("attributes",attributes)

option_data.put("value", sku_option?.value)

if(Objects.nonNull(sku_option?.option)){
options.put(sku_option?.option, option_data)
}

sku.put("options",options)
ss_variants.add(sku)
}
}
}

index.put("ss_variants", JsonOutput.toJson(ss_variants))
124 changes: 124 additions & 0 deletions packages/snap-platforms/magento2/groovy/ss_variants.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
Snap variants script for Magento2

Generates a JSON string with format:
ss_variants = [
{
attributes: { ... },
mappings: { core: { ... } },
options: {
[optionName]: { value: '', ... }
}
}
]

Each object (variant) in the array represents a variation of the product and each of the `options` should reflect that configuration.
When using this in Snap any properties found in `mappings.core` and `attributes` will be "masked" when the variant is selected.
See Snap documentation for more details.

*/

import groovy.json.JsonSlurper
import groovy.json.JsonOutput
import org.apache.commons.lang.StringUtils


def slurper = new JsonSlurper()

def imageUrls = [:]
if (Objects.nonNull(doc.swatch_json_data) && !StringUtils.isEmpty(doc.swatch_json_data as String)) {
def swatchData = slurper.parseText(doc.swatch_json_data as String)
if (Objects.nonNull(swatchData)) {
swatchData.each { imageData ->
if (Objects.nonNull(imageData?.color) && Objects.nonNull(imageData?.image)) {
imageUrls.put(imageData?.color, imageData?.image)
}
}
}
}

if (Objects.nonNull(doc.json_config) && !StringUtils.isEmpty(doc.json_config as String)) {
def jsonConfig = slurper.parseText(doc.json_config as String)
def ss_swatches = []

if (Objects.nonNull(jsonConfig?.attributes)) {
def productIds = []
jsonConfig.attributes*.value*.options*.products?.each { rawProductIds ->
if (Objects.nonNull(rawProductIds)) {
rawProductIds.each {
if (Objects.nonNull(it)) {
productIds.addAll(it)
}
}
}
}
productIds = productIds?.unique()

productIds.each { uniqueProductId ->
def productId = uniqueProductId
def ss_variants = [:]
def options = [:]

def colour = null
def size = null
def colourAttributeId = null
def colourOptionId = null
def sizeAttributeId = null
def sizeOptionId = null
jsonConfig?.attributes?.each { attribute ->
if (Objects.nonNull(attribute?.value?.code)) {
def isColour = attribute?.value?.code == "colour"
def optionData = [:]

optionData.put("attributeId", attribute?.key)

if (Objects.nonNull(attribute?.value?.options) && !(attribute?.value?.options as List).isEmpty()) {
(attribute?.value?.options as List).each { attributeSubOption ->
if (Objects.nonNull(attributeSubOption?.products) && (attributeSubOption?.products as List).contains(productId)) {
if (isColour) {
colour = attributeSubOption?.label
colourAttributeId = attribute?.key
colourOptionId = attributeSubOption?.id
} else {
size = attributeSubOption?.label
sizeAttributeId = attribute?.key
sizeOptionId = attributeSubOption?.id
}
optionData.put("value", attributeSubOption?.label)
optionData.put("optionId", attributeSubOption?.id)
}
}
}
options.put(attribute?.value?.code, optionData)
}
}

def core = [:]

if (colourAttributeId && colourOptionId && sizeOptionId && sizeAttributeId) {
core.put("url", doc?.url + "#" + colourAttributeId + "=" + colourOptionId + "&" + sizeAttributeId + "=" + sizeOptionId)
}

if (Objects.nonNull(colour) && Objects.nonNull(imageUrls?.get(colour))) {
core.put("imageUrl", imageUrls?.get(colour))
}

core.put("uid", uniqueProductId)
def mappings = [:]
mappings.put("core", core)

ss_variants.put("mappings", mappings)

def attributes = [:]
attributes.put("available", true)
if (Objects.nonNull(colour) && Objects.nonNull(size)) {
attributes.put("title", "$colour / $size")
}
ss_variants.put("attributes", attributes)
ss_variants.put("options", options)
ss_swatches.add(ss_variants)
}

index.ss_variants = JsonOutput.toJson(ss_swatches)
}
}
188 changes: 188 additions & 0 deletions packages/snap-platforms/shopify/groovy/ss_variants.groovy
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/*
Snap variants script for Shopify

Generates a JSON string with format:
ss_variants = [
{
attributes: { ... },
mappings: { core: { ... } },
options: {
[optionName]: { value: '', ... }
}
}
]

Each object (variant) in the array represents a variation of the product and each of the `options` should reflect that configuration.
When using this in Snap any properties found in `mappings.core` and `attributes` will be "masked" when the variant is selected.
See Snap documentation for more details.

*/

import groovy.json.JsonSlurper
import groovy.json.JsonOutput

/* CONFIGURATION */

// optional image to use if no variant image is found
def fallback_image = ''

// dimension modification for variant images
def shopify_image_dimension_suffix = ''
def shopify_thumbnail_dimension_suffix = ''


/* CODE */

// helper function to add a suffix to the Shopify images
def addImageSuffix = { img, suffix ->
matcher = (img =~ /(.+)(\.(?:(?i)jpg|jpeg|gif|png|svg|webp|avif|heic).+)/)
if (matcher) {
return matcher[0][1] + "_" + suffix + matcher[0][2]
} else {
return img
}
}

// JSON slurper
def slurper = new JsonSlurper()
def variants_json = slurper.parseText(doc.variants)
def options_json = slurper.parseText(doc.options)
def variant_images_json
try{
variant_images_json = slurper.parseText(doc.variant_images_json)
} catch (err) {
variant_images_json = []
}

/* create an options map and array from options_json */
def options_map = [:]

options_json.each { option ->
def option_position_string = 'option' + option.position
def option_name = option.name.toLowerCase().replace(' ', '_')
options_map[option_position_string] = option_name
}

/* create an options_image_map from variant_images_json*/
def options_image_map = [:]

variant_images_json.each { variant_image ->
def option_map_reference = options_image_map

options_map.eachWithIndex { option_key, option, idx ->
def option_value = variant_image[option]
if (idx + 1 == options_map.size()) {
if ( option_value ) {
option_map_reference[option_value] = variant_image.img
}
} else {
if (!option_map_reference[option_value] && option_value) {
option_map_reference[option_value] = [:]
}
if (option_value) {
option_map_reference = option_map_reference[option_value]
}
}
}
}

/* map variants_json -> variants structure and put into array */
def variant_array = []

// variant data to put into core fields
def core_fields_mapping = [
uid: "id",
msrp: "compare_at_price",
price: "price",
sku: "sku",
]

// attributes outside of the options
def attributes_fields_mapping = [
quantity: "inventory_quantity", // property must be named "quantity" for proper functionality
title: "title",
]

variants_json.each { variant ->
def variant_object = [:]
variant_object.mappings = [:]
variant_object.mappings.core = [:]
variant_object.attributes = [:]
variant_object.options = [:]

// convert into a variant object
/*
{
"mappings": {
"core": { ... }
},
"attributes": {
...
}
}
*/

/* populate core mappings */
core_fields_mapping.each { core_field_name, variant_field_name ->
variant_object.mappings.core[core_field_name] = variant[variant_field_name]
}
// add variant URL to core fields
variant_object.mappings.core.url = "/products/" + doc.handle + "?variant=" + variant.id
// add image core fields if an image if found for the variant
def option_path = [variant.option1, variant.option2, variant.option3]

def variant_image_reference = options_image_map
option_path.each { option ->
try {
if (option && variant_image_reference[option]) {
variant_image_reference = variant_image_reference[option]
}
} catch (err) {
variant_image_reference = variant_image_reference
}
}

// image found in mapping
if (variant_image_reference && variant_image_reference instanceof String) {
variant_object.mappings.core.imageUrl = variant_image_reference
variant_object.mappings.core.thumbnailImageUrl = variant_image_reference

// add image suffix
if (shopify_image_dimension_suffix) {
variant_object.mappings.core.imageUrl = addImageSuffix(variant_image_reference, shopify_image_dimension_suffix)
}
// add thumbnail image suffix
if (shopify_thumbnail_dimension_suffix) {
variant_object.mappings.core.thumbnailImageUrl = addImageSuffix(variant_image_reference, shopify_thumbnail_dimension_suffix)
}
} else if (fallback_image) {
variant_object.mappings.core.imageUrl = fallback_image
variant_object.mappings.core.thumbnailImageUrl = fallback_image
}

/* populate attributes */
attributes_fields_mapping.each { attribute_field_name, variant_field_name ->
variant_object.attributes[attribute_field_name] = variant[variant_field_name]
}

// determine availability
if (variant.inventory_policy == "continue" || variant.inventory_management == "null" || (variant.inventory_policy == "deny" && variant.inventory_quantity > 0)) {
variant_object.attributes.available = true
} else {
variant_object.attributes.available = false
}

/* populate options */
options_map.each { option_number, option_name ->
if(variant[option_number]) {
variant_object.options[option_name] = [
value: variant[option_number]
]
}
}

// add variant object to the array
variant_array.push(variant_object)
}

index.ss_variants = JsonOutput.toJson(variant_array)
Loading
Loading