Showing posts with label C#. Show all posts
Showing posts with label C#. Show all posts

Tuesday, September 8, 2020

Sitecore Experience Commerce (Generate a custom order number with policies)

Recently, I got a requirement to generate a custom order number, As the default number is a GUID. I did a similar task in Sitecore Commerce 8.2.1.  here is a link . I used a custom store procedure to generate the order number but would be very straight forward, As the requirement was to generate only random numbers for a fixed digit.

Steps to do that -

1. Create a new plugin -

2.  Give it a name let's say 

Sitecore.Plugin.CustomOrderGenerator

The plugin will look like this -  Now build the plugin


Define the policy here, I need the policy to put a Prefix and make a decision whether to generate a random number or sequential numbers



Add a reference to Sitecore.Commerce.Plugin.Catalog - Because my XC version is 9.3, I have chosen version 5.0.43

Second reference for Commerce.Plugin.Order


Replace OrderPlacedAssignConfirmationIdBlock pipeline block with your custom block



  [PipelineDisplayName("Sitecore.Commerce.Plugin.Sample.CustomOrderGeneratorBlock")]  
   public class CustomOrderGeneratorBlock : PipelineBlock<Order, Order, CommercePipelineExecutionContext>  
   {  
     private readonly FindEntitiesInListCommand _getEntitiesInListCommand;  
     public CustomOrderGeneratorBlock(FindEntitiesInListCommand findEntitiesInListCommand) : base((string)null)  
     {  
       _getEntitiesInListCommand = findEntitiesInListCommand;  
     }  
     public override Task<Order> Run(Order order, CommercePipelineExecutionContext context)  
     {  
       order.OrderConfirmationId = GenerateCustomOrderNumber(order, context, _getEntitiesInListCommand);  
       return Task.FromResult<Order>(order);  
     }  
     private string GenerateCustomOrderNumber(Order order, CommercePipelineExecutionContext context, FindEntitiesInListCommand findEntitiesInListCommand)  
     {  
       var contactComponent = order.GetComponent<ContactComponent>();  
       var orders = (IEnumerable<Order>)findEntitiesInListCommand.Process<Order>(context.CommerceContext, CommerceEntity.ListName<Order>(), 0, int.MaxValue).Result.Items;  
       var orderCount = orders.Count();  
       if (orders.Any())  
       {  
         OrderGeneratorPolicy policy = context.GetPolicy<OrderGeneratorPolicy>();  
         string nextOrderNumber;  
         if (policy.IsRandomNumber)  
         {  
           nextOrderNumber = GenerateNumber(policy.TotalDigitMin, policy.TotalDigitMax);  
         }  
         else  
         {  
           nextOrderNumber = Convert.ToString(orderCount + 1);  
         }  
         return policy.Prefix + nextOrderNumber.ToString();  
       }  
       return Guid.NewGuid().ToString("B");  
     }  
     private string GenerateNumber(int min, int max)  
     {  
       Random r = new Random();  
       int randNum = r.Next(min, max);  
       return randNum.ToString();  
     }  
   }  
When we run the order flow, We can see the result on the order confirmation page.

A few additional notes - Make sure you have registered your policies correctly.

1.  The name should be correct  Plugin.CustomOrderGenerator.PolicySet-1.0.0.json - I think the when we do the bootstrap the application Global.json file consider the ref version ( not sure) but it's better to keep the same naming convention as an example - PlugIn.Payments.Braintree.PolicySet-1.0.0.json

2. Make sure your the definition withing the file is correct and using the correct namespace, As an example below

 {  
  "$type": "Sitecore.Commerce.Core.PolicySet, Sitecore.Commerce.Core",  
  "Id": "Entity-PolicySet-CustomOrderGenerator",  
  "Version": 1,  
  "IsPersisted": false,  
  "Name": "CustomOrderGenerator",  
  "Policies": {  
   "$type": "System.Collections.Generic.List`1[[Sitecore.Commerce.Core.Policy, Sitecore.Commerce.Core]], mscorlib",  
   "$values": [  
    {  
     "$type": "Plugin.CustomOrderGenerator.OrderGeneratorPolicy,Plugin.CustomOrderGenerator",  
     "Environment": "sandbox",  
     "Prefix": "XX",  
     "IsRandomNumber": true,  
     "TotalDigitMin": 9999999,  
     "TotalDigitMax": 1000000  
    }  
   ]  
  }  
 }  


3. Add entity entry in all roles

{ "$type": "Sitecore.Commerce.Core.PolicySetPolicy, Sitecore.Commerce.Core", "PolicySetId": "Entity-PolicySet-BraintreePolicySet" },


That's so much easy, Let me know if have any questions ;) 

Friday, September 4, 2020

Sitecore Experience Commerce ( Fix for AddCartLine: Value cannot be null )

 


Recently, I got below error while adding an item into the cart -

Sitecore XP and XC Version 9.3 

 {"Lines":null,"Email":null,"Subtotal":null,"TaxTotal":null,"Total":null,
"ShippingTotal":null,"TotalAmount":0,"Shipments":null,"Payments":null,"Parties"
:null,"AccountingParty":null,"Discount":null,"PromoCodes":null,  


Investigation steps -
  1. Initially, I thought this could be related to data, so I refreshed the cache, updated the XC template and did the reindex.
  2. I verified data exits in the Solr index.
  3. Found one issue in xConnect related to model - When I browse the xConnect found model is a not correct issue, and that got fix when I updated the right model.
  4. I did the bootstrap and item sync path 
  5. I did add to cart through the postman, and it worked perfectly fine. you need to pass below details
 {  
   "cartId":"Cart01",  
   "itemId": "XXX |AW098 04|5",  
   "quantity": 1  
 }  
The issue still exists after performing all above 5 points. Finally, I have redeployed complete XP and XC website and did all steps again like commerce refresh cache, bootstrap and indexing. That also didn't resolve the issue.


 Fix - FInally, I had to restore all three databases - Master, XCGlobal and XCShared and that help us to see the add to cart functionality again.

but still, what was the issue? - After further investigation, I came to know that during the catalog import process we got below errors -

 Entity-SellableItem-7042259#Entity-SellableItem-demohandtowel1#Entity-SellableItem-demoitem1#Entity-SellableItem-DN136182#Entity-SellableItem-DN136185#Entity-SellableItem-DN136186#Entity-SellableItem-DN136188#Entity-SellableItem-DN136200#Entity-SellableItem-DN136201#Entity-SellableItem-DN136204#Entity-SellableItem-DN136207#Entity-SellableItem-DN136210#Entity-SellableItem-DN139713#Entity-SellableItem-DN139715#Entity-SellableItem-DN139716#Entity-SellableItem-DN142257#Entity-SellableItem-DN151084#Entity-SellableItem-DN142603#Entity-SellableItem-DN142604#Entity-SellableItem-DN142608#Entity-SellableItem-DN142609#Entity-SellableItem-DN151084#Entity-SellableItem-DN151248#Entity-SellableItem-DN151249#Entity-SellableItem-DN151250#Entity-SellableItem-DN151254#Entity-SellableItem-DN162370#Entity-SellableItem-DN162371#Entity-SellableItem-DN162373#Entity-SellableItem-DN162374#Entity-SellableItem-DN162375#Entity-SellableItem-DNEN96#Entity-SellableItem-eb101#Entity-SellableItem-eb102test#Entity-SellableItem-N151248#Entity-SellableItem-TestProduct123'|Environment='Entity-CommerceEnvironment-XXXXX'|Message=  
 'Violation of PRIMARY KEY constraint 'PK_VersioningEntity'.  
  Cannot insert duplicate key in object 'sitecore_commerce_storage.VersioningEntity'.  
  The duplicate key value is (0604f03b-b6a7-a7c4-72d4-23f95337b340).\r\nDuplicate key was ignored.\r\nDuplicate key was ignored.\r\nDuplicate key was ignored.\r\nThe statement has been terminated.'|Number='2627'|Procedure='sitecore_commerce_storage.InsertEntities'|Line='645']",  
       "CommerceTermKey": "SQL:blocks:AddEntities"  

and that's the issue, we ran the import process, and there was an existing reference, 

Finally, I cleaned the environment and reimported it again, and that had resolved the issue entirely.

Thursday, September 3, 2020

Sitecore Experience Commerce (Steps to configure a new currency)

 


Here are simple steps to configure new currency in Sitecore commerce (XC) -

Setup currency in XP -

Go to this path - /sitecore/Commerce/Commerce Control Panel/Shared Settings/Currency Settings/Currency Sets



Create a new currency item and choose the correct configuration, so here we have done the master configuration, Now we need to configure this currency at the store level -

Go to /sitecore/Commerce/Commerce Control Panel/Storefront Settings/Storefronts/YourStoreName/Currencies Display Adjustments/AddNewCurrencyhere



We are done with XP settings now - Let's configured the Sitecore commerce now.

Go to this path -

C:\inetpub\wwwroot\yousite.dev.local\App_Config\Include\Y.Commerce.Engine

Create patch file for below settings

 <defaultShopCurrency>USD</defaultShopCurrency>

Update the BizFx solution and update below configuration-

  "Language": "en",  
  "Currency": "USD",  
Good so here are the final steps - Need to configure the commerce engine environment policies

    {  
     "$type": "Sitecore.Commerce.Core.GlobalCurrencyPolicy, Sitecore.Commerce.Core",  
     "DefaultCurrencySet": "0F65742E-317F-44B0-A4DE-EBF06209E8EA"  
Update the Id for new items created in step first -
 CommerceAuthoring-1.0.0.json  
 CommerceMinions-1.0.0.json  
 CommerceShops-1.0.0.json   
 CommerceAuthoring-1.0.0.json  
 Don't forget to bootstrap as we have changed the configuration here. It's that much easy!

Let me know if you have any questions.

Sitecore Experience Commerce (Postorder components)

Sitecore Experience Commerce (Postorder components)

Recently, I was working on sending the order details to the backend system (SAP), and here is my experience.

Fist, You need to define your pipeline and block, Or if you have any existing feature like Order you can create a new partnership for that - I choose the minion services to pick the Order and send it to the SAP system.

The important part is how to get all the required details and send it to the backend system.

Here are some essential components which we would need to get the information



You may need to add a reference for these components -



       var contactDetails = arg.GetComponent<ContactComponent>();  
       var paymentDetails = arg.GetComponent<FederatedPaymentComponent>();  
       var fulfilmentDetails = arg.GetComponent<FulfillmentComponent>();  
       var listDetails = arg.GetComponent<ListMembershipsComponent>();  
       var listTransientDetails = arg.GetComponent<TransientListMembershipsComponent>();  

For all order line items - We can simply run a for-each loop to get the information.

  foreach (var orderLine in order.Lines)  
           {  
           }  
Fill all the properties in the object, generate the serialized JSON and send it to your backend system.

It's that much simple.

Let me know if need any detail or help on that.

Friday, May 8, 2020

Sitecore EXM configuration options and steps.

Here is my experience with EXM configuration - I got a requirement to configure the EXM.

I initially did through the SMTP and it worked fine but later on, we came to know to update it to use Sitecore email cloud.

I faced a few issues and here are the details -

Integration options -



I followed this document  - https://kb.sitecore.net/articles/947205 to configure the cloud but found a few issues.

The first

I used the same configuration, 



When I changed the URL to EU - As mentioned below.

 Geo-location     URL  
 EU     https://sparkpost-eu.cloud.sitecore.net  
 US     https://sparkpost.cloud.sitecore.net  

I got below error.


Finally, I came to know that for the cloud it would need an additional license- Ref - https://doc.sitecore.com/users/exm/100/email-experience-manager/en/index-en.html


We had also discussed to Sitecore support team and they also confirmed that it's related to licensing.







Monday, November 25, 2013

Generic functionality and sample program.

Generics refers to a technique of writing code for a class without specifying the data type that the class works with.

First we should now why we required generic

Earlier in C# 1.1 we have object programming and there we  can create object  and in case of typesafe and performace we were creating another classes.

In generic basically we are defining the datatype.

Let say.
  class Generic
    {
        T[] itemsType;
        public static string Name ="test";
    }
}
Calling the generic function
   String nameValue = "";
            nameValue = Generic<string>.Name;

Simple generic program:-
Create a class below
class Address {

        public int SrNo { get; set; }
        public string Name { get; set; }

        public Address(int srNoInput, string NameInput)
        {
            this.SrNo = srNoInput;
            this.Name = NameInput;
        }

    }

Use this class through generic functionality

       List<Address> Addresslist = new List<Address>();

            Addresslist.Add( new Address(1,"Fist"));
            Addresslist.Add( new Address(2,"Second"));
            Addresslist.Add( new Address(3,"Third"));

            foreach( Address Add in Addresslist)
            {

                Console.WriteLine("Address Number:- "  +  Add.SrNo);
                Console.WriteLine("Address Name r:- " + Add.Name);


            }



Wednesday, October 16, 2013

Converting time zone in asp.net,C# and vb.net through framework 3.5.

First add below references.

Namespace:  System
Assembly:  System. Core (in System. Core. dell)

Sample function that works for all of you.

Create below function in common classes.

  Public Function GmtToPacific (ByVal dateTime As DateTime) As DateTime
        Return TimeZoneInfo. ConvertTimeFromUtc (dateTime, TimeZoneInfo. FindSystemTimeZoneById ("Pacific Standard Time"))

    End Function

Calls this function and pass input date in UTC/GMT format.

Dim objName as new CommonClassName

objName .GmtToPacific(sinceDate.ToUniversalTime.ToString())


Friday, October 11, 2013

Some date format mostly using for UTC time zone, VB.NET and C#.


yyyy-MM-ddTHH:mm:ss.000
yyyy-MM-ddTHH:mm:ssZ

Date.ToString("yyyy-MM-ddTHH:mm:ssZ")
Format(Date., "yyyy-MM-ddTHH:mm:ss.000")