Blog

This is Part 7 of a seven-part series describing how to implement Workflow Engine for nopCommerce CMS. Click here for Part 1

All of the infrastructure we've built so far has lead to this moment. At long last, we can build the final piece of our schema: the Process table.

Process

This table stores current StateId and some statistic information which is updated by Actions.

The Table

Let's look at the schema of the Process table:

What did we accomplish in this series?

We're trying to design a generic engine for nopCommerce CMS, one that can be used for many disparate processes, and as such the complexity of this design reflects the complexity of the requirements.

Shortcomings of This Design

There are a few shortcomings of this design:

  • Currently, there's no way to say "Stay in this state for X days; after X days, move to another state." We cannot cause Entities to move along in the Workflow due to time elapsed.

  • We don't currently have a way to designate that a specific individual needs to perform an Action or receive an Activity.

  • It is possible that a request will need multiple things to happen before it can continue in the workflow, and we didn’t allow it by implementing the relationship between Transition and Action as many-to-one

That said, most of these shortcomings are fairly easy to implement; we actually did solve a few of them for our company's workflow engine.

Remember: this is only a models and some tables for nopCommerce CMS. The design doesn't account for how this service would actually be implemented in code.

Whew! That was a lot of steps! But what we ended up with was a generic, extensible, reusable workflow engine for nopCommerce CMS that can handle a huge variety of processes.

Thanks for reading! If you found this series helpful (or just need to yell at us for something We did incorrectly) let us know in the comments.

This is Part 6 of a seven-part series describing how to implement Workflow Engine for nopCommerce CMS. Click here for Part 1
We've now got most of the Workflow tables defined, but we are still missing a few things.
One of those things is a definition for exactly who can perform Transitions; we're going to add SubjectToAcl att to the transition model and use nopCommerce AclRecord table for our Security


namespace DevPartner.Nop.Plugin.Core.Models.Workflow
{
    [SystemName("Transition")]
    [SubjectToAcl]
    public class TransitionModel : DPModel
    {
        [DataSource("../*[@type='State']")]
        [Required]
        [ShowOnListPage]
        [EditorTemplate("DropdownList")]
        public int FromState { get; set; }
        [DataSource("../*[@type='State']")]
        [Required]
        [ShowOnListPage]
        [EditorTemplate("DropdownList")]
        public int ToState { get; set; }
        [DataSource("System/Workflow/Action")]
        [ShowOnListPage]
        [EditorTemplate("DropdownList")]
        public int? Action { get; set; }
        [DataSource("System/Workflow/Activity")]
        [EditorTemplate("SuggestionList")]
        public int? Activity { get; set; }
        [DPParent]
        public WorkflowModel Parent { get; set; }
    }
}
What did we accomplish?

In this part, we nailed down exactly who could perform Transition by adding SubjectToAcl att.
In the next part of this series, we get to the real meat of the system. We'll show how individual Entity can track which Actions can be performed against them, and we'll see how we can use that list to determine which Transition the Entity needs to follow. Next up is Part 7 of this series, The Process table and Shortcomings.

This is Part 5 of a seven-part series describing how to implement Workflow Engine for nopCommerce CMS. Click here for Part 1
In previous post, we showed what Customers can do to Entities, and this post we will show what happens to the Customers as a result.

Activities

Activities are things that can happen as a result of a request Entity entering a State or following a Transition.
For example, let's see the diagram from Part 1 again.

In Step 3 of this flowchart, we may want to create notifications and send message to all subscribers according to their preferences on a request, so that they will receive automatic emails about new product request. However, if the Store Owner denies the request we will want to notify the Buyer, but if Store Owner approves the request we need to notify the Buyer and all subscribers.
In other words, in this example adding notification is an activity that we want to happen when an entity reaches a certain state, and sending email is an activity that we want to happen when a certain transition is followed. We need to design for both scenarios.
First, we need to know what kinds of activity we can do. This model is just like Action model. Here's the design for the Activity model:


