<?xml version="1.0" encoding="utf-8"?><rss version="2.0"><channel xmlns:atom="http://www.w3.org/2005/Atom"><title>Dev Partner: Blog</title><link>http://localhost:15537/</link><description>Blog</description><lastBuildDate>Sat, 03 Sep 2022 12:01:40 Z</lastBuildDate><atom:link href="http://localhost:15537/blog/rss/1" rel="self" type="application/rss+xml" /><item><guid isPermaLink="false">urn:store:5:blog:post:26</guid><link>http://localhost:15537/tip-1-cleaning-validating-nopcommerce-data-customers</link><title>Tip 1 - Cleaning / validating nopCommerce data (customers)</title><description>&lt;div class="markdown-content markdown-render-area body-m"&gt;&lt;!-- Info Alert --&gt;
&lt;div class="alert alert-info alert-dismissible fade show" role="alert"&gt;&lt;button type="button" class="close" data-dismiss="alert" aria-label="Close"&gt; &lt;span aria-hidden="true"&gt;×&lt;/span&gt; &lt;/button&gt;
&lt;h4 class="h5"&gt;&lt;i class="fa fa-info-circle"&gt;&lt;/i&gt; tip&lt;/h4&gt;
&lt;p&gt;💡 Learn more : &lt;a href="/validation-plugin" class="wiki-broken-link"&gt;Validating new customers online&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;!-- End Info Alert --&gt;
&lt;h2 id="user-content-remove-nopcommerce-fake-customers" mlp="2"&gt;Remove nopCommerce fake customers&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;pagePath=/Tip%201%20%252D%20Cleaning%20and%20validating%20nopCommerce%20data%20(customers)&amp;amp;pageId=118&amp;amp;_a=edit&amp;amp;anchor=remove-nopcommerce-fake-customers" class=" shareHeaderAnchor" aria-labelledby="user-content-remove-nopcommerce-fake-customers"&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p mlp="3"&gt;Using nopCommerce day after day means that your database will grow, and some data will be not relevant. It can be many reasons behind the scene for this, e.x.&lt;/p&gt;
&lt;ul mlp="4"&gt;
&lt;li mlp="5"&gt;one of our customer use product import, and he had to remove products from time to time&lt;/li&gt;
&lt;li mlp="7"&gt;if you are like me, you will get a lot of customers registration because of the bots. Those bots crawl your site buy different reasons and some of them are able to go through reCaptcha.&lt;br /&gt; In this post, I'll walk you through steps of finding data that are not needed and removing them.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="user-content-part-1---determine-how-much-space-on-disk-each-table-is-consuming%2C-and-which-tables-should-be-cleaned-first" mlp="9"&gt;Part 1 - Determine how much space on disk each table is consuming, and which tables should be cleaned first&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;pagePath=/Tip%201%20%252D%20Cleaning%20and%20validating%20nopCommerce%20data%20(customers)&amp;amp;pageId=118&amp;amp;_a=edit&amp;amp;anchor=part-1---determine-how-much-space-on-disk-each-table-is-consuming%2C-and-which-tables-should-be-cleaned-first" class=" shareHeaderAnchor" aria-labelledby="user-content-part-1---determine-how-much-space-on-disk-each-table-is-consuming%2C-and-which-tables-should-be-cleaned-first"&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre class="hljs"&gt;&lt;code class="sql"&gt;&lt;span class="hljs-keyword"&gt;SELECT&lt;/span&gt; 
    t.NAME &lt;span class="hljs-keyword"&gt;AS&lt;/span&gt; TableName,
    s.Name &lt;span class="hljs-keyword"&gt;AS&lt;/span&gt; SchemaName,
    p.rows,
    &lt;span class="hljs-keyword"&gt;SUM&lt;/span&gt;(a.total_pages) * &lt;span class="hljs-number"&gt;8&lt;/span&gt; &lt;span class="hljs-keyword"&gt;AS&lt;/span&gt; TotalSpaceKB, 
    &lt;span class="hljs-keyword"&gt;CAST&lt;/span&gt;(&lt;span class="hljs-keyword"&gt;ROUND&lt;/span&gt;(((&lt;span class="hljs-keyword"&gt;SUM&lt;/span&gt;(a.total_pages) * &lt;span class="hljs-number"&gt;8&lt;/span&gt;) / &lt;span class="hljs-number"&gt;1024.00&lt;/span&gt;), &lt;span class="hljs-number"&gt;2&lt;/span&gt;) &lt;span class="hljs-keyword"&gt;AS&lt;/span&gt; &lt;span class="hljs-built_in"&gt;NUMERIC&lt;/span&gt;(&lt;span class="hljs-number"&gt;36&lt;/span&gt;, &lt;span class="hljs-number"&gt;2&lt;/span&gt;)) &lt;span class="hljs-keyword"&gt;AS&lt;/span&gt; TotalSpaceMB,
    &lt;span class="hljs-keyword"&gt;SUM&lt;/span&gt;(a.used_pages) * &lt;span class="hljs-number"&gt;8&lt;/span&gt; &lt;span class="hljs-keyword"&gt;AS&lt;/span&gt; UsedSpaceKB, 
    &lt;span class="hljs-keyword"&gt;CAST&lt;/span&gt;(&lt;span class="hljs-keyword"&gt;ROUND&lt;/span&gt;(((&lt;span class="hljs-keyword"&gt;SUM&lt;/span&gt;(a.used_pages) * &lt;span class="hljs-number"&gt;8&lt;/span&gt;) / &lt;span class="hljs-number"&gt;1024.00&lt;/span&gt;), &lt;span class="hljs-number"&gt;2&lt;/span&gt;) &lt;span class="hljs-keyword"&gt;AS&lt;/span&gt; &lt;span class="hljs-built_in"&gt;NUMERIC&lt;/span&gt;(&lt;span class="hljs-number"&gt;36&lt;/span&gt;, &lt;span class="hljs-number"&gt;2&lt;/span&gt;)) &lt;span class="hljs-keyword"&gt;AS&lt;/span&gt; UsedSpaceMB, 
    (&lt;span class="hljs-keyword"&gt;SUM&lt;/span&gt;(a.total_pages) - &lt;span class="hljs-keyword"&gt;SUM&lt;/span&gt;(a.used_pages)) * &lt;span class="hljs-number"&gt;8&lt;/span&gt; &lt;span class="hljs-keyword"&gt;AS&lt;/span&gt; UnusedSpaceKB,
    &lt;span class="hljs-keyword"&gt;CAST&lt;/span&gt;(&lt;span class="hljs-keyword"&gt;ROUND&lt;/span&gt;(((&lt;span class="hljs-keyword"&gt;SUM&lt;/span&gt;(a.total_pages) - &lt;span class="hljs-keyword"&gt;SUM&lt;/span&gt;(a.used_pages)) * &lt;span class="hljs-number"&gt;8&lt;/span&gt;) / &lt;span class="hljs-number"&gt;1024.00&lt;/span&gt;, &lt;span class="hljs-number"&gt;2&lt;/span&gt;) &lt;span class="hljs-keyword"&gt;AS&lt;/span&gt; &lt;span class="hljs-built_in"&gt;NUMERIC&lt;/span&gt;(&lt;span class="hljs-number"&gt;36&lt;/span&gt;, &lt;span class="hljs-number"&gt;2&lt;/span&gt;)) &lt;span class="hljs-keyword"&gt;AS&lt;/span&gt; UnusedSpaceMB
&lt;span class="hljs-keyword"&gt;FROM&lt;/span&gt; 
    sys.tables t
&lt;span class="hljs-keyword"&gt;INNER&lt;/span&gt; &lt;span class="hljs-keyword"&gt;JOIN&lt;/span&gt;      
    sys.indexes i &lt;span class="hljs-keyword"&gt;ON&lt;/span&gt; t.OBJECT_ID = i.object_id
&lt;span class="hljs-keyword"&gt;INNER&lt;/span&gt; &lt;span class="hljs-keyword"&gt;JOIN&lt;/span&gt; 
    sys.partitions p &lt;span class="hljs-keyword"&gt;ON&lt;/span&gt; i.object_id = p.OBJECT_ID &lt;span class="hljs-keyword"&gt;AND&lt;/span&gt; i.index_id = p.index_id
&lt;span class="hljs-keyword"&gt;INNER&lt;/span&gt; &lt;span class="hljs-keyword"&gt;JOIN&lt;/span&gt; 
    sys.allocation_units a &lt;span class="hljs-keyword"&gt;ON&lt;/span&gt; p.partition_id = a.container_id
&lt;span class="hljs-keyword"&gt;LEFT&lt;/span&gt; &lt;span class="hljs-keyword"&gt;OUTER&lt;/span&gt; &lt;span class="hljs-keyword"&gt;JOIN&lt;/span&gt; 
    sys.schemas s &lt;span class="hljs-keyword"&gt;ON&lt;/span&gt; t.schema_id = s.schema_id
&lt;span class="hljs-keyword"&gt;WHERE&lt;/span&gt; 
    t.NAME &lt;span class="hljs-keyword"&gt;NOT&lt;/span&gt; &lt;span class="hljs-keyword"&gt;LIKE&lt;/span&gt; &lt;span class="hljs-string"&gt;'dt%'&lt;/span&gt; 
    &lt;span class="hljs-keyword"&gt;AND&lt;/span&gt; t.is_ms_shipped = &lt;span class="hljs-number"&gt;0&lt;/span&gt;
    &lt;span class="hljs-keyword"&gt;AND&lt;/span&gt; i.OBJECT_ID &amp;gt; &lt;span class="hljs-number"&gt;255&lt;/span&gt; 
&lt;span class="hljs-keyword"&gt;GROUP&lt;/span&gt; &lt;span class="hljs-keyword"&gt;BY&lt;/span&gt; 
    t.Name, s.Name, p.Rows
&lt;span class="hljs-keyword"&gt;ORDER&lt;/span&gt; &lt;span class="hljs-keyword"&gt;BY&lt;/span&gt; 
    TotalSpaceMB &lt;span class="hljs-keyword"&gt;DESC&lt;/span&gt;, t.Name
&lt;/code&gt;&lt;/pre&gt;
&lt;p mlp="11"&gt;Results for my DB:&lt;/p&gt;
&lt;p mlp="11"&gt;&lt;img src="/content/images/uploaded/Blog/TipsAndTricks/TipsAndTricks1-Clean-nopCommerce-DB.png" alt="" /&gt;&lt;/p&gt;
&lt;p mlp="12"&gt;As you can see the biggist tables are Customer, GenericAttribute and QueuedEmail&lt;/p&gt;
&lt;p mlp="13"&gt;How do you fix it?&lt;/p&gt;
&lt;h3 id="user-content-part-2---removing-fake-customers%3A" mlp="14"&gt;Part 2 - Removing fake customers:&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;pagePath=/Tip%201%20%252D%20Cleaning%20and%20validating%20nopCommerce%20data%20(customers)&amp;amp;pageId=118&amp;amp;_a=edit&amp;amp;anchor=part-2---removing-fake-customers%3A" class=" shareHeaderAnchor" aria-labelledby="user-content-part-2---removing-fake-customers%3A"&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p mlp="15"&gt;Ideally we should validate all customers emails with 3d party webservice but I have 1Mln recods and most of those customers spent less then one minute.&lt;br /&gt; So let's remove customers that didn't create an order, post and so on. I don't need customers that did zero activity on my site.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code class="sql"&gt;&lt;span class="hljs-keyword"&gt;DELETE&lt;/span&gt; c &lt;span class="hljs-keyword"&gt;FROM&lt;/span&gt; Customer c
 &lt;span class="hljs-keyword"&gt;LEFT&lt;/span&gt; &lt;span class="hljs-keyword"&gt;JOIN&lt;/span&gt; ActivityLog al &lt;span class="hljs-keyword"&gt;ON&lt;/span&gt; al.CustomerId=c.Id
 &lt;span class="hljs-keyword"&gt;LEFT&lt;/span&gt; &lt;span class="hljs-keyword"&gt;JOIN&lt;/span&gt; [dbo].[ShoppingCartItem] sci &lt;span class="hljs-keyword"&gt;ON&lt;/span&gt; sci.CustomerId=c.Id
 &lt;span class="hljs-keyword"&gt;LEFT&lt;/span&gt; &lt;span class="hljs-keyword"&gt;JOIN&lt;/span&gt; [dbo].[Forums_Post] fp &lt;span class="hljs-keyword"&gt;ON&lt;/span&gt; fp.CustomerId=c.Id
 &lt;span class="hljs-keyword"&gt;LEFT&lt;/span&gt; &lt;span class="hljs-keyword"&gt;JOIN&lt;/span&gt; Forums_Topic ft &lt;span class="hljs-keyword"&gt;ON&lt;/span&gt; fp.CustomerId=c.Id
 &lt;span class="hljs-keyword"&gt;LEFT&lt;/span&gt; &lt;span class="hljs-keyword"&gt;JOIN&lt;/span&gt; [&lt;span class="hljs-keyword"&gt;Order&lt;/span&gt;] o &lt;span class="hljs-keyword"&gt;ON&lt;/span&gt; o.CustomerId=c.Id
 &lt;span class="hljs-keyword"&gt;LEFT&lt;/span&gt; &lt;span class="hljs-keyword"&gt;JOIN&lt;/span&gt; [dbo].[DP_Entity] e1 &lt;span class="hljs-keyword"&gt;ON&lt;/span&gt; e1.CustomerId=c.Id
 &lt;span class="hljs-keyword"&gt;LEFT&lt;/span&gt; &lt;span class="hljs-keyword"&gt;JOIN&lt;/span&gt; [dbo].[DP_Entity] e2 &lt;span class="hljs-keyword"&gt;ON&lt;/span&gt; e2.CustomerIdOfLastChange=c.Id
&lt;span class="hljs-keyword"&gt;WHERE&lt;/span&gt; &lt;span class="hljs-keyword"&gt;DATEDIFF&lt;/span&gt;(&lt;span class="hljs-keyword"&gt;MINUTE&lt;/span&gt;, c.CreatedOnUtc, LastActivityDateUtc)&amp;lt;&lt;span class="hljs-number"&gt;1&lt;/span&gt; &lt;span class="hljs-keyword"&gt;AND&lt;/span&gt; c.Id&amp;gt;&lt;span class="hljs-number"&gt;3&lt;/span&gt; 
 &lt;span class="hljs-keyword"&gt;AND&lt;/span&gt; al.Id &lt;span class="hljs-keyword"&gt;IS&lt;/span&gt; &lt;span class="hljs-literal"&gt;NULL&lt;/span&gt;
 &lt;span class="hljs-keyword"&gt;AND&lt;/span&gt; sci.Id &lt;span class="hljs-keyword"&gt;IS&lt;/span&gt; &lt;span class="hljs-literal"&gt;NULL&lt;/span&gt;
 &lt;span class="hljs-keyword"&gt;AND&lt;/span&gt; fp.Id &lt;span class="hljs-keyword"&gt;IS&lt;/span&gt; &lt;span class="hljs-literal"&gt;NULL&lt;/span&gt;
 &lt;span class="hljs-keyword"&gt;AND&lt;/span&gt; ft.Id &lt;span class="hljs-keyword"&gt;IS&lt;/span&gt; &lt;span class="hljs-literal"&gt;NULL&lt;/span&gt;
 &lt;span class="hljs-keyword"&gt;AND&lt;/span&gt; o.Id &lt;span class="hljs-keyword"&gt;IS&lt;/span&gt; &lt;span class="hljs-literal"&gt;NULL&lt;/span&gt;
 &lt;span class="hljs-keyword"&gt;AND&lt;/span&gt; e1.Id &lt;span class="hljs-keyword"&gt;IS&lt;/span&gt; &lt;span class="hljs-literal"&gt;NULL&lt;/span&gt;
 &lt;span class="hljs-keyword"&gt;AND&lt;/span&gt; e2.Id &lt;span class="hljs-keyword"&gt;IS&lt;/span&gt; &lt;span class="hljs-literal"&gt;NULL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="user-content-part-3---removing-fake-customers-atts%3A" mlp="17"&gt;Part 3 - Removing fake customers atts:&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;pagePath=/Tip%201%20%252D%20Cleaning%20and%20validating%20nopCommerce%20data%20(customers)&amp;amp;pageId=118&amp;amp;_a=edit&amp;amp;anchor=part-3---removing-fake-customers-atts%3A" class=" shareHeaderAnchor" aria-labelledby="user-content-part-3---removing-fake-customers-atts%3A"&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre class="hljs"&gt;&lt;code class="SQL"&gt;&lt;span class="hljs-keyword"&gt;DELETE&lt;/span&gt; ga
  &lt;span class="hljs-keyword"&gt;FROM&lt;/span&gt; [dbo].[GenericAttribute] ga
	&lt;span class="hljs-keyword"&gt;LEFT&lt;/span&gt; &lt;span class="hljs-keyword"&gt;JOIN&lt;/span&gt; [dbo].[Customer] c &lt;span class="hljs-keyword"&gt;on&lt;/span&gt; ga.EntityId=c.Id
  &lt;span class="hljs-keyword"&gt;WHERE&lt;/span&gt; KeyGroup=&lt;span class="hljs-string"&gt;'Customer'&lt;/span&gt; &lt;span class="hljs-keyword"&gt;AND&lt;/span&gt; c.Id &lt;span class="hljs-keyword"&gt;IS&lt;/span&gt; &lt;span class="hljs-literal"&gt;NULL&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="user-content-part-4---removing-queuedemail-and-log%3A" mlp="19"&gt;Part 4 - Removing QueuedEmail and Log:&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;pagePath=/Tip%201%20%252D%20Cleaning%20and%20validating%20nopCommerce%20data%20(customers)&amp;amp;pageId=118&amp;amp;_a=edit&amp;amp;anchor=part-4---removing-queuedemail-and-log%3A" class=" shareHeaderAnchor" aria-labelledby="user-content-part-4---removing-queuedemail-and-log%3A"&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre class="hljs"&gt;&lt;code class="SQL"&gt;&lt;span class="hljs-keyword"&gt;TRUNCATE&lt;/span&gt; &lt;span class="hljs-keyword"&gt;TABLE&lt;/span&gt; [dbo].[QueuedEmail]
&lt;span class="hljs-keyword"&gt;TRUNCATE&lt;/span&gt; &lt;span class="hljs-keyword"&gt;TABLE&lt;/span&gt; [dbo].[&lt;span class="hljs-keyword"&gt;Log&lt;/span&gt;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p mlp="21"&gt;I hope this helps someone out there and if you want to stay in touch then I can be found on &lt;a href="http://twitter.com/devpartnerbiz" rel="noopener noreferrer" target="_blank"&gt;Twitter&lt;/a&gt; &lt;span class="fabric-icon ms-Icon--NavigateExternalInline font-size" role="presentation" aria-hidden="true"&gt; &lt;/span&gt; or &lt;a href="http://github.com/devpartner" rel="noopener noreferrer" target="_blank"&gt;GitHub&lt;/a&gt; &lt;span class="fabric-icon ms-Icon--NavigateExternalInline font-size" role="presentation" aria-hidden="true"&gt; &lt;/span&gt;.&lt;/p&gt;
&lt;/div&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:25</guid><link>http://localhost:15537/search-tutorial-how-do-i-solr-relevancy</link><title>Search Tutorial. How do I.  Solr Relevancy</title><description>&lt;h2&gt;How can I change field boosts&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Open C:\Bitnami\solr-8.3.0-0\apache-solr\server\solr\mpp_index\conf\solrconfig.xml&lt;/li&gt;
&lt;li&gt;Find /dp_select SearchHandler&lt;/li&gt;
&lt;li&gt;Specify boosts on fields in parameters such as qf param&lt;br /&gt; For example:
&lt;pre class="hljs"&gt;&lt;code class="xml"&gt;&lt;str name="qf"&gt;part_number_search^1 universal_product_codes^0.7  vendor_part_numbers^0.7 cross_reference_parts^0.7  manufacturer_search^0.5 attr_search^0.5 description_search^0.4 vendor_descriptions^0.3  short_description^0.3 product_name^0.3 attributes^0.1 long_description^0.1 description_hl^0.01&lt;/str&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
copy your changes to dp_suggest handler&lt;/ol&gt;
&lt;h2&gt;How can I apply changes of solrconfig.xml&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Navigate to the &lt;a href="http://127.0.0.1:81/solr/"&gt;SOLR admin page&lt;/a&gt; :&lt;/li&gt;
&lt;li&gt;Go to Core admin, mpp_index, press reload &lt;img class="img-fluid" src="/content/images/uploaded/Search/Blog/SolrConfigApplyChanges.png" alt="Solr Config Apply Changes" /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Query and Analysis Debugging&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Go to your index, Query &lt;img class="img-fluid" src="/content/images/uploaded/Search/Blog/QueryAnalysisDebugging.png" alt="Query Analysis Debugging" /&gt;&lt;/li&gt;
&lt;li&gt;Specify dp_select query handler&lt;/li&gt;
&lt;li&gt;Check the debugQuery checkbox &lt;img class="img-fluid" src="/content/images/uploaded/Search/Blog/debugQueryOn.png" alt="Debug Query On" /&gt; You can see how the query parser parsed your query (which includes the analysis phase). This sets the query parameter "debugQuery=on", and results in the return of an extra list named "debug" containing the parsed query.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;How can I change the score of a document based on the &lt;em&gt;value&lt;/em&gt; of a field (say, "hits_boost" or "velocity_boost")&lt;/h2&gt;
&lt;p&gt;Change &lt;a href="https://lucene.apache.org/solr/guide/6_6/function-queries.html"&gt;FunctionQuery&lt;/a&gt; in the boost param&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code class="xml"&gt;&lt;str name="boost"&gt;div(sum(hits_boost,velocity_boost,ga_product_boost,ga_category_boost), 4)&lt;/str&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For example:&lt;br /&gt; Use a FunctionQuery as part of your query.&lt;/p&gt;
&lt;h2&gt;How can I boost results that have a field that matches a specific value.&lt;/h2&gt;
&lt;p&gt;The bq parameter specifies an additional, optional, query clause that will be added to the user’s main query to influence the score. For example, if you wanted to add a relevancy boost for manufacturer=Mark's and is_on_clearance=true documents:&lt;br /&gt; For example:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code class="xml"&gt;&lt;str name="bq"&gt;
        manufacturer:Mark's^2
        is_on_clearance:true^2
    &lt;/str&gt;&lt;/code&gt;&lt;/pre&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:24</guid><link>http://localhost:15537/how-to-create-your-first-form-with-nopcommerce-cms-form-builder</link><title>How to create  Your First Form With nopCommerce CMS Form Builder</title><description>&lt;p&gt;Create new forms and add them to your nopCommerce site.&lt;/p&gt;
&lt;h2 id="creating-the-view-model"&gt;Creating the view model&lt;/h2&gt;
&lt;p&gt;First, we're going to create the model for the request form by adding a new class to the /Models folder of your plugin. Let's call it RequestModel.cs&lt;/p&gt;
&lt;pre&gt;&lt;code class="csharp"&gt;
[SystemName("Request")] //EntityType.Name 
[Parent("Content Management/Request")] //Parent folder for each template
[Icon("fa-envelope")] //Icon for menu 
public class RequestModel : DPModel
{
    [Required]
    public string Phone { get; set; }
    [Required]
    public string Email { get; set; }
    public string Message { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="creating-updating-entitytype"&gt;Creating/updating EntityType&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Build your plugin and upload to the website&lt;/li&gt;
&lt;li&gt;Restart your nopCommerce&lt;/li&gt;
&lt;li&gt;Go to the nopCommerce administration menu &amp;gt;&amp;gt; DevCommerce &amp;gt;&amp;gt; CMS &amp;gt;&amp;gt; Core Settings you will see the Core settings like in the following image: &lt;img class="img-fluid" src="/content/images/uploaded/CMS/Builder/MappingForms.png" alt="MappingForms.png" /&gt;&lt;/li&gt;
&lt;li&gt;Click "Update" button to initialize Request entity type&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="managing-forms"&gt;Managing Forms&lt;/h2&gt;
&lt;p&gt;After going to the nopCommerce administration menu &amp;gt;&amp;gt; DevCommerce &amp;gt;&amp;gt; Module &amp;gt;&amp;gt; Form Builder you will see the list of forms like in the following image: &lt;img class="img-fluid" src="/content/images/uploaded/CMS/Builder/UpdateEntityTypes.png" alt="UpdateEntityTypes.png" /&gt;&lt;/p&gt;
&lt;p class="has-line-data" data-line-start="1" data-line-end="9"&gt;Create a new form, you will need and choose EntityType(Request in our case) that will represent form fields in SearchEntityType field.&lt;br /&gt; Also specify the following atts:&lt;br /&gt; EditPageTemplate - choose form builder template&lt;br /&gt; Layout - choose page layout. We use TwoColomns Layout by default&lt;br /&gt; SuccessMessage -&lt;br /&gt; ListPageUrl - you will need to specify this att only in case if you would like to show a list of Request to customer&lt;br /&gt; FinalButtonTitle -&lt;br /&gt; ShowCaptcha -&lt;/p&gt;
&lt;h2 id="how-to-view-the-form-entries-"&gt;How to View the Form Entries?&lt;/h2&gt;
&lt;p&gt;One of the best features that DevPartner Form Builder offers is the dedicated admin menu for form entries. To access it, you will need:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;specify AdminMenu att in your model. For example: [AdminMenu("DevCommerce/Request")]&lt;/li&gt;
&lt;li&gt;specify [ShowOnListPage] att for fields that you would like to see on your list in admin area&lt;/li&gt;
&lt;li&gt;update your entity type.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let's modify our RequestModel.cs&lt;/p&gt;
&lt;pre&gt;&lt;code class="csharp"&gt;
[SystemName("Request")] //EntityType.Name 
[Parent("Content Management/Request")] //Parent folder for each template
[Icon("fa-envelope")] //Icon for menu 
[AdminMenu("DevCommerce/Request")] 
public class RequestModel : DPModel
{
    [Required]
    [ShowOnListPage]
    public string Phone { get; set; }
    [Required]
    [ShowOnListPage]
    public string Email { get; set; }
    public string Message { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;After updating&lt;/p&gt;
&lt;p&gt;Here, you can see all the form entries to your form.&lt;/p&gt;
&lt;p&gt;&lt;img src="/content/images/uploaded/CMS/Builder/Request.png" alt="Request.png" /&gt;&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:20</guid><link>http://localhost:15537/how-to-create-task-to-import-additional-n-images-for-products-based-on-nopcommerce-sync-plugin</link><title>How to create task to import additional n images for products based on nopCommerce Sync Plugin</title><description>&lt;p mlp="1"&gt;Case: only first image imported from Excel file. How can i add additional images?&lt;/p&gt;
&lt;p&gt;1. Please create additional Product picture tasks to import Picture2, Picture3 and so on in your config file&lt;/p&gt;
&lt;pre&gt;&lt;code class="json"&gt;
{
  "Name": "Import ProductPicture2",
  "NopKeyGroup": "Product_Picture_Mapping",
  "DtoSystemName": "DTOProductPicture",
  "Timeout": 6000,
  "DataSource": "ProductPicture",
  "SqlScriptPath": "~/Plugins/DevPartner.Sync/SqlScripts/Catalog/DP_MergeProductPictureScript.sql",
  "MappingFields": [
    {
      "SourceField": "Sku",
      "EntityField": "ProductExtId",
      "ConversionName": "VendorConvertion"
    },
    {
      "SourceField": "Picture2",
      "EntityField": "PictureExtId",
      "ConversionName": "Picture"
    }
  ]
},
{
  "Name": "Import ProductPicture3",
  "NopKeyGroup": "Product_Picture_Mapping",
  "DtoSystemName": "DTOProductPicture",
  "Timeout": 6000,
  "DataSource": "ProductPicture",
  "SqlScriptPath": "~/Plugins/DevPartner.Sync/SqlScripts/Catalog/DP_MergeProductPictureScript.sql",
  "MappingFields": [
    {
      "SourceField": "Sku",
      "EntityField": "ProductExtId",
      "ConversionName": "VendorConvertion"
    },
    {
      "SourceField": "Picture3",
      "EntityField": "PictureExtId",
      "ConversionName": "Picture"
    }
  ]
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2. Add additional tasks to your import task "DevCommerce.Sync" -&amp;gt; "ScheduleTasks"&lt;/p&gt;
&lt;pre&gt;&lt;code class="json"&gt;
"ScheduleTasks": [
  {
    "Name": "Sync schedule task",
    "Tasks": [
      "Import products",
      "Import ProductPicture",
      "Import ProductPicture2",
      "Import ProductPicture3",
      "Import product tags",
      "Import product categories"
    ]
&lt;/code&gt;&lt;/pre&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:19</guid><link>http://localhost:15537/nopcommerce-sync-how-to-use-tableconvertion</link><title>How to use TableConvertion in nopCommerce Sync plugin</title><description>&lt;p&gt;In this tutorial, we'll show how to use TableConvertion to add DeliveryDate mapping to product import.&lt;/p&gt;
&lt;p&gt;- Open your pluginsettings.json file&lt;/p&gt;
&lt;p&gt;- Add TableLookup conversion to "DevCommerce.Sync" -&amp;gt; "Conversions" section ",&lt;/p&gt;
&lt;pre&gt;&lt;code class="json"&gt;{
"Name": "DeliveryDateConvertion",
"Type": "TableLookup",
"IdColumnName": "Id",
"ValueColumnName": "Name",
"TableName": "DeliveryDate"
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;- Add conversion mapping for DeliveryDateId column of the Product import task&lt;/p&gt;
&lt;pre&gt;&lt;code class="json"&gt;{
"EntityField": "DeliveryDateId",
"DefaultValue": "0",
"ConversionName": "DeliveryDateConvertion"
},
&lt;/code&gt;&lt;/pre&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:18</guid><link>http://localhost:15537/creating-a-tierprice-import-based-on-nopcommerce-sync-plugin</link><title>Creating a TierPrice import based on nopCommerce Sync plugin</title><description>&lt;p&gt;In this tutorial, I'll be using the nopCommerce Sync plugin to implement a TierPrice import.&lt;/p&gt;
&lt;p&gt;We will start coding with the creating DTO, move on to the Map class, and finally end on SQL import script.&lt;/p&gt;
&lt;h2&gt;Getting started - create base nopCommerce plugin&lt;/h2&gt;
&lt;p&gt;Create a new class library project "DevPartner.Nop.Plugin.Sync.DynamicsCrm". Add the following folders and plugin.json file. You can view the plugin.json file content below:&lt;/p&gt;
&lt;pre&gt;&lt;code class="json"&gt;
{
  "Group": "Dev-Partner",
  "FriendlyName": "DevPartner Sync.DynamicsCrm",
  "SystemName": "DevPartner.Sync.DynamicsCrm",
  "Version": "1.0",
  "SupportedVersions": [ "4.20" ],
  "Author": "Dev-Partner.biz",
  "DisplayOrder": 3,
  "FileName": "DevPartner.Nop.Plugin.Sync.DynamicsCrm.dll",
  "Description": "This plugin allows to send orders and customers to DynamicsCrm"
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add references to the DevPartner.Nop.Plugin.Sync projects. This will be enough for us, as other dependencies, such as Nop.Web.Framework, Nop.Core and Nop.Data, will be connected automatically?&lt;/p&gt;
&lt;h2&gt;Creating new DTO&lt;/h2&gt;
&lt;p&gt;Inside of the "domain" namespace we're going to create a public class named DTOTierPrice. This class extends TierPrice.&lt;/p&gt;
&lt;pre&gt;&lt;code class="json"&gt;

[SystemName("DTOTierPrice")]
[Table("DP_Sync_TierPrice")]
[ImportScript("~/Plugins/DevPartner.Sync/SqlScripts/Catalog/DP_MergeTierPriceScript.sql")]
public class DTOTierPrice : TierPrice, IDTOBaseEntity
{
    [Required]
    [MaxLength(400)]
    public string ProductExtId { get; set; }

    [Required]
    [MaxLength(400)]
    public string StoreExtId { get; set; }

    [Required]
    [MaxLength(400)]
    public string CustomerRoleExtId { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Map class&lt;/h2&gt;
&lt;p&gt;The next class to create is the mapping class.&lt;/p&gt;
&lt;pre&gt;&lt;code class="csharp"&gt;
public class SyncTierPriceMap : NopEntityTypeConfiguration&lt;dtotierprice&gt;, IDTOBaseMap
{

}
&lt;/dtotierprice&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;SQL import script&lt;/h2&gt;
&lt;p&gt;The next important step for us will be the migration script, which update TierPrice directly in the database.&lt;/p&gt;
&lt;pre&gt;&lt;code class="sql"&gt;SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
BEGIN TRANSACTION;

    MERGE [dbo].[TierPrice] trgt
    USING (SELECT DISTINCT p.[Id] as ProductId, s.[Id] as StoreId, cr.[Id] as CustomerRoleId
	      FROM [dbo].[DP_Sync_TierPrice] tp
		     inner join [dbo].[Product] p on p.[ExtId] = tp.[ProductExtId]
		     inner join [dbo].[Store] s on s.[ExtId] = tp.[StoreExtId]
		     inner join [dbo].[CustomerRole] cr on cr.[ExtId] = tp.[CustomerRoleExtId]
		     ) AS src
    ON trgt.[ProductId]=src.ProductId AND trgt.[StoreId]=src.StoreId AND trgt.[CustomerRoleId]=src.CustomerRoleId
    WHEN NOT MATCHED
        THEN INSERT 
               ([ProductId]
               ,[StoreId]
               ,[CustomerRoleId]
               ,[Quantity]
               ,[Price]
               ,[StartDateTimeUtc]
               ,[EndDateTimeUtc])
         VALUES
               (src.[ProductId]
               ,src.[StoreId]
               ,src.[CustomerRoleId]
               ,src.[Quantity]
               ,src.[Price]
               ,src.[StartDateTimeUtc]
               ,src.[EndDateTimeUtc])
	    WHEN MATCHED AND (trgt.[Quantity] &amp;lt;&amp;gt; src.[Quantity]
            OR trgt.[Price] &amp;lt;&amp;gt; src.[Price]
            OR trgt.[StartDateTimeUtc] &amp;lt;&amp;gt; src.[StartDateTimeUtc]
            OR trgt.[EndDateTimeUtc] &amp;lt;&amp;gt; src.[EndDateTimeUtc])
	    THEN UPDATE
		    SET [Quantity] = src.[Quantity],
            [Price] = src.[Price],
            [StartDateTimeUtc] = src.[StartDateTimeUtc],
            [EndDateTimeUtc] = src.[EndDateTimeUtc]; 
COMMIT;
&lt;/code&gt;&lt;/pre&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:17</guid><link>http://localhost:15537/setup-dynamics-crm-for-nopcommerce</link><title>Sync Dynamics CRM  Tutorial for nopCommerce</title><description>&lt;h2&gt;App registration&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Log into portal.azure.com using your Office 365 administrator user of your Dynamics CRM subscription.&lt;/li&gt;
&lt;li&gt;Find Azure Active Director &lt;img class="img-fluid" src="/content/images/uploaded/Blog/Sync/DynamicCRM/FindAzureActiveDirector.png" alt="Find Azure Active Director" /&gt;&lt;/li&gt;
&lt;li&gt;Open App registrations and add New application registrations &lt;img class="img-fluid" src="/content/images/uploaded/Blog/Sync/DynamicCRM/AppRegistrations.png" alt="App Registrations" /&gt;&lt;/li&gt;
&lt;li&gt;Enter "Name" and "Sign-on URL", the URL could be anything (&lt;a href="https://localhost"&gt;https://localhost&lt;/a&gt; for example) &lt;img class="img-fluid" src="/content/images/uploaded/Blog/Sync/DynamicCRM/EnterName.png" alt="image.png" /&gt;&lt;/li&gt;
&lt;li&gt;Select the app you just created, go to Certificates &amp;amp; secrets. Click New client secret, Enter a key description then tick Expires - never and click Add button &lt;img class="img-fluid" src="/content/images/uploaded/Blog/Sync/DynamicCRM/CertificatesSecrets.png" alt="Certificates Secrets" /&gt;&lt;/li&gt;
&lt;li&gt;Go to "Required Permissions", click Add, select "Dynamics CRM" then tick "Access Common Data Service as organization users". &lt;img class="img-fluid" src="/content/images/uploaded/Blog/Sync/DynamicCRM/Permissions.png" alt="Permissions" /&gt; &lt;img class="img-fluid" src="/content/images/uploaded/Blog/Sync/DynamicCRM/Permissions2.png" alt="Permissions2" /&gt;&lt;/li&gt;
&lt;li&gt;Copy the following fields from the App Registration Overview page: Application (client) ID Directory (tenant) ID &lt;img class="img-fluid" src="/content/images/uploaded/Blog/Sync/DynamicCRM/AppRegistrationSettings.png" alt="App Registration Settings" /&gt;&lt;/li&gt;
&lt;li&gt;Copy the Client Secret &lt;img class="img-fluid" src="/content/images/uploaded/Blog/Sync/DynamicCRM/ClientSecret.png" alt="Client Secret" /&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Add CRM application user&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;To let CRM know about the "client application" or "user", you'll need to add an application user.&lt;/li&gt;
&lt;li&gt;Go to CRM\Security Roles, create a new Security Role or just copy the "System Administrator" Role &lt;img class="img-fluid" src="/content/images/uploaded/Blog/Sync/DynamicCRM/SecurityRoles.png" alt="Security Roles" /&gt;&lt;/li&gt;
&lt;li&gt;Go to CRM\Settings\Security\Users, create a new User, change the form to "Application User"&lt;/li&gt;
&lt;li&gt;Enter the required fields with the Application ID that you have in the previous step. Once saved, CRM will autopopulate the Azure AD Object ID and the URI.&lt;/li&gt;
&lt;li&gt;Add the user to the Security Role created from the previous step.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Creating Application User in Dynamics CRM portal&lt;/h2&gt;
&lt;p class="has-line-data" data-line-start="0" data-line-end="10"&gt;Go to Dynamics Settings -&amp;gt; Security -&amp;gt; Users&lt;br /&gt; &lt;img class="img-fluid" src="/content/images/uploaded/Blog/Sync/DynamicCRM/Users.png" alt="Users" /&gt;&lt;br /&gt; Click on Add New User&lt;br /&gt; Select **Application Users **view&lt;br /&gt; 2017 05 26 12 05 23 Users Enabled Users Microsoft Dynamics 365&lt;br /&gt; Click on Add New User and select Application User from dropdown (*IMPORTANT).&lt;br /&gt; 2017 05 26 12 06 17 Users Application Users Microsoft Dynamics 365 1&lt;br /&gt; 2017 05 26 12 06 36 User New User&lt;br /&gt; Enter Azure AD ID (we copied in earlier steps, Full name, and email address of the account.&lt;br /&gt; 2017 05 26 12 07 29 User New User&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:15</guid><link>http://localhost:15537/nopcommerce-seo-sitemap-2020-how-to-avoid-100-cpu-usage</link><title>nopCommerce SEO sitemap 2020 + How to avoid 100% CPU usage</title><description>&lt;div class="markdown-content markdown-render-area body-m"&gt;
&lt;h2 id="user-content-poblem" mlp="1"&gt;Poblem&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;_a=edit&amp;amp;pagePath=%2FnopCommerce%20SEO%20sitemap%202020%20%2B%20Case%20to%20avoid%20100%25%20CPU%20usage&amp;amp;pageId=27&amp;amp;anchor=poblem" class=" shareHeaderAnchor" aria-labelledby="user-content-poblem"&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p mlp="2"&gt;One of our customer recently became aware that his site had been hacked some of their product pages didn’t response.&lt;br /&gt; They have taken steps to rectify the problem as below:&lt;/p&gt;
&lt;ol mlp="3"&gt;
&lt;li mlp="4"&gt;Completely rebuilt the site&lt;/li&gt;
&lt;li mlp="6"&gt;Try to use Redis and IIS Farm to improve performance&lt;/li&gt;
&lt;/ol&gt;
&lt;p mlp="8"&gt;It helped to solve an issue with product page opening but their CPU usage (at live website) has been at 100% causing site to load slowly. Analyzing this issue we discovered that it is google bots that are crawling the site extremely hard causing the issue, (we have tried to block them via firewall and when we do so the CPU usage drops and sites become responsive again), We obviously want the site to rank again, so would like google to crawl the site in more intelligent way.&lt;/p&gt;
&lt;h2 id="user-content-overview" mlp="9"&gt;Overview&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;_a=edit&amp;amp;pagePath=%2FnopCommerce%20SEO%20sitemap%202020%20%2B%20Case%20to%20avoid%20100%25%20CPU%20usage&amp;amp;pageId=27&amp;amp;anchor=overview" class=" shareHeaderAnchor" aria-labelledby="user-content-overview"&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p mlp="10"&gt;A website has almost ~100 millions pages, ~25 mln. products and 4 languages. It's one of the biggest nopCommerce website and it uses Solr Search Plugin to support this amount of products.&lt;/p&gt;
&lt;h2 id="user-content-solution" mlp="11"&gt;Solution&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;_a=edit&amp;amp;pagePath=%2FnopCommerce%20SEO%20sitemap%202020%20%2B%20Case%20to%20avoid%20100%25%20CPU%20usage&amp;amp;pageId=27&amp;amp;anchor=solution" class=" shareHeaderAnchor" aria-labelledby="user-content-solution"&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p mlp="12"&gt;We decided to help google to understand the last modification date for each product URL and generate sitemap dynamically once per day. We used Solr search plugin so we can easily generate product sitemap dynamically. Our extension also had to updates sitemaps every day and update them in the sitemap index file.&lt;/p&gt;
&lt;p mlp="13"&gt;Also our APP has to follow next limits to create well-structure sitemap index and sitemaps:&lt;/p&gt;
&lt;h3 id="user-content-limits" mlp="14"&gt;Limits&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;_a=edit&amp;amp;pagePath=%2FnopCommerce%20SEO%20sitemap%202020%20%2B%20Case%20to%20avoid%20100%25%20CPU%20usage&amp;amp;pageId=27&amp;amp;anchor=limits" class=" shareHeaderAnchor" aria-labelledby="user-content-limits"&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul mlp="15"&gt;
&lt;li mlp="16"&gt;50 000 per sitemap index&lt;/li&gt;
&lt;li mlp="18"&gt;500 sitemap indexes&lt;/li&gt;
&lt;li mlp="20"&gt;50 000 per sitemap&lt;/li&gt;
&lt;li mlp="22"&gt;50 MB per sitemap&lt;/li&gt;
&lt;/ul&gt;
&lt;p mlp="24"&gt;Google Search Console provides SEO specialist with information about how many URLs in each sitemap are indexed. It helps with monitoring of indexation.&lt;/p&gt;
&lt;h3 id="user-content-sitemap-index" mlp="25"&gt;Sitemap index&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;_a=edit&amp;amp;pagePath=%2FnopCommerce%20SEO%20sitemap%202020%20%2B%20Case%20to%20avoid%20100%25%20CPU%20usage&amp;amp;pageId=27&amp;amp;anchor=sitemap-index" class=" shareHeaderAnchor" aria-labelledby="user-content-sitemap-index"&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p mlp="26"&gt;Here is the template of our sitemap index with two files:&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code class="xml"&gt;&lt;span class="php"&gt;&lt;span class="hljs-meta"&gt;&amp;lt;?&lt;/span&gt;xml version=&lt;span class="hljs-string"&gt;"1.0"&lt;/span&gt; encoding=&lt;span class="hljs-string"&gt;"UTF-8"&lt;/span&gt;&lt;span class="hljs-meta"&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;urlset&lt;/span&gt; &lt;span class="hljs-attr"&gt;xmlns&lt;/span&gt;=&lt;span class="hljs-string"&gt;"http://www.sitemaps.org/schemas/sitemap/0.9"&lt;/span&gt;
&amp;lt;?&lt;span class="hljs-attr"&gt;xml&lt;/span&gt; &lt;span class="hljs-attr"&gt;version&lt;/span&gt;=&lt;span class="hljs-string"&gt;"1.0"&lt;/span&gt; &lt;span class="hljs-attr"&gt;encoding&lt;/span&gt;=&lt;span class="hljs-string"&gt;"UTF-8"&lt;/span&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;sitemapindex&lt;/span&gt; &lt;span class="hljs-attr"&gt;xmlns&lt;/span&gt;=&lt;span class="hljs-string"&gt;"https://www.sitemaps.org/schemas/sitemap/0.9"&lt;/span&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;sitemap&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;loc&lt;/span&gt;&amp;gt;&lt;/span&gt;https://www.yourstore.com/sitemap1.xml&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;loc&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;lastmod&lt;/span&gt;&amp;gt;&lt;/span&gt;2020-01-05T12:00:00-02:00&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;lastmod&lt;/span&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;sitemap&lt;/span&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;sitemap&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;loc&lt;/span&gt;&amp;gt;&lt;/span&gt;https://www.yourstore.com/sitemap2.xml&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;loc&lt;/span&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;lastmod&lt;/span&gt;&amp;gt;&lt;/span&gt;2020-01-04T12:00:00-02:00&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;lastmod&lt;/span&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;sitemap&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;sitemapindex&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id="user-content-alternate-languages-support" mlp="28"&gt;Alternate languages support&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;_a=edit&amp;amp;pagePath=%2FnopCommerce%20SEO%20sitemap%202020%20%2B%20Case%20to%20avoid%20100%25%20CPU%20usage&amp;amp;pageId=27&amp;amp;anchor=alternate-languages-support" class=" shareHeaderAnchor" aria-labelledby="user-content-alternate-languages-support"&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p mlp="29"&gt;Our site has 4 languages so we link them by using “hreflang” attribute. It help to the search engine gets to know about our product pages language easily to show in the search results page of specific country or region.&lt;/p&gt;
&lt;pre class="hljs"&gt;&lt;code class="xml"&gt;&lt;span class="php"&gt;&lt;span class="hljs-meta"&gt;&amp;lt;?&lt;/span&gt;xml version=&lt;span class="hljs-string"&gt;"1.0"&lt;/span&gt; encoding=&lt;span class="hljs-string"&gt;"UTF-8"&lt;/span&gt;&lt;span class="hljs-meta"&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;urlset&lt;/span&gt; &lt;span class="hljs-attr"&gt;xmlns&lt;/span&gt;=&lt;span class="hljs-string"&gt;"http://www.sitemaps.org/schemas/sitemap/0.9"&lt;/span&gt;
  &lt;span class="hljs-attr"&gt;xmlns:xhtml&lt;/span&gt;=&lt;span class="hljs-string"&gt;"http://www.w3.org/1999/xhtml"&lt;/span&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;url&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;loc&lt;/span&gt;&amp;gt;&lt;/span&gt;http://www.yourstore.com/&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;loc&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;lastmod&lt;/span&gt;&amp;gt;&lt;/span&gt;2017-10-20T17:30:00-02:00&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;lastmod&lt;/span&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;xhtml:link&lt;/span&gt;
       &lt;span class="hljs-attr"&gt;rel&lt;/span&gt;=&lt;span class="hljs-string"&gt;"alternate"&lt;/span&gt; &lt;span class="hljs-attr"&gt;hreflang&lt;/span&gt;=&lt;span class="hljs-string"&gt;"en-us"&lt;/span&gt;
       &lt;span class="hljs-attr"&gt;href&lt;/span&gt;=&lt;span class="hljs-string"&gt;"http://www.yourstore.com/en/product1"&lt;/span&gt;
    /&amp;gt;&lt;/span&gt;
    &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;xhtml:link&lt;/span&gt;
       &lt;span class="hljs-attr"&gt;rel&lt;/span&gt;=&lt;span class="hljs-string"&gt;"alternate"&lt;/span&gt; &lt;span class="hljs-attr"&gt;hreflang&lt;/span&gt;=&lt;span class="hljs-string"&gt;"de"&lt;/span&gt;
       &lt;span class="hljs-attr"&gt;href&lt;/span&gt;=&lt;span class="hljs-string"&gt;"http://www.yourstore.com/de/product1"&lt;/span&gt;
    /&amp;gt;&lt;/span&gt;
    &lt;span class="hljs-tag"&gt;&amp;lt;&lt;span class="hljs-name"&gt;xhtml:link&lt;/span&gt;
       &lt;span class="hljs-attr"&gt;rel&lt;/span&gt;=&lt;span class="hljs-string"&gt;"alternate"&lt;/span&gt; &lt;span class="hljs-attr"&gt;hreflang&lt;/span&gt;=&lt;span class="hljs-string"&gt;"ru"&lt;/span&gt;
       &lt;span class="hljs-attr"&gt;href&lt;/span&gt;=&lt;span class="hljs-string"&gt;"http://www.yourstore.com/ru/product1"&lt;/span&gt;
    /&amp;gt;&lt;/span&gt;
  &lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;url&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;span class="hljs-tag"&gt;&amp;lt;/&lt;span class="hljs-name"&gt;urlset&lt;/span&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p mlp="31"&gt;Also our APP follows next Sitemap rules:&lt;/p&gt;
&lt;h3 id="user-content-additional-sitemap-rules" mlp="32"&gt;Additional Sitemap Rules&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;_a=edit&amp;amp;pagePath=%2FnopCommerce%20SEO%20sitemap%202020%20%2B%20Case%20to%20avoid%20100%25%20CPU%20usage&amp;amp;pageId=27&amp;amp;anchor=additional-sitemap-rules" class=" shareHeaderAnchor" aria-labelledby="user-content-additional-sitemap-rules"&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul mlp="33"&gt;
&lt;li mlp="34"&gt;UTF-8 encoding&lt;/li&gt;
&lt;li mlp="36"&gt;Entity escaping&lt;/li&gt;
&lt;/ul&gt;
&lt;table class="table" mlp="38"&gt;
&lt;thead mlp="39"&gt;
&lt;tr mlp="40"&gt;&lt;th mlp="41"&gt;Character&lt;/th&gt;&lt;th mlp="42"&gt;Escape&lt;/th&gt;&lt;th mlp="43"&gt;Code&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody mlp="44"&gt;
&lt;tr&gt;
&lt;td&gt;Ampersand&lt;/td&gt;
&lt;td&gt;&amp;amp;&lt;/td&gt;
&lt;td&gt;&amp;amp;amp;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Double&lt;/td&gt;
&lt;td&gt;"&lt;/td&gt;
&lt;td&gt;&amp;amp;quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single&lt;/td&gt;
&lt;td&gt;'&lt;/td&gt;
&lt;td&gt;&amp;amp;apos;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Less than&lt;/td&gt;
&lt;td&gt;&amp;lt;&lt;/td&gt;
&lt;td&gt;&amp;amp;lt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Greater than&lt;/td&gt;
&lt;td&gt;&amp;gt;&lt;/td&gt;
&lt;td&gt;&amp;amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul mlp="45"&gt;
&lt;li mlp="46"&gt;other non-ASCII characters escaping:&lt;br /&gt; For example, the URL&lt;br /&gt; &lt;a href="https://www.yourstore.com/p%C3%A4ge1" rel="noopener noreferrer" target="_blank" mlp="48"&gt;https://www.yourstore.com/päge1&lt;/a&gt; &lt;span class="fabric-icon ms-Icon--NavigateExternalInline font-size" role="presentation" aria-hidden="true"&gt; &lt;/span&gt; requires escaping of character ( ä ):&lt;br /&gt; &lt;a href="https://www.yourstore.com/p%C3%A4ge1" rel="noopener noreferrer" target="_blank"&gt;https://www.yourstore.com/p%C3%A4ge1&lt;/a&gt; &lt;span class="fabric-icon ms-Icon--NavigateExternalInline font-size" role="presentation" aria-hidden="true"&gt; &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="user-content-robots.txt." mlp="49"&gt;Robots.txt.&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;_a=edit&amp;amp;pagePath=%2FnopCommerce%20SEO%20sitemap%202020%20%2B%20Case%20to%20avoid%20100%25%20CPU%20usage&amp;amp;pageId=27&amp;amp;anchor=robots.txt." class=" shareHeaderAnchor" aria-labelledby="user-content-robots.txt."&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p mlp="50"&gt;The last step of the sitemap implementation was to notify every search engine about our changes. We added the following string to robots.txt&lt;br /&gt; Sitemap: &lt;a href="https://yourstore.com/sitemap-index.xml" rel="noopener noreferrer" target="_blank" mlp="51"&gt;https://yourstore.com/sitemap-index.xml&lt;/a&gt; &lt;span class="fabric-icon ms-Icon--NavigateExternalInline font-size" role="presentation" aria-hidden="true"&gt; &lt;/span&gt;&lt;/p&gt;
&lt;h2 id="user-content-results" mlp="52"&gt;Results&lt;a href="https://ki.visualstudio.com/nop39/_wiki/wikis/nop39.wiki?wikiVersion=GBwikiMaster&amp;amp;_a=edit&amp;amp;pagePath=%2FnopCommerce%20SEO%20sitemap%202020%20%2B%20Case%20to%20avoid%20100%25%20CPU%20usage&amp;amp;pageId=27&amp;amp;anchor=results" class=" shareHeaderAnchor" aria-labelledby="user-content-results"&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul mlp="53"&gt;
&lt;li mlp="54"&gt;CPU usage drops till 16-30%&lt;/li&gt;
&lt;li mlp="56"&gt;Our marketers called to us and ask what did we do with site and why our PageRank significantly increased))).&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:22</guid><link>http://localhost:15537/dynamics-crm-issues-error-when-trying-to-saveread-a-record-in-microsoft-dynamics-crm-the-specified-user-is-either-disabled-or-is-not-a-member-of-any-business-unit</link><title>Error when trying to read/save in Microsoft Dynamics CRM  Online by using nopCommerce Sync plugin</title><description>&lt;h2&gt;Symptoms Error when trying to read/save a record in Microsoft CRM Online: "The specified user is either disabled or is not a member of any business unit"&lt;/h2&gt;
&lt;p&gt;This can happen when there is an external app try to read/save an entity and the app is set to execute under the context of a user that is no longer enabled in the system, or you don't have an active user with your app id. &lt;img class="img-fluid" src="/content/images/uploaded/Sync/OnlineCrm.png" alt="OnlineCrm.png" /&gt; It looks like we need to create a new user with our app id but the problem is to make it work we will need to enable the user and to enable it we will need to buy a licence. I suppose it's ~50 USD per month. Do I need it for trial/test version of CRM that I need just to implement a simple connector?&lt;/p&gt;
&lt;p&gt;There is an app that fires when an WhoAmI request and contact is saved. The actions performed by the app are executed under the context of the user named in the identity of the app, not the user that is performing the “Save” action.&lt;/p&gt;
&lt;p&gt;If the user named in the execution context of the plugin is disabled, this can cause record saving actions to fail for other users.&lt;/p&gt;
&lt;h2&gt;Resolution Locate the plugins for the affected entity by performing the steps outlined below:&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Open Advanced Find in Dynamics CRM&lt;/li&gt;
&lt;li&gt;Change the “Look For” drop-down in Advanced Find to: SDK Message Processing Steps&lt;/li&gt;
&lt;li&gt;Under SDK Message Processing Steps, select Impersonating User field - Contains Data and Click on Results&lt;/li&gt;
&lt;li&gt;Locate the affected entity under the Primary Object Type Code column&lt;/li&gt;
&lt;li&gt;Check the custom plugin which is installed for the affected entity in the first column&lt;/li&gt;
&lt;li&gt;Note the Impersonating User for this custom plugin, and close the Advanced Find window&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Check to see if the impersonating user for this custom plugin is disabled in CRM Online by performing the steps outlined below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Within the Dynamics CRM web interface, Click on Settings, click on Administration, click on Users&lt;/li&gt;
&lt;li&gt;Change the view to Disabled Users, and check for the user that was listed as the Impersonating User on the plugin&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Enable this disabled user by performing the steps outlined below:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Select this disabled user&lt;/li&gt;
&lt;li&gt;On the ribbon you will find enable button&lt;/li&gt;
&lt;li&gt;Click on the enable button&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;More Information&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You can also find all the custom plugins installed in your CRM Online instance under Settings, click on Customizations, click on Customize the System, and select Plug-in Assemblies.&lt;/li&gt;
&lt;li&gt;Even the System Administrator will get the same error message.&lt;/li&gt;
&lt;/ol&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:21</guid><link>http://localhost:15537/how-to-add-taxid-att-in-product-details-import-for-nopcommerce-sync-plugin</link><title>How to add TaxId att in product details import for nopCommerce Sync plugin</title><description>&lt;p&gt;Base on source data for TaxId we can have different import scenarios. We will show in this article how to map TaxCategoryId and use Lookup and TableLookup conversion types.&lt;/p&gt;
&lt;p&gt;1. nopCommerce TaxCategoryId is used in your Data Source for products&lt;/p&gt;
&lt;p&gt;It's a simplest scenario. We will need just to specify mapping for TaxCategoryId in ImportProducts task by adding SourceField att with xpath for your XML element(for example "./taxid")&lt;/p&gt;
&lt;pre&gt;&lt;code class="json"&gt;{
"SourceField": "./taxid",
"EntityField": "TaxCategoryId"
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2. nopCommerce TaxCategory.Name is used in your Data Source for products&lt;/p&gt;
&lt;p&gt;We will need to use TableLookup conversion here.&lt;/p&gt;
&lt;p&gt;- Add TaxCategoryConvertion to the Conversions array&lt;/p&gt;
&lt;pre&gt;&lt;code class="json"&gt;{
"Name": "TaxCategoryConvertion",
"Type": "TableLookup",
"IdColumnName": "Id",
"ValueColumnName": "Name",
"TableName": "TaxCategory"
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;- Specify conversion for your mapping&lt;/p&gt;
&lt;pre&gt;&lt;code class="json"&gt;{
"SourceField": "./taxname",
"EntityField": "TaxCategoryId",
"ConversionName": "TaxCategoryConvertion"
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;3. External Tax Names is used in your Data Source for products&lt;/p&gt;
&lt;p&gt;If you're not planning to change tax categories dynamically, we can use Lookup conversion here to map your external names to nopCommerce TaxCategoryId.&lt;/p&gt;
&lt;p&gt;- Add TaxCategoryConvertion to the Conversions array&lt;/p&gt;
&lt;pre&gt;&lt;code class="json"&gt;
{
"Name": "TaxCategoryConvertion",
"Type": "Lookup",
"Maps": {
"Electronics &amp;amp; Software": "2",
}
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;- Specify conversion for your mapping&lt;/p&gt;
&lt;pre&gt;&lt;code class="json"&gt;{
"SourceField": "./taxname",
"EntityField": "TaxCategoryId",
"ConversionName": "TaxCategoryConvertion"
},
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Also, you can create your own conversion for more complex scenario..&lt;br /&gt; For example, if you need to have lookup in your external system or add Tax Categories to nopCommerce dynamically.&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:23</guid><link>http://localhost:15537/how-to-setup-dynamics-365-app-without-requiring-a-licensed-user</link><title>How to setup Dynamics 365 app without requiring a licensed user</title><description>&lt;p&gt;&lt;br /&gt;1. Follow &lt;a href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/walkthrough-register-dynamics-365-app-azure-active-directory"&gt;these steps&lt;/a&gt; by Microsoft to Register a Dynamics 365 for Customer Engagement app with Azure Active Director  and take note of the “Application ID” of the application you just created&lt;br /&gt;2. Follow the instructions &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal#get-application-id-and-authentication-key"&gt;here&lt;/a&gt; for creating a security key for the app you registered the step before and note down the generated “security key” &lt;br /&gt;3. On your Dynamics 365 instance you want this to access go to Settings &amp;gt; Security &amp;gt; Users&lt;br /&gt;4. On the view selector, select “Application Users”&lt;br /&gt; &lt;img class="img-fluid" src="/content/images/uploaded/Sync/MsCrm/ApplicationUsers.png" /&gt; &lt;br /&gt;5. Select “New”&lt;br /&gt;6. On the create new user form, if not already selected, change the form used to “User:application user”&lt;br /&gt; &lt;img class="img-fluid" src="/content/images/uploaded/Sync/MsCrm/ApplicationUser.png" /&gt; &lt;br /&gt;7. Create the new user&lt;br /&gt;a. Username: give it a username&lt;br /&gt;b. Application ID: this will be the application id of the Azure app you registered and took note of earlier&lt;br /&gt;c. Full Name: give it a full name&lt;br /&gt;d. Primary Email: give it an email address&lt;br /&gt;8. After the user is created, like normal user, accounts it will need to be given a security role, this can be either one of the out of box security roles or my recommendation is to create a security role that just has the permissions required for the app to function as required.&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:16</guid><link>http://localhost:15537/sync-tutorial-1-installing-nopcommerce-sync-cloud-plugin-and-example-of-usage</link><title>nopCommerce - Installing Sync &amp; Cloud plugin</title><description>&lt;p&gt;1. extract plugins.&lt;br /&gt; 2. copy plugins into your "nopCommerce\Plugins" directory.&lt;br /&gt; 3. login as admin&lt;br /&gt; 4. reStart nopCommerce application.&lt;br /&gt; 5. go to admin area-&amp;gt;configuration-&amp;gt;Plugins&lt;br /&gt; 6. install Core plugin from your admin panel, then Cloud storage, then Azure, then Sync plugin&lt;br /&gt;&lt;img class="img-fluid" width="1000" height="334" alt="" src="/content/images/uploaded/Tutorial/Sync/Cloud1.png" /&gt;&lt;/p&gt;
&lt;p&gt;7. Create Blob Storage Account&lt;br /&gt;&lt;img class="img-fluid" width="1000" height="709" alt="" src="/content/images/uploaded/Tutorial/Sync/Cloud2.png" /&gt;&lt;/p&gt;
&lt;p&gt;8. Create Container for pictures and separate container for thumb images&lt;br /&gt;&lt;img class="img-fluid" width="1000" height="407" alt="" src="/content/images/uploaded/Tutorial/Sync/Cloud3.png" /&gt;&lt;/p&gt;
&lt;p&gt;9. Copy Azure Blob Settings&lt;br /&gt;&lt;img class="img-fluid" width="1000" height="690" alt="" src="/content/images/uploaded/Tutorial/Sync/Cloud4.png" /&gt;&lt;/p&gt;
&lt;p&gt;10. Insert Settings&lt;br /&gt;&lt;img class="img-fluid" width="1000" height="255" alt="" src="/content/images/uploaded/Tutorial/Sync/Cloud5.png" /&gt;&lt;/p&gt;
&lt;p&gt;11. Created DB backup and change Storage Provider&lt;br /&gt;&lt;img class="img-fluid" width="1000" height="270" alt="" src="/content/images/uploaded/Tutorial/Sync/Cloud6.png" /&gt;&lt;/p&gt;
&lt;p&gt;12. Open /Sync/Mapping page and create "Category import" task&lt;br /&gt; Data Source = Xml Import&lt;br /&gt; Xml File Path = \Plugins\DevPartner.Misc.Sync\Xml\XmlDataNopDevV2.xml&lt;br /&gt; Xml Map Path = ROW&lt;br /&gt; Import Task Name = Category import&lt;br /&gt; Import Shedule Task = Once per night&lt;br /&gt; nopCommerce Entity = Category&lt;/p&gt;
&lt;p&gt;Entity Field:&lt;br /&gt; Name = ./Categories&lt;br /&gt; SeName = ./Categories. Click Advance Edit and choose "Conversion Type"=translite&lt;br /&gt; ExtId = ./Categories&lt;/p&gt;
&lt;p&gt;13. Create Manufacture import task&lt;br /&gt; Data Source = Xml Import&lt;br /&gt; Xml File Path = \Plugins\DevPartner.Misc.Sync\Xml\XmlDataNopDevV2.xml&lt;br /&gt; Xml Map Path = ROW&lt;br /&gt; Import Task Name = Manufacture import&lt;br /&gt; Import Shedule Task = Once per night&lt;br /&gt; nopCommerce Entity = Manufacture&lt;/p&gt;
&lt;p&gt;Entity Field:&lt;br /&gt; Name = ./Manufacturers&lt;br /&gt; SeName = ./Manufacturers. Click Advance Edit and choose "Conversion Type"=translite&lt;br /&gt; ExtId = ./Manufacturers&lt;/p&gt;
&lt;p&gt;14. Create Product import task&lt;br /&gt; Data Source = Xml Import&lt;br /&gt; Xml File Path = \Plugins\DevPartner.Misc.Sync\Xml\XmlDataNopDevV2.xml&lt;br /&gt; Xml Map Path = ROW&lt;br /&gt; Import Task Name = Product import&lt;br /&gt; Import Shedule Task = Once per night&lt;br /&gt; nopCommerce Entity = Product&lt;/p&gt;
&lt;p&gt;Entity Field:&lt;br /&gt; Name = ./Name&lt;br /&gt; FullDescription = ./FullDescription&lt;br /&gt; Sku = ./SKU&lt;br /&gt; ManufacturerPartNumber = ./ManufacturerPartNumber&lt;br /&gt; StockQuantity = ./StockQuantity&lt;br /&gt; DisableBuyButton = ./DisableBuyButton&lt;br /&gt; Price = ./Price. Click Advance Edit and choose "Conversion Type"=RegEx. Pattern - ^[1-9]\d*(\.\d+)?&lt;br /&gt; OldPrice = ./OldPrice&lt;br /&gt; Published = ./Published&lt;br /&gt; SeName = ./SKU. Click Advance Edit and choose "Conversion Type"=translite&lt;br /&gt; ExtId = ./SKU&lt;/p&gt;
&lt;p&gt;15. Create Product Picture Import task&lt;br /&gt; Data Source = Xml Import&lt;br /&gt; Xml File Path = \Plugins\DevPartner.Misc.Sync\Xml\XmlDataNopDevV2.xml&lt;br /&gt; Xml Map Path = product&lt;br /&gt; XSL Transporm = \Plugins\DevPartner.Misc.Sync\XsltConversion\PicturesRoger.xslt&lt;br /&gt; Import Task Name = Product Picture import&lt;br /&gt; Import Shedule Task = Once per night&lt;br /&gt; nopCommerce Entity = ProductPicture&lt;/p&gt;
&lt;p&gt;Entity Fields:&lt;br /&gt; PictureExtId = ./@PicturePath&lt;br /&gt; ProductExtId = ./@SKU&lt;/p&gt;
&lt;p&gt;16. Create CategoryProduct Import task&lt;br /&gt; Data Source = Xml Import&lt;br /&gt; Xml File Path = \Plugins\DevPartner.Misc.Sync\Xml\XmlDataNopDevV2.xml&lt;br /&gt; Xml Map Path = ROW&lt;br /&gt; Import Task Name = CategoryProduct import&lt;br /&gt; Import Shedule Task = Once per night&lt;br /&gt; nopCommerce Entity = CategoryProduct&lt;/p&gt;
&lt;p&gt;Entity Fields:&lt;br /&gt; ProductExtId = ./SKU&lt;br /&gt; CategoryExtId = ./Categories&lt;/p&gt;
&lt;p&gt;17. Create ManufactureProduct Import task&lt;br /&gt; Data Source = Xml Import&lt;br /&gt; Xml File Path = \Plugins\DevPartner.Misc.Sync\Xml\XmlDataNopDevV2.xml&lt;br /&gt; Xml Map Path = ROW&lt;br /&gt; Import Task Name = ManufactureProduct import&lt;br /&gt; Import Shedule Task = Once per night&lt;br /&gt; nopCommerce Entity = ProductManufactures&lt;/p&gt;
&lt;p&gt;Entity Fields:&lt;br /&gt; ProductExtId = ./SKU&lt;br /&gt; ManufactureExtId = ./Manufactures&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:14</guid><link>http://localhost:15537/designing-a-workflow-engine-for-nopcommerce-cms-part-7-the-process-table-and-shortcomings</link><title>Designing a Workflow Engine  for nopCommerce CMS Part 7: The Process table and Shortcomings</title><description>&lt;p&gt;&lt;em&gt;This is Part 7 of a seven-part series describing how to implement &lt;a href="http://en.wikipedia.org/wiki/Workflow" target="_top"&gt;Workflow&lt;/a&gt; Engine for nopCommerce CMS. &lt;a href="/designing-a-workflow-engine-for-nopcommerce-cms-intro"&gt;Click here for Part 1&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;Process&lt;/h3&gt;
&lt;p&gt;This table stores current StateId and some statistic information which is updated by Actions.&lt;/p&gt;
&lt;h4&gt;The Table&lt;/h4&gt;
&lt;p&gt;Let's look at the schema of the Process table:&lt;/p&gt;
&lt;p&gt;&lt;img src="/content/images/uploaded/Blog/Workflow/Process.png" alt="" width="407" height="318" /&gt;&lt;/p&gt;
&lt;h3&gt;What did we accomplish in this series?&lt;/h3&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;Shortcomings of This Design&lt;/h3&gt;
&lt;p&gt;There are a few shortcomings of this design:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We don't currently have a way to designate that a specific individual needs to perform an Action or receive an Activity.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;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&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Remember: &lt;strong&gt;this is only a models and some tables for nopCommerce CMS&lt;/strong&gt;. The design doesn't account for how this service would actually be implemented in code.&lt;/p&gt;
&lt;p&gt;Whew! That was a lot of steps! But what we ended up with was a &lt;strong&gt;generic, extensible, reusable workflow engine for nopCommerce CMS&lt;/strong&gt; that can handle a huge variety of processes.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:13</guid><link>http://localhost:15537/designing-a-workflow-engine-for-nopcommerce-cms-part-6-security</link><title>Designing a Workflow Engine  for nopCommerce CMS Part 6: Security</title><description>&lt;p&gt;This is Part 6 of a seven-part series describing how to implement &lt;a href="http://en.wikipedia.org/wiki/Workflow" target="_top"&gt;Workflow&lt;/a&gt; Engine for nopCommerce CMS. &lt;a class="western" href="/designing-a-workflow-engine-for-nopcommerce-cms-intro" target="_top"&gt;Click here for Part 1&lt;/a&gt;&lt;br /&gt; We've now got most of the Workflow tables defined, but we are still missing a few things.&lt;br /&gt; 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&lt;/p&gt;
&lt;pre&gt;&lt;code class="csharp"&gt;
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; }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;What did we accomplish?&lt;/h5&gt;
&lt;p&gt;In this part, we nailed down exactly who could perform Transition by adding &lt;strong&gt;SubjectToAcl&lt;/strong&gt; att.&lt;br /&gt; 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.&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:12</guid><link>http://localhost:15537/designing-a-workflow-engine-for-nopcommerce-cms-part-5-activities</link><title>Designing a Workflow Engine for nopCommerce CMS Part 5:  Activities</title><description>&lt;p&gt;This is Part 5 of a seven-part series describing how to implement &lt;a href="http://en.wikipedia.org/wiki/Workflow" target="_top"&gt;Workflow&lt;/a&gt; Engine for nopCommerce CMS. &lt;a class="western" href="/designing-a-workflow-engine-for-nopcommerce-cms-intro" target="_top"&gt;Click here for Part 1&lt;/a&gt;&lt;br /&gt; 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.&lt;/p&gt;
&lt;h5&gt;Activities&lt;/h5&gt;
&lt;p&gt;&lt;strong&gt;Activities&lt;/strong&gt; are things that can happen as a result of a request Entity entering a State or following a Transition.&lt;br /&gt; For example, let's see the diagram from Part 1 again.&lt;/p&gt;
&lt;p&gt;&lt;img width="250" height="434" alt="" src="/content/images/uploaded/Blog/Workflow/Diagram.png" /&gt;&lt;br /&gt; &lt;br /&gt; 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.&lt;br /&gt; 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.&lt;br /&gt; 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:&lt;/p&gt;
&lt;pre&gt;&lt;code class="csharp"&gt;
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; }
    }
}
&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;We'll use the following activities:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Send Email&lt;/strong&gt;: Specifies that we should send an email to one or more recipients.&lt;br /&gt;
&lt;pre&gt;&lt;code class="csharp"&gt;
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();
        }
    }
}
            &lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create product&lt;/strong&gt;: Specifies that we should convert entity to nopCommerce product.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create notifications&lt;/strong&gt;: Specifies that we should create notifications to subscribers according to their subscriptions preferences.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You could define quite a few more kinds of Activities, but for now we'll just use those three.&lt;/p&gt;
&lt;h5&gt;State and Transition Activities&lt;/h5&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When the Entity enters a State&lt;/li&gt;
&lt;li&gt;When the Entity follows a Transition&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;pre&gt;&lt;code class="csharp"&gt;
         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; }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;What did we accomplish?&lt;/h5&gt;
&lt;p&gt;In this post, we demonstrated what kinds of Activities can be kicked off by certain States or Transitions.&lt;br /&gt; 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 &lt;strong&gt;Security&lt;/strong&gt;.&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:11</guid><link>http://localhost:15537/designing-a-workflow-engine-for-nopcommerce-cms-part-4-actions</link><title>Designing a Workflow Engine for nopCommerce CMS Part 4: Actions</title><description>&lt;p&gt;This is Part 4 of a seven-part series describing how to implement &lt;a href="http://en.wikipedia.org/wiki/Workflow" target="_top"&gt;Workflow&lt;/a&gt; Engine for nopCommerce CMS. &lt;a class="western" href="http://dev-partner.biz/" target="_top"&gt;Click here for Part 1&lt;/a&gt;&lt;br /&gt; 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.&lt;br /&gt; Let's start by creating Actions.&lt;/p&gt;
&lt;h5&gt;Actions&lt;/h5&gt;
&lt;p&gt;Actions are things a user can perform upon an Entity.&lt;br /&gt; 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.&lt;br /&gt; Now we need the model for the Actions themselves. Actions can be used for different Workflows so our model will look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="csharp"&gt;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; }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Approve&lt;/strong&gt;: The actioner is suggesting that the entity should move to the next state.
&lt;pre&gt;&lt;code class="csharp"&gt;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();
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deny&lt;/strong&gt;: The actioner is suggesting that the entity should move to the previous state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cancel&lt;/strong&gt;: The actioner is suggesting that the entity should move to the Cancelled state in the workflow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restart&lt;/strong&gt;: The actioner suggesting that the entity be moved back to the Start state in the Workflow.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resolve&lt;/strong&gt;: The actioner is suggesting that the request be entity all the way to the Completed state.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Transition Actions&lt;/h5&gt;
&lt;p&gt;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?&lt;br /&gt; The relationship between Transition and Action is many-to-one in our case. So let’s add Action field to the Transition model.&lt;/p&gt;
&lt;pre&gt;&lt;code class="csharp"&gt;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; }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this post, we demonstrated how we can store what Actions can be performed by Customers.&lt;br /&gt; 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.&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:10</guid><link>http://localhost:15537/designing-a-workflow-engine-for-nopcommerce-cms-part-3-states-and-transitions</link><title>Designing a Workflow Engine  for nopCommerce CMS Part 3: States and Transitions</title><description>&lt;p&gt;This is Part 3 of a seven-part series describing how to implement &lt;a href="http://en.wikipedia.org/wiki/Workflow"&gt;Workflow &lt;/a&gt;Engine for nopCommerce CMS. &lt;a href="http://shop.dev-partner.biz/designing-a-workflow-engine-for-nopcommerce-cms-intro"&gt;Click here for Part 1&lt;/a&gt;&lt;br /&gt;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!&lt;/p&gt;
&lt;h5&gt;State Types&lt;/h5&gt;
&lt;p&gt;A &lt;strong&gt;State Type&lt;/strong&gt; 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:&lt;/p&gt;
&lt;p&gt;&lt;img src="/content/images/uploaded/Blog/Workflow/Workflow_StateType.png" alt="" width="410" height="174" /&gt;&lt;/p&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;p&gt;&lt;img src="/content/images/uploaded/Blog/Workflow/Workflow_StateType_Items.png" alt="" width="846" height="167" /&gt;&lt;/p&gt;
&lt;p&gt;Here's the reasoning for each of these types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Should only be one per workflow. This state is the state into which a new Entity is placed when it is created.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Default: &lt;/strong&gt; A regular state with no special designation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Complete: &lt;/strong&gt;A state signifying that any Entity in this state have completed normally.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Denied: &lt;/strong&gt;A state signifying that any Entity in this state has been denied (e.g. never got started and will not be worked on).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cancelled: &lt;/strong&gt;A state signifying that any Entity in this state has been cancelled (e.g. work was started but never completed).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Auto transition: &lt;/strong&gt;A state signifying that any Entity in this state should be implemented associated action and entity should be transited to the next state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wait: &lt;/strong&gt;A state signifying that any Entity in this state have been assigned to somebody and waited any action.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Every State must have exactly one of these State Types. But what makes a State?&lt;/p&gt;
&lt;h5&gt;States&lt;/h5&gt;
&lt;p&gt;A &lt;strong&gt;State&lt;/strong&gt; is &lt;strong&gt;a position in the Workflow that a given Entity can be in at any given moment&lt;/strong&gt;. States are unique to Workflow, and each State has a name, a description, and a type. Our State model looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="csharp"&gt;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; }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;IMPORTANT NOTE&lt;/strong&gt;: We should add StateType to AttExtRef before converting model to our DB.&lt;/p&gt;
&lt;pre&gt;&lt;code class="sql"&gt;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 &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h5&gt;Transitions&lt;/h5&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;Transition&lt;/strong&gt; is &lt;strong&gt;a path between two States that shows how an Entity can travel between them&lt;/strong&gt;. Transitions are unique to Workflow. Our Transition model looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="csharp"&gt;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; }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h5&gt;What did we accomplish?&lt;/h5&gt;
&lt;p&gt;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.&lt;br /&gt; 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.&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:9</guid><link>http://localhost:15537/designing-a-workflow-engine-for-nopcommerce-cms-part-2-the-workflow-model</link><title>Designing a Workflow Engine  for nopCommerce CMS Part 2: The Workflow Model</title><description>&lt;p&gt;This is Part 2 of a seven-part series describing how to implement &lt;a href="http://en.wikipedia.org/wiki/Workflow"&gt;Workflow &lt;/a&gt;Engine for nopCommerce CMS.&lt;a href="http://shop.dev-partner.biz/designing-a-workflow-engine-for-nopcommerce-cms-intro"&gt; Click here for Part 1&lt;/a&gt;&lt;br /&gt; Before we can design anything else in this Workflow Engine, we first need to define what exactly makes a Workflow.&lt;/p&gt;
&lt;h5&gt;The Workflow&lt;/h5&gt;
&lt;p&gt;A &lt;strong&gt;Workflow&lt;/strong&gt; is the &lt;strong&gt;collection of all other data that is unique to a group of users and how they want their request Entities approved&lt;/strong&gt;. In our design, a Workflow is infrastructure that is used to define and associate most other information.&lt;/p&gt;
&lt;p&gt;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 &lt;strong&gt;DPModel&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="csharp"&gt;
namespace DevPartner.Nop.Plugin.Core.Models.Workflow
{
    [SystemName("Workflow")]
    [Parent("System/Workflow/Workflow")]
    [AdminMenu("DevCommerce/Workflow/Workflow")]
    public class WorkflowModel : DPModel
    {
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;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.&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:8</guid><link>http://localhost:15537/designing-a-workflow-engine-for-nopcommerce-cms-intro</link><title>Designing a Workflow Engine for nopCommerce CMS: Intro</title><description>&lt;p&gt;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:&lt;br /&gt; 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?&lt;br /&gt; We realized that these processes were essentially &lt;a href="http://en.wikipedia.org/wiki/Finite-state_machine"&gt;finite-state machines&lt;/a&gt; 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).&lt;br /&gt; Upon further research, what we discovered was that these collections of Requests, States, Transitions, Actions, and so on had a name: they were &lt;a href="http://en.wikipedia.org/wiki/Workflow"&gt;Workflows&lt;/a&gt;.&lt;/p&gt;
&lt;h5&gt;What is a Workflow?&lt;/h5&gt;
&lt;p&gt;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:&lt;/p&gt;
&lt;p&gt;&lt;img width="227" height="399" alt="" src="/content/images/uploaded/Blog/Workflow/Diagram.png" /&gt;&lt;/p&gt;
&lt;h5&gt;Example Steps in a Workflow&lt;/h5&gt;
&lt;p&gt;Let's illustrate that flow chart another way, by enumerating the steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Buyer submits a request that says "I need a product that would allow me to repair my car."&lt;/li&gt;
&lt;li&gt;Buyer submits that request to Store Owner by using website, who checks that request correct and approves the request.&lt;/li&gt;
&lt;li&gt;Store Owner’s approval creates notifications for vendors according to their subscriptions.&lt;/li&gt;
&lt;li&gt;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.&lt;/li&gt;
&lt;li&gt;Vendor submit that proposal to Store Owner by using website, who checks that proposal request correct and approves the request.&lt;/li&gt;
&lt;li&gt;Store Owner’s approval send notifications to buyer with orders to begin purchasing.&lt;/li&gt;
&lt;li&gt;If Store Owner approves the proposal, it is marked initial request complete, and no more action can be taken against it.&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;Lots of Similarity&lt;/h5&gt;
&lt;p&gt;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.&lt;br /&gt; After reviewing several of the currently-existing workflows, our team discovered that they all had similar components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;different types of&lt;/strong&gt; &lt;strong&gt;entities&lt;/strong&gt; that is reviewed, approved, or implemented by various people.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;set of highly-variable data&lt;/strong&gt; that was associated to each entity.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;series of decisions (called a Workflow)&lt;/strong&gt; that determine who was next going to review the Entity or action which should be implemented.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;set of notifications&lt;/strong&gt; that could go to various groups of people.&lt;/li&gt;
&lt;li&gt;A small number of people that were &lt;strong&gt;in charge of the Workflow itself&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Designing a Workflow Engine&lt;/h5&gt;
&lt;p&gt;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):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="/designing-a-workflow-engine-for-nopcommerce-cms-intro"&gt;Part 1: Intro&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="designing-a-workflow-engine-for-nopcommerce-cms-part-2-the-workflow-model"&gt;Part 2: The Workflow Model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/designing-a-workflow-engine-for-nopcommerce-cms-part-3-states-and-transitions"&gt;Part 3: States and Transitions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/designing-a-workflow-engine-for-nopcommerce-cms-part-4-actions"&gt;Part 4: Actions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/designing-a-workflow-engine-for-nopcommerce-cms-part-5-activities"&gt;Part 5: Activities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/designing-a-workflow-engine-for-nopcommerce-cms-part-6-security"&gt;Part 6: Security&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/designing-a-workflow-engine-for-nopcommerce-cms-part-7-the-process-table-and-shortcomings"&gt;Part 7: The Process table and Shortcomings&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;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.&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:1</guid><link>http://localhost:15537/creating-custom-nopcommerce-cloudstorage-provider</link><title>Creating custom CloudStorage provider</title><description>&lt;p&gt;To create a new Storage Provider, which will be used in &lt;strong&gt;CloudStorage&lt;/strong&gt; plugin use &lt;strong&gt;ItPartner.Nop.Plugin.Misc.CloudStorage.CustomProvider&lt;/strong&gt; project as source.&lt;/p&gt;
&lt;p&gt;The process can be divided into 4 major steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Set system name of your provider and path to it's dll.&lt;br /&gt;See &lt;code&gt;CustomProviderPlugin.cs&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="prettyprint linenums"&gt;&lt;code&gt;public static readonly string PROVIDER_SYSTEM_NAME = "CustomProvider";
public static readonly string PROVIDER_DIRECTORY_PATH = "~/Plugins/ItPartner.Misc.CloudStorage.CustomProvider/";
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set you provider's initializator which is used to register and access you provider in CloudStorage plugin.&lt;br /&gt;See &lt;code&gt;Services/CustomProviderServiceInitializer.cs&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="prettyprint linenums"&gt;&lt;code&gt;public class CustomProviderServiceInitializer : ICloudStorageProviderInitializer
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It should return instance of provider service for each storage type: pictures, downloads and content files:&lt;/p&gt;
&lt;pre class="prettyprint linenums"&gt;&lt;code&gt;public ICloudStorageProviderService GetPictureProvider()
{
    return _customeProviderPictureService;
}

public ICloudStorageProviderService GetDownloadProvider()
{
    return _customeProviderDownloadService;
}

public ICloudStorageProviderService GetContentProvider()
{
    return _customeProviderContentService; 
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Change configuration model, view and controller's methods . &lt;br /&gt; On &lt;code&gt;Controllers/CustomProviderController.cs&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="prettyprint linenums"&gt;&lt;code&gt;public ActionResult Configure()
{
    var providerSettings = _settingService.LoadSetting&amp;lt;CustomProviderSettings&amp;gt;();

    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);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Change the &lt;code&gt;Models/ConfigurationModel.cs&lt;/code&gt; and &lt;code&gt;Views/CustomProvider/_ProviderSettings.cshtml&lt;/code&gt; according to your settings&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add logic to provider's service. &lt;br /&gt;On &lt;code&gt;Services/CustomProviderService.cs&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="prettyprint linenums"&gt;&lt;code&gt;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
}

//...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;pre class="prettyprint linenums"&gt;&lt;code&gt;private readonly string _container;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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!&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:2</guid><link>http://localhost:15537/sitecore-faq</link><title>Sitecore FAQ</title><description>&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;On what sitecore versions your developers are familiar with? &lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We did website based on Sitecore 6.x- Sitecore 7.x.&lt;/p&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;strong&gt;Have you done any MVC Sitecore projects or only webforms based?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All internal projects were based on MVC. Other our projects were based on webforms.&lt;/p&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;strong&gt;I assume, you have a Sitecore partner license?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;strong&gt;What is minimum contract length for your staff?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;strong&gt;Do you use a work monitoring software that we can log into as necessary, and view in real-time?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Yes, we use TimeDoctor software&lt;/p&gt;
&lt;ol start="6"&gt;
&lt;li&gt;&lt;strong&gt;What is the speed of internet connection?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I don’t know exactly but I’m sure that it’ll cover all your needs.&lt;/p&gt;
&lt;ol start="7"&gt;
&lt;li&gt;&lt;strong&gt;Do you charge some extra costs for location of staff in your physical office? (in case they work from home)&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;They work from our office and we have some space for a new people.&lt;/p&gt;
&lt;ol start="8"&gt;
&lt;li&gt;&lt;strong&gt;Guarantee/replacement of staff - what is the procedure if we are unhappy with individual staff performance?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;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&lt;/p&gt;
&lt;ol start="9"&gt;
&lt;li&gt;&lt;strong&gt;Do you have security protocols that can protect our data?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We can sign NDA. We can use your example or we can provide you with our templates.&lt;/p&gt;
&lt;ol start="10"&gt;
&lt;li&gt;&lt;strong&gt;Which sitecore modules did you use?&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;List of Sitecore modules:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Sitecore Rocks&lt;/li&gt;
&lt;li&gt;Web Forms for Marketers&lt;/li&gt;
&lt;li&gt;E-Commerce Services&lt;/li&gt;
&lt;li&gt;Social Connected&lt;/li&gt;
&lt;li&gt;dtSearch&lt;/li&gt;
&lt;li&gt;SEO Toolkit&lt;/li&gt;
&lt;li&gt;Sitecore DMS&lt;/li&gt;
&lt;li&gt;E-mail Campaign Manager&lt;/li&gt;
&lt;li&gt;Calendar&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;List of shared source modules:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;User Interaction: Google Maps, Page Rate&lt;/li&gt;
&lt;li&gt;Web Site Optimization: Meta-Tags, Taxonomy Module, Custom Item Generator&lt;/li&gt;
&lt;li&gt;Social: EviTwitter, WeBlog, Telligent Community Integration&lt;/li&gt;
&lt;li&gt;Productivity Tools: Sublayout Parameter Helper, Sitecore Stuff, Item Translator, News Mover&lt;/li&gt;
&lt;li&gt;Search: Index Viewer, Lucene Search, Advanced Database Crawler&lt;/li&gt;
&lt;li&gt;Media: Sitecore Field Types&lt;/li&gt;
&lt;li&gt;Link Management: Link Provider&lt;/li&gt;
&lt;li&gt;Rules: Item Naming Rules, Mobile Device Detector, Geo Lite Resolver&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;strong&gt;Benefits of working with us&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;• You don’t need to buy software, hardware and other infrastructure;&lt;/p&gt;
&lt;p&gt;• We have always improved our knowledge;&lt;/p&gt;
&lt;p&gt;• Our team has more than 5000 hours of success development on nopCommerce platform&lt;/p&gt;
&lt;p&gt;• Our team has more than 1500 hours of success development on Sitecore platform&lt;/p&gt;
&lt;p&gt;• 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).&lt;/p&gt;
&lt;div id="dc_vk_code" style="display: none;"&gt; &lt;/div&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:7</guid><link>http://localhost:15537/nopcommerce-erp-fsd-weservice</link><title>nopCommerce ERP FSD WeService</title><description>&lt;h2&gt;General description&lt;/h2&gt;
&lt;p&gt;The Web service will be implemented by using Web API.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;Data will be represented by an object serialized in json and encrypted by the public key.&lt;/p&gt;
&lt;p&gt;Token will be a string that has been encrypted by the public key.&lt;/p&gt;
&lt;p&gt;Encryption / decryption will be performed using the RSACryptoServiceProvider.&lt;/p&gt;
&lt;p&gt;To generate a key pair the developer can use&lt;/p&gt;
&lt;pre&gt;using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider()) 
{ 
publicKey = rsa.ToXmlString(false); 
privateKey = rsa.ToXmlString(true); 
} 
&lt;/pre&gt;
&lt;p&gt;The developer can work with JSON using the JavaScriptSerializer&lt;/p&gt;
&lt;p&gt;An algorithm of generating data to be send:&lt;/p&gt;
&lt;p&gt;Create an object&lt;/p&gt;
&lt;pre&gt;public class MyClass 
{ 
public int ProductId; 
public int Quantity; 
} 
MyClass dataObj = new MyClass {ProductId = 10, Quantity = 100}; 
&lt;/pre&gt;
&lt;p&gt;2) Serialize an object using the JavaScriptSerializer&lt;/p&gt;
&lt;pre&gt;var serializer = new JavaScriptSerializer(); 
string message = serializer.Serialize(dataObj); 
&lt;/pre&gt;
&lt;p&gt;3) Encode a data and a token and create an object for sending&lt;/p&gt;
&lt;pre&gt;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}; 
&lt;/pre&gt;
&lt;p&gt;4) Serialize the object using JavaScriptSerializer&lt;/p&gt;
&lt;pre&gt;string result = Serializer.Serialize(param); 
&lt;/pre&gt;
&lt;p&gt;5) Send the result.&lt;/p&gt;
&lt;h2&gt;An algorithm for receiving data:&lt;/h2&gt;
&lt;p&gt;1) Get the data from the request content&lt;/p&gt;
&lt;pre&gt;string contentResult = string.Empty; 
Request.Content.ReadAsStringAsync().ContinueWith((task) =&amp;gt; 
{ 
contentResult = task.Result; 
}); 
&lt;/pre&gt;
&lt;p&gt;2) Deserialize a json string to object&lt;/p&gt;
&lt;pre&gt;var serializer = new JavaScriptSerializer(); 
MyParam encryptedData = serializer.Deserialize&amp;lt;MyParam&amp;gt;(contentResult); 
&lt;/pre&gt;
&lt;p&gt;3) Decrypt the token&lt;/p&gt;
&lt;pre&gt;using (var rsa = new RSACryptoServiceProvider()) 
{ 
rsa.FromXmlString(privateKey); 
var token = Encoding.UTF8.GetString(rsa.Decrypt(encryptedData.Token, true)); 
} 
&lt;/pre&gt;
&lt;p&gt;4) Compare the resulting token to the original. If they do not match, then send an error message. If they match, go further.&lt;/p&gt;
&lt;p&gt;5) Decrypting data&lt;/p&gt;
&lt;pre&gt;string dataStr = string.Empty; 
using (var rsa = new RSACryptoServiceProvider()) 
{ 
rsa.FromXmlString(privateKey); 
dataStr = Encoding.UTF8.GetString(rsa.Decrypt(encryptedData.Data, true)); 
} 
&lt;/pre&gt;
&lt;p&gt;6) Deserialize the final json to an object&lt;/p&gt;
&lt;pre&gt;MyClass dataObj = serializer.Deserialize&amp;lt;MyClass&amp;gt;(dataStr); 
&lt;/pre&gt;
&lt;h2&gt;Actions&lt;/h2&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;AddUpdateProductToCart&lt;/h3&gt;
&lt;h4&gt;Input parameters:&lt;/h4&gt;
&lt;p&gt;· Product ID – a NopCommerce product identifier.&lt;/p&gt;
&lt;p&gt;· Quantity –product quantity.&lt;/p&gt;
&lt;h4&gt;Output parameters:&lt;/h4&gt;
&lt;p&gt;· Status – true, if necessary quantity of products is available, false – if not available.&lt;/p&gt;
&lt;p&gt;· Product ID – null.&lt;/p&gt;
&lt;p&gt;· Stock quantity – null.&lt;/p&gt;
&lt;p&gt;If Status is equal to value false, then the following should be added to output parameters&lt;/p&gt;
&lt;p&gt;o Product ID – a NopCommerce product identifier;&lt;/p&gt;
&lt;p&gt;o Stock quantity – a product quantity which is available.&lt;/p&gt;
&lt;h4&gt;Description:&lt;/h4&gt;
&lt;p&gt;The method verifies the value Stock quantity for the specified product ID and compares this value to the quantity parameter.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;When the user changes the quantity of the products in the basket, the plugin sends a request to the web service, causing AddUpdateProductToCart.&lt;/p&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;p&gt;When a user makes a purchase and clicks Checkout, the plugin sends a request to a web service to the remote method CheckoutCart.&lt;/p&gt;
&lt;h3&gt;ChecoutCart&lt;/h3&gt;
&lt;h4&gt;Input parameters:&lt;/h4&gt;
&lt;p&gt;· List&amp;lt;Product ID, Quantity&amp;gt; - a list of NopCommerce product identifiers and quantities.&lt;/p&gt;
&lt;h4&gt;Output parameters:&lt;/h4&gt;
&lt;p&gt;· 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.&lt;/p&gt;
&lt;p&gt;· List&amp;lt;Product ID, Stock quantity&amp;gt; - null.&lt;/p&gt;
&lt;p&gt;If Status has a value false, then the following should be added to output parameters&lt;/p&gt;
&lt;p&gt;o List&amp;lt;Product ID, Stock quantity&amp;gt; - a list of products and quantities that are available.&lt;/p&gt;
&lt;h4&gt;Description:&lt;/h4&gt;
&lt;p&gt;Checks values ​​Stock quantity for each product from the list and compares them with the values ​​of quantity.&lt;/p&gt;
&lt;p&gt;When a user submits a request and clicks Confirm, the plugin sends a request to a web server to the remote method ConfirmOrder.&lt;/p&gt;
&lt;h3&gt;BeforeConfirmOrder&lt;/h3&gt;
&lt;h4&gt;Input parameters:&lt;/h4&gt;
&lt;p&gt;· List&amp;lt;Product ID, Quantity&amp;gt; - a list of products identifiers and their quantities.&lt;/p&gt;
&lt;h6&gt;Output parameters:&lt;/h6&gt;
&lt;p&gt;· Status – false, if the request can't be satisfied at least on one point, true – if all products are available.&lt;/p&gt;
&lt;p&gt;· List&amp;lt;Product ID, Stock quantity&amp;gt; - null.&lt;/p&gt;
&lt;p&gt;· ERP Order ID – a ERP order identifier.&lt;/p&gt;
&lt;p&gt;If Status has a value false, then the following should be added to output parameters&lt;/p&gt;
&lt;p&gt;o List&amp;lt;Product ID, Stock quantity&amp;gt; - a list of products and their quantities that are available.&lt;/p&gt;
&lt;h4&gt;Description:&lt;/h4&gt;
&lt;p&gt;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.&lt;/p&gt;
&lt;h3&gt;AfterConfirmOrder&lt;/h3&gt;
&lt;h4&gt;Input parameters:&lt;/h4&gt;
&lt;p&gt;· ERP Order ID - a ERP order identifier.&lt;/p&gt;
&lt;p&gt;· NC Order ID – a NopCommerce order identifier.&lt;/p&gt;
&lt;p&gt;· NC Order status – a NopCommerce order status (Pending, Processing, Complete, Cancelled)&lt;/p&gt;
&lt;h4&gt;Output parameters:&lt;/h4&gt;
&lt;p&gt;· Status – true, if a data is successfully received.&lt;/p&gt;
&lt;h4&gt;Description:&lt;/h4&gt;
&lt;p&gt;It adds a NopCommerce order identifier and status to a ERP order.&lt;/p&gt;
&lt;h3&gt;ChangeOrderStatus&lt;/h3&gt;
&lt;h4&gt;Input parameters:&lt;/h4&gt;
&lt;p&gt;· NC Order ID – a NopCommerce order identifier.&lt;/p&gt;
&lt;p&gt;· NC Order Status – a NopCommerce order status (Pending, Processing, Complete, Cancelled)&lt;/p&gt;
&lt;h4&gt;Output parameters:&lt;/h4&gt;
&lt;p&gt;· Status – true, if the order is sent to a customer.&lt;/p&gt;
&lt;h4&gt;Description:&lt;/h4&gt;
&lt;p&gt;It changes the order status.&lt;/p&gt;
&lt;p&gt;To periodically synchronize the items in the plugin the Scheluled Task will work. This task will call a remote method SyncProducts.&lt;/p&gt;
&lt;h3&gt;SyncProducts&lt;/h3&gt;
&lt;h4&gt;Input parameters:&lt;/h4&gt;
&lt;p&gt;· List&amp;lt;Product ID&amp;gt; - a list of products identifiers.&lt;/p&gt;
&lt;h4&gt;Output parameters:&lt;/h4&gt;
&lt;p&gt;· List&amp;lt;Product ID, Stock quantity&amp;gt; - a list of products and their quantities that are available.&lt;/p&gt;
&lt;h4&gt;Description:&lt;/h4&gt;
&lt;p&gt;Receives a value Stock quantity for each NopCommerce Product ID from ERP, generates a list of products and their quantities and sends back.&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:6</guid><link>http://localhost:15537/sitecore-for-marketing-specialist</link><title>Sitecore for marketing specialist</title><description>&lt;p&gt;It is extremely difficult to overestimate a website and a corporate site as an important marketing tool. We find information on the web, we are engaged in a dialogue, and maintain communication with colleagues and close ones; and, the main thing, we also make choice on the network. Feedback, promotional materials, advertising campaigns, information on the website — all that leads the customer to informed choice of a product or a service, and marketing is assigned with the task to competently analyze and manage all types of online communications with the customer.&lt;/p&gt;
&lt;p&gt;At the dawn of the Internet, the first content management systems proposed purely editor’s role to marketing specialists. Wrote a text, and then published. Today, a similar approach to work with the corporate site does not add value at best and, at worst, makes a lot of harm. Namely, the unique trade offer of Sitecore has been built on such understanding.&lt;/p&gt;
&lt;p&gt;It is the adequacy to up-to-date challenges and vision of strategic task solutions for marketing that Sitecore is chosen by market leaders. The developers of this platform are focused on presentation of a wide range of possibilities, tools, and methods in the simplest possible manner.&lt;/p&gt;
&lt;p&gt;Sitecore combines the classical system for content management (the same “wrote – published”), as well as an expanded analytical tool kit and a set for marketing automation. All that is rather easy to use, a marketing specialist being the high-priory target audience for Sitecore.&lt;/p&gt;
&lt;p&gt;One of the platform parts, web analytics, helps understand who visits the corporate site and what their aims are. Beside the standard functionality, like geography of the site visitors, it is possible to learn what visitors have been looking for, the results they have achieved, and the content, appearing to be the most useful. All that is undoubtedly important for understanding conversion processes and, with the help of reporting systems, assists in getting the comprehensive view of the current situation, as well as in reacting to it immediately.&lt;/p&gt;
&lt;p&gt;For Sitecore, it is important not only to analyze users but personalize content in compliance with the user profile. Sitecore reveals compliance with the profile assigned and shows only personalized content. Example: by previous actions, the digital marketing system will determine whether you a man or a woman, and will offer only men’s or women’s products in the campaigns’ part of the page.&lt;/p&gt;
&lt;p&gt;Detailed user profiles with personalization of the content will lead to increase in conversion and resource loyalty — the site satisfies all requirements and speaks one language with them.&lt;/p&gt;
&lt;p&gt;When marketing is assigned with the task to generate demand and increase the number of visitors, various advertising campaigns can be used. Undoubtedly, it is important to track the analysis and efficiency of such campaigns, in order to adjust targets and save the budget. Sitecore enables to learn the actual ROI for such campaigns. The marketing toolkit helps obtain target indicators and fix conversion up to the level of individual sessions. Online campaigns, context advertising systems, media advertising on partner’s sites — individual sessions are linked together through global cookies so that marketing could get a comprehensive view of each user profile, history of their visits, and preferences.&lt;/p&gt;
&lt;p&gt;Besides, one of Sitecore components enables to hold multi-variant and A/B-testing of different parts of the page that will allow marketing make informed choice in favour of the successful solution and accept the best possible variant.&lt;/p&gt;
&lt;p&gt;Nestle, Siemens, Toshiba, Mazda, and many other leading international companies have made the same informed choice in favour of Sitecore. Like any other complicated technological product, Sitecore requires expertise and attention to details at the stage of development, migration, and integration. The high level of IT Partner team proved by practice allows utilizing Sitecore functionality with maximum efficiency. And this, in its turn, helps the company marketing broaden its capabilities and gives undisputable competitive advantage in gaining customers.&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:5</guid><link>http://localhost:15537/sitecore-for-it-director</link><title>Sitecore for IT Director</title><description>&lt;p&gt;At the present stage of development, IT department faces the task of providing the company with necessary IT services. One of the marketing needs – the efficient corporate resource - requires development and on-going support by efforts of IT specialists. In fact, it is one more additional IT service that also needs to be managed and maintained. Sitecore understands it and offers the most weighted and balanced solution to IT directors for organization of the corporate resource or a group of the company websites.&lt;/p&gt;
&lt;h2&gt;Security&lt;/h2&gt;
&lt;p&gt;Sitecore utilizes the security model of .net-applications and includes tools for user authentication and authorization, as well as tools for handling authenticated users within the application. One of the key guarantees for providing security is Microsoft technology stack, the Sitecore platform being based on. Windows Server tools allow for creating the maximum secure environment for the corporate resource hosting. For Microsoft, such issues are of high priority: vulnerabilities being remedied and problems fixed in a timely manner. Products are provided with high-quality technical support and continuous updates.&lt;/p&gt;
&lt;p&gt;Besides, own tools have been implemented in Sitecore to restrict access for different user categories to work with the platform. The administrator has always the possibility to create necessary user roles and assign specific permits for work with the platform.&lt;/p&gt;
&lt;h2&gt;Scalability&lt;/h2&gt;
&lt;p&gt;Sitecore architecture allows adding power and fault-tolerance with minimal financial costs and time. From the very start, Sitecore has been developed with regard to needs of large companies and, today, it is capable of servicing thousands of simultaneous user requests. The platform provides cluster support for high load resources and a convenient management console for a large number of separate websites. All that allows the company, without serious investments into the structure, grow and expand its presence on the Internet. Besides, Sitecore supports Amazon EC2 and Windows Azure cloud platforms.&lt;/p&gt;
&lt;h2&gt;Integration and development&lt;/h2&gt;
&lt;p&gt;An important Sitecore advantage will become integration with the current infrastructure of IT services that have already been deployed in the company. So, the modular Sitecore architecture will enable to integrate the content with Sharepoint Server, and open API-interface of methods and classes - to implement any necessary interaction within the company processes without any extra efforts. The Sitecore Data Providers subsystem implements connection to database, Web service or external system, and will allow working with content, as if it were the internal documents of Sitecore.&lt;/p&gt;
&lt;p&gt;.NET-developers will appreciate the initial support of Visual Studio with Intellisense. Sitecore discloses the entire event model and enables to adjust request processing, using the capabilities of open pipeline architecture. The support of the newest .net-functions and strict separation of content from representation will become an additional means for increase in the developer's labour productivity.&lt;/p&gt;
&lt;h2&gt;IT Partner&lt;/h2&gt;
&lt;p&gt;Our company has gold and silver Microsoft competencies in the number of key infrastructure technologies, including Server Platform, Data Platform, and Software Development. Considering experience in work with Sitecore, including in the large and sophisticated “Skolkovo” project, the status of the first official partner in Russia, and availability of certified developers, we are able to provide high-quality embedding of Sitecore platform, development and adding the necessary functionality, and the follow-up technical support.&lt;/p&gt;</description></item><item><guid isPermaLink="false">urn:store:5:blog:post:4</guid><link>http://localhost:15537/my-favorite-sitecore-features</link><title>My favorite Sitecore features</title><description>&lt;p&gt;This article enlists some of my favorite peculiarities of Sitecore platform. It’s just the list of features I like in Sitecore. No assigned order or priorities here.&lt;/p&gt;
&lt;h2&gt;Asp.net&lt;/h2&gt;
&lt;p&gt;Sitecore is built over the platform of ASP.NET WebForms that allows using finished classes and controls. In the latest version, Sitecore has added support to dynamically developing ASP.NET MVC framework.&lt;/p&gt;
&lt;p&gt;In fact, Sitecore can be described as ASP.NET extension that provides a number of additional functions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;1. graphic interface;&lt;/li&gt;
&lt;li&gt;2. analytics;&lt;/li&gt;
&lt;li&gt;3. CMS capabilities (layout management, workflow, versioning, translation, publishing).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Expandability&lt;/h2&gt;
&lt;p&gt;Expandable architecture is one of the main things that distinguishes Sitecore among other CMS. In fact, CMS can satisfy any requirement of an organization. It’s important, as every customer can expand CMS, by adding functions they need. Expandable architecture is especially useful for performance of integration tasks with other systems; so, for example, integration modules for SharePoint, CRM, Word, Visual Studio etc. have been developed for Sitecore&lt;/p&gt;
&lt;p&gt;Sitecore is built on the basis of pipeline architecture. Developers like such architecture: after getting acquainted once with pipeline architecture, you fail to understand how you could work without it earlier. It’s especially important when it is necessary to expand the functional capabilities of the enterprise-level system. It is also important that beside pipeline in Sitecore one can manage events, processes, and data providers. It is possible thanks to the fact that in Sitecore you can override any entity in web.config or in files included into web.config. So, it is possible to override the existing operations, develop own application (by using Sitecore user interfaces), add functions, data type or a new pipeline.&lt;/p&gt;
&lt;h2&gt;Presentation components&lt;/h2&gt;
&lt;p&gt;A decent engine has been implemented in Sitecore to manage layouts that separates content and presentation levels. All components of the presentation layer (xsl rendering, sublayouts(ascx), web controls, method rendering) comprise caching configurations that allows tuning the system and enhances its performance by way of installing caching checkboxes on frequently used components.&lt;/p&gt;
&lt;p&gt;In Sitecore, developers are initially geared to designing finished components. The components themselves become easily adjusted. I would like to pay special attention to the possibility to write controls with the help of xslt. The possibility is trivial but implemented by far not in all CMS… Thanks to xslt, any person who knows Html can assemble a simple site based on Sitecore.&lt;/p&gt;
&lt;h2&gt;Analytics&lt;/h2&gt;
&lt;p&gt;This system module shifts the focus of development to analytics. The functions embedded initially in the system allow obtaining daily reports on achievement of marketing purposes, on whether both a new functionality and the system in general being in demand. Such functions enable to manage development and adjust marketing activities on instant-feedback basis. The possibility arises to automate works with the customers, display the content they are interested in based on actions performed by them in the system for the last year. It is possible to form the page content based on the customer geographical location or profile settings (sex, date of birth, etc.). Sitecore analytics is expandable in the same manner as Sitecore itself. For example, you can install charge-free heatmap module for analyzing usability of the site pages that allows display places on the page where a user clicks a mouse and where not. Moreover, it is possible to track actions either of all the users or of a defined group.&lt;/p&gt;
&lt;h2&gt;Modules&lt;/h2&gt;
&lt;p&gt;A great plus of Sitecore are modules written for this CMS (over 200) both by Sitecore itself and its partners. At that, about 90% of the modules are distributed charge-free and can serve an excellent base for development of own components. So, for example, if you wish to support several versions of the site language and, in so doing, you do not want to spend serious resources on a translator, then you can install Item Translator and with the help of Bing or Google provider make primary translation of your site in 1 click.&lt;/p&gt;
&lt;p&gt;We would like to mention separately Web Forms For Marketing module that allows for creating a finished form within several minutes; meanwhile, customization options for such form are practically unlimited. In order to create forms, you don’t need any programming skills: it will be enough to set up necessary fields, select required validators, assign a topic, and post necessary actions to ‘send data to Sitecore’ button. In addition, a comprehensive list of possible actions has already been assigned in the module that can be used by selecting the required from the list. In this manner, one can save the results of the form filling to the database, send them by email, perform bulk mail-out to the subscribed users, send SMS or MMS, create an interest in CRM, calculate analytical indicators, and personalize the content to be displayed for the user. Also, it will be rather easy to add new actions or validators into the form.&lt;/p&gt;</description></item></channel></rss>