This section explains how to programatically create a task that will update Litium Studio price lists from prices from an ERP system. The prices in Litium Studio is updated based on the time interval the scheduled task is running.
The prices in Litium Studio might not be "real-time" in sync with the ERP system, but this gives better performance.
A scheduled task is a work unit that will be executed in a particular time. To create the scheduled task implement the Litium.Foundation.Tasks.ITask interface in a class. Then the implementation class has to be registered in the web.config file.
Following example shows a sample task that update the article prices.
using Litium.Foundation.Tasks;
using Litium.Foundation.Modules.ProductCatalog;
using Litium.Foundation.Security;
namespace Litium.Studio.KC.Samples.Integration
{
/// <summary>
/// Update the prices from a ERP system.
/// </summary>
public class PriceUpdater : ITask
{
/// <summary>
/// Update the prices from a ERP system.
/// </summary>
/// <param name="token">Security token</param>
/// <param name="parameters">Parameters. This will be empty for this example.</param>
public void ExecuteTask(SecurityToken token, string parameters)
{
//PriceListImporter class is explained seperately.
var priceListImporter = new PriceListImporter();
//for each price list
foreach (var pricecList in ModuleProductCatalog.Instance.PriceLists.GetAll())
{
//update each price list.
priceListImporter.Import(pricecList.Name, token);
}
}
}
}
Say for example, the above class is implemented in a dll called Litium.Studio.AddOns.Samples.ScheduledTasks.dll, then your web.config entry to run this task periodically each day would look as follows.
<taskSettings>
<scheduledTasks>
<!-- scheduledTask
type="Fullname and Assambly of class to run"
startTime="Time to start task, if task runs more then once per day, first possible occurance will be found based upon interval"
interval="Periodicity, can be D,H,M. eg 2d(every second day), 30M (every 30 minutes)
parameters="Parameters sent to task, optional"-->
<scheduledTask type="Litium.Studio.KC.Samples.Integration.PriceUpdater, Litium.Studio.KC.Samples.Integration" startTime="00:00" interval="1d"/>
</scheduledTasks>
</taskSettings>
Importing price lists
The ERP system might be too slow to get the price one by one for each article, and therefore it is recommended that the price list be written to a phsyical files folder which is accessible to Litium Studio. One best location is the files folder defined in the web.config file.
Following is a sample implementation which assumes that the price list name is the same as the xml file written to the file share, and reads the file and update the prices.
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml.XPath;
using Litium.Foundation;
using Litium.Foundation.Modules.ProductCatalog;
using Litium.Foundation.Modules.ProductCatalog.Articles;
using Litium.Foundation.Modules.ProductCatalog.Carriers;
using Litium.Foundation.Security;
namespace Litium.Studio.KC.Samples.Integration
{
public class PriceListImporter
{
/// <summary>
/// Imports the specified price list name.
/// </summary>
/// <param name="priceListName">Name of the price list.</param>
/// <param name="token">The token.</param>
public void Import(string priceListName, SecurityToken token)
{
Stream articlesStream = null;
XPathDocument document = null;
var filePath = Path.Combine(Solution.Instance.DataSettings.FilesDirectory, @"KCSamplesData\"+ priceListName + ".xml");
if (File.Exists(filePath))
{
document = new XPathDocument(filePath);
}
else
{
//this section is only intended to simplyfy deploying the KC samples.
//For KC sample data, we read from the assembly manifest.
articlesStream = this.GetType().Assembly.GetManifestResourceStream("Litium.Studio.KC.Samples.Integration.Data." + priceListName + ".xml");
document = new XPathDocument(articlesStream);
}
var priceListItems = new List<PriceListItem>();
try
{
if (document != null)
{
var navigator = document.CreateNavigator();
var iterator = navigator.Select("/Articles/Article");
while (iterator.MoveNext())
{
var fullName = iterator.Current.SelectSingleNode("FullName").Value;
var price = iterator.Current.SelectSingleNode("Price").Value;
var vatPercentage = iterator.Current.SelectSingleNode("VatPercentage").Value;
priceListItems.Add(new PriceListItem(){FullName = fullName,
Price = decimal.Parse(price, CultureInfo.InvariantCulture),
VatPercentage = decimal.Parse(vatPercentage, CultureInfo.InvariantCulture)});
}
}
}
finally
{
//cleanup.
if (articlesStream != null)
articlesStream.Close();
}
//update the pricelist.
UpdatePriceList(priceListName, priceListItems, token);
}
public static void UpdatePriceList(string pricelistName, List<PriceListItem> priceListItems, SecurityToken token)
{
//get the pricelist
if (ModuleProductCatalog.Instance.PriceLists.Exists(pricelistName))
{
var priceList = ModuleProductCatalog.Instance.PriceLists.Get(pricelistName, token);
var priceListCarrier = priceList.GetAsCarrier(true);
foreach (var priceListItem in priceListItems)
{
//before we set a price, we makesure that article is already imported and exists.
Article article = null;
if (Article.TryGet(priceListItem.FullName, out article, token))
{
//update the item in the pricelist.
var priceListArticle = priceListCarrier.Articles.FirstOrDefault(x => x.ArticleID == article.ID);
if (priceListArticle != null)
{
//update price.
priceListArticle.Price = priceListItem.Price;
priceListArticle.VATPercentage = priceListItem.VatPercentage;
}
else
{
//add to pricelist.
var priceListArticleCarrier = new PriceListArticleCarrier(article.ID,
priceListItem.Price,
priceListCarrier.ID,
priceListItem.VatPercentage);
priceListCarrier.Articles.Add(priceListArticleCarrier);
}
}
}
//update the whole pricelist at once.
priceList.SetValuesFromCarrier(priceListCarrier, token);
}
}
/// <summary>
/// Represent a row in the custom price list we are importing.
/// </summary>
public struct PriceListItem
{
/// <summary>
/// Gets or sets the full name.
/// </summary>
/// <value>
/// The full name. This is the field that map to article number in Litium Studio product catalog.
/// </value>
public string FullName { get; set; }
/// <summary>
/// Gets or sets the price.
/// </summary>
/// <value>
/// The price.
/// </value>
public decimal Price { get; set; }
/// <summary>
/// Gets or sets the vat percentage. This value is between 0 and 1.
/// </summary>
/// <value>
/// The vat percentage.
/// </value>
public decimal VatPercentage { get; set; }
}
}
}
The corresponding XML file it reads has the following format.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Articles xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Article>
<FullName>Pride and Prejudice by Jane Austen [Paperback]</FullName>
<Price>99</Price>
<VatPercentage>0.06</VatPercentage>
</Article>
<Article>
<FullName>Jane Eyre by Charlotte Bronte [Paperback]</FullName>
<Price>99</Price>
<VatPercentage>0.06</VatPercentage>
</Article>
</Articles>
Alternatively, you may also use the price list import menu button from back-office to import price lists. But then, it is not an automated process.