DNN Hotcakes Server Side API for creating a Single Variant - e-commerce

I'm using Hotcakes Commerce and the e-commerce platform on my DNN site. I've been using the server side API for Hotcakes to transfer product information from one install of Hotcakes to a clean install of Hotcakes. Long story short, one of my database tables got modified somehow and not knowing how it will affect the platform in the future I needed to move all the product data to a clean install of the platform. I've accomplished most of what I needed through building a console application and using the server side API.
The last piece I need is to create the variant information for each product. The only methods I've seen in the server side API is ProductOptionsGenerateAllVariants().
Is there a way to create a single variant using the server-side API?

This is somewhat straightforward to do, assuming that you understand choices/options and variants - as well as the differences between the two.
For the uninitiated... A choice or option allows a customer to specify a different version of the same product, nothing more. An example of this might be changing a t-shirt color from blue to grey. Nothing else changes, except the color.
A variant is still a choice at its core, but it does an additional thing which is to possibly change the SKU and/or pricing. An example of this would be choosing the size of your screen when buying a laptop. The 17" screen will be more expensive than the 15" screen, inventory may be affected differently, and possibly a different SKU/model number entirely.
When you create a single variant, you'll need the correct information to do so, which having choices created, with their variant property set to true, and you'll then need to associate those to the product. That being said, in some stores, there could potentially be millions of possible variants for even a single product. So, as such, the code is not as clean as anyone would like, but an example is below.
using System;
using System.Collections.Generic;
using System.Linq;
using Hotcakes.Commerce.Catalog;
using Hotcakes.Commerce.Extensions;
// get an instance of the application
var HccApp = HccAppHelper.InitHccApp();
// get an instance of the product which you'd like to add a variant to
var product = HccApp.CatalogServices.Products.FindBySku("SAMPLE003");
// get a list of the options that can become variants
var variantOptions = product.Options.VariantsOnly();
// we'll fill this list with choices that we wish to make variants below
var selections = new List<OptionSelection>();
// repeat this line of code for each choice in the product that makes up this variant
// replace both of the parameters when adding the new OptionSelection, based on your use case
selections.Add(new OptionSelection(variantOptions[0].Bvin, "REPLACE THIS WITH THE INDIVIDUAL CHOICE BVIN"));
// create a new variant object
var newVariant = new Variant()
{
ProductId = product.Bvin
};
// specify the choices that make up this variant
newVariant.Selections.AddRange(selections);
// get the unique key to use to compare below
var variantKey = newVariant.UniqueKey();
// check to see if the variant already exists first
if (!product.Variants.Any(v => v.UniqueKey() == variantKey))
{
// create the single variant
HccApp.CatalogServices.ProductVariants.Create(newVariant);
}

Related

Should controller take "id" as PathVariable or should it take "page-id"

We are trying to create SEO friendly roads. In this context, we decided to make changes to the url.
E.g: /141(id) --> /example-page-141
I argue that we should get the "id" value as PathVariable on the back-end side. Another solution is to take "/example-page-141" as #PathVariable and find 141 in it. Which is the right solution?
Solution
#GetMapping("/get/{id}")
public ResponseEntity<?> getProductDetail(#PathVariable Long id)
Product product = productService.getProductDetail(id);
return new ResponseEntity<>(product, HttpStatus.OK);
}
Solution
#GetMapping("/get/{id}")
public ResponseEntity<?> getProductDetail(#PathVariable String id) {
String[] bits = id.split("-");
Long idLong = Long.valueOf(bits[bits.length-1]);
Product product = productService.getProductDetail(idLong);
return new ResponseEntity<>(product, HttpStatus.OK);
}
What are the pros and cons of splitting from the backend or frontend?
I would go with Option 1. Why? because it keeps the splitting logic in the frontend where it belongs. SEO is way more related to frontend than with backend, and as such, you should hide this complexity from the backend service.
One additional benefit is that if at some point in time the ID prefix changes, you can keep the changes in one place (frontend) and not in both frontend and backend which would require syncing the changes so that the backend service continued to be able to respond to the requests (of course you could have an alternative for this, but bottom line is that you would need to touch two codebases instead of a single one).
There is no black or white answer here as there is no real harm in using any of them.
But, if you are going with the approach#2, you will be dealing with the followings:
You are tying the URL or the path param to have a fixed pattern i.e. x-x-x-<page_no>.
Also, unnecessary string processing overhead on the backend.
Choice is yours! :)

Rally print stories with parent feature name in the card generated

