Ejemplo n.º 1
0
        private async Task ValidateVariantsAsync(SuperHSProduct superProduct, string token)
        {
            List <Variant> allVariants = new List <Variant>();

            if (superProduct.Variants == null || !superProduct.Variants.Any())
            {
                return;
            }

            try
            {
                var allProducts = await _oc.Products.ListAllAsync(accessToken : token);

                if (allProducts == null || !allProducts.Any())
                {
                    return;
                }

                foreach (Product product in allProducts)
                {
                    if (product.VariantCount > 0 && product.ID != superProduct.Product.ID)
                    {
                        allVariants.AddRange((await _oc.Products.ListVariantsAsync(productID: product.ID, pageSize: 100, accessToken: token)).Items);
                    }
                }
            }
            catch (Exception ex)
            {
                return;
            }

            foreach (Variant variant in superProduct.Variants)
            {
                if (!allVariants.Any())
                {
                    return;
                }

                List <Variant> duplicateSpecNames = allVariants.Where(currVariant => IsDifferentVariantWithSameName(variant, currVariant)).ToList();
                if (duplicateSpecNames.Any())
                {
                    throw new Exception($"{duplicateSpecNames.First().ID} already exists on a variant. Please use unique names for SKUS and try again.");
                }
            }
        }
Ejemplo n.º 2
0
 public async Task <SuperHSProduct> Put([FromBody] SuperHSProduct obj, string id)
 {
     return(await _command.Put(id, obj, UserContext.AccessToken));
 }
Ejemplo n.º 3
0
 public async Task <SuperHSProduct> Post([FromBody] SuperHSProduct obj)
 {
     return(await _command.Post(obj, UserContext));
 }
