Appendix D: Understand the Add to Cart BML – Customized Integrations (19C and Earlier)

Users with legacy integration sites (19C and earlier) who have previously customized their Add to Cart BML need to modify their BML to include site-specific reference file locations.

The following provides the Add to Cart BML for Customized Integrations 19C and Earlier:

// Rec Item Properties
part = String[1];
quantity = String[1];
price = String[1];
selected = String[1];
sparepaths = String[1];
sparepaths[0] = "/configuration/configureResponse/spare/rule/item/part";
sparepaths[1] = "/configuration/configureResponse/spare/rule/item/quantity";
sparepaths[2] = "/configuration/configureResponse/spare/rule/item/price";
sparepaths[3] = "/configuration/configureResponse/spare/rule/item/selected";

// BOM Item Properties
bomItem = String[1];
bomItem[0] = "/configuration/configureResponse/bomItem";

// Model/Price Properties
models = string[1];
configIdSearch = string[1];
currpath = String[1];
totalPrices = string[1];
bomTotals = string[1];
models[0] = "/configuration/configureResponse/item/model";
configIdSearch[0] = "/configuration/configureResponse/item/@configurationId";
currpath[0] = "/configuration/configureResponse/attributes/attribute[@_variableName='currencyCode']/value";
totalPrices[0] = "/configuration/configureResponse/price/totalPrice";
bomTotals[0] = "/configuration/configureResponse/price/bomPrice";
priceTotal = 0.0;
baseModelPrice = 0.0;
recurringSubtotal = 0.0;

// Extract data from configXML
outputModel = readxmlsingle(configXML, models);
outputConfigIds = readxmlsingle(configXML, configIdSearch);
currXML = readxmlsingle(configXML, currpath);
currency = get(currXML, currpath[0]);
outputPrices = readxmlsingle(configXML, totalPrices);
bomPrices = readxmlsingle(configXML, bomTotals);
output1 = readxmlmultiple(configXML, sparepaths);
bomItemXMLDict = readxmlsingle(configXML, bomItem);
bomItemString = get(bomItemXMLDict, "/configuration/configureResponse/bomItem");

payloadTemplate = urldatabyget("https://cpq-046.us.example.com/bmfsweb/slc10xgj/image/CommerceCloud/AddToCartPayload-Cloud.txt", "", "");
model1 = "";
totalPrice1 = "";

// Get Model data
for model in models {
  model1 = get(outputModel, model);
}

// Get Price data
for totalPrice in totalPrices {
  totalPrice1 = get(outputPrices, totalPrice);
  totalPrice0 = replace(totalPrice1, ",", "");
  if (isnumber(substring(totalPrice0, 1))) {
    totalPrice2 = getcurrencyvalue(totalPrice1, currency);
    priceTotal = priceTotal + totalPrice2;
  }
}
baseModelPrice = priceTotal;

// Add BOM total price
if (containskey(bomPrices, bomTotals[0])) {
  for bomPrice in bomTotals {
    bomTotal = get(bomPrices, bomPrice);
    bomTotalReplace = replace(bomTotal, ",", "");
    if (isnumber(substring(bomTotalReplace, 1))) {
      bomTotalPrice = getcurrencyvalue(bomTotal, currency);
      priceTotal = bomTotalPrice + priceTotal;
    }
  }
}

// Get ConfigID
configId = "";
for id in configIdSearch {
  configId = get(outputConfigIds, id);
}

// Get Recommended Items
for sparepath in sparepaths {
  if (find(sparepath, "part") <  > -1) {
    part = get(output1, sparepath);
  }
  elif(find(sparepath, "quantity") <  > -1) {
    quantity = get(output1, sparepath);
  }
  elif(find(sparepath, "price") <  > -1) {
    price = get(output1, sparepath);
  }
  elif(find(sparepath, "selected") <  > -1) {
    selected = get(output1, sparepath);
  }
}

// Format Rec Items payload
recItemList = "";
if (isnull(part)) {
  print("No Recommended Items");
} else {
  recItems = sizeofarray(part);
  recItemsInt = integer[recItems];

  i = 0;
  for recItem in recItemsInt {
    if (selected[i] == "true") {
      //recurring price from parts BMQL
      part_num = part[i];
      partCustomFields = bmql("SELECT part_number, custom_field5, custom_field4, custom_field6, custom_field8 FROM _parts WHERE part_number = $part_num");
      recItemPayloadTemplate = urldatabyget("https://cpq-046.us.example.com/bmfsweb/slc10xgj/image/CommerceCloud/Recommended_Items_Payload-Cloud.txt", "", "");
      recItemPayloadTemplate = replace(recItemPayloadTemplate, "{{quantity}}", quantity[i]);
      recItemPayloadTemplate = replace(recItemPayloadTemplate, "{{part}}", part[i]);

      for each in partCustomFields {
        if (get(each, "custom_field8") == "Recurring") {
          recItemPayloadTemplate = replace(recItemPayloadTemplate, "{{pricePeriod}}", get(each, "custom_field4"));
          recItemPayloadTemplate = replace(recItemPayloadTemplate, "{{recurringPrice}}", get(each, "custom_field5"));
          recItemPayloadTemplate = replace(recItemPayloadTemplate, "{{duration}}", get(each, "custom_field6"));
          //recurringSubtotal = recurringSubtotal + get(each, "custom_field5");
        } else {
          childPayloadJson = json(recItemPayloadTemplate);
          jsonremove(childPayloadJson, "recurringCharge");
          recItemPayloadTemplate = jsontostr(childPayloadJson);
        }
      }

      //remove region specific formatting for price
      sPrice0 = substring(price[i], 1);
      sPrice0 = replace(sPrice0, ",", "");

      if (isnumber(sPrice0)) {
        priceTotal = priceTotal + atof(sPrice0);
        recItemPayloadTemplate = replace(recItemPayloadTemplate, "{{price}}", sPrice0);
      } else {
        recItemPayloadTemplate = replace(recItemPayloadTemplate, "{{price}}", "0");
      }
      if (recItemList == "") {
        recItemList = recItemPayloadTemplate;
      } else {
        recItemList = recItemList + "," + recItemPayloadTemplate;
      }
    }
    i = i + 1;
  }
}