I've used Joel Krooswyk's Print All Backlog Story Cards solution for printing all stories in a backlog.
What I'd like to do is to extend this to have each card print the name of the parent feature that the card belongs to so I can print them all up and lay them on a table for a collaborative estimation session.
The issue is, I'm having trouble finding how to do it.
A snippet of his code in question:
queryArray[0] = {
key: CARD_TYPE,
type: 'hierarchicalrequirement',
query: '((Iteration.Name = "") AND (Release.Name = ""))',
fetch: 'Name,Iteration,Owner,FormattedID,PlanEstimate,ObjectID,Description,UserName',
order: 'Rank'
};
I can't seem to find the element to fetch!
Parent was listed on an example queries page(intended for use in the browser query functionality), with Parent.Name containing the actual text but so that hasn't worked - trying to find a reference that is clear about it seems to be eluding me.
I've looked at the type definition located at:
https://rally1.rallydev.com/slm/webservice/v2.0/typedefinition/?fetch=ObjectID&pagesize=100&pretty=true
Going to the hierarchical requirement's type definition from that page indicates it has a Parent field in one form or another.
I'm not even sure that that one will solve what I'm looking at.
A bit stuck, and I'm not sure what I'm trying to do is even possible with the hierarchical requirement object type.
Note: I assume even if I do find it I'll need to add some code to deal parentless stories- not worried about that though, that's easy enough to deal with once I find the actual value.
Many thanks to anyone who can help :)
I modified Joel's app to include PI/Feature's FormattedID to the cards when a story has a parent PI/Feature.
You may see the code in this github repo.
Parent field of a user story references another user story.
If you want to read a parent portfolio item of a user story, which is a Feature object, use Feature attribute or PortfolioItem attribute. Both will work:
if (data[i].PortfolioItem) {
//feature = data[i].PortfolioItem.FormattedID; //also works
//feature = data[i].Feature.Name; //also works
feature = data[i].Feature.FormattedID;
} else {
feature = "";
}
as long as the version of API is set in the code to 1.37 or above (up to 1.43).
PrintStoryCards app is AppSDK1 app.
1.33 is the latest version of AppSDK1.x
1.29, which the app is using is not aware of PortfoilioItems.
PortfolioItem was introduced in Rally in WS API version 1.37.
See API versioning section in the WS API documentation .
If you want to access Portfolio Items, or other features introduced in later versions of WS API up to 1.43 this syntax will allow it.
<script type="text/javascript" src="/apps/1.33/sdk.js?apiVersion=1.43"></script>
This has to be used with caution. One thing that definitely will break is around calculations of timebox start and end dates. That's why many legacy Rally App Catalog apps are still at 1.29.
This is due to changes in API Version 1.30.
Note that this method of setting a more advanced version of WS API for AppSDK1 does not work with v2.0 of WS API.
You should be able to add PortfolioItem to your fetch. Parent is the field used if the parent is a story. PortfolioItem is the field used if the parent is a Feature (or whatever your lowest level PI is).
Then in the results you can just get it like this:
var featureName = (story.PortfolioItem && story.PortfolioItem.Name) || 'None';

change type from user stories to feature

I want to move about 100 user stores to features. I use query to get the type, but I don't know how to change it.
query.query_string = "(FormattedID = \"US4332\")"
results = #rally.find(query)
#res = results.first
puts #res["_type"]
Unfortunately it is not possible to change work item type, and this limitation is not specific to Web Services API, and applies to UI too, with the exception of converting a defect to a story in the UI.
The closest you'll be able to get is to create new features as close to copies of the original stories as possible (including moving children, etc).

Ektron Workarea