Ejemplo n.º 4
0
        public async Task <SuperHSProduct> Put(string id, SuperHSProduct superProduct, string token)
        {
            // Update the Product itself
            var _updatedProduct = await _oc.Products.SaveAsync <HSProduct>(superProduct.Product.ID, superProduct.Product, token);

            // Two spec lists to compare (requestSpecs and existingSpecs)
            IList <Spec> requestSpecs  = superProduct.Specs.ToList();
            IList <Spec> existingSpecs = (await _oc.Products.ListSpecsAsync(id, accessToken: token)).Items.ToList();
            // Two variant lists to compare (requestVariants and existingVariants)
            IList <HSVariant> requestVariants  = superProduct.Variants;
            IList <Variant>   existingVariants = (await _oc.Products.ListVariantsAsync(id, pageSize: 100, accessToken: token)).Items.ToList();
            // Calculate differences in specs - specs to add, and specs to delete
            var specsToAdd    = requestSpecs.Where(s => !existingSpecs.Any(s2 => s2.ID == s.ID)).ToList();
            var specsToDelete = existingSpecs.Where(s => !requestSpecs.Any(s2 => s2.ID == s.ID)).ToList();

            // Get spec options to add -- WAIT ON THESE, RUN PARALLEL THE ADD AND DELETE SPEC REQUESTS
            foreach (var rSpec in requestSpecs)
            {
                foreach (var eSpec in existingSpecs)
                {
                    if (rSpec.ID == eSpec.ID)
                    {
                        await Throttler.RunAsync(rSpec.Options.Where(rso => !eSpec.Options.Any(eso => eso.ID == rso.ID)), 100, 5, o => _oc.Specs.CreateOptionAsync(rSpec.ID, o, accessToken: token));

                        await Throttler.RunAsync(eSpec.Options.Where(eso => !rSpec.Options.Any(rso => rso.ID == eso.ID)), 100, 5, o => _oc.Specs.DeleteOptionAsync(rSpec.ID, o.ID, accessToken: token));
                    }
                }
                ;
            }
            ;
            // Create new specs and Delete removed specs
            var defaultSpecOptions = new List <DefaultOptionSpecAssignment>();
            await Throttler.RunAsync(specsToAdd, 100, 5, s =>
            {
                defaultSpecOptions.Add(new DefaultOptionSpecAssignment {
                    SpecID = s.ID, OptionID = s.DefaultOptionID
                });
                s.DefaultOptionID = null;
                return(_oc.Specs.SaveAsync <Spec>(s.ID, s, accessToken: token));
            });

            await Throttler.RunAsync(specsToDelete, 100, 5, s => _oc.Specs.DeleteAsync(s.ID, accessToken: token));

            // Add spec options for new specs
            foreach (var spec in specsToAdd)
            {
                await Throttler.RunAsync(spec.Options, 100, 5, o => _oc.Specs.CreateOptionAsync(spec.ID, o, accessToken: token));
            }
            // Patch Specs with requested DefaultOptionID
            await Throttler.RunAsync(defaultSpecOptions, 100, 10, a => _oc.Specs.PatchAsync(a.SpecID, new PartialSpec {
                DefaultOptionID = a.OptionID
            }, accessToken: token));

            // Make assignments for the new specs
            await Throttler.RunAsync(specsToAdd, 100, 5, s => _oc.Specs.SaveProductAssignmentAsync(new SpecProductAssignment {
                ProductID = id, SpecID = s.ID
            }, accessToken: token));

            HandleSpecOptionChanges(requestSpecs, existingSpecs, token);
            // Check if Variants differ
            var  variantsAdded    = requestVariants.Any(v => !existingVariants.Any(v2 => v2.ID == v.ID));
            var  variantsRemoved  = existingVariants.Any(v => !requestVariants.Any(v2 => v2.ID == v.ID));
            bool hasVariantChange = false;

            foreach (Variant variant in requestVariants)
            {
                ValidateRequestVariant(variant);
                var currVariant = existingVariants.Where(v => v.ID == variant.ID);
                if (currVariant == null || currVariant.Count() < 1)
                {
                    continue;
                }
                hasVariantChange = HasVariantChange(variant, currVariant.First());
                if (hasVariantChange)
                {
                    break;
                }
            }
            // IF variants differ, then re-generate variants and re-patch IDs to match the user input.
            if (variantsAdded || variantsRemoved || hasVariantChange || requestVariants.Any(v => v.xp.NewID != null))
            {
                //validate variant names before continuing saving.
                await ValidateVariantsAsync(superProduct, token);

                // Re-generate Variants
                await _oc.Products.GenerateVariantsAsync(id, overwriteExisting : true, accessToken : token);

                // Patch NEW variants with the User Specified ID (Name,ID), and correct xp values (SKU)
                await Throttler.RunAsync(superProduct.Variants, 100, 5, v =>
                {
                    v.ID   = v.xp.NewID ?? v.ID;
                    v.Name = v.xp.NewID ?? v.ID;
                    if ((superProduct?.Product?.Inventory?.VariantLevelTracking) == true && v.Inventory == null)
                    {
                        v.Inventory = new PartialVariantInventory {
                            QuantityAvailable = 0
                        };
                    }
                    if (superProduct.Product?.Inventory == null)
                    {
                        //If Inventory doesn't exist on the product, don't patch variants with inventory either.
                        return(_oc.Products.PatchVariantAsync(id, $"{superProduct.Product.ID}-{v.xp.SpecCombo}", new PartialVariant {
                            ID = v.ID, Name = v.Name, xp = v.xp, Active = v.Active
                        }, accessToken: token));
                    }
                    else
                    {
                        return(_oc.Products.PatchVariantAsync(id, $"{superProduct.Product.ID}-{v.xp.SpecCombo}", new PartialVariant {
                            ID = v.ID, Name = v.Name, xp = v.xp, Active = v.Active, Inventory = v.Inventory
                        }, accessToken: token));
                    }
                });
            }
            ;
            // If applicable, update OR create the Product PriceSchedule
            var tasks = new List <Task>();
            Task <PriceSchedule> _priceScheduleReq = null;

            if (superProduct.PriceSchedule != null)
            {
                _priceScheduleReq = UpdateRelatedPriceSchedules(superProduct.PriceSchedule, token);
                tasks.Add(_priceScheduleReq);
            }
            // List Variants
            var _variantsReq = _oc.Products.ListVariantsAsync <HSVariant>(id, pageSize: 100, accessToken: token);

            tasks.Add(_variantsReq);
            // List Product Specs
            var _specsReq = _oc.Products.ListSpecsAsync <Spec>(id, accessToken: token);

            tasks.Add(_specsReq);

            await Task.WhenAll(tasks);

            return(new SuperHSProduct
            {
                Product = _updatedProduct,
                PriceSchedule = _priceScheduleReq?.Result,
                Specs = _specsReq?.Result?.Items,
                Variants = _variantsReq?.Result?.Items,
            });
        }