namespace DevPartner.Nop.Plugin.Core.Models.Workflow
{
    [SystemName("Activity")]
    [Parent("System/Workflow/Activity")]
    [AdminMenu("DevCommerce/Workflow/Activity")]
    public class ActivityModel : DPModel
    {
        public string AssemblyType { get; set; }
    }
}

We'll use the following activities:

  • Send Email: Specifies that we should send an email to one or more recipients.
    
    namespace DevPartner.Nop.Plugin.Core.Services.Activities
    {
        /// 
        /// Send Email: Specifies that we should send an email to one or more recipients.
        /// 
        [SystemName("SendEmail")]
        public class SendEmailActivity : IActivity
        {
            public void Execute(object msg)
            {
                throw new NotImplementedException();
            }
        }
    }
                
  • Create product: Specifies that we should convert entity to nopCommerce product.
  • Create notifications: Specifies that we should create notifications to subscribers according to their subscriptions preferences.

You could define quite a few more kinds of Activities, but for now we'll just use those three.

State and Transition Activities

Once we've got the base Activity defined, we can start designing how the Activities are associated to States and Transitions. As a reminder, we want to be able to kick off Activities in two situations:

  • When the Entity enters a State
  • When the Entity follows a Transition

This means that we still need to associate Activities with States and Transitions, So let’s add Activity field to the Transition and State model:


         namespace DevPartner.Nop.Plugin.Core.Models.Workflow
{
    [SystemName("Transition")]
    public class TransitionModel : DPModel
    {
        [DataSource("../*[@type='State']")]
        [Required]
        [ShowOnListPage]
        [EditorTemplate("DropdownList")]
        public int FromState { get; set; }
        [DataSource("../*[@type='State']")]
        [Required]
        [ShowOnListPage]
        [EditorTemplate("DropdownList")]
        public int ToState { get; set; }
        [DataSource("System/Workflow/Action")]
        [ShowOnListPage]
        [EditorTemplate("DropdownList")]
        public int? Action { get; set; }
        [DataSource("System/Workflow/Activity")]
        [EditorTemplate("SuggestionList")]
        public int? Activity { get; set; }
        [DPParent]
        public WorkflowModel Parent { get; set; }
    }
}
namespace DevPartner.Nop.Plugin.Core.Models.Workflow
{
    [SystemName("State")]
    public class StateModel : DPModel
    {
        [AttExtRefType("StateType")]
        [Required]
        [ShowOnListPage]
        [EditorTemplate("DropdownList")]
        public int StateType { get; set; }
        [DataSource("System/Workflow/Activity")]
        [EditorTemplate("SuggestionList")]
        public int? Activity { get; set; }
        [DPParent]
        public WorkflowModel Parent { get; set; }
    }
}
What did we accomplish?

In this post, we demonstrated what kinds of Activities can be kicked off by certain States or Transitions.
We still have a piece of all this missing, though: exactly who can actually perform the Transitions? We'll answer that question in the next post, Part 6 of this series, where we will discuss Security.

This is Part 4 of a seven-part series describing how to implement Workflow Engine for nopCommerce CMS. Click here for Part 1
Having already defined our Workflow Infrastructure, and our StateTypes and Transitions, we can now start to design models for what a User can actually perform to an Entity in this engine.
Let's start by creating Actions.

Actions

Actions are things a user can perform upon an Entity.
Say we've got a request Entity to deliver a new bumper BMW X5 2005, and that Entity includes the shipping address. The person who is in charge of approving new Entity, Store owner, takes a look at the Entity and decides that, yeah, it's a good Entity without ads. He submits an Approval to the Entity, which can cause the Entity to go to the next state. Store owner has submitted an Action.
Now we need the model for the Actions themselves. Actions can be used for different Workflows so our model will look like this:

namespace DevPartner.Nop.Plugin.Core.Models.Workflow
{
    [SystemName("Action")]
    [Parent("System/Workflow/Action")]
    [AdminMenu("DevCommerce/Workflow/Action")]
    public class ActionModel : DPModel
    {
        public string AssemblyType { get; set; }
    }
}

Since we don't want to allow an infinite number of kinds of actions that can be performed, we are going to implement several basic Actions:

  • Approve: The actioner is suggesting that the entity should move to the next state.
    namespace DevPartner.Nop.Plugin.Core.Services.Actions
    {
        /// 
        /// The actioner is suggesting that the entity should move to the next state.
        /// 
        [SystemName("Approve")]
        public class ApproveAction : IAction
        {
            public void Execute(object msg)
            {
                throw new NotImplementedException();
            }
        }
    }
  • Deny: The actioner is suggesting that the entity should move to the previous state.
  • Cancel: The actioner is suggesting that the entity should move to the Cancelled state in the workflow.
  • Restart: The actioner suggesting that the entity be moved back to the Start state in the Workflow.
  • Resolve: The actioner is suggesting that the request be entity all the way to the Completed state.
Transition Actions

Now that we've defined what Actions could ever be performed, we need to get more specific: which Action can be performed for a particular Transition?
The relationship between Transition and Action is many-to-one in our case. So let’s add Action field to the Transition model.

namespace DevPartner.Nop.Plugin.Core.Models.Workflow
{
    [SystemName("Transition")]
    public class TransitionModel : DPModel
    {
        [DataSource("../*[@type='State']")]
        [Required]
        [ShowOnListPage]
        [EditorTemplate("DropDownList")]
        public int FromState { get; set; }
        [DataSource("../*[@type='State']")]
        [Required]
        [ShowOnListPage]
        [EditorTemplate("DropDownList")]
        public int ToState { get; set; }
        [DataSource("System/Workflow/Action")]
        [ShowOnListPage]
        [EditorTemplate("DropdownList")]
        public int? Action { get; set; }
        [DPParent]
        public WorkflowModel Parent { get; set; }
    }
}

In this post, we demonstrated how we can store what Actions can be performed by Customers.
We still have an outstanding problem, though: What should happen each time we go to a new State (or follow a new Transition) for a given Entity? All that and more in the next post, Part 5 of this adventure, which discusses Activities.

This is Part 3 of a seven-part series describing how to implement Workflow Engine for nopCommerce CMS. Click here for Part 1
Now that we've got the Workwlow model created, we can start building models for the actual process itself. In this part, we'll design the models that will hold the different States an Entity can be in as part of a Workflow, and we'll also design the tables that show how to get from one State to another (which are called Transitions). First, though, we need a table that shows what different types of States can exist. Let's get started!

State Types

A State Type is a categorization of the individual States. In our design, it is an unchangeable list, so in code we would probably use an Enumeration to represent it. Since we're making this database design fully-normalized, we're going to include this set of data as a table, with the following structure:

Because we don't want to have any user-defined State Types, there's no relationship to Workflow for this table. We're treating this table as unchangeable, and will always have the following values:

Here's the reasoning for each of these types:

  • Should only be one per workflow. This state is the state into which a new Entity is placed when it is created.
  • Default: A regular state with no special designation.
  • Complete: A state signifying that any Entity in this state have completed normally.
  • Denied: A state signifying that any Entity in this state has been denied (e.g. never got started and will not be worked on).
  • Cancelled: A state signifying that any Entity in this state has been cancelled (e.g. work was started but never completed).
  • Auto transition: A state signifying that any Entity in this state should be implemented associated action and entity should be transited to the next state.
  • Wait: A state signifying that any Entity in this state have been assigned to somebody and waited any action.

Every State must have exactly one of these State Types. But what makes a State?

States

A State is a position in the Workflow that a given Entity can be in at any given moment. States are unique to Workflow, and each State has a name, a description, and a type. Our State model looks like this:

namespace DevPartner.Nop.Plugin.Core.Models.Workflow
{
    [SystemName("State")]
    public class StateModel : DPModel
    {
        [AttExtRefType("StateType")]
        [Required]
        [ShowOnListPage]
        [EditorTemplate("DropdownList")]
        public int StateType { get; set; }

        [DPParent]
        public WorkflowModel Parent { get; set; }
    }
}

IMPORTANT NOTE: We should add StateType to AttExtRef before converting model to our DB.

if not exists(select 1 from [dbo].[DP_AttExtRefType] where [Name] = 'StateType')
begin

	DECLARE @stateTypeExtRefTypeId int

	INSERT INTO [dbo].[DP_AttExtRefType]
			   ([Name]
			   ,[ExtTableName]
			   ,[ExtIdFieldName])
		 VALUES
			   ('StateType'
			   ,'DP_StateType'
			   ,'Id')

	SET @stateTypeExtRefTypeId = @@IDENTITY

	INSERT INTO [dbo].[DP_AttExtRefFields]
			   ([AttExtRefTypeId]
			   ,[FieldName]         
			   ,[IsSearchable]
			   ,[AttDataTypeId])
		 VALUES
			   (@stateTypeExtRefTypeId
			   ,'Name'
			   ,1
			   ,6)
end 

We should remember, though, that each Workflow is supposed to represent a flow chart, and to do that we need to be able to move Entities between the States. We can do so by designing models for Transitions.

Transitions

If a the lead store owner approves an entity, and it should now go to the vendors according to their subscription, how can we design our data so as to represent that that move is possible? We create a Transition.

A Transition is a path between two States that shows how an Entity can travel between them. Transitions are unique to Workflow. Our Transition model looks like this:

namespace DevPartner.Nop.Plugin.Core.Models.Workflow
{
    [SystemName("Transition")]
    public class TransitionModel : DPModel
    {
        [DataSource("../*[@type='State']")]
        [Required]
        [ShowOnListPage]
        [EditorTemplate("DropdownList")]
        public int FromState { get; set; }

        [DataSource("../*[@type='State']")]
        [Required]
        [ShowOnListPage]
        [EditorTemplate("DropdownList")]
        public int ToState { get; set; }

        [DPParent]
        public WorkflowModel Parent { get; set; }
    }
}
What did we accomplish?

In this post, we gave form to the building blocks of the Workflow by defining the States where an Entity can exist and the Transitions between those States.
We still have an outstanding problem, though: how do we invoke our Transitions? How do we actually cause an Entity to move from one State to another? All that and more in the next post, Part 4 of this adventure, which discusses Actions.

This is Part 2 of a seven-part series describing how to implement Workflow Engine for nopCommerce CMS. Click here for Part 1
Before we can design anything else in this Workflow Engine, we first need to define what exactly makes a Workflow.

The Workflow

A Workflow is the collection of all other data that is unique to a group of users and how they want their request Entities approved. In our design, a Workflow is infrastructure that is used to define and associate most other information.

Our Workflow model is very simple, as it is just an ID, a Name and a Description so we can inherit our model from basic DPModel


namespace DevPartner.Nop.Plugin.Core.Models.Workflow
{
    [SystemName("Workflow")]
    [Parent("System/Workflow/Workflow")]
    [AdminMenu("DevCommerce/Workflow/Workflow")]
    public class WorkflowModel : DPModel
    {
    }
}

This model, though it is very simple, is the central point of reference for the rest of the design; most of the models in this engine (e.g. State, Transition, EntityType, etc.) will need to be related back to this model, either directly or indirectly.

  • 1:15:15 PM
  • Saturday, October 21, 2017
Designing a Workflow Engine for nopCommerce CMS: Intro

Designing a Workflow Engine for nopCommerce CMS: Intro

