public virtual async Task <CartViewModel> CreateCartViewModelAsync(CreateRecurringOrderCartViewModelParam param)
        {
            var lineItems = param.Cart.GetLineItems();

            param.ProductImageInfo = new ProductImageInfo
            {
                ImageUrls = await ImageService.GetImageUrlsAsync(lineItems).ConfigureAwait(false),
            };

            var methodDisplayNames = await LookupService.GetLookupDisplayNamesAsync(new GetLookupDisplayNamesParam
            {
                CultureInfo = param.CultureInfo,
                LookupType  = LookupType.Order,
                LookupName  = "PaymentMethodType",
            });

            param.PaymentMethodDisplayNames = methodDisplayNames;

            var roProgramNames = lineItems.Select(x => x.RecurringOrderProgramName)
                                 .Where(l => !string.IsNullOrEmpty(l))
                                 .Distinct(StringComparer.OrdinalIgnoreCase)
                                 .ToList();
            var programTasks = roProgramNames.Select(programName => RecurringOrdersRepository.GetRecurringOrderProgram(ComposerContext.Scope, programName));
            var programs     = await Task.WhenAll(programTasks);

            param.RecurringOrderPrograms = programs.ToList();

            var vm = RecurringOrderCartViewModelFactory.CreateRecurringOrderCartViewModel(param);

            await ExtendLineItems(vm, ComposerContext.Scope, ComposerContext.CustomerId, ComposerContext.CultureInfo);

            return(vm);
        }
        protected virtual async Task <bool> ExtendLineItems(CartViewModel vm, string scope, Guid customerId, CultureInfo culture)
        {
            var recurringOrderLineItems = await RecurringOrdersRepository.GetRecurringOrderTemplates(scope, customerId).ConfigureAwait(false);

            foreach (var lineItem in vm.LineItemDetailViewModels)
            {
                var roLineItemVm = lineItem.AsExtensionModel <IRecurringOrderLineItemViewModel>();

                roLineItemVm.RecurringScheduleDetailUrl = FindUrl(recurringOrderLineItems, lineItem, culture);
            }

            return(true);
        }
        public async virtual Task MapRecurringOrderLineitemFrequencyName(RecurringOrderTemplateViewModel template, CultureInfo culture)
        {
            if (template.RecurringOrderTemplateLineItemViewModels == null)
            {
                return;
            }

            var uniqueProgramNames = template.RecurringOrderTemplateLineItemViewModels
                                     .Select(x => x.RecurringOrderProgramName)
                                     .Where(l => !string.IsNullOrWhiteSpace(l))
                                     .Distinct(StringComparer.OrdinalIgnoreCase)
                                     .ToList();

            if (uniqueProgramNames.Count > 0)
            {
                var tasks    = uniqueProgramNames.Select(programName => RecurringOrdersRepository.GetRecurringOrderProgram(ComposerContext.Scope, programName));
                var programs = await Task.WhenAll(tasks).ConfigureAwait(false);

                foreach (var lineitem in template.RecurringOrderTemplateLineItemViewModels)
                {
                    if (RecurringOrderTemplateHelper.IsRecurringOrderLineItemValid(lineitem))
                    {
                        var program = programs.FirstOrDefault(p => string.Equals(p.RecurringOrderProgramName, lineitem.RecurringOrderProgramName, StringComparison.OrdinalIgnoreCase));

                        if (program != null)
                        {
                            var frequency = program.Frequencies.FirstOrDefault(f => string.Equals(f.RecurringOrderFrequencyName, lineitem.RecurringOrderFrequencyName, StringComparison.OrdinalIgnoreCase));

                            if (frequency != null)
                            {
                                var localization = frequency.Localizations.FirstOrDefault(l => string.Equals(l.CultureIso, culture.Name, StringComparison.OrdinalIgnoreCase));

                                if (localization != null)
                                {
                                    lineitem.RecurringOrderFrequencyDisplayName = localization.DisplayName;
                                }
                                else
                                {
                                    lineitem.RecurringOrderFrequencyDisplayName = frequency.RecurringOrderFrequencyName;
                                }
                            }
                        }
                        var programViewModel = RecurringOrderProgramViewModelFactory.CreateRecurringOrderProgramViewModel(program, culture);
                        lineitem.RecurringOrderProgramFrequencies = programViewModel?.Frequencies;
                    }
                }
            }
        }
        protected virtual async Task <ProductViewModel> SetViewModelRecurringOrdersRelatedProperties(GetProductParam param, ProductViewModel vm, Overture.ServiceModel.Products.Product product)
        {
            if (param == null)
            {
                throw new ArgumentNullException(nameof(param));
            }
            if (vm == null)
            {
                throw new ArgumentNullException(nameof(vm));
            }

            var recurringOrdersEnabled = RecurringOrdersSettings.Enabled;

            var recurringOrderProgramName = product.PropertyBag.GetValueOrDefault <string>(Constants.ProductAttributes.RecurringOrderProgramName);

            if (string.IsNullOrWhiteSpace(recurringOrderProgramName))
            {
                return(vm);
            }

            vm.RecurringOrderProgramName            = recurringOrderProgramName;
            vm.Context["RecurringOrderProgramName"] = recurringOrderProgramName;

            var program = await RecurringOrdersRepository.GetRecurringOrderProgram(param.Scope, recurringOrderProgramName).ConfigureAwait(false);

            if (program == null)
            {
                return(vm);
            }


            vm.IsRecurringOrderEligible            = recurringOrdersEnabled;
            vm.Context["IsRecurringOrderEligible"] = recurringOrdersEnabled;

            if (recurringOrdersEnabled)
            {
                var recurringOrderProgramViewModel = RecurringOrderProgramViewModelFactory.CreateRecurringOrderProgramViewModel(program, param.CultureInfo);

                vm.RecurringOrderFrequencies            = recurringOrderProgramViewModel.Frequencies;
                vm.Context["RecurringOrderFrequencies"] = recurringOrderProgramViewModel.Frequencies;
            }

            return(vm);
        }
        public virtual async Task <CartViewModel> CreateCartViewModelAsync(CreateRecurringOrderCartViewModelParam param)
        {
            var lineItems = param.Cart.GetLineItems();

            param.ProductImageInfo = new ProductImageInfo
            {
                ImageUrls = await ImageService.GetImageUrlsAsync(lineItems).ConfigureAwait(false),
            };

            var methodDisplayNames = await LookupService.GetLookupDisplayNamesAsync(new GetLookupDisplayNamesParam
            {
                CultureInfo = param.CultureInfo,
                LookupType  = LookupType.Order,
                LookupName  = "PaymentMethodType",
            });

            param.PaymentMethodDisplayNames = methodDisplayNames;

            var programTasks = new Dictionary <string, Task <Overture.ServiceModel.RecurringOrders.RecurringOrderProgram> >(StringComparer.OrdinalIgnoreCase);

            foreach (var el in lineItems)
            {
                var programName = el.RecurringOrderProgramName;
                if (string.IsNullOrEmpty(programName) || programTasks.ContainsKey(programName))
                {
                    continue;
                }

                programTasks.Add(programName, RecurringOrdersRepository.GetRecurringOrderProgram(ComposerContext.Scope, programName));
            }

            var programs = await Task.WhenAll(programTasks.Values);

            param.RecurringOrderPrograms = programs.ToList();

            var vm = RecurringOrderCartViewModelFactory.CreateRecurringOrderCartViewModel(param);

            await ExtendLineItems(vm, ComposerContext.Scope, ComposerContext.CustomerId, ComposerContext.CultureInfo);

            return(vm);
        }
        public virtual async Task <RecurringOrderCartsRescheduleResultViewModel> UpdateRecurringOrderCartNextOccurenceAsync(UpdateRecurringOrderCartNextOccurenceParam param)
        {
            if (!RecurringOrdersSettings.Enabled)
            {
                return(new RecurringOrderCartsRescheduleResultViewModel());
            }

            if (param == null)
            {
                throw new ArgumentNullException(nameof(param), ArgumentNullMessageFormatter.FormatErrorMessage(nameof(param)));
            }

            //get customer cart
            var cart = await CartRepository.GetCartAsync(new GetCartParam {
                CartName        = param.CartName,
                CultureInfo     = param.CultureInfo,
                CustomerId      = param.CustomerId,
                Scope           = param.Scope,
                ExecuteWorkflow = false
            }).ConfigureAwait(false);

            var originalCartName = param.CartName;

            //get customer recurring lineitems
            var listOfRecurringLineItems = await RecurringOrdersRepository.GetRecurringOrderTemplates(param.Scope, param.CustomerId);

            if (listOfRecurringLineItems == null)
            {
                throw new InvalidOperationException($"Recurring lineItems for customer {param.CustomerId} not found");
            }

            var recurringLineItem = new RecurringOrderLineItem();
            var continueShipment  = true;

            //We need to conserve the same time
            foreach (var shipment in cart.Shipments)
            {
                foreach (var lineitem in shipment.LineItems)
                {
                    if (RecurringOrderCartHelper.IsRecurringOrderLineItemValid(lineitem))
                    {
                        var recurringOrderLineitem = listOfRecurringLineItems.RecurringOrderLineItems?.FirstOrDefault(l =>
                                                                                                                      RecurringOrderTemplateHelper.IsLineItemAndRecurringTemplateLineItemSameProduct(lineitem, l));

                        if (recurringOrderLineitem != null)
                        {
                            recurringLineItem = recurringOrderLineitem;
                            continueShipment  = false;
                            break;
                        }
                    }
                }
                if (!continueShipment)
                {
                    break;
                }
            }

            var newDate = param.NextOccurence;

            if (Guid.Empty != recurringLineItem.RecurringOrderLineItemId)
            {
                var nextOccurenceWithTime = recurringLineItem.NextOccurence;

                newDate = new DateTime(param.NextOccurence.Year, param.NextOccurence.Month, param.NextOccurence.Day,
                                       nextOccurenceWithTime.Hour, nextOccurenceWithTime.Minute, nextOccurenceWithTime.Second, DateTimeKind.Utc);
            }

            var listOfRecurringOrderLineItemsUpdated = await CartRepository.RescheduleRecurringCartAsync(new RescheduleRecurringCartParam()
            {
                CustomerId    = param.CustomerId,
                NextOccurence = newDate,
                Scope         = param.Scope,
                CartName      = param.CartName
            });

            var vm = new RecurringOrderCartsRescheduleResultViewModel();

            var carts = await CartRepository.GetRecurringCartsAsync(new GetRecurringOrderCartsViewModelParam
            {
                BaseUrl     = param.BaseUrl,
                Scope       = param.Scope,
                CustomerId  = param.CustomerId,
                CultureInfo = param.CultureInfo
            });

            vm.RescheduledCartHasMerged = !carts.Any(rc => string.Compare(rc.Name, originalCartName, StringComparison.OrdinalIgnoreCase) == 0);

            var cartsVm = await GetRecurringOrderCartListViewModelFromCartsAsync(new GetRecurringOrderCartsViewModelFromCartsParam
            {
                Carts       = carts,
                BaseUrl     = param.BaseUrl,
                CultureInfo = param.CultureInfo
            });

            vm.RecurringOrderCartsViewModel = cartsVm;

            var url = RecurringCartUrlProvider.GetRecurringCartsUrl(new GetRecurringCartsUrlParam
            {
                CultureInfo = param.CultureInfo
            });

            vm.RecurringCartsUrl = url;

            return(vm);
        }
        public virtual async Task <RecurringOrderCartsRescheduleResultViewModel> UpdateRecurringOrderCartNextOccurenceAsync(UpdateRecurringOrderCartNextOccurenceParam param)
        {
            if (!RecurringOrdersSettings.Enabled)
            {
                return(new RecurringOrderCartsRescheduleResultViewModel());
            }

            if (param == null)
            {
                throw new ArgumentNullException(nameof(param));
            }

            //get customer cart
            var cart = await CartRepository.GetCartAsync(new GetCartParam
            {
                CartName        = param.CartName,
                CultureInfo     = param.CultureInfo,
                CustomerId      = param.CustomerId,
                Scope           = param.Scope,
                ExecuteWorkflow = false
            }).ConfigureAwait(false);

            //get customer recurring lineitems
            var listOfRecurringLineItems = await RecurringOrdersRepository.GetRecurringOrderTemplates(param.Scope, param.CustomerId)
                                           ?? throw new InvalidOperationException($"Recurring lineItems for customer {param.CustomerId} not found");

            var continueShipment = true;
            var newDate          = param.NextOccurence;

            if (listOfRecurringLineItems.RecurringOrderLineItems != null && listOfRecurringLineItems.RecurringOrderLineItems.Any())
            {
                var lookup = listOfRecurringLineItems.RecurringOrderLineItems.ToLookup(el => el.ProductId, el => el, StringComparer.OrdinalIgnoreCase);

                //We need to conserve the same time
                foreach (var shipment in cart.Shipments)
                {
                    foreach (var lineitem in shipment.LineItems)
                    {
                        if (string.IsNullOrEmpty(lineitem.RecurringOrderFrequencyName) ||
                            string.IsNullOrEmpty(lineitem.RecurringOrderProgramName))
                        {
                            continue;
                        }

                        var recurringOrderLineitem = lookup[lineitem.ProductId]?
                                                     .FirstOrDefault(x => string.Equals(x.VariantId, lineitem.VariantId, StringComparison.OrdinalIgnoreCase));
                        if (recurringOrderLineitem == null)
                        {
                            continue;
                        }

                        //V: Kept the same logic just for case, but think checking a guid was provided to figure out, have we found an object or not
                        if (recurringOrderLineitem.RecurringOrderLineItemId != Guid.Empty)
                        {
                            var nextOccurenceWithTime = recurringOrderLineitem.NextOccurence;

                            newDate = new DateTime(newDate.Year, newDate.Month, newDate.Day,
                                                   nextOccurenceWithTime.Hour, nextOccurenceWithTime.Minute, nextOccurenceWithTime.Second, DateTimeKind.Utc);
                        }
                        continueShipment = false;
                        break;
                    }
                    if (!continueShipment)
                    {
                        break;
                    }
                }
            }

            var listOfRecurringOrderLineItemsUpdated = await CartRepository.RescheduleRecurringCartAsync(new RescheduleRecurringCartParam()
            {
                CustomerId    = param.CustomerId,
                NextOccurence = newDate,
                Scope         = param.Scope,
                CartName      = param.CartName
            });

            var vm = new RecurringOrderCartsRescheduleResultViewModel();

            var carts = await CartRepository.GetRecurringCartsAsync(new GetRecurringOrderCartsViewModelParam
            {
                BaseUrl     = param.BaseUrl,
                Scope       = param.Scope,
                CustomerId  = param.CustomerId,
                CultureInfo = param.CultureInfo
            });

            vm.RescheduledCartHasMerged = !carts.Any(rc => string.Equals(rc.Name, param.CartName, StringComparison.OrdinalIgnoreCase));

            var cartsVm = await GetRecurringOrderCartListViewModelFromCartsAsync(new GetRecurringOrderCartsViewModelFromCartsParam
            {
                Carts       = carts,
                BaseUrl     = param.BaseUrl,
                CultureInfo = param.CultureInfo
            });

            vm.RecurringOrderCartsViewModel = cartsVm;

            var url = RecurringCartUrlProvider.GetRecurringCartsUrl(new GetRecurringCartsUrlParam
            {
                CultureInfo = param.CultureInfo
            });

            vm.RecurringCartsUrl = url;

            return(vm);
        }