Archive for March, 2010

Sorting products by name in ASPDotNetStorefront with language support

Saturday, March 27th, 2010

OK, not the most elegant article title but it seemed like the best way to describe the issue. If you saw our recent article about how to implement sorting product results by price in ASPDNSF you’ll see that we mentioned sorting results by name and how this was a harder problem to solve.

Multiple language product result sorting in ASPDotNetStorefront

Harder? You might be thinking that nothing is easier than sorting by Product name. In fact, the default ASPDNSF_GetProducts() Stored procedure sorts by product name if no other sort entity is specified.

The problem comes when your site supports multiple languages. An English ’shirt’ is a German ‘hemd’ and this demands that product results are returned in a different order if sorting by name.

In a single language store, ASPDotNetStorefront stores the product name as you would expect as ‘Product Name’. In a multi-language store, each name field contains all language versions of the product name like this:


<ml><locale name="en-US">English language Name</locale><locale name="en-DE">German language Name</locale></ml>

In such an environment, a standard SQL ‘order by name’ will not work so something more advanced is required.

Use XML within SQL Server

The solution is to use SQL Server’s powerful XML and XPath processing to extract the correct version of the product name for sorting.

If you read the previous article, to add sorting by name, you need to add some additional sortentity values as follows:


if @sortEntity = 2000 /* Ascending name */
begin
  insert into @sort(ProductID)
  select p.ProductID from Product p with (NOLOCK)
  join ProductCategory pc with (NOLOCK) on p.ProductID = pc.ProductID
  where p.Published = 1 and p.Deleted = 0
  and pc.categoryID = @categoryID
  order by CAST(CAST(p.Name as xml).query('data(//locale[@name=sql:variable("@localeName")])')  as varchar(200))
end
else if @sortEntity = 2001 /* Descending name */
begin
  insert into @sort(ProductID)
  select p.ProductID from Product p with (NOLOCK)
  join ProductCategory pc with (NOLOCK) on p.ProductID = pc.ProductID
  where p.Published = 1 and p.Deleted = 0
  and pc.categoryID = @categoryID
  order by CAST(CAST(p.Name as xml).query('data(//locale[@name=sql:variable("@localeName")])')  as varchar(200)) desc
end

This code converts the ASPDotNetStorefront product name into XML and then performs an XPath query on it to extract the correct product name based on the Customer’s locale (@localeName is passed in as a parameter to the Stored Procedure you created previously).

If you need assistance with implementing a solution such as this within your own ASPDotNetStorefront store, then please get in touch. Based in the UK, Webopius have been building and extending ASPDotNetStorefront solutions since version 7 for a variety of global customers.

ASPDotNetStorefront – sort products by price

Saturday, March 13th, 2010

We’ve always wondered why the standard ASPDotNetStorefront templates and database procedures don’t offer the Customer the chance to filter and sort their product results by price (low>high or high>low) or to show sale items first or even sort by product name.

In standard configuration, ASPDotNetStorefront supports sorting by the ‘display order’ field which you can configure in the Admin screens. However, many Customers and store Business owners ask for a much more flexible range of dynamic sort options for their ASPDNSF sites… and other e-commerce systems offer this capability out of the box.

In this article, we’ll show you the steps necessary to enhance you ASPDotNetStorefront system with price sorting. Sorting by name is a little more complex because of multi-language support so we’ll be writing another post about this later.

You can use the techniques here to add sorting by any field you wish. For example, we have used this method in ASPDotNetStorefront sites to add:

  • Sort by Sale item products first
  • Sort by Publication date (for books)
  • Show Featured items first (using the product type attribute to flag particular items as featured)
  • Sort by product price
  • Sort by product name (with multi-language support – different sort results depending on the language)
  • Sort by Author name (for books)

Step 1. Create a new aspdnsf_GetProducts() database procedure

The first part of making this enhancement is to create a new version of the standard aspdnsf_GetProducts() stored procedure. If you have ASPDotNetStorefront ML7.x, you can use SQL Server management studio to view the code of this procedure. If you are using ML8.x, you will need to look at the database install scripts (file Create AspDotNetStorefront database.sql).

We recommend creating a new procedure rather than editing the existing procedure because future ASPDotNetStorefront site upgrades are much simpler this way as you are not changing core source code.

So, create a new procedure called something like CUSTOM_GetProducts() and copy the original aspdnsf_GetProducts() procedure. Because this is part of the original ASPDNSF source code, we are unable to show you the full code here but will walk you through the process. If you need these changes made for you, please contact us and we can usually have the full price sorting solution implemented and tested on your ASPDotNetStorefront store.

Step 2. Change the sort code

If you look at your code, you will see a table called #DisplayOrder being declared and below this, some code that inserts specific values the #DisplayOrder table depending on the value of @sortEntity.

All of this code needs to be replaced with a new sort method. We will still use the @sortEntity field but will sort on price ascending if @sortEntity=1000 and on descending price if @sortEntity=1001. The #DisplayOrder table will be replaced with a new sort table called @sort.

First, remove the declarations for #DisplayOrder and create a new declaration for your new @sort table like this:

declare @sort table(DisplayOrder int not null identity primary key,ProductID int)

Basically this creates a table of ProductIDs. As each @sort row is inserted, SQL Server auto generates a primary key (DisplayOrder) that we will use in a join later to ensure product results come back in the correct order.

Now, replace the old #DisplayOrder logic with some new sort logic like this:


if @sortEntity = 1000 /* Ascending price */
   begin
   insert into @sort(ProductID)
   select p.ProductID from Product p with (NOLOCK)
   join ProductVariant pv with (NOLOCK) on p.ProductId = pv.ProductId
   join ProductCategory pc with (NOLOCK) on p.ProductID = pc.ProductID
   where p.Published = 1 and p.Deleted = 0 and pc.categoryID = @categoryID
   and pv.IsDefault = 1 order by pv.Price
end
else if @sortEntity = 1001 /* Descending price */
    begin
    insert into @sort(ProductID)
    select p.ProductID from Product p with (NOLOCK)
    join ProductVariant pv with (NOLOCK) on p.ProductID = pv.ProductID
    join ProductCategory pc with (NOLOCK) on p.ProductID = pc.ProductID
    where p.Published = 1 and p.Deleted = 0 and pc.categoryID = @categoryID
    and pv.IsDefault = 1 order by pv.Price DESC
end

As you can see, if @sortEntity=1000, the @sort table is populated with published products in ascending price order. If @sortEntity=1001, the table is populated with products in descending price order. Both use the default variant pricing – change this if you need to.

Note: the above sort code filters based on the current category. If you are using Manufacturer or Section (Department) based sorting, you’ll need to add these filters to your sort options.

Step 3. Use the new sort code

Having created a new sort table, you now need to modify the section of the procedure referring to @productfilter to use the @sort rather than #displayorder table.

Look for the INSERT @productfilter code and…

1. Replace the join on #displayorder line with:

join @sort sort on sort.ProductID = p.ProductID

2. Replace ‘order by do.displayorder’ with:

order by sort.DisplayOrder

You will need to make the above changes twice as the @productfilter table is created in two parts of an if clause depending on inventoryfilter value.

Step 4. Use your new sort within product category templates

Now you’ve written your new sort method, you can use it within your ASPDotNetStorefront category templates. Typically, we use a drop down menu control with the various sort options. We also pass &sort=1001 or &sort=1002 via the page URL because when paging between product results, your sort parameter will also need to be used.

As you can see, the procedure supports adding more sort options later, such as 2000 for ascending name, 2001 descending name, 3000 for sale items first and so on. In the next article, we’ll show you how to write a custom sort by name that takes account of the ASPDotNetStorefront locale so that products are sorted correctly as the store language changes.

If you would like a solution such as this implemented on your ASPDotNetStorefront site, or would like to discuss other ideas, please contact Webopius. We are one of the leading UK-based web development companies with extensive ASPDotNetStorefront experience.

Creating a new ASPDotNetStorefront paging control

Sunday, March 7th, 2010

The standard ASPDotNetStorefront paging control looks something like this:

paging-old

Nothing particularly wrong with the idea but it is generated as a series of <a> tags without css id or class names. As a result, it offers limited capability for styling to match your store and more importantly, if you have many pages, the standard ASPDotNetStorefront control can get quite wide because all pages available are shown.

An improved, styled ASPDotNetStorefront paging control

Webopius have developed a new paging control that will be familiar to users of sites such as FlickR, it looks like this:
New ASPDotNetStorefront paging control

I hope you agree, it looks better? More importantly, it only shows the first page, the last page and a maximum of two available pages either side of the current page. If your store’s category has a lot of product results, the control never gets too large. Also, the control is rendered as an unordered list <ul> with the class name ‘paginator’. The current page is identified with the class name ‘thispage’.

The result is a much more elegant paging control that can easily be styled with CSS to suit your store.

A direct replacement for the existing ASPDotNetStorefront paging control

Our new paging control can be inserted as a direct replacement for the existing ASPDotNetStorefront page control by replacing the existing line in your XSL templates:


<xsl:value-of select="aspdnsf:PagingControl($BaseURL, $CurrentPage, /root/Products2/Product/pages)" disable-output-escaping="yes" />

With this:


<xsl:value-of select="Webopius:CustPagingControl($BaseURL, $CurrentPage, /root/Products2/Product/pages, 12, $TotalProducts)" disable-output-escaping="yes" />

No source code required

This new control has been implemented as a stand-alone library and just needs copying into your store with a one line change to the web.config file. You do not need the ASPDotNetStorefront source code to implement this control on your site.

If you would like a copy of this paging control installed into your store to improve your ASPDotNetStorefront site’s visitor experience, please contact us. We can usually have it installed and tested within an hour.

Other ASPDotNetStorefront Enhancements available

