public void Can_run_activity_validatelineitems()
		{
			var orderGroup = CreateCart();

			orderGroup.OrderForms[0].LineItems[0].Catalog = "default";
			orderGroup.OrderForms[0].LineItems[0].CatalogItemId = "v-9948444183";
			orderGroup.OrderForms[0].LineItems[0].FulfillmentCenterId = "default";
			orderGroup.OrderForms[0].LineItems[0].Quantity = 4;
			orderGroup.OrderForms[0].LineItems[1].Catalog = "default";
			orderGroup.OrderForms[0].LineItems[1].CatalogItemId = "v-b000068ilf";
			orderGroup.OrderForms[0].LineItems[1].FulfillmentCenterId = "default";
			orderGroup.OrderForms[0].LineItems[1].Quantity = 10;


			var invAvailable = new Inventory
				{
					AllowBackorder = true,
					AllowPreorder = true,
					FulfillmentCenterId = "default",
					InStockQuantity = 10,
					Sku = "v-9948444183",
					ReservedQuantity = 1,
					Status = InventoryStatus.Enabled.GetHashCode(),
					BackorderQuantity = 5,
					PreorderQuantity = 3
				};

			var invNotAvailable = new Inventory
				{
					AllowBackorder = true,
					AllowPreorder = true,
					FulfillmentCenterId = "default",
					InStockQuantity = 14,
					Sku = "v-b000068ilf",
					ReservedQuantity = 10,
					BackorderQuantity = 10,
					Status = InventoryStatus.Enabled.GetHashCode(),
					PreorderQuantity = 4
				};

			var mockUnitOfWork = new Mock<IUnitOfWork>();
			var repository = new Mock<IInventoryRepository>();
			repository.Setup(x => x.Inventories).Returns(() => new[] { invAvailable, invNotAvailable }.AsQueryable());
			repository.Setup(x => x.UnitOfWork).Returns(mockUnitOfWork.Object);
			repository.SetupAllProperties();

			var item1 = new Product
				{
					ItemId = "v-9948444183",
					TrackInventory = true,
					IsActive = true,
					IsBuyable = true,
					StartDate = DateTime.UtcNow.AddDays(-1),
					EndDate = DateTime.UtcNow.AddDays(1)
				};

			var item2 = new Product
				{
					ItemId = "v-b000068ilf",
					IsActive = true,
					IsBuyable = true,
					TrackInventory = true,
					StartDate = DateTime.UtcNow.AddDays(-1),
					EndDate = DateTime.UtcNow.AddDays(1)
				};

			var catrepository = new Mock<ICatalogRepository>();
			catrepository.Setup(x => x.Items).Returns(() => new Item[] { item1, item2 }.AsQueryable());
			catrepository.Setup(x => x.UnitOfWork).Returns(mockUnitOfWork.Object);
			catrepository.SetupAllProperties();

			var store = new Store { StoreId = orderGroup.StoreId, Catalog = orderGroup.OrderForms[0].LineItems[0].Catalog };
			var storeRepository = new Mock<IStoreRepository>();
			storeRepository.Setup(x => x.Stores).Returns(() => new[] { store }.AsQueryable());

			var priceList = new Pricelist { PricelistId = "default", Currency = "USD" };
			var priceList2 = new Pricelist { PricelistId = "sale", Currency = "USD" };
			var prices = new[] 
            {
                new Price { List = 100, Sale = 90, MinQuantity = 1, ItemId = "v-9948444183" , PricelistId = "default"},
                new Price { List = 95, Sale = 85, MinQuantity = 5, ItemId = "v-9948444183", PricelistId = "default"},
                new Price { List = 98, Sale = 88, MinQuantity = 1, ItemId = "v-9948444183" , PricelistId = "sale"},
                new Price { List = 93, Sale = 83, MinQuantity = 5, ItemId = "v-9948444183", PricelistId = "sale"},
                new Price { List = 60, Sale = 50, MinQuantity = 1, ItemId = "v-b000068ilf" , PricelistId = "default"},
                new Price { List = 55, Sale = 45, MinQuantity = 5, ItemId = "v-b000068ilf", PricelistId = "default"},
                new Price { List = 58, Sale = 48, MinQuantity = 1, ItemId = "v-b000068ilf" , PricelistId = "sale"},
                new Price { List = 53, Sale = 43, MinQuantity = 5, ItemId = "v-b000068ilf", PricelistId = "sale"}

            };

			var priceRepository = new Mock<IPricelistRepository>();
			priceRepository.Setup(x => x.Pricelists).Returns(() => new[] { priceList2, priceList }.AsQueryable());
			priceRepository.Setup(x => x.Prices).Returns(prices.AsQueryable);

			var customerService = new CustomerSessionService();
			var session = customerService.CustomerSession;
			session.Currency = "USD";
			session.Pricelists = new[] { "Sale", "Default" };

			var currencyService = new CurrencyService();

			var cacheRepository = new Mock<ICacheRepository>();
			cacheRepository.SetupAllProperties();

			var activity = new ValidateLineItemsActivity(repository.Object, catrepository.Object, storeRepository.Object, customerService, priceRepository.Object, currencyService, null, null, cacheRepository.Object);

			var result = InvokeActivity(activity, orderGroup);

			var order = result.OrderGroup;
			// now check totals            

			// Order totals
			// Order form totals
			var form = order.OrderForms[0];

			Assert.True(form.LineItems.Count == 2);
			Assert.True(form.LineItems[0].InStockQuantity == 9);
			Assert.True(form.LineItems[0].PreorderQuantity == 3);
			Assert.True(form.LineItems[0].ListPrice == 88);
			Assert.True(form.LineItems[1].ListPrice == 43);
		}
		public void Can_run_activity_adjustinventory()
		{
			var invAvailable = new Inventory
				{
					AllowBackorder = true,
					AllowPreorder = true,
					BackorderAvailabilityDate = DateTime.Now,
					PreorderAvailabilityDate = DateTime.Now,
					FulfillmentCenterId = "default",
					InStockQuantity = 10,
					Sku = "v-9948444183",
					ReservedQuantity = 1,
					Status = InventoryStatus.Enabled.GetHashCode()
				};

			var invNotAvailable = new Inventory
				{
					AllowBackorder = true,
					AllowPreorder = true,
					BackorderAvailabilityDate = DateTime.Now,
					PreorderAvailabilityDate = DateTime.Now,
					FulfillmentCenterId = "default",
					InStockQuantity = 14,
					Sku = "v-b000068ilf",
					ReservedQuantity = 10,
					BackorderQuantity = 10,
					Status = InventoryStatus.Enabled.GetHashCode()
				};

			var mockUnitOfWork = new Mock<IUnitOfWork>();
			var repository = new Mock<IInventoryRepository>();
			repository.Setup(x => x.Inventories).Returns(() => new[] { invAvailable, invNotAvailable }.AsQueryable());
			repository.Setup(x => x.UnitOfWork).Returns(mockUnitOfWork.Object);
			repository.SetupAllProperties();

			var item1 = new Product
				{
					ItemId = "v-9948444183",
					TrackInventory = true
				};

			var item2 = new Product
				{
					ItemId = "v-b000068ilf",
					TrackInventory = true
				};
			var catrepository = new Mock<ICatalogRepository>();
			catrepository.Setup(x => x.Items).Returns(() => new Item[] { item1, item2 }.AsQueryable());
			catrepository.Setup(x => x.UnitOfWork).Returns(mockUnitOfWork.Object);
			catrepository.SetupAllProperties();

			var customerSession = new Mock<ICustomerSessionService>();

			var cacheRepository = new Mock<ICacheRepository>();
			cacheRepository.SetupAllProperties();

			var orderGroup = CreateCart();
			var activity = new AdjustInventoryActivity(catrepository.Object, repository.Object, customerSession.Object, cacheRepository.Object);
			//activity.InventoryRepository = _repository.Object;
			//activity.CatalogRepository = _catrepository.Object;

			orderGroup.OrderForms[0].LineItems[0].CatalogItemId = "v-9948444183";
			orderGroup.OrderForms[0].LineItems[0].FulfillmentCenterId = "default";
			orderGroup.OrderForms[0].LineItems[0].Quantity = 6;
			orderGroup.OrderForms[0].LineItems[1].CatalogItemId = "v-b000068ilf";
			orderGroup.OrderForms[0].LineItems[1].FulfillmentCenterId = "default";
			orderGroup.OrderForms[0].LineItems[1].Quantity = 10;

			InvokeActivity(activity, orderGroup);

			// validate adjusted inventory
			var inventory = repository.Object.Inventories.SingleOrDefault(i => i.FulfillmentCenterId.Equals("default", StringComparison.OrdinalIgnoreCase)
																			   && i.Sku.Equals("v-9948444183", StringComparison.OrdinalIgnoreCase));

			Assert.True(inventory != null && inventory.InStockQuantity == 4);

			inventory = repository.Object.Inventories.SingleOrDefault(i => i.FulfillmentCenterId.Equals("default", StringComparison.OrdinalIgnoreCase)
																		   && i.Sku.Equals("v-b000068ilf", StringComparison.OrdinalIgnoreCase));

			Assert.True(inventory != null && inventory.InStockQuantity == 10);
			Assert.True(inventory != null && inventory.BackorderQuantity == 4);
		}
        /// <summary>
        /// Populates the inventory information.
        /// </summary>
        /// <param name="inventory">The inventory.</param>
        /// <param name="lineItem">The line item.</param>
		private void PopulateInventoryInfo(Inventory inventory, LineItem lineItem)
		{
			
			if (inventory == null)
			{
				return;
			}

			// Inventory info
			lineItem.AllowBackorders = inventory.AllowBackorder &&
					 inventory.BackorderAvailabilityDate.HasValue &&
					 inventory.BackorderAvailabilityDate.Value <= DateTime.Now;

			lineItem.AllowPreorders = inventory.AllowPreorder &&
								inventory.PreorderAvailabilityDate.HasValue &&
								inventory.PreorderAvailabilityDate.Value <= DateTime.Now;


			//Init quantities once
			lineItem.BackorderQuantity = lineItem.BackorderQuantity == 0 ? inventory.BackorderQuantity : lineItem.BackorderQuantity;
			lineItem.InStockQuantity = lineItem.InStockQuantity == 0 ? inventory.InStockQuantity - inventory.ReservedQuantity : lineItem.InStockQuantity;
			lineItem.PreorderQuantity = lineItem.PreorderQuantity == 0  ? inventory.PreorderQuantity : lineItem.PreorderQuantity;
			lineItem.InventoryStatus = ((InventoryStatus)inventory.Status).ToString();
		}
        private ItemAvailability GetItemAvailabilityInternal(Item item, Inventory inventory)
        {
            var retVal = new ItemAvailability
            {
                MinQuantity = item.MinQuantity,
                MaxQuantity = item.MaxQuantity,
                ItemId = item.ItemId
            };

            if (item.IsBuyable
                && item.StartDate < CustomerSession.CurrentDateTime
                && (!item.EndDate.HasValue || item.EndDate > CustomerSession.CurrentDateTime))
            {
                if (item.TrackInventory)
                {
                    if (inventory != null && (InventoryStatus)inventory.Status == InventoryStatus.Enabled)
                    {
                        var inStock = inventory.InStockQuantity - inventory.ReservedQuantity;

                        if (inStock > 0
                            && (item.AvailabilityRule == (int)AvailabilityRule.Always
                                || item.AvailabilityRule == (int)AvailabilityRule.WhenInStock))
                        {
                            retVal.MaxQuantity = inStock;
                            retVal.Availability = ItemStoreAvailabity.InStore;
                            retVal.MaxQuantity = Math.Max(retVal.MinQuantity, retVal.MaxQuantity);
                            retVal.MinQuantity = Math.Min(retVal.MinQuantity, retVal.MaxQuantity);
                            return retVal;
                        }
                        if (inventory.AllowBackorder
                            && inventory.BackorderAvailabilityDate.HasValue
                            && (item.AvailabilityRule == (int)AvailabilityRule.Always
                                || item.AvailabilityRule == (int)AvailabilityRule.OnBackorder))
                        {
                            retVal.MaxQuantity = inStock + inventory.BackorderQuantity;

                            if (retVal.MaxQuantity > 0)
                            {
                                retVal.Availability = ItemStoreAvailabity.AvailableForBackOrder;
                                retVal.Date = inventory.BackorderAvailabilityDate;
                                retVal.MaxQuantity = Math.Max(retVal.MinQuantity, retVal.MaxQuantity);
                                retVal.MinQuantity = Math.Min(retVal.MinQuantity, retVal.MaxQuantity);
                                return retVal;
                            }
                        }

                        if (inventory.AllowPreorder
                            && inventory.PreorderAvailabilityDate.HasValue)
                        {

                            retVal.MaxQuantity = inventory.PreorderQuantity;

                            if (retVal.MaxQuantity > 0 &&
                                (item.AvailabilityRule == (int)AvailabilityRule.Always ||
                                 item.AvailabilityRule == (int)AvailabilityRule.OnPreorder))
                            {
                                retVal.Availability = ItemStoreAvailabity.AvailableForPreOrder;
                                retVal.Date = inventory.PreorderAvailabilityDate;
                                retVal.MaxQuantity = Math.Max(retVal.MinQuantity, retVal.MaxQuantity);
                                retVal.MinQuantity = Math.Min(retVal.MinQuantity, retVal.MaxQuantity);
                                return retVal;
                            }
                        }
                    }
                }
                else
                {
                    retVal.MaxQuantity = item.MaxQuantity;
                    if (retVal.MaxQuantity > 0
                        && (item.AvailabilityRule == (int)AvailabilityRule.Always
                            || item.AvailabilityRule == (int)AvailabilityRule.WhenInStock))
                    {
                        retVal.Availability = ItemStoreAvailabity.InStore;
                    }
                    retVal.MaxQuantity = Math.Max(retVal.MinQuantity, retVal.MaxQuantity);
                    retVal.MinQuantity = Math.Min(retVal.MinQuantity, retVal.MaxQuantity);
                }
            }

            return retVal;
        }
        private static bool AdjustStockInventoryQuantity(LineItem lineItem, Inventory inventory)
        {
            var delta = GetLineItemAdjustedQuantity(lineItem);

			var allowBackorder = inventory.AllowBackorder && 
				inventory.BackorderAvailabilityDate.HasValue && 
				inventory.BackorderAvailabilityDate.Value <= DateTime.Now;

			var allowPreorder = inventory.AllowPreorder &&
				inventory.PreorderAvailabilityDate.HasValue &&
				inventory.PreorderAvailabilityDate.Value <= DateTime.Now;

	        var inventoryAdjusted = false;

            //arrival
            if (delta > 0)
            {
                // need distribute delta between InStock, Backorder, Preorder.
                if (lineItem.InStockQuantity > 0)
                {                                 
	                var inStock = delta;

	                if (allowPreorder)
	                {
						var preorderdelta = Math.Min(delta, lineItem.PreorderQuantity - inventory.PreorderQuantity);
		                inventory.PreorderQuantity += preorderdelta;
						inStock -= preorderdelta;
	                }
	                if (allowBackorder)
	                {
						var backorderDelta = Math.Min(delta, lineItem.BackorderQuantity - inventory.BackorderQuantity);
		                inventory.BackorderQuantity += backorderDelta;
		                inStock -= backorderDelta;
	                }
					inventory.InStockQuantity += inStock;
					inventoryAdjusted = true;
                } //need distribute delta between Preorder and Backorder
                else if (lineItem.InStockQuantity == 0)
                {
                    if (lineItem.PreorderQuantity > 0 && allowPreorder)
                    {
                        inventory.PreorderQuantity += delta;
						inventoryAdjusted = true;
                    }
                    else if (lineItem.BackorderQuantity > 0 && allowBackorder)
                    {
                        inventory.BackorderQuantity += delta;
						inventoryAdjusted = true;
                    }
                }
            }//consumption
            else
            {
                delta = Math.Abs(delta);
                var instock = inventory.InStockQuantity - inventory.ReservedQuantity;
                if (instock >= delta) // Adjust the main inventory
                {
                    inventory.InStockQuantity -= delta;
					inventoryAdjusted = true;
                }
                else if (instock > 0) // there still exist items in stock
                {
	                if (allowBackorder)
	                {
		                // Calculate difference between currently available and backorder
		                var backorderDelta = delta - instock;

		                if (inventory.BackorderQuantity >= backorderDelta)
		                {
			                // Update inventory
			                inventory.InStockQuantity -= instock;
			                inventory.BackorderQuantity -= backorderDelta;
							inventoryAdjusted = true;
		                }
	                }
                }
                else if (instock == 0)
                {
					if (allowBackorder && inventory.BackorderQuantity >= delta)
					{
						inventory.BackorderQuantity -= delta;
						inventoryAdjusted = true;
					}
					else if (allowPreorder && inventory.PreorderQuantity >= delta)
					{
						inventory.PreorderQuantity -= delta;
						inventoryAdjusted = true;
					}
                }
            }

			return inventoryAdjusted;
        }