Our company was developed CMS plugin to simplify process of creating new entities for nopCommerce. We are using this plugin extremely in our development process and it’s really good solution for creating new pages and templates for nopCommerce. Also we started to use it for implementing Business logic and noticed that a lot of processes were relatively similar:
Our company started thinking that, since we had so many similar processes like approvals and notifications, could we build a database-driven tool to manage all of them?
We realized that these processes were essentially finite-state machines which had a request Entity in a given State at any particular time, and which also defined how to travel from one state to another (Transitions) and what needed to happen in order to invoke that travel (Actions).
Upon further research, what we discovered was that these collections of Requests, States, Transitions, Actions, and so on had a name: they were Workflows.

What is a Workflow?

A Workflow is a series of decisions made by different people that determines what happens to a particular request that one of those people made, according to a defined and repeatable process. An example of this process is shown in this flowchart:

Example Steps in a Workflow

Let's illustrate that flow chart another way, by enumerating the steps:

  1. Buyer submits a request that says "I need a product that would allow me to repair my car."
  2. Buyer submits that request to Store Owner by using website, who checks that request correct and approves the request.
  3. Store Owner’s approval creates notifications for vendors according to their subscriptions.
  4. Vendor, who looks over the initial request and decides that they have some products which can be useful for buyer and he and his company can solve buyer issues. He create proposal for the request.
  5. Vendor submit that proposal to Store Owner by using website, who checks that proposal request correct and approves the request.
  6. Store Owner’s approval send notifications to buyer with orders to begin purchasing.
  7. If Store Owner approves the proposal, it is marked initial request complete, and no more action can be taken against it.
Lots of Similarity

We had many different kinds of leads to develop similar workflows in our organization, and we wanted to determine if we could build a generic, database-driven service that could represent many (if not all) of these processes in one central place.
After reviewing several of the currently-existing workflows, our team discovered that they all had similar components:

  • different types of entities that is reviewed, approved, or implemented by various people.
  • A set of highly-variable data that was associated to each entity.
  • A series of decisions (called a Workflow) that determine who was next going to review the Entity or action which should be implemented.
  • A set of notifications that could go to various groups of people.
  • A small number of people that were in charge of the Workflow itself.
Designing a Workflow Engine

In this series, we're going to walk through the model design of our Workflow app and show each part of the solution was implemented, and finally how they were all wired together. We're going to do this in seven parts (this post is Part 1):

This isn't the only design that can implement Workflows, and it has been simplified from our actual implemented design. But we believe that putting our design ideas down on paper (as it were) will help us understand our design better.

  • 8:29:07 PM
  • Tuesday, February 23, 2016
Creating custom CloudStorage provider

Creating custom CloudStorage provider

To create a new Storage Provider, which will be used in CloudStorage plugin use ItPartner.Nop.Plugin.Misc.CloudStorage.CustomProvider project as source.