You might also be interested in other enhancements we have available for your ASPDotNetStorefront store, including:

  • iPhone and mobile versions of ASPDotNetStorefront templates for your store
  • Sort ASPDotNetStorefront product results by price and name
  • For multi-language sites, sort product results based on the language the user is viewing the site in
  • Overlay product images with icons such as ‘Sale’, ‘Top seller’, ‘Rare!’ – you choose the icon, you set a flag on the product and the icons are automatically generated
  • Featured product, random product or latest product shown at the top of your category results
  • Featured product carousel on your ASPDotNetStorefront site home page
  • Custom styling of the shopping cart without requiring the source code
  • Multi-language product import module
  • Bulk image resizing system for ASPDotNetStorefront – scans all your large images and automatically creates icon and medium images
  • Custom product fields and custom product to product relationships

…and the list goes on. We have worked with ASPDotNetStorefront for many years and believe we provide one of the best ASPDotNetStorefront development and support services for your business. Why not try Webopius?

Consorzio Triveneto payment gateway for ASPDotNetStorefront (ASPDNSF)

Friday, March 5th, 2010

We’ve recently written a new payment gateway for ASPDotNetStorefront allowing stores to make payments using the Consorzio Triveneto payment system. Consorzio Triveneto is a ‘boomerang’ gateway that takes the customer off the store to a hosted payment page to enter their card details before returning them back. It operates in a similar way to other ASPDotNetStorefront boomerang gateways such as PayPal express and Worldpay.

Writing a new ASPDotNetStorefront payment gateway

In developing this new gateway, we spent a lot of time working in the payment processing system used in ASPDNSF and took advantage of the excellent, modular way in which you can easily extend the available number of payment methods. We thought it would be useful to share the method used.

If you are developing a new gateway, you will need to have purchased the ASPDotNetStorefront source code because it involves modifying the ASPDNSFGateways.dll library and making changes to the Checkout Payment pages.

The payment gateway process in ASPDotNetStorefront

An overview of the Consorzio Triveneto gateway process within ASPDNSF is shown to the right.

ASPDNSF Triveneto Payment gateway flow

It works in a slightly different way to a gateway like Worldpay, in that before you are taken to the Triveneto Payment screen, you need to send the gateway the payment details and you receive back the URL for making payment. The final step is also different in that you have to pass back a URL to Triveneto informing it which page to send the customer to (Error or Order Confirmation).

In addition to making changes to the gateway library and checkout payment pages, we created three new aspx pages specific to the Triveneto Gateway: trivenetoprocess, trivenetoerror and trivenetosuccess.

The basic approach in writing the gateway was:

Step 1 – Tell the ASPDotNetStorefront configuration wizard about your new gateway

The first step in creating a new gateway is to give it a unique identifier and update the ASPDotNetStorefront admin system’s configuration wizard so that it offers the new gateway as a configuration choice.

In our example, we used the identifier ‘TRIVENETO’ for our new gateway and edited the admin directory file wizard.aspx with a new line:


<asp:ListItem Value="TRIVENETO">Consorzio Triveneto</asp:ListItem>

Step 2 – Update the ASPDotNetStorefront Gateway library

Next, we modified the ASPSNDSF Gateway library to recognize ‘TRIVENETO’ as a valid gateway and added code in to receive information during a Make Payment request. If the order is successful, the gateway simply returns and the customer is sent to the order confirmation page. If unsuccessful, the gateway creates a record in the failed transactions table with the technical details of the failure and the customer is taken to the error page before returning to the shopping cart.

Step 3 – Update the Checkout payment page

The next stage is to update the checkout payment page so that it can send a payment request to the hosted payment page. This is a case of creating a form containing the payment elements (currency, language, amount, tracking id etc).

You will need to edit the source of checkoutpayment.aspx.cs and create a new if statement for your gateway. In our case, we created an ‘if {GW== Gateway.ro_GWTRIVENTO} …’ section.

Triveneto requires URLs to be passed for both error and standard response conditions. We created new AppConfig values for these and also added support for both Test and Live payment processing.

In our model, the checkout payment form sends the payment information to the new page called ‘trivenetoprocess.aspx’.

Step 4 – Capture the payment

trivenetoprocess.aspx takes the payment information received from checkoutpayment.aspx and creates a URL format specific to the Consorzio Triveneto gateway specification. This URL is then sent to the Live/Test payment URL which returns a unique Payment ID and Payment URL, or an Error message.

The Customer is then sent to the Payment URL to enter their credit card details.

Step 5 – Handle errors

If the Customer enters incorrect card details, Triveneto returns them to the error URL on your site, in our case, this is trivenetoerror.aspx. Trivenetoerror.aspx parses the error information and presents a description of the error to the Customer. The Customer then clicks on a link to be taken back to the shopping cart.

Step 6 – Handle payment processing

With correct card details, Triveneto will process the payment and return the Customer to the trivenetosuccess.aspx page. Despite the filename, the transaction may still have been rejected (such as due to an authorisation issue). This page checks the state of the payment and if successful, creates a new order record within ASPDotNetStorefront.

New payment gateways for ASPDotNetStorefront

If you would like to discuss development and installation of new or existing payment gateways for ASPDotNetStorefront, please contact us. Webopius have extensive experience in developing for ASPDotNetStorefront and always spend time understanding your business and requirements.