variants product example Projects.

 Ticket 93818: [Holz Pichler] 3.3. Item variants – “range value” attributes


























Cache methods on Manager.

 Project Kavo 

ExtendedProductCategoryManager
/// Ticket 88704: [Kavo] 3.9. PDP – RELATED ITEMS
        /// <summary>
        /// Get product categories by product child level.
        /// </summary>
        /// <param name="level">product's child level</param>
        /// <returns></returns>
        public virtual IProductCategoryCollection GetProductCategoriesByLevel(int level)
        {
            bool fromCache;
            var categories = CacheManager.FromCache(ErpCollectionCacheKey<IProductCategory>() + "CategoriesByLevel" + level,
                    () => ((ExtendedOfflineProductCategoryProvider)Provider).GetProductCategoriesByLevel(level),
                    out fromCache);
 
            return categories;
        }


use a unique key for cacheKey 

/// Ticket 88704: [Kavo] 3.9. PDP – RELATED ITEMS
/// <summary>
/// Get related product item.
/// </summary>
/// <param name="categoryId"></param>
/// <returns></returns>
public virtual IRelatedProductSet GetRelatedProductSetByCategoryId(string categoryId)
{  
   var cacheKey = CacheKey.ForContentCollection<IRelatedProductSet>(categoryId);
   var list = CommerceFrameworkBase.Content.GetContentCacheContainer()
       .FromCache(cacheKey, () => ((ExtendedOfflineProductProvider)Provider).GetRelatedProductSetByCategoryId(categoryId));
        return list;
}


cache with List exampe. 

ExtendedProductManager
/// Ticket 88704: [Kavo] 3.9. PDP – RELATED ITEMS
/// <summary>
/// Get related product items by category ids.
/// </summary>
/// <param name="categoryId">category id</param>
/// <returns>related product item</returns>
public virtual IList<IRelatedProductSet> GetRelatedProductSetsByCategoryIds(List<string> categoryIdList)
{    
    string categoryIdListString = string.Join(" ", categoryIdList.ToArray());
    var cacheKey = CacheKey.ForContentCollection<IRelatedProductSet>(categoryIdListString);
    var list = CommerceFrameworkBase.Content.GetContentCacheContainer()
        .FromCache(cacheKey, () => ((ExtendedOfflineProductProvider)Provider).GetRelatedProductSetsByCategoryIds(categoryIdList));
    return list;                       
}


another simple way to cache

ExtendedCommonManager
public IPIMModelsDataCollection GetPIMModels(string makeId)
{
var key = CacheKey.ForContentCollection<PIMModelsData>() + "PIMModels" + makeId;
return CacheManager.FromCache(key, () => ((ExtendedOfflineCommonProvider)Providers.Offline.Common).GetPIMModels(makeId));
}


public IPIMMakesDataCollection GetPIMMakes()
        {
            var key = CacheKey.ForContentCollection<PIMMakesData>() + "PIMMakes";
            return CacheManager.FromCache(key, () => ((ExtendedOfflineCommonProvider)Providers.Offline.Common).GetPIMModels());
        }



Short Notes

 How to get matching items from two List by LinQ


var CategoryIdList = product.CategoryIds;
var relatedProductItems = ((ExtendedProductManager)CommerceFrameworkBase.Products).GetRelatedProductItems();
          
var relatedProductItemsList = relatedProductItems.Where(m => CategoryIdList.Contains(m.CategoryId)).ToList();

not matching (use (not) ! for statment)

var relatedProductItemsList = relatedProductItems.Where(m => !CategoryIdList.Contains(m.CategoryId)).ToList();

anothr way 

var basketRangeValueFields = ((BasketLine)basketLine).RangeValueList;
                       var machingRangeValueFields = excictingLineRangeValues.Where(x => basketRangeValueFields.Any(y => x.Id == y.Id && x.Value == y.Value)).ToList();
                       var result = (machingRangeValueFields.Count == basketRangeValueFields.Count);


multiple fields check with two list

// Ticket 93818: [Holz Pichler] 3.3.Item variants – “range value” attributes.
            var excictingLineRangeValues = ((BasketLine)line1).RangeValueList;
            var newLineRangeValues = ((BasketLine)line2).RangeValueList;
 
            if (excictingLineRangeValues != null && newLineRangeValues != null)
            {
                var machingRangeValueFields = excictingLineRangeValues.Where(x => newLineRangeValues.Any(y => x.Name == y.Name && x.Id == y.Id && x.Value == y.Value)).ToList();
                var result = (machingRangeValueFields.Count == newLineRangeValues.Count);
                return result;
            }



How to call constant data on Sana admin

Kavo : AdminMenuInitializer.

Topmedia:

CreateAdminMenuLink(Admin.ResourceManager.GetString(Sana.Commerce.Constants.ProductFinder), urlHelper.Action("ProductFinder", "ProductIndex"),
                           PermissionOn.SearchSettings)),


Drop Down

<div class="form-group">
    @Html.LabelFor(x => Model.SelectedProductType, htmlAttributes: new { @class = "control-label col-md-2" })
    <br />
    <div class="">
        @Html.DropDownListFor(x => Model.SelectedProductType, new SelectList(Model.ProductTypes, "Code", "Name"),
        " Select" , htmlAttributes: new { @class = "form-control", id = "ProductType" })
        @Html.ValidationMessageFor(x => x.SelectedProductType, "", new { @class = "text-danger" })
    </div>
</div>


Website ID

var websiteId = CommerceFrameworkBase.Context.WebsiteId;


reload page by controler 

return Redirect(Request.UrlReferrer.ToString());


Selected Web shop lanuage

var currentLanguage = CommerceFrameworkBase.Context.LanguageId;
var culture = CultureInfo.GetCultureInfo(currentLanguage);


Customer is b2b or b2c
var shopContext = ShopContext.GetCurrent(); 
shopContext.IsB2cCustomer

Loggin time out : 

Add this to Web config File  after two minutes it will logout

 <!--Increase the frontend login session expires time -->
    <add key="FrontendAuthenticationTimeout" value="2" />


Customer segment :

How to identify current customer match with customer segments

eg:Intergria helthcare> ExtendedProductController > UpdateProductTabDescriptions > line97

ShopApi.UserState.IsCurrentUserInSegment(Shop, customerSegmentIndications) 


Add Logs   views

using Sana.Utilities.Logging;
var log = ObjectManager.GetInstance<ILog>();
            log.Add("1.EditOrderTemplate() method : " + "\r\n"); // Log file will remove after test 


Admin Paging Grid Creation.

 Ex: Kavo .  // Ticket 88704: [Kavo] 3.9. PDP – RELATED ITEMS 

RelatedProductsController

















get value from entity fields


Project Kavo : ExtendedProfileControllers. > 

GetB2BCustomerCreationEmailTags



//Get Tax No from Entity fields
           var taxNo = model.Customer.Fields.Values.Where(x => x.Name == "TaxNo").FirstOrDefault().Value;
           replaceTags.Add("TAXNO", GetCountryName(taxNo.ToString())); 







create new Table in Databses in sana and map hibernate

 kavo Project.

create table in DB , add script to database update folder

D:\development\Florette_935_2\DatabaseUpdates

create new hbm or update existing.

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false" namespace="Sana.Commerce.Catalog" assembly="Sana.Commerce.Sdk">
  <class name="RelatedProductItems" table="RelatedProductItems">
    <id name="Id" type="Guid">
      <generator class="guid" />
    </id>
    <property name="WebsiteId" type="string" length="50" not-null="true" />
    <property name="CategoryId" type="string" length="50" not-null="false" />
    <property name="ProductSetId" type="Guid" length="50" not-null="true" />
  </class>


need to set correct name space . else get an error.

eh:Catalog.hbm.xml

namespace="Sana.Commerce.Catalog" <-----

RelatedProductitem.cs

namespace Sana.Commerce.Catalog <---------
{
    [Serializable]
    [DataContract(Name = "RelatedProductItem", Namespace = "")]
    public class RelatedProductItem : IRelatedProductItem
    {
        /// <summary>
        /// Gets or sets the stock range identifier.
        /// </summary>
        [IgnoreDataMember]
        public Guid Id { get; set; }
 
        /// <summary>
        /// Gets or sets the website identifier.
        /// </summary>
        [IgnoreDataMember]
        public string WebsiteId { get; set; }

        /// <summary>
        /// Gets or sets the category identifier.
        /// </summary>
        [DataMember]
        public string CategoryId { get; set; }

        /// <summary>
        /// Gets or sets the out of stock value.
        /// </summary>
        [DataMember]
        public Guid ProductSetId { get; set; }
 
    }


namespace Sana.Commerce.Catalog
{
    /// Ticket 88704: [Kavo] 3.9. PDP – RELATED ITEMS
    /// <summary>
    /// Describes related product item.
    /// </summary>
    public interface IRelatedProductSet : IIdentityObject
    {
        /// <summary>
        /// Gets or sets the website identifier.
        /// </summary>
        string WebsiteId { get; set; }
 
        /// <summary>
        /// Gets or sets the category identifier.
        /// </summary>
        string CategoryId { get; set; }
 
        /// <summary>
        /// Gets or sets the Product set id.
        /// </summary>
        Guid ProductSetId { get; set; }
    }
}


Top media Ticket 100006: [Topmedia] 3.1. Search – Product Finder

create table on DB 

CREATE TABLE [dbo].[ProductTypes](
[Id] [uniqueidentifier] NOT NULL,
[WebsiteId] [nvarchar](50) NOT NULL,
[Code] [nvarchar](50) NULL,
[Name] [nvarchar](100) NULL,
CONSTRAINT [PK_ProductTypes] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
 
ALTER TABLE [dbo].[ProductTypes]  WITH CHECK ADD  CONSTRAINT [FK_ProductTypes_ProductTypes] FOREIGN KEY([Id])
REFERENCES [dbo].[ProductTypes] ([Id])
GO
 
ALTER TABLE [dbo].[ProductTypes] CHECK CONSTRAINT [FK_ProductTypes_ProductTypes]
GO

common.hbm.xml

<class name="ProductType" table="ProductTypes" polymorphism="explicit">
    <id name="Id" type="Guid">
      <generator class="guid" />
    </id>
    <property name="WebsiteId" type="string" length="50" not-null="true" />
    <property name="Code" type="string" length="50" not-null="false" />
    <property name="Name" type="string" length="100" not-null="false" />
  </class>


When u want to get datafrom DB use OfflineCommonProvider

from ERP use ExtendedCommonProvider


How to call these methods . This is calling on General import runing

public class ExtendedSyncTask: SyncTask
    {
        protected override void Synchronize()
        {
            base.Synchronize();
 
            var offlineCommonProvider = Providers.Offline.Common;
            var onlineCommonProvider = Providers.Common;
 
            // Ticket 100006: [Topmedia] 3.1. Search – Product Finder
            // Get Prodcuct type data from ERP.
            var pickupLocations = ((ExtendedCommonProvider)onlineCommonProvider).GetProductTypes();
            ((ExtendedOfflineCommonProvider)offlineCommonProvider).DeleteAllProductTypes();
            ((ExtendedOfflineCommonProvider)offlineCommonProvider).SaveProductTypes(pickupLocations);
            taskLog.Add(this, "Saved product types.");
 
        }
 
    }


Get data from ERP  (online)

public class ExtendedCommonProvider : CommonProvider, IExtendedCommonProvider
    {
 
        public virtual IList<IProductType> GetProductTypes()
        {
            var request = new List<XElement>(); 
            var result = ExecuteRequest("GetProductTypes", request); 
             var productTypes = result.Elements("ProductType").Select(e => ((ExtendedCommonXmlParser)Parser).ParseProductType(e)).ToList();
             
            foreach (var item in productTypes)
            {
                item.WebsiteId = Context.WebsiteId;
            }
            return productTypes;
        }
         
    }


get data from DB offline

public class ExtendedOfflineCommonProvider : OfflineCommonProvider, IExtendedCommonProvider
    {
        /// Ticket 100006: [Topmedia] 3.1. Search – Product Finder
        /// <summary>
        /// Delete all product types.
        /// </summary>
        public virtual void DeleteAllProductTypes()
        {
            WrapDataAccessException(() =>
            {
                using (var sm = CreateSessionManager(false))
                {
                    var productTypes = GetProductTypes();
                    foreach (var productType in productTypes)
                    {
                        sm.Session.Delete(productType);
                    }
                    sm.Commit();
                }
            }, "Cannot delete pickup locations for {0} website".FormatWith(Context.WebsiteId));
        }
 
        /// Ticket 100006: [Topmedia] 3.1. Search – Product Finder
        /// <summary>
        ///  Get product types.
        /// </summary>
        /// <returns></returns>
        public virtual IList<IProductType> GetProductTypes()
        {
            using (var sm = CreateSessionManager(true))
            {
                var productTypes = sm.Session.CreateCriteria(GetRegisteredType<IProductType>())
                    .Add(NHibernate.Criterion.Restrictions.Eq("WebsiteId", CommerceFrameworkBase.Context.WebsiteId))
                    .List<IProductType>();               
                return productTypes;
            }
        }
 
        /// Ticket 100006: [Topmedia] 3.1. Search – Product Finder
        /// <summary>
        /// Save product types.
        /// </summary>
        /// <param name="productTypes"></param>
        public virtual void SaveProductTypes(IList<IProductType> productTypes)
        {
            WrapDataAccessException(() =>
            {
                using (var sm = CreateSessionManager(false))
                {
                    productTypes.Each(c => sm.Session.SaveOrUpdate(c));
                    sm.Commit();
                }
            }, "Cannot save pickup location");
        }
 
 
    }




order confirmation e-mail not working. check list

  Send order confirmation e-mail : always send order conf.

1. Check db > PaymentTransactionInfos table > ConfirmationEmailSent set to true :

2. If true : hosting issue

If false sana issue . Check db have any multiple data for same order  

 protected virtual bool ShouldSendConfirmationEmail(IPaymentTransactionInfo transaction)
{
var checkoutProcess = transaction.CheckoutProcessName;
if (checkoutProcess == CheckoutProcesses.EditOrder || checkoutProcess == CheckoutProcesses.EditQuote)
return true;
if (transaction.ConfirmationEmailSent)
return false;
var transactions = CommerceFrameworkBase.PaymentData.GetPaymentTransactionsInfo(transaction.OrderId, transaction.WebsiteId);
return !transactions.Any(t => t.ConfirmationEmailSent);
}