I need to develop an application that extracts all the contents in Content Tab of the Ektron Workarea and I have to keep tree structure of folders (taxonomies,collections,forms,etc.) also.When I click the content I need to get the Content ID in the code behind also.I need to do all these in a single function.
I tried this requirement with the concept of content block widget in workarea.When we drag that widget and edit it a pop up will come and it displays the folders of work area in tree structure.But when I created an aspx page, put the same code and I browse that page I didn't get the tree structure of all contents.Only the main tabs(Folders,Taxonomies and search ) are visible.Then I drag the user control in the aspx page .But it also doest work.
So how will I solve the above problem.
Can I pull all the contents in tree structure from work area from the root using API codes?.Then can anyone please give the API code to solve?
Please anyone reply!
Assuming you are using 8.6 look here to start with:
http://reference.ektron.com/developer/framework/content/contentmanager/getlist.aspx
Update:
I think I misread your question the first time around. Allow me to expand on my answer a bit. My original answer with the web services assumes that you are rendering the content tree from some sort of "presentation tier" -- a different web site, a console app, or a WPF/WinForms app, etc.
You can get the recursive folder structure with something like this:
private FolderData GetFolderWithChildren(long folderId)
{
var folderApi = new Ektron.Cms.API.Folder();
var folderData = folderApi.GetFolder(folderId);
// This next method is marked as obsolete in v9.0;
// a newer overload is available in v9.0, but I
// don't know if it's available in v8.0
folderData.ChildFolders = folderApi.GetChildFolders(folderId, true);
}
I'm a little confused as to what exactly you're trying to accomplish. If you want to show the entire tree structure graphically, have you tried taking the code and markup from the edit view of the content widget and using it on your non-edit view?
I must say, your requirement that "I need to do all these in a single function" worries me a bit. Workarea content trees can get really large very quickly. If you're trying to load all of the folders and all the taxonomies and all the collections, etc. Then the user will likely be waiting a long time for the page to load, and you risk running into timeout issues.
-- Original Answer --
Ektron v8.0 doesn't have the 3-tier option, which is too bad because that would really make your job a lot easier. In v8.0, there are ASMX web services that you can reference, including:
/workarea/webservices/content.asmx
/workarea/webservices/webserviceapi/user/user.asmx
There are lots more than this; browse through the folders within /workarea/ to see what's available.
It's been a while since I've worked with these services, so I'm a little rusty...
Suppose you add references to those two services I listed above and name them ContentService and UserService. The first thing you'll want to do is set the authentication headers. Then you can call the service methods in much the same way as the old legacy apis.
var contentApi = new ContentService.Content();
contentApi.AuthenticationHeaderValue = new ContentService.AuthenticationHeader();
contentApi.AuthenticationHeaderValue.Username = username;
contentApi.AuthenticationHeaderValue.Password = password;
contentApi.AuthenticationHeaderValue.Domain = domain;
var userApi = new UserService.User();
userApi.AuthenticationHeaderValue = new UserService.AuthenticationHeader();
userApi.AuthenticationHeaderValue.Username = username;
userApi.AuthenticationHeaderValue.Password = password;
userApi.AuthenticationHeaderValue.Domain = domain;
var ud = userApi.GetUserbyUsername("jimmy456");
long folderID = 85;
bool recursive = true;
ContentData[] folderContent = contentApi.GetChildContent(folderID, recursive, "content_id");

Kentico Ecommerce: getting top selling categories

I am using Kentico 7.0, ecommerce version.
I would like to create a sidebar menu that shows the eshop's top selling product categories. I am a kentico newbie so I am looking around for the correct terminology/guidance so that I can dig deeper.
The ideal approach in my opinion would be to be able to add a field on categories, which is used to filter categories for the menu. This way I can either have some kind of job that updates the fields automatically based on sales, OR provide a manual override for an admin to specify whether a category will show up on the menu. Of course some kind of weight would also be needed to specify menu item ordering.
Which way should I look?
HAve you tried using the "Top N products by sales" web part that is available? you can configure from which part of the content tree (products) it should pull the data - in the Path property you can use also a path expression or macro that is resolved dynamically so the web part can display different products in different sections.
There are many ways to code for Kentico. I personally find the API is a bit clunky and on quite a few occasions I was surprised that a method didn't exist requiring extra calls to get the required results. I do use the Kentico API more when putting data in to Kentico. Pulling it out I use the following.
STORED PROC
Write a SQL stored procedure to get the top X categories - GetTop5Categories.
Look at the COM_* tables, specifically COM_OrderItem, linking OrderItemSKUID back to COM_SKU (or View_COM_SKU_Joined if you need to get to the IA).
This will get you the top selling products with a group by, a count, a top X and an order by.
Then you can link to other tables such as CMS_Category or CMS_Document (depending on how you setup your categories). The bonus of this is that procs are compiled, you do all your data manipulation there (it's what MSSQL specialises in!) and you only send back what you need to in the result set.
DOMAIN (leveraging EF)
I usually create a separate class library project myproject.domain and put an Entity Framework edmx in there mapped back to the Kentico DB. Add the proc to the EDMX, then create a Function Import MyProject_GetTop5Categories from your newly imported proc.
WEB
add a reference to the domain project from your web project, and a 'using at the top of the codebehind of the control.
using myproject.domain;
then in Page_Load for the control:
...
if(!IsPostBack)
{
var entities = new MyProjectModelContainer();
var list = entities.MyProject_GetTop5Categories().ToList();
StringBuilder sb = new StringBuilder("<ul>");
foreach(var category in list)
{
sb.Append("<li><a href='"+category.Link+"'>" + category.Name + "</a></li>");
}
sb.Append("<ul>");
listPlaceHolder = sb.ToString();
}
handwritten so probably a typo or two in there :)
HTH