The process can be divided into 4 major steps:

  1. Set system name of your provider and path to it's dll.
    See CustomProviderPlugin.cs:

    public static readonly string PROVIDER_SYSTEM_NAME = "CustomProvider";
    public static readonly string PROVIDER_DIRECTORY_PATH = "~/Plugins/ItPartner.Misc.CloudStorage.CustomProvider/";
    
  2. Set you provider's initializator which is used to register and access you provider in CloudStorage plugin.
    See Services/CustomProviderServiceInitializer.cs:

    public class CustomProviderServiceInitializer : ICloudStorageProviderInitializer
    

    It should return instance of provider service for each storage type: pictures, downloads and content files:

    public ICloudStorageProviderService GetPictureProvider()
    {
        return _customeProviderPictureService;
    }
    
    public ICloudStorageProviderService GetDownloadProvider()
    {
        return _customeProviderDownloadService;
    }
    
    public ICloudStorageProviderService GetContentProvider()
    {
        return _customeProviderContentService; 
    }
    
  3. Change configuration model, view and controller's methods .
    On Controllers/CustomProviderController.cs:

    public ActionResult Configure()
    {
        var providerSettings = _settingService.LoadSetting<CustomProviderSettings>();
    
        var configurationModel = new ConfigurationModel()
        {
            ProviderSystemName = _customProviderServiceInitializer.GetSystemName(),
    
            AccountName = providerSettings.AccountName,
            AccountKey = providerSettings.AccountKey,
            ContainerName = providerSettings.ContainerName,
            CDN = providerSettings.CDN,
            UseCDN = providerSettings.UseCDN
        };
    
        return PartialView("~/Plugins/ItPartner.Misc.CloudStorage.CustomProvider/Views/CustomProvider/_ProviderSettings.cshtml",
            configurationModel);
    }
    

    Change the Models/ConfigurationModel.cs and Views/CustomProvider/_ProviderSettings.cshtml according to your settings

  4. Add logic to provider's service.
    On Services/CustomProviderService.cs:

    public override string InsertFile(string fileName, string contentType, byte[] binary)
    {
          //some of your code for inserting file in storage
    }
    
    public override bool IsFileExsit(string fileName)
    {
         //some of your code for checking the existence of file in storage
    }
    
    //...
    

    There is a point to create separate instances of provider service for each item type. For example, you can set different container names for pictures, downloads and files and make every provider service store container name in it. That will minimize the count of loading provider settings.

    private readonly string _container;
    

Please note that some methods like MoveFile, RenameFile, CreateDirectory and etc. are already implemented in abstract class BaseCloudStorageProviderService (you can see them in "Services/CustomProviderService.cs" called with base.ImplementedMethodName instead of throwing NotImplementedException). It was made for situations, when there is no correct method to move file for example. In that case we're going to download the whole file, upload it to another location and delete the old one. No doubt, that hurts perfomance and may have other difficulties, so if you have an oppotunity to implement it better without extra actions, override them!

  • 5:13:17 PM
  • Wednesday, December 9, 2015
Sitecore FAQ

Sitecore FAQ

  1. On what sitecore versions your developers are familiar with?

We did website based on Sitecore 6.x- Sitecore 7.x.

  1. Have you done any MVC Sitecore projects or only webforms based?

All internal projects were based on MVC. Other our projects were based on webforms.

  1. I assume, you have a Sitecore partner license?

No, our license was expired. So it will be good if you provide us with your license or we should add about 2000 Euro to the final price to buy the development license.

  1. What is minimum contract length for your staff?

We would like that the minimal length of the contract will be at least 6 months or more but it’s a question to discuss. I suppose it could be one month just to start.

  1. Do you use a work monitoring software that we can log into as necessary, and view in real-time?

Yes, we use TimeDoctor software

  1. What is the speed of internet connection?

I don’t know exactly but I’m sure that it’ll cover all your needs.

  1. Do you charge some extra costs for location of staff in your physical office? (in case they work from home)

They work from our office and we have some space for a new people.

  1. Guarantee/replacement of staff - what is the procedure if we are unhappy with individual staff performance?

Every of our staff members is qualified so I suppose that this situation is possible only in case if we hire a new staff for your needs. So if we have this situation we will be able to replace somebody for two weeks

  1. Do you have security protocols that can protect our data?

We can sign NDA. We can use your example or we can provide you with our templates.

  1. Which sitecore modules did you use?

List of Sitecore modules:

  • Sitecore Rocks
  • Web Forms for Marketers
  • E-Commerce Services
  • Social Connected
  • dtSearch
  • SEO Toolkit
  • Sitecore DMS
  • E-mail Campaign Manager
  • Calendar

List of shared source modules:

  • User Interaction: Google Maps, Page Rate
  • Web Site Optimization: Meta-Tags, Taxonomy Module, Custom Item Generator
  • Social: EviTwitter, WeBlog, Telligent Community Integration
  • Productivity Tools: Sublayout Parameter Helper, Sitecore Stuff, Item Translator, News Mover
  • Search: Index Viewer, Lucene Search, Advanced Database Crawler
  • Media: Sitecore Field Types
  • Link Management: Link Provider
  • Rules: Item Naming Rules, Mobile Device Detector, Geo Lite Resolver

 Benefits of working with us

