/// <summary> /// Retrieve product stock broke down by location /// </summary> /// <param name="sku"></param> /// <param name="warehouseId"></param> /// <param name="token"></param> /// <param name="mark"></param> /// <returns></returns> public async Task <IEnumerable <SkubanaProductStock> > GetDetailedProductStock(string sku, long warehouseId, CancellationToken token, Mark mark = null) { if (mark == null) { mark = Mark.CreateNew(); } if (token.IsCancellationRequested) { var exceptionDetails = CreateMethodCallInfo(base.Config.Environment.BaseApiUrl, mark, additionalInfo: this.AdditionalLogInfo()); SkubanaLogger.LogTraceException(new SkubanaException(string.Format("{0}. Retrieve product detailed stock request was cancelled", exceptionDetails))); } using (var throttler = new Throttler(5, 1)) { using (var command = new GetProductStockCommand(base.Config, sku, warehouseId) { Throttler = throttler }) { var stock = await base.GetAsync <IEnumerable <DetailedProductStock> >(command, token, mark).ConfigureAwait(false); return(stock.Select(s => new SkubanaProductStock() { ProductId = s.Product.Id, ProductSku = s.Product.Sku, OnHandQuantity = s.Quantity, LocationName = s.Location.LocationName })); } } }
/// <summary> /// Create products stocks /// </summary> /// <param name="productsQuantities"></param> /// <param name="warehouseId"></param> /// <param name="token"></param> /// <param name="mark"></param> /// <returns></returns> private async Task CreateProductsStock(IEnumerable <SkubanaProductStock> productsStock, long warehouseId, CancellationToken token, Mark mark = null) { if (mark == null) { mark = Mark.CreateNew(); } if (token.IsCancellationRequested) { var exceptionDetails = CreateMethodCallInfo(base.Config.Environment.BaseApiUrl, mark, additionalInfo: this.AdditionalLogInfo()); SkubanaLogger.LogTraceException(new SkubanaException(string.Format("{0}. Create products stocks request was cancelled", exceptionDetails))); } var chunks = productsStock.SplitToChunks(base.Config.CreateProductStockBatchSize); using (var throttler = new Throttler(1, 30)) { foreach (var chunk in chunks) { var command = new CreateProductsStockCommand(base.Config, chunk, warehouseId) { Throttler = throttler }; var response = await base.PutAsync <SkubanaResponse <UpdatedProductStockInfo> >(command, token, mark).ConfigureAwait(false); if (response.Errors != null && response.Errors.Any()) { throw new SkubanaException(response.Errors.ToJson()); } } } }
/// <summary> /// Retrieve products stock totals. /// This is the physical inventory count present (e.g. it does not include potentially buildable bundles or kits). /// In transit quantity does not include pending Purchase Orders. /// </summary> /// <param name="warehouseId"></param> /// <param name="token"></param> /// <param name="mark"></param> /// <returns></returns> public async Task <IEnumerable <SkubanaProductStock> > GetProductsStock(long warehouseId, CancellationToken token, Mark mark = null) { if (mark == null) { mark = Mark.CreateNew(); } if (token.IsCancellationRequested) { var exceptionDetails = CreateMethodCallInfo(base.Config.Environment.BaseApiUrl, mark, additionalInfo: this.AdditionalLogInfo()); SkubanaLogger.LogTraceException(new SkubanaException(string.Format("{0}. Get products stock total request was cancelled", exceptionDetails))); } var productsStock = new List <SkubanaProductStock>(); int pageIndex = 1; using (var throttler = new Throttler(10, 1)) { while (true) { var command = new RetrieveProductsStocksTotalCommand(base.Config, warehouseId, pageIndex, base.Config.RetrieveProductsStocksTotalPageSize) { Throttler = throttler }; var pageData = await base.GetAsync <IEnumerable <ProductStock> >(command, token, mark).ConfigureAwait(false); if (pageData == null || !pageData.Any()) { break; } ++pageIndex; productsStock.AddRange(pageData.Select(p => new SkubanaProductStock() { ProductId = p.Product.Id, ProductSku = p.Product.Sku, OnHandQuantity = p.OnHandQuantity })); } } return(productsStock); }
public async Task <IEnumerable <SkubanaWarehouse> > ListWarehouses(CancellationToken token, Mark mark = null) { if (mark == null) { mark = Mark.CreateNew(); } if (token.IsCancellationRequested) { var exceptionDetails = CreateMethodCallInfo(base.Config.Environment.BaseApiUrl, mark, additionalInfo: this.AdditionalLogInfo()); SkubanaLogger.LogTraceException(new SkubanaException(string.Format("{0}. List warehouses request was cancelled", exceptionDetails))); } using (var command = new ListWarehousesCommand(base.Config)) { var response = await base.GetAsync <IEnumerable <Warehouse> >(command, token, mark); return(response.Select(r => r.ToSVWarehouse())); } }
public async Task <IEnumerable <SkubanaProduct> > GetProductsUpdatedAfterAsync(DateTime updatedAfterUtc, CancellationToken token, Mark mark = null) { if (mark == null) { mark = Mark.CreateNew(); } if (token.IsCancellationRequested) { var exceptionDetails = CreateMethodCallInfo(base.Config.Environment.BaseApiUrl, mark, additionalInfo: this.AdditionalLogInfo()); SkubanaLogger.LogTraceException(new SkubanaException(string.Format("{0}. Retrieve updated products request was cancelled", exceptionDetails))); } var result = new List <SkubanaProduct>(); using (var throttler = new Throttler(5, 1)) { var page = 1; while (true) { var command = new RetrieveProductsUpdatedAfterCommand(base.Config, updatedAfterUtc, page, base.Config.RetrieveProductsPageSize) { Throttler = throttler }; var response = await base.GetAsync <IEnumerable <Product> >(command, token, mark).ConfigureAwait(false); if (response == null || !response.Any()) { break; } result.AddRange(response.Where(p => p.Type == ProductType.CoreProduct.Type) .Select(r => r.ToSVProduct())); ++page; } } return(result); }
public async Task <IEnumerable <SkubanaOrder> > GetModifiedOrdersAsync(DateTime startDateUtc, DateTime endDateUtc, long warehouseId, CancellationToken token, Mark mark = null) { if (mark == null) { mark = Mark.CreateNew(); } if (token.IsCancellationRequested) { var exceptionDetails = CreateMethodCallInfo(base.Config.Environment.BaseApiUrl, mark, additionalInfo: this.AdditionalLogInfo()); SkubanaLogger.LogTraceException(new SkubanaException(string.Format("{0}. Get modified orders request was cancelled", exceptionDetails))); } var result = new List <SkubanaOrder>(); var page = 1; using (var throttler = new Throttler(5, 1)) { while (true) { var command = new RetrieveOrdersCommand(base.Config, startDateUtc, endDateUtc, warehouseId, page, base.Config.RetrieveOrdersPageSize) { Throttler = throttler }; var pageData = await base.GetAsync <IEnumerable <Order> >(command, token, mark).ConfigureAwait(false); if (pageData == null || !pageData.Any()) { break; } result.AddRange(pageData.Select(o => o.ToSVOrder())); ++page; } } return(result); }
public async Task <IEnumerable <SkubanaProduct> > GetProductsBySkus(IEnumerable <string> skus, CancellationToken token, Mark mark = null) { if (mark == null) { mark = Mark.CreateNew(); } if (token.IsCancellationRequested) { var exceptionDetails = CreateMethodCallInfo(base.Config.Environment.BaseApiUrl, mark, additionalInfo: this.AdditionalLogInfo()); SkubanaLogger.LogTraceException(new SkubanaException(string.Format("{0}. Retrieve products request was cancelled", exceptionDetails))); } var chunks = skus.SplitToChunks(base.Config.RetrieveProductsBySkusBatchSize); var result = new List <SkubanaProduct>(); using (var throttler = new Throttler(5, 1)) { foreach (var chunk in chunks) { var command = new RetrieveProductsCommand(base.Config, chunk) { Throttler = throttler }; var response = await base.GetAsync <IEnumerable <Product> >(command, token, mark); if (response != null) { // Skubana product search isn't strict var products = response.Select(r => r.ToSVProduct()).Where(p => chunk.Any(c => c.ToLower().Equals(p.Sku.ToLower()))).ToList(); result.AddRange(products); } } } return(result); }
/// <summary> /// Adjust products stocks quantities, will override existing quantities. /// This endpoint should be used carefully as it might override pending activity. /// Product's stock should already exists. /// </summary> /// <param name="skusQuantitiesByLocation"></param> /// <param name="warehouseId"></param> /// <param name="token"></param> /// <param name="mark"></param> /// <returns></returns> private async Task <AdjustProductStockQuantityResponse> AdjustProductsStockQuantities(IEnumerable <SkubanaProductStock> skusQuantities, long warehouseId, CancellationToken token, Mark mark = null) { if (mark == null) { mark = Mark.CreateNew(); } if (token.IsCancellationRequested) { var exceptionDetails = CreateMethodCallInfo(base.Config.Environment.BaseApiUrl, mark, additionalInfo: this.AdditionalLogInfo()); SkubanaLogger.LogTraceException(new SkubanaException(string.Format("{0}. Adjust products stocks quantities request was cancelled", exceptionDetails))); } var chunks = skusQuantities.SplitToChunks(this.Config.UpdateProductStockBatchSize); var result = new AdjustProductStockQuantityResponse(); using (var throttler = new Throttler(1, 10)) { foreach (var chunk in chunks) { var command = new AdjustProductsStockCommand(base.Config, chunk, warehouseId) { Throttler = throttler }; var response = await base.PostAsync <SkubanaResponse <UpdatedProductStockInfo> >(command, token, mark).ConfigureAwait(false); if (response.Errors != null && response.Errors.Any()) { var criticalErrors = new List <SkubanaResponseError>(); foreach (var error in response.Errors) { if (error.ErrorCode == SkubanaValidationErrors.ProductStockNotFound.Code) { var locationWithoutStock = chunk[error.Index - 1].LocationName; if (result.ProductsWithoutStocks.TryGetValue(chunk[error.Index - 1].ProductSku, out List <string> locations)) { locations.Add(locationWithoutStock); } else { result.ProductsWithoutStocks.Add(chunk[error.Index - 1].ProductSku, new List <string>() { { locationWithoutStock } }); } } else if (error.ErrorCode == SkubanaValidationErrors.ProductDoesNotExist.Code) { result.ProductsNotExist.Add(error.Identifier); } else { criticalErrors.Add(error); } } if (criticalErrors.Any()) { throw new SkubanaException(criticalErrors.ToJson()); } } } } return(result); }