Skip to content

Instantly share code, notes, and snippets.

@jaredholdcroft
Created September 11, 2013 17:51
Show Gist options
  • Save jaredholdcroft/6527236 to your computer and use it in GitHub Desktop.
Save jaredholdcroft/6527236 to your computer and use it in GitHub Desktop.
package com.jag.middleware.core.mapper;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import org.w3c.dom.Document;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import com.demandware.schema.catalog.Catalog;
import com.demandware.schema.catalog.ComplexTypeCategory;
import com.demandware.schema.catalog.ComplexTypeCategoryAssignment;
import com.demandware.schema.catalog.ComplexTypeHeader;
import com.demandware.schema.catalog.ComplexTypeImageInternalLocation;
import com.demandware.schema.catalog.ComplexTypeImageSettings;
import com.demandware.schema.catalog.ComplexTypeImageViewTypes;
import com.demandware.schema.catalog.ComplexTypeProduct;
import com.demandware.schema.catalog.ComplexTypeProductImage;
import com.demandware.schema.catalog.ComplexTypeProductImageGroup;
import com.demandware.schema.catalog.ComplexTypeProductImages;
import com.demandware.schema.catalog.ComplexTypeProductVariations;
import com.demandware.schema.catalog.ComplexTypeProductVariationsAttributes;
import com.demandware.schema.catalog.ComplexTypeProductVariationsVariant;
import com.demandware.schema.catalog.ComplexTypeProductVariationsVariants;
import com.demandware.schema.catalog.ComplexTypeRecommendation;
import com.demandware.schema.catalog.ComplexTypeVariationAttribute;
import com.demandware.schema.catalog.ComplexTypeVariationAttributeValue;
import com.demandware.schema.catalog.ObjectFactory;
import com.demandware.schema.catalog.SharedTypeCustomAttribute;
import com.demandware.schema.catalog.SharedTypeLocalizedString;
import com.demandware.schema.catalog.SharedTypeLocalizedText;
import com.demandware.schema.catalog.SharedTypeSiteSpecificBoolean;
import com.demandware.schema.catalog.SharedTypeSiteSpecificCustomAttribute;
import com.demandware.schema.catalog.SharedTypeSiteSpecificDateTime;
import com.demandware.schema.catalog.SharedTypeSiteSpecificSiteMapChangeFrequency;
import com.demandware.schema.catalog.SharedTypeSiteSpecificSiteMapPriority;
import com.demandware.schema.catalog.SimpleTypeCategoryAssignmentPosition;
import com.demandware.schema.catalog.SimpleTypeImportMode;
import com.demandware.schema.catalog.SimpleTypeRecommendationSourceType;
import com.demandware.schema.catalog.SimpleTypeSiteMapChangeFrequency;
import com.jag.middleware.core.catalog.DeletedEntity;
import com.jag.middleware.core.category.AttributeConstants;
import com.jag.middleware.core.category.AttributeValue;
import com.jag.middleware.util.DateUtils;
import com.stormhq.commerce.catalog.CatalogExport;
import com.stormhq.commerce.catalog.asset.ProductCategoryColorMapping;
import com.stormhq.commerce.catalog.asset.DigitalAsset;
import com.stormhq.commerce.catalog.asset.DigitalAssetType;
import com.stormhq.commerce.catalog.category.Category;
import com.stormhq.commerce.catalog.product.BaseProduct;
import com.stormhq.commerce.catalog.product.Product;
import com.stormhq.commerce.catalog.product.ProductGroup;
import com.stormhq.commerce.catalog.product.ProductGrouping;
import com.stormhq.commerce.catalog.product.ProductSKU;
import com.stormhq.core.lookup.service.LookupDataService;
import java.util.Arrays;
public class CatalogMapper extends BaseJaxbMapper<CatalogExport, Catalog> {
/**
* Demandware node name for category child product assignment.
*/
public static final String DW_NODE_CATEGORY_PG_ASSIGNMENT = "category-assignment";
public static final String DW_NODE_IMAGE= "image";
/**
* This isn't actually a DW node name. We use it as a delete type to signify
* and attribute which needs to be blanked out.
*/
public static final String DW_NODE_PG_ATTR_VALUE = "pg-attr-value";
public static final String DW_NODE_PRODUCT_RECOMMENDATION = "cross-sell";
public static final String DW_NODE_PRODUCT = "product";
/**
* String delimiter to separate attribute code value and its index.
*/
public static final String ATTR_ALT_DISPLAY_DELIMITER = "_";
public static final String ATTRIBUTE_ID_PRODUCT_TYPE_DELIMITER = "-";
public static final String ATTR_ID_VARIANT_COLOR_CHIP = "variantColorChip";
public static final String ATTR_ID_VARIANT_STYLE_CODE = "productStyleCode";
/**
* Define defaultProdImage for a variant, so it overrides the master.
* Otherwise, we would have two sets of images.
*/
private static final String ATTR_ID_VARIANT_PROD_IMAGE = "defaultProdImage"; //"variantProdImage";
public static final String DEMANDWARE_ROOT = "root";
private ObjectFactory objectFactory = new ObjectFactory();
/**
* The root category ID. If we have a category that matches this, we should send to
* Demandware with an ID of "root".
*/
private Integer rootCategoryId;
/**
* The catalog ID for Demandware.
* This has to match something in Business Manager, otherwise the file is ignored.
*/
private String catalogId;
/**
* The brand. Not really used for anything, but Demandware has a field for it.
*/
private String brand;
/**
* Map of JAG image codes to DW image types.
*/
private Map<String,String> exportImageTypes = new TreeMap<String,String>();
private AttributeComparatorFactory comparatorFactory;
private Map<String, Comparator<ProductSKU>> skuComparators;
/**
* Used to look up export attributes.
*/
private LookupDataService lookupDataService;
@Override
protected void marshal(Object object,Document doc) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(getMarshalPackageName(object));
Marshaller marshaller = jaxbContext.createMarshaller();
//marshaller.setProperty(marshaller.JAXB_SCHEMA_LOCATION, "");
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_NO_NAMESPACE_SCHEMA_LOCATION, "catalog.xsd");
marshaller.marshal(object,doc);
}
@Override
protected Catalog objectToObject(CatalogExport export) {
// This method can actually generate a single XML file
// for exporting the entire CatalogExport object,
// but in practice we have to break the export into parts
// so that they're exported in the right order.
// For example, the catalog-product assignments
// have to be sent after the category and the product are in place.
// init
initializeImageTypes(export.getAssetTypes());
// Export should be pre-separated by brand.
Catalog catalog = objectFactory.createCatalog();
catalog.setCatalogId(catalogId);
//Check if we want to export asset types via <header> element
if(export.isExportAssetTypes()) {
catalog.setHeader(assetTypeHeader(catalog, export.getAssetTypesByDWOrder()));
}
// Export categories
if (!export.getCategories().isEmpty()) {
for (Category c : export.getCategories().values()) {
if (c.isDeleted()) {
ComplexTypeCategory deletedCategory = objectFactory
.createComplexTypeCategory();
deletedCategory.setCategoryId(c.getId().toString());
deletedCategory.setMode(SimpleTypeImportMode.DELETE);
catalog.getCategory().add(deletedCategory);
} else if (!c.getId().equals(export.getRootCategoryId()) ||
c.getId().equals(this.rootCategoryId)) {
// If this is a full publish (export.root == mapper.root),
// create a node for the parent category.
// Otherwise, just create nodes for the children.
ComplexTypeCategory mappedCategory = createCategory(c);
catalog.getCategory().add(mappedCategory);
}
}
}
// Export products
TreeMap<String, TreeMap<String, String>> sharedAttributeMap = new TreeMap<String, TreeMap<String, String>>();
if (CollectionUtils.isNotEmpty(export.getProducts())) {
for (Product p : export.getProducts()) {
// variation master.
try {
catalog.getProduct().add(createVariationMaster(p, export.getAssetTypesByDWOrder()));
} catch (Exception e) {
warn("Exception while mapping product "+p.getProductGroup().toString());
e.printStackTrace();
}
// variants
for (ProductSKU sku : p.getProductGroup().getSkus()) {
// Delta SKU publish: suppressed for 1.7 until product save logic can be fixed.
if (sku.getLastPublishedDate()==null || sku.getModifiedDate().after(sku.getLastPublishedDate())) {
catalog.getProduct().add(createVariant(sku, p));
}
// Check for customer-selectable attributes.
for (AttributeValue av : sku.getAttributeValues()) {
if (av.getAttribute().isCustomerSelectable()) {
// Store shared attributes in the master list.
String attributeName = av.getAttribute().getName();
if (sharedAttributeMap.get(attributeName) == null) {
sharedAttributeMap.put(attributeName,
new TreeMap<String, String>());
}
if (av.isDefault()) {
sharedAttributeMap.get(attributeName).put(av.getCode(),
av.getDisplayName());
}
}
}
}
}
}
// Category-product mappings
// These are done separately.
//
if (export.getCategoryProductMappings().size() > 0) {
for (Integer cid : export.getCategoryProductMappings().keySet()) {
int idx=0;
for (Integer pid : export.getCategoryProductMappings().get(cid)) {
ComplexTypeCategoryAssignment assignment = categoryAssignment(cid, pid);
// add sort order.
assignment.setPosition(SimpleTypeCategoryAssignmentPosition.AUTO);
assignment.setCustomAttributes(objectFactory.createSharedTypeCustomAttributes());
SharedTypeCustomAttribute attribute = objectFactory.createSharedTypeCustomAttribute();
attribute.setAttributeId("sortOrder");
attribute.getContent().add(String.valueOf(idx++));
assignment.getCustomAttributes().getCustomAttribute().add(attribute);
if ( cid.equals(export.getProductDefaultCategory().get(pid)) ) {
assignment.setPrimaryFlag(Boolean.TRUE);
}
catalog.getCategoryAssignment().add(assignment);
}
}
// Add deletes later.
}
// Cross sells are done separately.
for (ProductGrouping grouping : export.getProductGroupings()) {
if (grouping.getGroupingType().equals(ProductGrouping.CROSS_SELL)) {
ComplexTypeRecommendation recommendation = createProductRecommendation(grouping);
catalog.getRecommendation().add(recommendation);
}
}
// Handle deletes.
// Product attribute deletes handled above with the product.
for (DeletedEntity entity : export.getDeletes()) {
if (entity.getEntityType().equals(DW_NODE_CATEGORY_PG_ASSIGNMENT)) {
ComplexTypeCategoryAssignment assignment = categoryAssignment(entity.getPrimaryId(),entity.getSecondaryId());
assignment.setMode(SimpleTypeImportMode.DELETE);
catalog.getCategoryAssignment().add(assignment);
} else if (entity.getEntityType().equals(DW_NODE_PRODUCT_RECOMMENDATION)) {
ProductGrouping grouping = new ProductGrouping();
grouping.setProductGroupId(entity.getPrimaryId());
grouping.setRelatedGroupId(entity.getSecondaryId());
ComplexTypeRecommendation recommendation =
createProductRecommendation(grouping);
recommendation.setMode(SimpleTypeImportMode.DELETE);
catalog.getRecommendation().add(recommendation);
} else if (entity.getEntityType().equals(DW_NODE_PRODUCT)) {
ComplexTypeProduct product = objectFactory.createComplexTypeProduct();
product.setMode(SimpleTypeImportMode.DELETE);
if (entity.getPrimaryId() != null) {
// PG ID
product.setProductId(entity.getPrimaryId().toString());
} else if (StringUtils.isNotBlank(entity.getStringId())) {
// SKU UPC
product.setProductId(entity.getStringId());
}
catalog.getProduct().add(product);
} else if (entity.getEntityType().equals(DW_NODE_IMAGE)) {
// No action; these are deleted directly from the Impex.
}
}
debug("Creating shared attributes list");
// Shared attribute map.
// Export shared attributes
// We need to show all values (i.e., not just the ones in this export)--
// Abandoning this unless we have a good solution for this problem.
// (i.e., all variation attributes will have local scope)
// for (String attributeId : sharedAttributeMap.keySet()) {
// info("Shared customer-selectable attribute: " + attributeId);
// addVariationAttribute(catalog, attributeId, attributeId,
// sharedAttributeMap.get(attributeId));
// }
return catalog;
}
/**
* Create the asset header
* @param catalog
* @param assetTypes
* @return
*/
protected ComplexTypeHeader assetTypeHeader(Catalog catalog, List<DigitalAssetType> assetTypes) {
ComplexTypeHeader header = objectFactory.createComplexTypeHeader();
ComplexTypeImageSettings imageSettings = objectFactory.createComplexTypeImageSettings();
header.setImageSettings(imageSettings);
ComplexTypeImageInternalLocation internalLocation = objectFactory.createComplexTypeImageInternalLocation();
internalLocation.setBasePath("/");
imageSettings.setInternalLocation(internalLocation);
imageSettings.setVariationAttributeId("variantColor");
imageSettings.setAltPattern(getBrand() + " Product");
imageSettings.setTitlePattern(getBrand() + " Product");
ComplexTypeImageViewTypes viewTypes = objectFactory.createComplexTypeImageViewTypes();
imageSettings.setViewTypes(viewTypes);
if(CollectionUtils.isNotEmpty(assetTypes)) {
//Sort order
List<DigitalAssetType> sortList = AssetTypeComparator.sort(assetTypes);
for (DigitalAssetType digitalAssetType : sortList) {
String demandWareName = digitalAssetType.getDemandwareNameOrDefault();
if (!viewTypes.getViewType().contains(demandWareName)) {
viewTypes.getViewType().add(demandWareName);
}
}
}
return header;
}
protected void initializeImageTypes(Collection<DigitalAssetType> assetTypes) {
exportImageTypes.clear();
for (DigitalAssetType t : assetTypes) {
String dwName = t.getDemandWareName(); // TODO I think this should be t.getDemandwareNameOrDefault()
if (StringUtils.isNotBlank(dwName)) {
exportImageTypes.put(t.getStandard(), dwName);
if (t.hasEnlarged()) {
exportImageTypes.put(t.getEnlarged(), dwName);
}
if (t.hasZoomable()) {
exportImageTypes.put(t.getZoomable(), dwName);
}
}
}
}
/**
* @param cid
* @param pid
* @return
*/
private ComplexTypeCategoryAssignment categoryAssignment(Integer cid, Integer pid) {
ComplexTypeCategoryAssignment assignment = objectFactory
.createComplexTypeCategoryAssignment();
assignment.setCategoryId(cid.toString());
assignment.setProductId(pid.toString());
return assignment;
}
/**
* Create a <code>category</code> tag.
*
* @param c the category object to be mapped.
* @return
*/
protected ComplexTypeCategory createCategory(Category c) {
ComplexTypeCategory mappedCategory = objectFactory
.createComplexTypeCategory();
mappedCategory.setCategoryId(getCategoryId(c.getId()));
mappedCategory.getDisplayName().add(
createSharedTypeLocalizedString(c.getDisplayName()));
mappedCategory.setOnlineFlag(Boolean.valueOf(c.isLiveOnSite()));
mappedCategory.setTemplate("");
mappedCategory.setSitemapIncludedFlag(Boolean.valueOf(c.isVisible()));
mappedCategory.setSitemapChangefrequency(SimpleTypeSiteMapChangeFrequency.DAILY);
mappedCategory.setSitemapPriority(Double.valueOf(1.0));
if(c.getOnlineFrom()!= null)
mappedCategory.setOnlineFrom(DateUtils.xmlDate(c.getOnlineFrom()));
if(c.getOnlineTo()!= null)
mappedCategory.setOnlineTo(DateUtils.xmlDate(c.getOnlineTo()));
if (c.getParent() != null) {
// this is a non-root category node.
// Parent Id
mappedCategory.setParent(getCategoryId(c.getParent().getId()));
// sort order
mappedCategory.setPosition(Double.valueOf(c.getPosition()));
// Custom Attributes
mappedCategory.setCustomAttributes(objectFactory
.createSharedTypeCustomAttributes());
// old sort order
// mappedCategory.getCustomAttributes().getCustomAttribute().add(
// createSharedTypeCustomAttribute("sortOrder",String.valueOf(sortOrderIndex)));
// Only use description if this is not the root.
mappedCategory.getDescription().add(
createSharedTypeLocalizedString(c.getDescription()));
}
return mappedCategory;
}
/**
* Return the category ID. Generally, this is the same ID as from the
* database, but there is one special case: the root category must have an
* ID of "root", per Demandware's specification.
*
* @param catId
* @return the category ID.
*/
private String getCategoryId(Integer catId) {
// Is the parent the root? Then the category ID is "root" per DW spec.
if (catId.equals(rootCategoryId))
return DEMANDWARE_ROOT;
return catId.toString();
}
/**
* @param p
* @return product object containing variation master node.
* @throws Exception
*/
protected ComplexTypeProduct createVariationMaster(Product p, Collection<DigitalAssetType> assetTypes) throws Exception {
ComplexTypeProduct mappedProduct = objectFactory.createComplexTypeProduct();
mappedProduct.setEan("");
mappedProduct.setUpc("");
mappedProduct.setUnit("");
ProductGroup pg = p.getProductGroup();
mappedProduct.setProductId(pg.getId().toString());
mappedProduct.getDisplayName().add(
createSharedTypeLocalizedString(pg.getDisplayName()));
mappedProduct.getShortDescription().add(
createSharedTypeLocalizedText(pg.getShortDescription()));
mappedProduct.getLongDescription().add(
createSharedTypeLocalizedText(pg.getLongDescription()));
// Don't use standard image fields; use custom attributes instead.
// mappedProduct.setImage(p.getProductGroupImageName("PD"));
// mappedProduct.setThumbnail(p.getProductGroupImageName("VA"));
mappedProduct.setMinOrderQuantity(new BigDecimal(1));
mappedProduct.setStepQuantity(new BigDecimal(1));
mappedProduct.setAvailableFlag(Boolean.valueOf(pg.isLiveOnSite()));
mappedProduct.getOnlineFlag().add(siteSpecificBoolean(pg.isLiveOnSite()));
mappedProduct.getSearchableFlag().add(siteSpecificBoolean(
pg.isLiveOnSite() && pg.isSearchable()));
//Add images here
createImages(mappedProduct, p, assetTypes);
//Set schedule dates
setScheduleDates(pg, mappedProduct);
mappedProduct.setTaxClassId("Standard");
//
AttributeValue brandAv = pg.getAttributeValueByAttributeName(AttributeConstants.VARIANT_BRAND);
if (brandAv != null) {
mappedProduct.setBrand(brandAv.getDisplayName());
} else {
mappedProduct.setBrand(this.getBrand());
}
mappedProduct.setManufacturerName(this.getBrand());
mappedProduct.getSitemapIncludedFlag().add(siteSpecificBoolean(pg.isVisible()));
SharedTypeSiteSpecificSiteMapChangeFrequency freq = objectFactory.createSharedTypeSiteSpecificSiteMapChangeFrequency();
//freq.setSiteId(catalogId);
freq.setValue(SimpleTypeSiteMapChangeFrequency.DAILY);
mappedProduct.getSitemapChangefrequency().add(freq);
SharedTypeSiteSpecificSiteMapPriority siteMapPriority = objectFactory.createSharedTypeSiteSpecificSiteMapPriority();
//siteMapPriority.setSiteId(catalogId);
siteMapPriority.setValue(1.0);
mappedProduct.getSitemapPriority().add(siteMapPriority);
//////////////////////////////////////////////
// Custom attributes:
//////////////////////////////////////////////
// pg attributes
SortedSet<AttributeValue> customAttrs = new TreeSet<AttributeValue>();
customAttrs.addAll(pg.getAttributeValues());
customAttrs.addAll(p.getDeletedAttributes());
for (AttributeValue av : customAttrs) {
// Use display names. Attributes are not normalized for product groups.
// Some of these might be deleted attribute values, which are to be sent as blank.
addCustomAttributeToProduct(mappedProduct,
av.getAttribute().getName(), av.getDisplayName());
}
//////////////////////////////////////////////
// Non-attribute custom attributes:
// These custom attributes don't come from the attributes table.
//////////////////////////////////////////////
// Add custom attribute for product style code (code name).
if (CollectionUtils.isEmpty(p.getIncludedStyles())) {
addCustomAttributeToProduct(mappedProduct, ATTR_ID_VARIANT_STYLE_CODE, "Style Code: "+pg.getCodeName());
} else {
List<String> styleCodes = new ArrayList<String>();
styleCodes.add(pg.getCodeName());
styleCodes.addAll(p.getIncludedStyles());
addCustomAttributeToProduct(mappedProduct, ATTR_ID_VARIANT_STYLE_CODE, "Style Codes: "+StringUtils.join(styleCodes, ", "));
}
// Add custom attribute for group code name and number
addCustomAttributeToProduct(mappedProduct, "coordinateGroupName", pg.getCoordinateGroupDescription());
addCustomAttributeToProduct(mappedProduct, "coordinateGroupCode", pg.getCoordinateGroupCode());
// Product type
addCustomAttributeToProduct(mappedProduct, "productType", pg.getProductType());
// "Also available in"
List<String> alsoAvailable = new ArrayList<String>();
AttributeValue petiteStyle = pg.getAttributeValueByAttributeName(AttributeConstants.PETITE_STYLE);
if (petiteStyle != null) {
alsoAvailable.add("Petite");
}
AttributeValue plusStyle = pg.getAttributeValueByAttributeName(AttributeConstants.PLUS_STYLE);
if (plusStyle != null) {
alsoAvailable.add("Plus");
}
addCustomAttributeToProduct(mappedProduct, "alsoAvailable", alsoAvailable);
// color mappings for each category
// and default color code
List<String> productCategoryImages = new ArrayList<String>();
for (ProductCategoryColorMapping color : p.getDefaultColorAssignments()) {
// default color code.
String colorCode = "";
for (AttributeValue colorAttr : pg.getSkuColors()) {
if (color.getColor().equals(colorAttr.getCode())) {
colorCode = getNormalizedAttrValue(colorAttr);
}
}
Collection<DigitalAsset> images = p.getImages().get(color.getColor());
if (rootCategoryId.equals(color.getCategoryId())) {
// pg images
addCustomAttributeToProduct(mappedProduct, "defaultProdImage", createImageAttributeValue(images));
// default color code.
for (AttributeValue colorAttr : pg.getSkuColors()) {
if (color.getColor().equals(colorAttr.getCode())) {
addCustomAttributeToProduct(mappedProduct, "defaultProductColorCode", colorCode);
}
}
} else if (images != null && !images.isEmpty()) {
String path = viewAllImage(images);
if (StringUtils.isNotBlank(path)) {
StringBuilder imageString = new StringBuilder();
imageString.append(color.getCategoryId());
imageString.append("|");
imageString.append(colorCode);
imageString.append("|");
imageString.append(path);
productCategoryImages.add(imageString.toString());
} else {
warn("No view-all for color ["+color.getColor()+"]");
}
} else {
warn("No images for color ["+color.getColor()+"]");
}
}
mappedProduct.getCustomAttributes().getCustomAttribute().add(
createSharedTypeCustomAttribute("defaultProductCategoryViewAllImage", productCategoryImages));
// generate "search colors" attribute
mappedProduct.getCustomAttributes().getCustomAttribute().add(
searchColorCustomAttribute(p, "searchColors", false));
// pg prices
NumberFormat numberInstance = NumberFormat.getNumberInstance();
numberInstance.setMinimumFractionDigits(2);
numberInstance.setMaximumFractionDigits(2);
numberInstance.setGroupingUsed(false);
addCustomAttributeToProduct(mappedProduct, "listPrice", numberInstance.format(pg.getListPrice()));
addCustomAttributeToProduct(mappedProduct, "maxSellPrice", numberInstance.format(pg.getMaxSellPrice()));
addCustomAttributeToProduct(mappedProduct, "minSellPrice", numberInstance.format(pg.getSellPrice()));
addCustomAttributeToProduct(mappedProduct, "onSale", pg.isOnSale() ? "true":"false");
mappedProduct.getSearchableIfUnavailableFlag().add(siteSpecificBoolean(pg.isSoldOutAllowed()));
// Deprecated: use searchable-if-unavailable
addCustomAttributeToProduct(mappedProduct, "allowSoldOut", pg.isSoldOutAllowed() ? "true":"false");
// 4. Shoprunner
addCustomAttributeToProduct(mappedProduct, "sr_eligible", pg.isShoprunnerEligible()?"Yes":"No");
//////////////////////////////////////////////
// Create Variants list
//////////////////////////////////////////////
// SKU attributes and SKUs
Collection<ProductSKU> skus = pg.getSkus();
info(pg.toString()+": making variants list of "+skus.size()+" SKUs");
ComplexTypeProductVariations variations = objectFactory
.createComplexTypeProductVariations();
// Variants: link to SKUs
variations.setVariants(createVariantList(skus, pg.getProductType()));
// Variation Attribute definitions
// These are the attributes and attribute values that are shared across all variants for this style.
if (skus.size() > 0) {
ComplexTypeProductVariationsAttributes variationAttributes =
objectFactory.createComplexTypeProductVariationsAttributes();
// Customer-selectable only.
List<String> variationAttributeNames =
getVariationAttributeNames( pg.getProductType() );
// Iterate through attribute values for all SKUs.
for (String attributeId : variationAttributeNames )
{
ComplexTypeVariationAttribute variationAttribute = createVariationAttribute(skus, attributeId,pg.getProductType());
if (variationAttribute != null) {
variationAttributes.getAttributeOrVariationAttributeOrSharedVariationAttribute().add(variationAttribute);
}
}
variations.setAttributes(variationAttributes);
}
// Done with variants, add to product.
mappedProduct.setVariations(variations);
return mappedProduct;
}
protected String viewAllImage(Collection<DigitalAsset> images) {
for (DigitalAsset asset : images) {
if (asset.isViewAll())
return asset.getResourcePath();
}
return "";
}
private SharedTypeSiteSpecificCustomAttribute searchColorCustomAttribute(Product p, String attributeName, boolean useAll)
throws Exception
{
Map<String, String> searchColors = new TreeMap<String,String>();
for (AttributeValue color : p.getProductGroup().getSkuColors()) {
if (useAll || p.getProductGroup().getLiveOnSiteByColor(color.getCode()) > 0) {
String colorCode = getNormalizedAttrValue(color);
String generalColorValue = "";
for (AttributeValue generalColor : p.getProductGroup().getSkuGeneralColors()) {
if (generalColor.getCode().equals(color.getCode())) {
generalColorValue = generalColor.getDisplayName();
}
}
StringBuilder row = new StringBuilder();
row.append(colorCode);
row.append("|");
row.append(color.getDisplayName());
row.append("|");
row.append(generalColorValue);
row.append("|");
Collection<DigitalAsset> images = p.getImages().get(color.getCode());
if (images != null && !images.isEmpty()) {
row.append(viewAllImage(images));
} else {
warn("No images for color ["+colorCode+"]");
}
row.append("|");
row.append(getColorChip(images));
searchColors.put(colorCode, row.toString());
}
}
SharedTypeSiteSpecificCustomAttribute searchColorCustomAttribute =
createSharedTypeCustomAttribute(attributeName,
new ArrayList<String>(searchColors.values()));
return searchColorCustomAttribute;
}
/**
* Creates image node having all the images by asset type. This should be called
* at the master level
* @param mappingProduct ComplexTypeProduct, product node
* @param product Product group
* @param assetTypes Asset types
*/
protected void createImages(ComplexTypeProduct mappingProduct, Product product, Collection<DigitalAssetType> assetTypes) {
if(assetTypes.isEmpty())
return;
ComplexTypeProductImages images = objectFactory.createComplexTypeProductImages();
mappingProduct.setImages(images);
// For variant master images (i.e default images),
// leave color blank
for (ProductCategoryColorMapping colorMappings : product.getDefaultColorAssignments()) {
if (rootCategoryId.equals(colorMappings.getCategoryId())) {
createImageGroups(images, null, product.getImages().get(colorMappings.getColor()), assetTypes);
break;
}
}
//Group all the assets by color
for (AttributeValue color : product.getProductGroup().getSkuColors()) {
// variation value has to match attribute value
// If the attribute value is normalized, then so too must the image group.
String normalizedColor = getNormalizedAttrValue(color);
if(product.getImages().containsKey(color.getCode())) {
createImageGroups(images, normalizedColor, product.getImages().get(color.getCode()), assetTypes);
}
}
cleanUpImages(images);
}
/**
* This method removes all the images group, which does not have any images
* e.g
<image-group variation-value="WHITELE" view-type="Left">
<image path="null" />
<image path="null" />
<image path="null" />
</image-group>
* On the other hand, this is valid e.g as there is one image available
* <image-group variation-value="WHITELE" view-type="Main">
<image path="product/PG.NWACCOLIA.WHITELE.PD.jpg" />
<image path="null" />
<image path="null" />
</image-group>
* As is this:
* <image-group variation-value="WHITELE" view-type="Main">
<image path="null" />
<image path="null2" />
<image path="product/PG.NWACCOLIA.WHITELE.PZ.jpg" />
</image-group>
but notice that we call the second image null2.
* @param images
*/
protected void cleanUpImages(ComplexTypeProductImages images) {
List<ComplexTypeProductImageGroup> removeProductImageGroup = new ArrayList<ComplexTypeProductImageGroup>();
for (ComplexTypeProductImageGroup imageGroup : images.getImageGroup()) {
List<ComplexTypeProductImage> imageGroupImages = imageGroup.getImage();
int nNull=0;
for (ComplexTypeProductImage image : imageGroupImages) {
// Does have a valid path, so break out.
if(image.getPath().equals("null")) {
nNull++;
if (nNull > 1) {
image.setPath("null"+nNull);
}
} else {
break;
}
}
if(imageGroupImages.size()==nNull) {
removeProductImageGroup.add(imageGroup);
}
}
images.getImageGroup().removeAll(removeProductImageGroup);
}
/**
* Generate image groups for a color (or the default color).
* For each asset type, check if it exists in the list of digital assets.
* If it exists, then export digital assets resource path,
* else export "null".
* <p>
<image-group view-type="BACK"> <-- for each asset type (view-type)
<image path="Test/PG.0191919NWR.GINGBMM.BK.jpg" /> <-- asset found
<image path="Test/PG.0191919NWR.GINGBMM.BE.jpg" /> <-- asset found
<image path="null" /> <-- asset not found
</image-group>
<image-group view-type="MAIN" variation-value="BLACKMM"> <-- variation value defined if color is not null
<image path="Test/PG.0191919NWR.GINGBMM.PD.jpg" /> <-- asset found
<image path="Test/PG.0191919NWR.GINGBMM.PE.jpg" /> <-- asset found
<image path="null" /> <-- asset not found
</image-group>
</p>
* @param images ComplexTypeProductImages
* @param color Digital asset color
* @param assets Product SKU assets (DigitalAsset)
* @param assetTypes Asset types (DigitalAssetType)
*/
protected void createImageGroups(ComplexTypeProductImages images,
String color, Collection<DigitalAsset> assets,
Collection<DigitalAssetType> assetTypes)
{
for (DigitalAssetType imageType : assetTypes) {
String demandWareName = imageType.getDemandwareNameOrDefault();
ComplexTypeProductImageGroup imageGroup = createImageGroup(images, demandWareName, color);
// Find the image with standard image code (e.g "PD")
// If it exists, create an XML node, otherwise put path=null
// If the image type has enlarged and zoomable types,
// Add nodes for those (or placeholders with path=null)
DigitalAsset standardImage = findDigitalAsset(imageType.getStandard(), assets);
if (imageType.hasEnlarged() || imageType.hasZoomable()) {
// Find the image with enlarged image code ("PE")
DigitalAsset enlargedImage = findDigitalAsset(imageType.getEnlarged(), assets);
// Find the image with enlarged image code ("PZ")
DigitalAsset zoomableImage = findDigitalAsset(imageType.getZoomable(), assets);
if (zoomableImage != null) {
// Just send zoomable
imageGroup.getImage().add(createImageNode(zoomableImage, "null"));
} else {
imageGroup.getImage().add(createImageNode(standardImage, "null"));
imageGroup.getImage().add(createImageNode(enlargedImage, "null"));
imageGroup.getImage().add(createImageNode(zoomableImage, "null"));
}
} else if (standardImage != null) {
imageGroup.getImage().add(createImageNode(standardImage, "null"));
}
}
}
/**
* Get the existing image group, or create one if not found.
*
* Creates ProductImageGroup. If ProductImageGroup has been already created for a given
* DemandWareName then do not create a new one. As long as following conditions are met.
* The Idea is to send all images under same image group
* a) If ProductImageGroup already exists for a given DemandWareName and the its
* "variation-value" (color) is null and the color passed to this method is null.
* In such situation return the existing ProductImageGroup (If color is null then its default color).
* b) If ProductImageGroup already exists for a given DemandWareName and the its
* "variation-value" (color) is not null and the color passed to this method
* matches with variation-value. In such situation return the existing ProductImageGroup.
* Otherwise create a new ProductImageGroup.
* @param images ComplexTypeProductImages has many ComplexTypeProductImageGroup
* @param demandwareViewName Demandware name for Digital asset type
* @param color Digital asset type color
* @return
*/
protected ComplexTypeProductImageGroup createImageGroup(
ComplexTypeProductImages images, String demandwareViewName, String color)
{
// See if we already have an image group
for (ComplexTypeProductImageGroup imageGroup : images.getImageGroup()) {
if(StringUtils.isNotBlank(imageGroup.getViewType())
&& imageGroup.getViewType().equals(demandwareViewName)) {
//Now check if the found ProductImageGroup's color (variation-value) is null
//and the passed color is null
if(imageGroup.getVariationValue() == null && color == null)
return imageGroup;
//Other wise check if the found ProductImageGroup's color matches with the passed
//color
else if(imageGroup.getVariationValue() != null
&& imageGroup.getVariationValue().equals(color))
return imageGroup;
}
}
//Looks like either the ProductImageGroup is not found or the above two conditions
// are not met, so create a new ProductImageGroup
ComplexTypeProductImageGroup newImageGroup = objectFactory.createComplexTypeProductImageGroup();
newImageGroup.setViewType(demandwareViewName);
// variation-value is never defined for default color assets
if (StringUtils.isNotBlank(color)) {
newImageGroup.setVariationValue(color);
}
images.getImageGroup().add(newImageGroup);
return newImageGroup;
}
/**
* @param imageGroup
* @param digitalAsset
* @param defaultName the path name to use if the asset is null.
*/
private ComplexTypeProductImage createImageNode(DigitalAsset digitalAsset, String defaultName) {
ComplexTypeProductImage image = objectFactory.createComplexTypeProductImage();
if(digitalAsset == null) {
image.setPath(defaultName);
} else {
image.setPath(digitalAsset.getResourcePath());
}
return image;
}
/**
* Find an asset matching an image type
* @param imageType
* @param assets
* @return the matching asset, or NULL if there is no match.
*/
private DigitalAsset findDigitalAsset(String imageType, Collection<DigitalAsset> assets) {
if (assets != null) {
for (DigitalAsset asset : assets) {
if(asset.getImageType().equals(imageType))
return asset;
}
}
return null;
}
/**
* Concatenates all of the image info into one string.
*
* image_attr_value := image_def ( |image_attr_value ) image_def :=
* IMAGE_SIZE|IMAGE_TYPE|IMAGE_FILE_NAME
*
* @param assets
* collection of images.
* @return a list of encoded strings for each image.
* @deprecated This attribute may go away now that we also send DW image-group nodes.
*/
@Deprecated
protected List<String> createImageAttributeValue(Collection<DigitalAsset> assets) {
List<String> images = new ArrayList<String>();
if (assets != null) {
for (DigitalAsset i : assets) {
// Skip color chip
String imageType = i.getImageType();
if (imageType.equals(DigitalAsset.IMAGE_TYPE_COLOR_CHIP)||
imageType.equals(DigitalAsset.IMAGE_TYPE_GENERIC_COLOR_CHIP)) {
continue;
}
StringBuilder imageSpec = new StringBuilder();
// DW Specification refers to this as image size,
// but the method is getImageType(),
// not to be confused with image type below.
imageSpec.append(imageType).append(
"|");
// image type: Main, Detail, Top, Bottom, etc.
String dwImageType = "Main";
if (exportImageTypes.containsKey(imageType)) {
dwImageType = exportImageTypes.get(imageType);
}
imageSpec.append(dwImageType+"|");
// Strip the path.
imageSpec.append(i.getResourcePath());
images.add(imageSpec.toString());
}
Collections.sort(images, new ImageLabelComparator());
}
return images;
}
/**
* Get attribute value comparator by product type.
* If none exists, try to get the default comparator for the attribute.
* @param name the attribute name
* @param productType the product type
* @return the attribute comparator (that sorts by code value, not display value)
*/
protected Comparator<String> getComparator(String name, String productType) {
if (comparatorFactory == null) return null;
return comparatorFactory.getComparator(name, productType);
}
private SharedTypeSiteSpecificDateTime siteSpecificDateTime(Date date) {
SharedTypeSiteSpecificDateTime ssDate = objectFactory.createSharedTypeSiteSpecificDateTime();
// ssDate.setSiteId(catalogId);
ssDate.setValue(DateUtils.xmlDate(date));
return ssDate;
}
protected void setScheduleDates(BaseProduct baseProduct, ComplexTypeProduct complexTypeProduct) {
Date scheduleStartDate = baseProduct.getScheduleStartDate();
Date scheduleEndDate = baseProduct.getScheduleEndDate();
if(scheduleStartDate != null) {
complexTypeProduct.getOnlineFrom().add(siteSpecificDateTime(scheduleStartDate));
} else {
complexTypeProduct.getOnlineFrom().add(null);
}
if(scheduleEndDate != null) {
complexTypeProduct.getOnlineTo().add(siteSpecificDateTime(scheduleEndDate));
} else {
complexTypeProduct.getOnlineTo().add(null);
}
}
/**
* @param productType the product type
* @return
*/
private List<String> getVariationAttributeNames(String productType) {
List<String> variationAttributeNames = null;
// Check for product-type-specific attributes.
if (StringUtils.isNotBlank(productType)) {
variationAttributeNames = lookupDataService.findValues("catalog.mapper.product.type." + productType);
}
// Use default if no product-type-specific attributes exist.
if (CollectionUtils.isEmpty(variationAttributeNames)) {
variationAttributeNames = lookupDataService.findValues("catalog.mapper.product.type.default");
}
//variant attribute names will be unsorted coming from the lookupdataservice
Collections.sort(variationAttributeNames);
return variationAttributeNames;
}
protected ComplexTypeVariationAttribute createVariationAttribute(
Collection<ProductSKU> skus, String attributeId, String productType) {
ComplexTypeVariationAttribute variationAttribute = objectFactory.createComplexTypeVariationAttribute();
variationAttribute.setAttributeId(attributeId);
variationAttribute.setVariationAttributeId(attributeId);
variationAttribute.setVariationAttributeValues(objectFactory.createComplexTypeVariationAttributeValues());
// TODO (JH): refactor to allow for non-code based sorting. For now variantColor is different...
if (attributeId.equalsIgnoreCase(AttributeConstants.COLOR_FABRIC)) {
List<AttributeValue> attributeValues = new ArrayList<>();
for (ProductSKU sku : skus) {
AttributeValue attrValue = sku.getAttributeValueByAttributeName(attributeId);
attributeValues.add(attrValue);
}
if (attributeValues.isEmpty())
return null;
else {
Collections.sort(attributeValues, AttributeValue.ListOrderComparator);
for (AttributeValue av : attributeValues) {
ComplexTypeVariationAttributeValue customAttrValue = objectFactory.createComplexTypeVariationAttributeValue();
customAttrValue.setValue(av.getCode());
// use hardwired "x-default" for now.
customAttrValue.getDisplayValue().add(createSharedTypeLocalizedString(av.getDisplayName(),"x-default"));
variationAttribute.getVariationAttributeValues().getVariationAttributeValue().add(customAttrValue);
}
return variationAttribute;
}
} else {
// Get all (distinct) values for each SKU
// Use a tree map; this will sort the attributes by natural order by default.
Map<String,String> attrValues = new TreeMap<>();
// Use comparator if one is specified for this attribute.
Comparator<String> comp = getComparator(attributeId,productType);
if (comp != null){
attrValues = new TreeMap<>(comp);
}
for (ProductSKU sku : skus) {
AttributeValue attrValue = sku.getAttributeValueByAttributeName(attributeId);
if (attrValue != null && attrValue.getAttribute().isCustomerSelectable()) {
// This is not default, append "-1" to the code. This will separate
// up to two sets of display values (one default, one non-default), but
// one of these days, we'll have more than two display values,
// at which point we'll either have to have a numeric priority/preference
// index, or we can order the attribute code-display value pairs in the db
// instead of in the context.
String key = getNormalizedAttrValue(attrValue);
attrValues.put(key, attrValue.getDisplayName());
} else if(attributeId.equals(AttributeConstants.INVENTORY_EXPECTED_DATE)
&& sku.getInventory().getExpectedDateValue() != null) {
String value = getStringDate(sku.getInventory().getExpectedDateValue());
attrValues.put(value, value);
}
}
if (attrValues.isEmpty())
return null;
else {
for (String code : attrValues.keySet()) {
ComplexTypeVariationAttributeValue customAttrValue = objectFactory.createComplexTypeVariationAttributeValue();
customAttrValue.setValue(code);
// use hardwired "x-default" for now.
customAttrValue.getDisplayValue().add(createSharedTypeLocalizedString(attrValues.get(code),"x-default"));
variationAttribute.getVariationAttributeValues().getVariationAttributeValue().add(customAttrValue);
}
return variationAttribute;
}
}
}
/**
* Creates the list of variants (skus) from the provided collection of skus
* @param skus
* @param productType the product type, used to find a comparator for ordering the SKUS.
* @return
*/
protected ComplexTypeProductVariationsVariants createVariantList(
Collection<ProductSKU> skus, String productType) {
ComplexTypeProductVariationsVariants variants = objectFactory
.createComplexTypeProductVariationsVariants();
List<ProductSKU> skuList = new ArrayList<ProductSKU>(skus);
// Check for comparator
if ( productType != null && skuComparators != null) {
debug("Looking for comparator for productType='" + productType + "'");
Comparator<ProductSKU> comp = skuComparators.get(productType);
if ( comp != null ) {
Collections.sort(skuList, comp);
}
}
for (ProductSKU sku : skuList) {
ComplexTypeProductVariationsVariant v = objectFactory
.createComplexTypeProductVariationsVariant();
//v1.setProductId(sku.getId().toString());
v.setProductId(sku.getUpc());
// we don't define default here, so no call to setDefault()
variants.getVariant().add(v);
}
return variants;
}
/**
* @param sku
* @return product object containing variant node.
*/
private ComplexTypeProduct createVariant(ProductSKU sku, Product p) {
ComplexTypeProduct mappedProduct = objectFactory.createComplexTypeProduct();
mappedProduct.setEan("");
mappedProduct.setUpc(sku.getUpc());
mappedProduct.setUnit("");
mappedProduct.setProductId(sku.getUpc());
mappedProduct.getDisplayName().add(
createSharedTypeLocalizedString(sku.getDisplayName()));
// Commented out: don't use standard image fields--use custom attribute
// instead.
// mappedProduct.setImage(p.getProductSKUImageName(sku, "PD"));
// mappedProduct.setThumbnail(p.getProductSKUImageName(sku, "VA"));
mappedProduct.setMinOrderQuantity(new BigDecimal(1));
mappedProduct.setStepQuantity(new BigDecimal(1));
// Sellability: TRUE if SKU is live-on-site AND parent PG is live-on-site
boolean sellable = p.getProductGroup().isLiveOnSite() && p.getProductGroup().isVisible() && sku.isLiveOnSite() && sku.isVisible();
mappedProduct.setAvailableFlag(Boolean.valueOf(sellable));
mappedProduct.getOnlineFlag().add(siteSpecificBoolean(sellable));
mappedProduct.getSearchableFlag().add(siteSpecificBoolean(sellable && p.getProductGroup().isSearchable()));
//Set schedule dates
setScheduleDates(sku, mappedProduct);
mappedProduct.setTaxClassId("Standard");
mappedProduct.setBrand(getBrand());
mappedProduct.setManufacturerName(getBrand());
mappedProduct.setManufacturerSku("");
mappedProduct.setPageAttributes(objectFactory.createComplexTypePageAttributes());
debug("createVariant(): " + sku.getAttributeValues().size() + " attribute values");
// Variant attributes and attribute values
List<String> variationAttributeNames = getVariationAttributeNames(p.getProductGroup().getProductType());
for (String attributeId : variationAttributeNames) {
AttributeValue av = sku.getAttributeValueByAttributeName(attributeId);
if (av != null) {
debug("Adding priority attribute: " + attributeId );
addAttributeValueToProduct(mappedProduct, av);
}
}
// Non-db attributes
// 1. inventory expected date
if(sku.getInventory().getExpectedDateValue() != null) {
addCustomAttributeToProduct(mappedProduct
, AttributeConstants.INVENTORY_EXPECTED_DATE
, getStringDate(sku.getInventory().getExpectedDateValue()));
}
// 2. SKU color chip
Collection<DigitalAsset> images = p.getImages().get(sku.getColorFabricAttributeCode());
addCustomAttributeToProduct(mappedProduct, ATTR_ID_VARIANT_COLOR_CHIP, getColorChip(images));
// 3. product images: taken from digital asset table.
addCustomAttributeToProduct(mappedProduct, ATTR_ID_VARIANT_PROD_IMAGE,
createImageAttributeValue(images));
// 4. Shoprunner
addCustomAttributeToProduct(mappedProduct, "sr_eligible",
sku.isShoprunnerEligible()&&p.getProductGroup().isShoprunnerEligible()?"Yes":"No");
return mappedProduct;
}
/**
* Get a color chip for a list of assets.
* @param assets collection of assets
* @return empty string if not found
*/
private String getColorChip(Collection<DigitalAsset> assets) {
if (assets != null && !assets.isEmpty()) {
for (DigitalAsset chip : assets) {
if (DigitalAsset.IMAGE_TYPE_COLOR_CHIP.equals(chip.getImageType())
|| DigitalAsset.IMAGE_TYPE_GENERIC_COLOR_CHIP.equals(chip.getImageType()))
return chip.getResourcePath();
}
}
return "";
}
private void addAttributeValueToProduct(ComplexTypeProduct mappedProduct,
AttributeValue av) {
debug("Adding attribute: " + av.getDisplayName() + " ("
+ av.getCode() + ")");
if (av.getAttribute().isCustomerSelectable()) {
// Shared attribute; normalize.
addCustomAttributeToProduct(mappedProduct, av.getAttribute().getName(),
getNormalizedAttrValue(av));
} else {
addCustomAttributeToProduct(mappedProduct, av.getAttribute().getName(),
av.getDisplayName());
}
}
/**
* Add a custom attribute with a single attribute value to a Product.
* @see CatalogMapper#addCustomAttributeToProduct(ComplexTypeProduct, String, List)
* @param mappedProduct
* @param attributeId attribute name
* @param attributeValue attribute value -- this gets wrapped into a list.
*/
private void addCustomAttributeToProduct(ComplexTypeProduct mappedProduct,
String attributeId, String attributeValue)
{
addCustomAttributeToProduct(mappedProduct, attributeId, Arrays.asList(attributeValue));
}
/**
* Add a custom attribute to a Product.
* @param mappedProduct
* @param attributeId attribute name
* @param values list of attribute values
*/
private void addCustomAttributeToProduct(ComplexTypeProduct mappedProduct,
String attributeId, List<String> values) {
if (mappedProduct.getCustomAttributes() == null) {
mappedProduct.setCustomAttributes(objectFactory
.createSharedTypeSiteSpecificCustomAttributes());
}
mappedProduct.getCustomAttributes().getCustomAttribute().add(
createSharedTypeCustomAttribute(attributeId, values));
}
private ComplexTypeRecommendation createProductRecommendation(
ProductGrouping grouping) {
ComplexTypeRecommendation recommendation = objectFactory.createComplexTypeRecommendation();
// 1 - cross-sell
// 2 - up-sell
// 3 - other
recommendation.setType("1");
recommendation.setSourceType(SimpleTypeRecommendationSourceType.PRODUCT);
recommendation.setSourceId(grouping.getProductGroupId().toString());
recommendation.setTargetId(grouping.getRelatedGroupId().toString());
return recommendation;
}
/**
* @param attributeId
* name of attribute
* @param content
* list of attribute values
* @param lang
* language
*/
private SharedTypeSiteSpecificCustomAttribute createSharedTypeCustomAttribute(
String attributeId, List<String> content, String lang) {
SharedTypeSiteSpecificCustomAttribute attribute = objectFactory
.createSharedTypeSiteSpecificCustomAttribute();
attribute.setAttributeId(attributeId);
attribute.setLang(lang);
// attribute.setSiteId(catalogId);
if (content.size() > 1) {
for (String s : content) {
debug("attribute: [" + attributeId + "], value=["
+ s.toString() + "]");
attribute.getContent().add(
objectFactory.createSharedTypeCustomAttributeValue(s));
}
} else if (content.size() > 0){
// Single value: Don't wrap in <value> tags
attribute.getContent().add(content.get(0));
}
return attribute;
}
/**
* Equivalent to createSharedTypeCustomAttribute(attributeId, content,
* "x-default");
*
* @param attributeId
* name of attribute
* @param content
* attribute value
*/
private SharedTypeSiteSpecificCustomAttribute createSharedTypeCustomAttribute(
String attributeId, List<String> content) {
return createSharedTypeCustomAttribute(attributeId, content, null);
}
/**
* Return a DW localized text.
*
* @param value
* @return
*/
private SharedTypeLocalizedText createSharedTypeLocalizedText(
String value, String lang) {
SharedTypeLocalizedText s = objectFactory.createSharedTypeLocalizedText();
s.setValue(value);
if (lang != null) {
s.setLang(lang);
}
// s.setLang(lang == null?"x-default":lang);
return s;
}
/**
* Return a DW localized text, using &quot;x-default&quot; as the
* language.
*
* @param value
* @return
*/
private SharedTypeLocalizedText createSharedTypeLocalizedText(String value) {
return createSharedTypeLocalizedText(value, null);
}
/**
* Return a DW localized string.
*
* @param value
* @return
*/
private SharedTypeLocalizedString createSharedTypeLocalizedString(
String value, String lang) {
SharedTypeLocalizedString s = objectFactory
.createSharedTypeLocalizedString();
s.setValue(value);
if (lang != null) {
s.setLang(lang);
}
// s.setLang(lang == null?"x-default":lang);
return s;
}
/**
* Return a DW localized string, using &quot;x-default&quot; as the
* language.
*
* @param value
* @return
*/
private SharedTypeLocalizedString createSharedTypeLocalizedString(String value) {
return createSharedTypeLocalizedString(value, null);
}
private SharedTypeSiteSpecificBoolean siteSpecificBoolean(boolean value) {
SharedTypeSiteSpecificBoolean flag = objectFactory.createSharedTypeSiteSpecificBoolean();
//flag.setSiteId(catalogId);
flag.setValue(value);
return flag;
}
/**
* @param attrValue
* @return
*/
private String getNormalizedAttrValue(AttributeValue attrValue) {
return attrValue.getCode()+ (attrValue.isDefault()?"":ATTR_ALT_DISPLAY_DELIMITER+"1");
}
private String getStringDate(Date date) {
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy");
return format.format(date);
}
public Integer getRootCategoryId() {
return rootCategoryId;
}
public void setRootCategoryId(Integer rootCategoryId) {
this.rootCategoryId = rootCategoryId;
}
public String getCatalogId() {
return catalogId;
}
public void setCatalogId(String catalogId) {
this.catalogId = catalogId;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public Map<String, String> getExportImageTypes() {
return exportImageTypes;
}
public void setExportImageTypes(Map<String, String> imageCodeMappings) {
this.exportImageTypes = imageCodeMappings;
}
public AttributeComparatorFactory getComparatorFactory() {
return comparatorFactory;
}
public void setComparatorFactory(AttributeComparatorFactory comparatorFactory) {
this.comparatorFactory = comparatorFactory;
}
public void setSkuComparators(
Map<String, Comparator<ProductSKU>> skuComparators) {
this.skuComparators = skuComparators;
}
public Map<String, Comparator<ProductSKU>> getSkuComparators() {
return skuComparators;
}
public void setLookupDataService(LookupDataService lookupDataService) {
this.lookupDataService = lookupDataService;
}
public LookupDataService getLookupDataService() {
return lookupDataService;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment