Example #1
0
        private async Task <Category> CreateOrGetCategory(CommercePipelineExecutionContext context, Catalog catalog, string categoryName, string parentCategoryId = null)
        {
            try
            {
                string categoryId = GenerateFullCategoryId(catalog.Name, categoryName);

                //Check if catalog with given name already exists before trying to create a new one
                Category category = await _findEntityCommand.Process(context.CommerceContext, typeof(Category),
                                                                     categoryId, false) as Category;

                if (category == null)
                {
                    context.Logger.LogInformation($"ProductImport:Category Not Found, result is nill _getCategoryCommand:{categoryId}");
                    context.Logger.LogInformation($"ProductImport:Creating Category: {categoryId}");
                    category = await _createCategoryCommand.Process(context.CommerceContext, catalog.Id, categoryName, categoryName, categoryName) as Category;

                    category.ParentCatalogList = catalog.SitecoreId;
                }
                else
                {
                    context.Logger.LogInformation($"ProductImport: Category found  _findEntityPipeline, catalog: {categoryName}");
                }
                return(category);
            }
            catch (Exception ex)
            {
                context.Logger.LogInformation($"ProductImport: Error during catelog process" + ex.Message);
                return(null);
            }
        }
        /// <summary>
        /// Runs the specified argument.
        /// </summary>
        /// <param name="arg">The argument.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public override async Task <CommerceEntity> Run(CommerceEntity arg, CommercePipelineExecutionContext context)
        {
            if (arg == null)
            {
                return(arg);
            }

            if (!(arg is SellableItem))
            {
                return(arg);
            }

            var sellableItem = (SellableItem)arg;
            var productId    = arg.Id.Substring($"{CommerceEntity.IdPrefix<SellableItem>()}".Length);

            productId = productId.Replace("-", " ");

            sellableItem.Id         = $"{CommerceEntity.IdPrefix<SellableItem>()}{productId}";
            sellableItem.ProductId  = productId;
            sellableItem.FriendlyId = productId;

            var targetSellableItem = await _findEntityCommand.Process(context.CommerceContext, typeof(SellableItem), sellableItem.Id).ConfigureAwait(false);

            if (targetSellableItem != null)
            {
                sellableItem.IsPersisted = true;
                sellableItem.Version     = targetSellableItem.Version;
            }

            return(sellableItem);
        }
Example #3
0
        public override async Task <ImportEntityArgument> Run(ImportEntityArgument arg, CommercePipelineExecutionContext context)
        {
            string entityId = arg.ImportHandler.EntityId;

            var entityToUpdate = arg.ImportHandler.GetCommerceEntity() ?? await _findEntityCommand
                                 .Process(context.CommerceContext, typeof(CommerceEntity), entityId)
                                 .ConfigureAwait(false);

            bool createNewVersion = entityToUpdate != null &&
                                    arg.CatalogImportPolicy.EntityVersioningScheme == EntityVersioningScheme.CreateNewVersion;

            if (entityToUpdate != null &&
                arg.CatalogImportPolicy.EntityVersioningScheme == EntityVersioningScheme.UpdateLatestUnpublished)
            {
                VersioningEntity versioningEntity = await _findEntityCommand.Process(context.CommerceContext, typeof(VersioningEntity), VersioningEntity.GetIdBasedOnEntityId(entityToUpdate.Id), new int?()).ConfigureAwait(false) as VersioningEntity;

                if (versioningEntity?.Versions != null && versioningEntity.Versions.Any())
                {
                    var unpublishedVersion = versioningEntity.Versions.Where(x => !x.Published).Max(x => x.Version);
                    if (unpublishedVersion <= 0 || entityToUpdate.EntityVersion != unpublishedVersion)
                    {
                        createNewVersion = true;
                    }
                }
            }

            if (createNewVersion)
            {
                var newVersion = entityToUpdate.EntityVersion + 1;
                await _addEntityVersionCommand.Process(context.CommerceContext, entityToUpdate, newVersion).ConfigureAwait(false);

                entityToUpdate = await _findEntityCommand.Process(context.CommerceContext, typeof(CommerceEntity), entityId, newVersion).ConfigureAwait(false);
            }

            if (entityToUpdate != null)
            {
                arg.IsNew = false;
                arg.ImportHandler.SetCommerceEntity(entityToUpdate);
            }

            return(arg);
        }
        /// <summary>
        /// Runs the specified argument.
        /// </summary>
        /// <param name="arg">The argument.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public override async Task <FindEntityArgument> Run(FindEntityArgument arg, CommercePipelineExecutionContext context)
        {
            Condition.Requires(arg).IsNotNull($"{this.Name}: the argument cannot be null.");

            context.Logger.LogInformation($"{this.Name} - Run IEntityMigrationPipeline:{arg.EntityId}");
            var targetEntity = await _findEntityCommand.Process(context.CommerceContext, typeof(CommerceEntity), arg.EntityId);

            arg.Entity = targetEntity;

            return(arg);
        }
Example #5
0
        public override async Task <ImportEntityArgument> Run(ImportEntityArgument arg, CommercePipelineExecutionContext context)
        {
            string entityId = arg.ImportHandler.EntityId;

            var entityToUpdate = await _findEntityCommand.Process(context.CommerceContext, typeof(CommerceEntity), entityId)
                                 .ConfigureAwait(false);

            if (entityToUpdate != null)
            {
                arg.IsNew = false;
                arg.ImportHandler.SetCommerceEntity(entityToUpdate);
            }

            return(arg);
        }
        /// <summary>
        /// Save Commmerce Entities collection into Commerce DB
        /// </summary>
        /// <param name="entityModel"></param>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task ImportCommerceEntities(EntityCollectionModel entityModel, CommercePipelineExecutionContext context)
        {
            try
            {
                foreach (var commerceEntity in entityModel.Entities)
                {
                    var entity         = Cast(commerceEntity, entityModel.EntityType);
                    var existingEntity = await _findEntityCommand.Process(context.CommerceContext, entity.GetType(), entity.Id);

                    if (existingEntity != null)
                    {
                        // Try to increase version count instead of delete
                        DeleteEntityArgument result = await _deleteEntityCommand.Process(context.CommerceContext, existingEntity.Id);

                        if (!result.Success)
                        {
                            Log.Error($"{this.GetType().Name}: Deletion of {existingEntity.Id} failed - new Entity was not imported");
                        }
                        else
                        {
                            entity.Version = 0;
                        }
                    }

                    //entity.EntityVersion = 1;
                    //entity.Version = 0;
                    entity.IsPersisted = false;
                    context.CommerceContext.AddUniqueEntityByType(entity);


                    var persistResult = await this._persistEntityCommand.Process(context.CommerceContext, entity);
                }

                if (entityModel.EntityType == typeof(Category))
                {
                    await AssociateCategoriesToParent(entityModel, context);
                }

                if (entityModel.EntityType == typeof(SellableItem))
                {
                    await AssociateSellableItemsToParent(entityModel, context);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }
        private async Task <Category> CreateOrGetCategory(CommercePipelineExecutionContext context, Catalog catalog, string categoryName, string parentCategoryId = null)
        {
            try
            {
                string categoryId = GenerateFullCategoryId(catalog.Name, categoryName);

                //Check if catalog with given name already exists before trying to create a new one
                Category category = await _findEntityCommand.Process(context.CommerceContext, typeof(Category), categoryId, false) as Category;

                if (category == null)
                {
                    context.Logger.LogInformation($"ProductImport:Category Not Found, result is nill _getCategoryCommand:{categoryId}");
                    context.Logger.LogInformation($"ProductImport:Creating Category: {categoryId}");
                    category = await _createCategoryCommand.Process(context.CommerceContext, catalog.Id, categoryName, categoryName, categoryName) as Category;

                    //category.ParentCatalogList = catalog.SitecoreId;

                    //int version = category.Version;
                    //if(category.Version != version + 1)

                    //var newItemVersion = category.EntityVersion + 1;
                    //await _addEntityVersionCommand.Process(context.CommerceContext, category, newItemVersion);

                    //Save Category Result
                    //var result = await _commander.Pipeline<IPersistEntityPipeline>()
                    //  .Run(new PersistEntityArgument(category), context.CommerceContext.GetPipelineContextOptions());


                    //if (string.IsNullOrWhiteSpace(parentCategoryId))
                    //    await _associateCategoryToParentCommand.Process(context.CommerceContext, catalog.Id, catalog.Id, category.Id);
                    //else
                    //    await _associateCategoryToParentCommand.Process(context.CommerceContext, catalog.Id, parentCategoryId, category.Id);


                    return(category);
                }
                else
                {
                    context.Logger.LogInformation($"ProductImport: Category found  _findEntityPipeline, catalog: {categoryName}");
                }
                return(category);
            }
            catch (Exception ex)
            {
                context.Logger.LogInformation($"ProductImport: Error during catelog process" + ex.Message);
                return(null);
            }
        }
        private async Task <Catalog> GetOrCreateCatalog(string catalogName, CommercePipelineExecutionContext context)
        {
            try
            {
                //Commerce would use a add different prefixes to internal IDs of different kinds of entities.
                //this will get us internal commerce ID for a given catalog name
                var commerceCatalogId = $"{CommerceEntity.IdPrefix<Catalog>()}{catalogName}";

                //Check if catalog with given name already exists before trying to create a new one
                Catalog catalog = await _findEntityCommand.Process(context.CommerceContext, typeof(Catalog), commerceCatalogId, null, false) as Catalog;

                if (catalog == null)
                {
                    var catalogBaseName = catalogName.Replace("_Catalog", string.Empty);

                    catalog = await _createCatalogCommand.Process(context.CommerceContext, catalogName, catalogDisplayName) as Catalog;

                    //Persist changes to Catalog (Price and Promo books associations created above) into Commerce database
                    var result = await _commander.Pipeline <IPersistEntityPipeline>()
                                 .Run(new PersistEntityArgument(catalog), context.CommerceContext.PipelineContextOptions);

                    catalog = result.Entity as Catalog;
                }
                else
                {
                    context.Logger.LogInformation($"ProductImport: catalog found  _findEntityPipeline, catalog: {catalogName}");
                }
                if (catalog == null)
                {
                    context.Logger.LogInformation($"ProductImport: Error during catalog process");
                }

                //TO DO: Need to apply Clear cache every fifth iteration: https://doc.sitecore.com/developers/91/sitecore-experience-commerce/en/optimize-the-commercecontext-cache-for-a-long-running-process.html
                //Refresh Commerce Cache
                context.CommerceContext = new CommerceContext(context.CommerceContext.Logger, context.CommerceContext.TelemetryClient)
                {
                    GlobalEnvironment = context.CommerceContext.GlobalEnvironment,
                    Environment       = context.CommerceContext.Environment,
                    Headers           = context.CommerceContext.Headers
                };
                return(catalog);
            }
            catch (Exception ex)
            {
                context.Logger.LogInformation($"ProductImport: Error during catalog process" + ex.Message);
                return(null);
            }
        }
Example #9
0
        private async Task <Catalog> GetOrCreateCatalog(string catalogName, CommercePipelineExecutionContext context)
        {
            try
            {
                //Commerce would use a add different prefixes to internal IDs of different kinds of entities.
                //this will get us internal commerce ID for a given catalog name
                var commerceCatalogId = $"{CommerceEntity.IdPrefix<Catalog>()}{catalogName}";

                //Check if catalog with given name already exists before trying to create a new one
                Catalog catalog = await _findEntityCommand.Process(context.CommerceContext, typeof(Catalog),
                                                                   commerceCatalogId, false) as Catalog;

                if (catalog == null)
                {
                    var catalogBaseName = catalogName.Replace("_Catalog", string.Empty);

                    catalog = await _createCatalogCommand.Process(context.CommerceContext, catalogName, catalogDisplayName) as Catalog;

                    //Persist changes to Catalog (Price and Promo books associations created above) into Commerce database
                    var result = await _commander.Pipeline <IPersistEntityPipeline>()
                                 .Run(new PersistEntityArgument(catalog), context.CommerceContext.GetPipelineContextOptions());

                    catalog = result.Entity as Catalog;
                }
                else
                {
                    context.Logger.LogInformation($"ProductImport: catalog found  _findEntityPipeline, catalog: {catalogName}");
                }
                if (catalog == null)
                {
                    context.Logger.LogInformation($"ProductImport: Error during catalog process");
                }
                return(catalog);
            }
            catch (Exception ex)
            {
                context.Logger.LogInformation($"ProductImport: Error during catalog process" + ex.Message);
                return(null);
            }
        }
Example #10
0
        public virtual async Task <Sitecore.Commerce.Plugin.Customers.Customer> Process(CommerceContext commerceContext, string customerID, bool subscribeEmail, string company)
        {
            try
            {
                var customerEntity = await _getCustomerCommand.Process(commerceContext, customerID);

                if (customerEntity != null)
                {
                    var customerEntityView = await _getEntityViewCommand.Process(commerceContext, customerEntity.Id, "Master", "", "");

                    var composerEditView = customerEntityView.ChildViews.Where(x => x.Name == "Details").FirstOrDefault() as EntityView;
                    if (composerEditView != null)
                    {
                        commerceContext.Logger.LogDebug($"Edit customer detail view loaded: {DateTime.Now}");
                        var updatedCustomerEntity = await _findEntityCommand.Process(commerceContext, typeof(Sitecore.Commerce.Plugin.Customers.Customer), composerEditView.EntityId) as Sitecore.Commerce.Plugin.Customers.Customer;

                        var customDetails = new CustomerExtended();
                        customDetails.ReceiveEmailUpdates = Convert.ToBoolean(subscribeEmail);
                        customDetails.Company             = company;
                        updatedCustomerEntity.SetComponent(customDetails);
                        await this._persistEntityPipeline.Run(new PersistEntityArgument(updatedCustomerEntity), commerceContext.PipelineContext);
                    }
                    else
                    {
                        commerceContext.Logger.LogInformation($"Edit customer entityview is empty: {DateTime.Now}");
                    }
                }
                else
                {
                    commerceContext.Logger.LogInformation($"Customer entityview is null: {DateTime.Now}");
                }
                return(customerEntity);
            }
            catch (Exception e)
            {
                commerceContext.Logger.LogInformation($"Exception occured in getting customer { e.StackTrace} and id is {e.Message}");
                return(await Task.FromException <Sitecore.Commerce.Plugin.Customers.Customer>(e));
            }
        }
        public override async Task <EntityView> Run(EntityView arg, CommercePipelineExecutionContext context)
        {
            if (string.IsNullOrEmpty(arg?.Action) ||
                !arg.Action.Equals(context.GetPolicy <KnownCustomPricingActionsPolicy>().SelectMembershipCurrency, StringComparison.OrdinalIgnoreCase) ||
                !arg.Name.Equals(context.GetPolicy <KnownCustomPricingViewsPolicy>().PriceCustomRow, StringComparison.OrdinalIgnoreCase))
            {
                return(arg);
            }

            var card = context.CommerceContext.GetObjects <PriceCard>().FirstOrDefault(p => p.Id.Equals(arg.EntityId, StringComparison.OrdinalIgnoreCase));

            if (card == null)
            {
                return(arg);
            }

            KnownResultCodes policy = context.GetPolicy <KnownResultCodes>();

            if (string.IsNullOrEmpty(arg.ItemId))
            {
                await context.CommerceContext.AddMessage(policy.ValidationError, "InvalidOrMissingPropertyValue",
                                                         new object[] { "ItemId" }, "Invalid or missing value for property 'ItemId'.")
                .ConfigureAwait(false);

                return(arg);
            }

            PriceSnapshotComponent snapshot = card.Snapshots.FirstOrDefault(s => s.Id.Equals(arg.ItemId, StringComparison.OrdinalIgnoreCase));

            if (snapshot == null)
            {
                await context.CommerceContext.AddMessage(policy.ValidationError, "PriceSnapshotNotFound",
                                                         new object[] { arg.ItemId, card.FriendlyId }, "Price snapshot " + arg.ItemId + " on price card " + card.FriendlyId + " was not found.")
                .ConfigureAwait(false);

                return(arg);
            }

            var currencyProperty = arg.Properties.FirstOrDefault(p => p.Name.Equals("Currency", StringComparison.OrdinalIgnoreCase));

            string currency = currencyProperty?.Value;

            if (string.IsNullOrEmpty(currency))
            {
                await context.CommerceContext.AddMessage(policy.ValidationError, "InvalidOrMissingPropertyValue",
                                                         new object[] { currencyProperty == null ? "Currency" : currencyProperty.DisplayName }, "Invalid or missing value for property 'Currency'.")
                .ConfigureAwait(false);

                return(arg);
            }

            if (snapshot.Tiers.Any(t => t.Currency.Equals(currency, StringComparison.OrdinalIgnoreCase)))
            {
                await context.CommerceContext.AddMessage(policy.ValidationError, "CurrencyAlreadyExists",
                                                         new object[] { currency, snapshot.Id, card.FriendlyId }, "Currency " + currency + " already exists for snapshot " + snapshot.Id + " on price card " + card.FriendlyId + ".")
                .ConfigureAwait(false);

                return(arg);
            }

            CurrencySet currencySet  = null;
            string      entityTarget = (await _findEntityCommand.Process(context.CommerceContext, typeof(PriceBook), card.Book.EntityTarget, false).ConfigureAwait(false) as PriceBook)?.CurrencySet.EntityTarget;

            if (!string.IsNullOrEmpty(entityTarget))
            {
                currencySet = await _getCurrencySetCommand.Process(context.CommerceContext, entityTarget).ConfigureAwait(false);

                if (currencySet != null)
                {
                    var    currencies = currencySet.GetComponent <CurrenciesComponent>().Currencies;
                    string str        = string.Join(", ", currencies.Select(c => c.Code));

                    if (!currencies.Any(c => c.Code.Equals(currency, StringComparison.OrdinalIgnoreCase)))
                    {
                        CommercePipelineExecutionContext executionContext = context;
                        CommerceContext commerceContext = context.CommerceContext;
                        string          validationError = context.GetPolicy <KnownResultCodes>().ValidationError;
                        string          commerceTermKey = "InvalidCurrency";
                        var             args            = new object[] { currency, str };
                        string          defaultMessage  = "Invalid currency '" + currency + "'. Valid currencies are '" + str + "'.";
                        executionContext.Abort(await commerceContext.AddMessage(validationError, commerceTermKey, args, defaultMessage).ConfigureAwait(false), context);
                        executionContext = null;

                        return(arg);
                    }
                }
            }

            currencyProperty.IsReadOnly = true;
            currencyProperty.Policies   = new List <Policy>()
            {
                new AvailableSelectionsPolicy(currencySet == null ||
                                              !currencySet.HasComponent <CurrenciesComponent>() ?  new List <Selection>() :  currencySet.GetComponent <CurrenciesComponent>()
                                              .Currencies.Select(c =>
                {
                    return(new Selection()
                    {
                        DisplayName = c.Code,
                        Name = c.Code
                    });
                }).ToList(), false)
            };

            EntityView priceCustomCellEntityView = new EntityView
            {
                Name     = context.GetPolicy <KnownCustomPricingViewsPolicy>().PriceCustomCell,
                EntityId = card.Id,
                ItemId   = snapshot.Id
            };

            var membershipLevels        = context.GetPolicy <MembershipLevelPolicy>().MembershipLevels;
            List <Selection> selections = currencySet == null || !currencySet.HasComponent <CurrenciesComponent>() ? new List <Selection>() : membershipLevels.Select(c =>
            {
                return(new Selection()
                {
                    DisplayName = c.MemerbshipLevelName,
                    Name = c.MemerbshipLevelName
                });
            }).ToList();

            AvailableSelectionsPolicy availableSelectionsPolicy = new AvailableSelectionsPolicy(selections, false);

            List <Policy> commercePolicies = new List <Policy>()
            {
                availableSelectionsPolicy
            };

            ViewProperty membershipLevelViewProperty = new ViewProperty()
            {
                Name         = "MembershipLevel",
                OriginalType = typeof(string).FullName,
                Policies     = commercePolicies
            };

            priceCustomCellEntityView.Properties.Add(membershipLevelViewProperty);

            ViewProperty quantityViewProperty = new ViewProperty();

            quantityViewProperty.Name         = "Quantity";
            quantityViewProperty.OriginalType = typeof(decimal).FullName;
            priceCustomCellEntityView.Properties.Add(quantityViewProperty);

            ViewProperty priceViewProperty = new ViewProperty
            {
                Name         = "Price",
                RawValue     = null,
                OriginalType = typeof(decimal).FullName
            };

            priceCustomCellEntityView.Properties.Add(priceViewProperty);
            arg.ChildViews.Add(priceCustomCellEntityView);
            arg.UiHint = "Grid";
            context.CommerceContext.AddModel(new MultiStepActionModel(context.GetPolicy <KnownCustomPricingActionsPolicy>().AddMembershipCurrency));

            return(arg);
        }
        /// <summary>
        /// Runs the specified argument.
        /// </summary>
        /// <param name="arg">The argument.</param>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        public override async Task <CommerceEntity> Run(CommerceEntity arg, CommercePipelineExecutionContext context)
        {
            if (arg == null)
            {
                return(arg);
            }

            if (!(arg is Order))
            {
                return(arg);
            }

            var migrationPolicy = context.CommerceContext?.GetPolicy <MigrationPolicy>();

            if (migrationPolicy == null)
            {
                await context.CommerceContext.AddMessage(
                    context.CommerceContext.GetPolicy <KnownResultCodes>().Error,
                    "InvalidOrMissingPropertyValue",
                    new object[] { "MigrationPolicy" },
                    $"{this.GetType()}. Missing MigrationPolicy").ConfigureAwait(false);

                return(arg);
            }

            Guid id;

            if (!Guid.TryParse(arg.Id, out id))
            {
                context.Logger.LogInformation($"{this.Name} - Invalid Order Id:{arg.Id}");
                return(arg);
            }

            arg.Id = $"{CommerceEntity.IdPrefix<Order>()}{id:N}";

            var targetOrder = await _findEntityCommand.Process(context.CommerceContext, typeof(Order), arg.Id).ConfigureAwait(false);

            if (targetOrder != null)
            {
                arg.IsPersisted = true;
                arg.Version     = targetOrder.Version;
                return(arg);
            }

            if (arg.HasComponent <ContactComponent>())
            {
                var indexByCustomerId = new EntityIndex
                {
                    Id       = $"{EntityIndex.IndexPrefix<Order>("Id")}{arg.Id}",
                    IndexKey = arg.GetComponent <ContactComponent>()?.CustomerId,
                    EntityId = arg.Id
                };

                if (!migrationPolicy.ReviewOnly)
                {
                    await this._persistEntityPipeline.Run(new PersistEntityArgument(indexByCustomerId), context).ConfigureAwait(false);
                }
            }

            var order = (Order)arg;
            var indexByConfirmationId = new EntityIndex
            {
                Id       = $"{EntityIndex.IndexPrefix<Order>("Id")}{order?.OrderConfirmationId}",
                IndexKey = order?.OrderConfirmationId,
                EntityId = arg.Id
            };

            if (!migrationPolicy.ReviewOnly)
            {
                await this._persistEntityPipeline.Run(new PersistEntityArgument(indexByConfirmationId), context).ConfigureAwait(false);
            }

            return(arg);
        }
Example #13
0
        public override async Task <CreateCouponsArgument> Run(
            CreateCouponsArgument arg,
            CommercePipelineExecutionContext context)
        {
            await this._getManagedListCommand.PerformTransaction(context.CommerceContext, async() =>
            {
                var policy = context.CommerceContext.GetPolicy <LoyaltyPointsPolicy>();

                LoyaltyPointsEntity loyaltyPointsEntity = await _findEntityCommand.Process(context.CommerceContext, typeof(LoyaltyPointsEntity),
                                                                                           Constants.EntityId, shouldCreate: true) as LoyaltyPointsEntity;
                if (loyaltyPointsEntity == null)
                {
                    await context.AbortWithError("Unable to access or create LoyaltyPointsEntity {0}",
                                                 "LoyaltyPointsEntityNotReturned", Constants.EntityId);
                    return;
                }

                // Prevent simultaneous updates, in case multiple minion instances. Since these might be on scaled servers, mutex lock uses database field.
                // Lock is read before count is checked, so that when first process finishes and releases row, counts will be replenished.
                // Notes:
                // 1. If this pipeline aborts, the lock should be rolled back.
                // 2. Assuming transactions are enabled, the second process should never see IsLocked=true, as the read won't return until the lock is released. However,
                //    this syntax should work on a non-transactional environment, and makes the intent of the code clearer.
                if (loyaltyPointsEntity.IsLocked)
                {
                    await context.AbortWithError("{0} is locked. If this condition persists, unset this value through the database.", "EntityLocked", Constants.EntityId);
                    return;
                }

                var list = await EnsureList(context, Constants.AvailableCouponsList);
                if (list == null)
                {
                    await context.AbortWithError("Unable to create list {0}", "UnableToCreateList", Constants.AvailableCouponsList);
                    return;
                }

                long count = await _getListCountCommand.Process(context.CommerceContext, Constants.AvailableCouponsList);
                context.Logger.LogDebug($"{this.Name}: List {Constants.AvailableCouponsList} has {count} items.");



                if (count <= policy.ReprovisionTriggerCount)
                {
                    loyaltyPointsEntity.IsLocked = true;
                    await _persistEntityCommand.Process(context.CommerceContext, loyaltyPointsEntity);

                    context.Logger.LogDebug($"{this.Name}: List {Constants.AvailableCouponsList} is at or under reprovision count of {policy.ReprovisionTriggerCount}.");

                    loyaltyPointsEntity.SequenceNumber++;
                    string suffix = loyaltyPointsEntity.SequenceNumber.ToString();

                    string promotionName = string.Format(Constants.GeneratedPromotion, suffix);
                    Promotion promotion  = await GeneratePromotion(context, promotionName);
                    if (promotion == null)
                    {
                        await context.AbortWithError("Unable to generate promotion {0}.", "PromotionNotFound",
                                                     promotionName);
                        return;
                    }

                    await AddCoupons(context, promotion, suffix);
                    if (context.IsNullOrHasErrors())
                    {
                        return;
                    }

                    await AllocateCoupons(context, promotion, suffix);
                    if (context.IsNullOrHasErrors())
                    {
                        return;
                    }

                    ApprovePromotion(context, promotion);

                    await CopyCouponsToList(context, loyaltyPointsEntity, list);
                    if (context.IsNullOrHasErrors())
                    {
                        return;
                    }

                    loyaltyPointsEntity.IsLocked = false;
                    await _persistEntityCommand.Process(context.CommerceContext, list);
                    await _persistEntityCommand.Process(context.CommerceContext, promotion);
                    await _persistEntityCommand.Process(context.CommerceContext, loyaltyPointsEntity);
                }
            });


            return(arg);
        }
        protected virtual async Task PopulateRowDetails(EntityView view, PriceCard card, string itemId, bool isAddAction, bool isEditAction, CommercePipelineExecutionContext context)
        {
            if (view == null || card == null || string.IsNullOrEmpty(itemId))
            {
                return;
            }

            if (isAddAction)
            {
                CurrencySet currencySet  = null;
                string      entityTarget = (await _findEntityCommand.Process(context.CommerceContext, typeof(PriceBook), card.Book.EntityTarget, false).ConfigureAwait(false) as PriceBook)?.CurrencySet.EntityTarget;

                if (!string.IsNullOrEmpty(entityTarget))
                {
                    currencySet = await _getCurrencySetCommand.Process(context.CommerceContext, entityTarget).ConfigureAwait(false);
                }

                List <Policy> commercePolicies = new List <Policy>()
                {
                    new AvailableSelectionsPolicy(currencySet == null ||
                                                  !currencySet.HasComponent <CurrenciesComponent>() ?  new List <Selection>() :  currencySet.GetComponent <CurrenciesComponent>().Currencies.Select(c =>
                    {
                        return(new Selection()
                        {
                            DisplayName = c.Code,
                            Name = c.Code
                        });
                    }).ToList(), false)
                };

                ViewProperty item = new ViewProperty()
                {
                    Name     = "Currency",
                    RawValue = string.Empty,
                    Policies = commercePolicies
                };
                view.Properties.Add(item);
            }
            else
            {
                string[] strArray = itemId.Split('|');
                if (strArray.Length != 2 || string.IsNullOrEmpty(strArray[0]) || string.IsNullOrEmpty(strArray[1]))
                {
                    context.Logger.LogError("Expecting a SnapshotId and Currency in the ItemId: " + itemId + ". Correct format is 'snapshotId|currency'", Array.Empty <object>());
                }
                else
                {
                    string snapshotId = strArray[0];
                    string currency   = strArray[1];
                    PriceSnapshotComponent snapshotComponent = card.Snapshots.FirstOrDefault(s => s.Id.Equals(snapshotId, StringComparison.OrdinalIgnoreCase));

                    if (snapshotComponent == null)
                    {
                        context.Logger.LogError("Price snapshot " + snapshotId + " on price card " + card.FriendlyId + " was not found.", Array.Empty <object>());
                    }
                    else
                    {
                        var list = snapshotComponent.GetComponent <MembershipTiersComponent>().Tiers;
                        IGrouping <string, CustomPriceTier> currencyGroup = list.GroupBy(t => t.Currency)
                                                                            .ToList()
                                                                            .FirstOrDefault(g => g.Key.Equals(currency, StringComparison.OrdinalIgnoreCase));

                        if (currencyGroup == null)
                        {
                            context.Logger.LogError("Price row " + currency + " was not found in snapshot " + snapshotId + " for card " + card.FriendlyId + ".", Array.Empty <object>());
                        }
                        else
                        {
                            view.Properties.Add(new ViewProperty
                            {
                                Name       = "Currency",
                                RawValue   = currencyGroup.Key,
                                IsReadOnly = true
                            });

                            if (isEditAction)
                            {
                                view.UiHint = "Grid";
                                currencyGroup.ForEach(tier =>
                                {
                                    EntityView entityView = new EntityView()
                                    {
                                        Name     = context.GetPolicy <KnownCustomPricingViewsPolicy>().PriceCustomCell,
                                        EntityId = card.Id,
                                        ItemId   = itemId
                                    };

                                    var membershipLevels = context.GetPolicy <MembershipLevelPolicy>().MembershipLevels;

                                    ViewProperty item1 = new ViewProperty()
                                    {
                                        Name         = "MembershipLevel",
                                        RawValue     = tier.MembershipLevel,
                                        OriginalType = typeof(string).FullName,
                                        IsReadOnly   = true,
                                        Policies     = new List <Policy>()
                                        {
                                            new AvailableSelectionsPolicy(membershipLevels.Select(c =>
                                            {
                                                return(new Selection()
                                                {
                                                    DisplayName = c.MemerbshipLevelName,
                                                    Name = c.MemerbshipLevelName
                                                });
                                            }).ToList(), false)
                                        }
                                    };
                                    entityView.Properties.Add(item1);

                                    entityView.Properties.Add(new ViewProperty()
                                    {
                                        Name       = "Quantity",
                                        RawValue   = tier.Quantity,
                                        IsReadOnly = true
                                    });

                                    entityView.Properties.Add(new ViewProperty()
                                    {
                                        Name       = "Price",
                                        RawValue   = tier.Price,
                                        IsRequired = false
                                    });

                                    view.ChildViews.Add(entityView);
                                });
                            }
                            else
                            {
                                view.Properties.Add(new ViewProperty
                                {
                                    Name       = "ItemId",
                                    RawValue   = itemId,
                                    IsReadOnly = true,
                                    IsHidden   = true
                                });

                                list.Select(t => t.MembershipLevel).Distinct().OrderBy(q => q).ToList().ForEach(availableMembershipLevel =>
                                {
                                    CustomPriceTier priceTier      = currencyGroup.FirstOrDefault(ct => ct.MembershipLevel == availableMembershipLevel);
                                    List <ViewProperty> properties = view.Properties;
                                    properties.Add(new ViewProperty()
                                    {
                                        Name       = availableMembershipLevel.ToString(CultureInfo.InvariantCulture),
                                        RawValue   = priceTier?.Price,
                                        IsReadOnly = true
                                    });
                                });
                            }
                        }
                    }
                }
            }
        }