• You don’t need to buy software, hardware and other infrastructure;

• We have always improved our knowledge;

• Our team has more than 5000 hours of success development on nopCommerce platform

• Our team has more than 1500 hours of success development on Sitecore platform

• We use TimeDoctor. (You will be able to see what we are doing in real time, as well as screenshots and associated tasks. Each month you will get the report of the time spent on your tasks).

  • 11:01:16 PM
  • Tuesday, July 14, 2015
nopCommerce ERP FSD WeService

nopCommerce ERP FSD WeService

General description

The Web service will be implemented by using Web API.

For safe operation with a web service an asymmetric encoding will be used. The NopCommerce plug-in and web service will have two pairs of public and private keys for encoding of outgoing and decoding of incoming requests.

For security reasons, the encrypted token will be sent as one of the parameters. The nopCommerce plugin or a web service will decrypt a token and compare it with a standard one and if they are the same, it will decrypt other parameters.

The user will be able to set up a public key 1, a private key 2, a token and a web service url for a plugin on a plugin configuration page in the admin area of NopCommerce.

Also a developer will be able to set up a private key 1, a public key 2 and a token for a web service in a web.config file.

All web service actions will take parameters in a json format from a Request.Content { byte[] Data, byte[] token }. The response will be sent in the same format.

Data will be represented by an object serialized in json and encrypted by the public key.

Token will be a string that has been encrypted by the public key.

Encryption / decryption will be performed using the RSACryptoServiceProvider.

To generate a key pair the developer can use

using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) 
{ 
publicKey = rsa.ToXmlString(false); 
privateKey = rsa.ToXmlString(true); 
} 

The developer can work with JSON using the JavaScriptSerializer

An algorithm of generating data to be send:

Create an object

public class MyClass 
{ 
public int ProductId; 
public int Quantity; 
} 
MyClass dataObj = new MyClass {ProductId = 10, Quantity = 100}; 

2) Serialize an object using the JavaScriptSerializer

var serializer = new JavaScriptSerializer(); 
string message = serializer.Serialize(dataObj); 

3) Encode a data and a token and create an object for sending

using (var rsa = new RSACryptoServiceProvider()) 
{ 
rsa.FromXmlString(publicKey); 
encryptedData = rsa.Encrypt(Encoding.UTF8.GetBytes(message), true); 
encryptedToken = rsa.Encrypt(Encoding.UTF8.GetBytes(token), true); 
} 
public class MyParam 
{ 
public byte[] Data; 
public byte[] Token; 
} 
MyParam param = new MyParam { Data = encryptedData, Token = encryptedToken}; 

4) Serialize the object using JavaScriptSerializer

string result = Serializer.Serialize(param); 

5) Send the result.

An algorithm for receiving data:

1) Get the data from the request content

string contentResult = string.Empty; 
Request.Content.ReadAsStringAsync().ContinueWith((task) => 
{ 
contentResult = task.Result; 
}); 

2) Deserialize a json string to object

var serializer = new JavaScriptSerializer(); 
MyParam encryptedData = serializer.Deserialize<MyParam>(contentResult); 

3) Decrypt the token

using (var rsa = new RSACryptoServiceProvider()) 
{ 
rsa.FromXmlString(privateKey); 
var token = Encoding.UTF8.GetString(rsa.Decrypt(encryptedData.Token, true)); 
} 

4) Compare the resulting token to the original. If they do not match, then send an error message. If they match, go further.

5) Decrypting data

string dataStr = string.Empty; 
using (var rsa = new RSACryptoServiceProvider()) 
{ 
rsa.FromXmlString(privateKey); 
dataStr = Encoding.UTF8.GetString(rsa.Decrypt(encryptedData.Data, true)); 
} 

6) Deserialize the final json to an object

MyClass dataObj = serializer.Deserialize<MyClass>(dataStr); 

Actions

Bellow you will find actions which the nopCommerce plugin will call. For convenience, the parameters are taken in an open format, but we must understand that it will be encrypted JSON.

When the user adds a product to a cart, the plugin sends a request to a web-service. For example, the plugin calls a remote method AddUpdateProductToCart.

AddUpdateProductToCart

Input parameters:

· Product ID – a NopCommerce product identifier.

· Quantity –product quantity.

Output parameters:

· Status – true, if necessary quantity of products is available, false – if not available.

· Product ID – null.

· Stock quantity – null.

If Status is equal to value false, then the following should be added to output parameters

o Product ID – a NopCommerce product identifier;

o Stock quantity – a product quantity which is available.

Description:

The method verifies the value Stock quantity for the specified product ID and compares this value to the quantity parameter.

If the quantity in Stock is less than the user wants to add to his cart, then the operation is canceled and the user is shown an error message indicating the maximum amount of products that can be added. If the answer is yes, then the item is added to the basket.

When the user changes the quantity of the products in the basket, the plugin sends a request to the web service, causing AddUpdateProductToCart.

If the quantity in Stock is bigger than the user wants to add to his cart, then the product quantity in the basket will be changed. If the Status is false, then the product quantity in the basket will remain the same, with indication of the maximum amount that can be added.

When a user makes a purchase and clicks Checkout, the plugin sends a request to a web service to the remote method CheckoutCart.

ChecoutCart

Input parameters:

· List<Product ID, Quantity> - a list of NopCommerce product identifiers and quantities.

Output parameters:

· Status – false, if the request can't be satisfied (at least one of the product has lower amount of quantity in stock), true – if all products are available.

· List<Product ID, Stock quantity> - null.

If Status has a value false, then the following should be added to output parameters

o List<Product ID, Stock quantity> - a list of products and quantities that are available.

Description:

Checks values ​​Stock quantity for each product from the list and compares them with the values ​​of quantity.

When a user submits a request and clicks Confirm, the plugin sends a request to a web server to the remote method ConfirmOrder.

BeforeConfirmOrder

Input parameters:

· List<Product ID, Quantity> - a list of products identifiers and their quantities.

Output parameters:

· Status – false, if the request can't be satisfied at least on one point, true – if all products are available.

· List<Product ID, Stock quantity> - null.

· ERP Order ID – a ERP order identifier.

If Status has a value false, then the following should be added to output parameters

o List<Product ID, Stock quantity> - a list of products and their quantities that are available.

Description:

Checks values Stock quantity for each product from the list and compares them with the values of quantity. If all of the products are available, the service fills an order for a specified list of products and it reserves products.

AfterConfirmOrder

Input parameters:

· ERP Order ID - a ERP order identifier.

· NC Order ID – a NopCommerce order identifier.

· NC Order status – a NopCommerce order status (Pending, Processing, Complete, Cancelled)

Output parameters:

· Status – true, if a data is successfully received.

Description:

It adds a NopCommerce order identifier and status to a ERP order.

ChangeOrderStatus

Input parameters:

· NC Order ID – a NopCommerce order identifier.

· NC Order Status – a NopCommerce order status (Pending, Processing, Complete, Cancelled)

Output parameters:

· Status – true, if the order is sent to a customer.

Description:

It changes the order status.

To periodically synchronize the items in the plugin the Scheluled Task will work. This task will call a remote method SyncProducts.

SyncProducts

Input parameters:

· List<Product ID> - a list of products identifiers.

Output parameters:

· List<Product ID, Stock quantity> - a list of products and their quantities that are available.

Description:

Receives a value Stock quantity for each NopCommerce Product ID from ERP, generates a list of products and their quantities and sends back.