Ejemplo n.º 5
0
        public async Task <SuperHSProduct> Post(SuperHSProduct superProduct, VerifiedUserContext user)
        {
            // Determine ID up front so price schedule ID can match
            superProduct.Product.ID = superProduct.Product.ID ?? CosmosInteropID.New();

            await ValidateVariantsAsync(superProduct, user.AccessToken);

            // Create Specs
            var defaultSpecOptions = new List <DefaultOptionSpecAssignment>();
            var specRequests       = await Throttler.RunAsync(superProduct.Specs, 100, 5, s =>
            {
                defaultSpecOptions.Add(new DefaultOptionSpecAssignment {
                    SpecID = s.ID, OptionID = s.DefaultOptionID
                });
                s.DefaultOptionID = null;
                return(_oc.Specs.SaveAsync <Spec>(s.ID, s, accessToken: user.AccessToken));
            });

            // Create Spec Options
            foreach (Spec spec in superProduct.Specs)
            {
                await Throttler.RunAsync(spec.Options, 100, 5, o => _oc.Specs.SaveOptionAsync(spec.ID, o.ID, o, accessToken: user.AccessToken));
            }
            // Patch Specs with requested DefaultOptionID
            await Throttler.RunAsync(defaultSpecOptions, 100, 10, a => _oc.Specs.PatchAsync(a.SpecID, new PartialSpec {
                DefaultOptionID = a.OptionID
            }, accessToken: user.AccessToken));

            // Create Price Schedule
            PriceSchedule _priceSchedule = null;

            //All products must have a price schedule for orders to be submitted.  The front end provides a default Price of $0 for quote products that don't have one.
            superProduct.PriceSchedule.ID = superProduct.Product.ID;
            try
            {
                _priceSchedule = await _oc.PriceSchedules.CreateAsync <PriceSchedule>(superProduct.PriceSchedule, user.AccessToken);
            }
            catch (OrderCloudException ex)
            {
                if (ex.HttpStatus == System.Net.HttpStatusCode.Conflict)
                {
                    throw new Exception($"Product SKU {superProduct.PriceSchedule.ID} already exists.  Please try a different SKU.");
                }
            }
            superProduct.Product.DefaultPriceScheduleID = _priceSchedule.ID;
            // Create Product
            if (user.Supplier != null)
            {
                var supplierName = await GetSupplierNameForXpFacet(user.Supplier.ID, user.AccessToken);

                superProduct.Product.xp.Facets.Add("supplier", new List <string>()
                {
                    supplierName
                });
            }
            var _product = await _oc.Products.CreateAsync <HSProduct>(superProduct.Product, user.AccessToken);

            // Make Spec Product Assignments
            await Throttler.RunAsync(superProduct.Specs, 100, 5, s => _oc.Specs.SaveProductAssignmentAsync(new SpecProductAssignment {
                ProductID = _product.ID, SpecID = s.ID
            }, accessToken: user.AccessToken));

            // Generate Variants
            await _oc.Products.GenerateVariantsAsync(_product.ID, accessToken : user.AccessToken);

            // Patch Variants with the User Specified ID(SKU) AND necessary display xp values
            await Throttler.RunAsync(superProduct.Variants, 100, 5, v =>
            {
                var oldVariantID = v.ID;
                v.ID             = v.xp.NewID ?? v.ID;
                v.Name           = v.xp.NewID ?? v.ID;

                if ((superProduct?.Product?.Inventory?.VariantLevelTracking) == true && v.Inventory == null)
                {
                    v.Inventory = new PartialVariantInventory {
                        QuantityAvailable = 0
                    };
                }
                if (superProduct.Product?.Inventory == null)
                {
                    //If Inventory doesn't exist on the product, don't patch variants with inventory either.
                    return(_oc.Products.PatchVariantAsync(_product.ID, oldVariantID, new PartialVariant {
                        ID = v.ID, Name = v.Name, xp = v.xp
                    }, accessToken: user.AccessToken));
                }
                else
                {
                    return(_oc.Products.PatchVariantAsync(_product.ID, oldVariantID, new PartialVariant {
                        ID = v.ID, Name = v.Name, xp = v.xp, Inventory = v.Inventory
                    }, accessToken: user.AccessToken));
                }
            });


            // List Variants
            var _variants = await _oc.Products.ListVariantsAsync <HSVariant>(_product.ID, accessToken : user.AccessToken);

            // List Product Specs
            var _specs = await _oc.Products.ListSpecsAsync <Spec>(_product.ID, accessToken : user.AccessToken);

            // Return the SuperProduct
            return(new SuperHSProduct
            {
                Product = _product,
                PriceSchedule = _priceSchedule,
                Specs = _specs.Items,
                Variants = _variants.Items,
            });
        }
Ejemplo n.º 6
0
        public async Task <ListPage <Document <MonitoredProductFieldModifiedNotification> > > ReadMonitoredSuperProductNotificationList(SuperHSProduct product, VerifiedUserContext user)
        {
            var token = await GetAdminToken();

            ListArgs <Document <MonitoredProductFieldModifiedNotification> > args;
            var queryParams = new Tuple <string, string>("ID", $"{product.Product.ID}_*");

            args = new ListArgs <Document <MonitoredProductFieldModifiedNotification> >()
            {
                PageSize = 100
            };
            args.Filters.Add(new ListFilter()
            {
                QueryParams = new List <Tuple <string, string> > {
                    queryParams
                }
            });

            var document = await GetDocumentsByPageAsync(args, token);

            return(document);
        }
 public async Task <ListPage <Document <MonitoredProductFieldModifiedNotification> > > ReadMonitoredSuperProductNotificationStatus([FromBody] SuperHSProduct product)
 {
     return(await _command.ReadMonitoredSuperProductNotificationList(product, VerifiedUserContext));
 }
 public async Task <SuperHSProduct> PostHydratedProduct([FromBody] SuperHSProduct obj)
 {
     return(await _command.SaveToQueue(obj, this.VerifiedUserContext, this.VerifiedUserContext.SupplierID));
 }