// Get the BOM Items
if (isnull(bomItemString)) {
  print "No BOM Items";
  bomItemString = "";
  payloadTemplate = replace(payloadTemplate, "{{BomItems}}", bomItemString);
} else {
  // Get part numbers for each BOM item, convert to string array for bmql
  bomJson = json(bomItemString);

  // Remove extraneous BOM fields (may have to revert if CC was expecting to use them)
  jsonpathremove(bomJson, "$..variableName");
  jsonpathremove(bomJson, "$..definition");
  jsonpathremove(bomJson, "$..category");

  // Replacing all 0 prices with actual number 0
  bomPriceArray = jsonpathgetmultiple(bomJson, "$.._price_unit_price_each");
  replace_lookup = boolean[];
  bomPricesString = jsonarraytostr(bomPriceArray);
  bomPricesString = replace(replace(replace(bomPricesString, "\"", ""), "[", ""), "]", "");
  bomPricesStringArray = split(bomPricesString, ",");

  i = 0;
  for each in bomPricesStringArray {
    append(replace_lookup, isnumber(each));
    i = i + 1;
  }

  i = 0;
  for each in replace_lookup {
    if (i == 0 and each == false) {
      jsonpathset(bomJson, "$.fields._price_unit_price_each", "0");
    }
    elif(each == false) {
      str = "$.children[" + string(i - 1) + "].fields._price_unit_price_each";
      jsonpathset(bomJson, str, "0");
    }

    i = i + 1;
  }

  bomItemString = jsontostr(bomJson);
  bomPartsArray = jsonpathgetmultiple(bomJson, "$..partNumber");
  bomPartsString = jsonarraytostr(bomPartsArray);
  bomPartsString = replace(replace(replace(bomPartsString, "\"", ""), "[", ""), "]", "");
  bomPartsStringArray = split(bomPartsString, ",");
  bomParts = bmql("SELECT part_number, custom_field5, custom_field4, custom_field6, custom_field8 FROM _parts WHERE part_number IN $bomPartsStringArray");

  // Get path for each part, add recurringCharge to them all
  for each in bomParts {
    partField = "\"partNumber\":\"" + get(each, "part_number") + "\",";
    recurringTemplate = "\"recurringCharge\":{ \"amount\":,\"frequency\":,\"duration\":},";

    if (get(each, "custom_field8") == "Recurring") {
      recurringTemplate = replace(recurringTemplate, "frequency\":", "frequency\":\"" + get(each, "custom_field4") + "\"");
      recurringTemplate = replace(recurringTemplate, "amount\":", "amount\":\"" + get(each, "custom_field5") + "\"");
      recurringTemplate = replace(recurringTemplate, "duration\":", "duration\":\"" + get(each, "custom_field6") + "\"");
    } else {
      recurringTemplate = "";
    }
    bomItemString = replace(bomItemString, partField, partField + recurringTemplate);
  }

  // Unflatten
  bomItemString = replace(bomItemString, "\"partNumber\":", "\"catalogRefId\":");
  bomItemString = replace(bomItemString, "On Request", "0"); // This may only fix English users
  bomJson = convertbomtohier(json(bomItemString));
  payloadTemplate = replace(payloadTemplate, "{{BomItems}}", jsontostr(bomJson));
}

// Format main template with subcomponents and properties
payloadTemplate = replace(payloadTemplate, "{{commerceItemId}}", "");
payloadTemplate = replace(payloadTemplate, "{{ConfigId}}", configId);
payloadTemplate = replace(payloadTemplate, "{{model}}", model1);
payloadTemplate = replace(payloadTemplate, "{{totalPrice}}", string(priceTotal));
payloadTemplate = replace(payloadTemplate, "{{basePrice}}", string(baseModelPrice));
payloadTemplate = replace(payloadTemplate, "{{currency}}", currency);
payloadTemplate = replace(payloadTemplate, "{{ChildItems}}", recItemList);
return payloadTemplate;