private void UpdatePrice(KCDataExchangeMaint masterGraph, KCMSMQInventoryPrice priceProduct, KCInventoryItemAPIHelper helper)
        {
            InventoryItem inventoryItem = masterGraph.ProductByInvCd.Select(priceProduct.InventoryID.Trim());

            if (inventoryItem != null)
            {
                KNSIKCInventoryItem kcProduct          = masterGraph.KCInventoryItem.SelectSingle(inventoryItem.InventoryID);
                InventoryItemPCExt  inventoryItemPCExt = inventoryItem.GetExtension <InventoryItemPCExt>();
                InventoryItem       parent             = KCGeneralDataHelper.GetInventoryItemByInventoryId(PXGraph.CreateInstance <KCDataExchangeMaint>(), inventoryItemPCExt.UsrKNCompositeID);

                logger.SetParentAndEntityIds(parent?.InventoryCD, inventoryItem.InventoryCD);

                try
                {
                    if (kcProduct.UsrKCCAID != null)
                    {
                        helper.EditProduct(KCMapInventoryItem.GetAPIMSMQInventoryPrice(priceProduct), kcProduct.UsrKCCAID);
                    }

                    logger.Information(KCMessages.MSMQSyncAPI);
                }
                catch (Exception e)
                {
                    logger.Information(e.Message);
                }
            }
        }
        public List <KCBulkProduct> HandleItems(List <KeyValuePair <string, InventoryItem> > productsForExport,
                                                Dictionary <string, KCAPIInventoryItem> MSMQPrices             = null,
                                                Dictionary <string, List <KCAPIQuantity> > MSMQQuantityUpdates = null)
        {
            if (productsForExport.Count == 0)
            {
                return(new List <KCBulkProduct>(0));
            }

            var dtos           = new List <Tuple <string, InventoryItem, KCBulkProduct> >(productsForExport.Count);
            var availableTasks = Environment.ProcessorCount - 1;
            var itemsToProcess = productsForExport.SplitList((productsForExport.Count / availableTasks) + 1).ToArray();

            Task[] tasks  = new Task[itemsToProcess.Length];
            object locker = new object();

            //force load extensions to slot (GetSlot<PXCacheExtensionCollection>)
            productsForExport[0].Value.GetExtension <InventoryItemPCExt>();

            //get slot data with extensions (slots are located in CallContext)
            var cacheExtensions = CallContext.GetData("PX.Data.PXCacheExtensionCollection");


            for (int x = 0; x < itemsToProcess.Length; x++)
            {
                int index = x;
                var items = itemsToProcess[index];
                tasks[index] = new Task(() =>
                {
                    //Set slot with extensions to other thread
                    CallContext.SetData("PX.Data.PXCacheExtensionCollection", cacheExtensions);
                    var graph = PXGraph.CreateInstance <KCBulkProductMaint>();
                    KCRelationshipSetupMaint relationshipGraph         = PXGraph.CreateInstance <KCRelationshipSetupMaint>();
                    KCClassificationsMappingMaint classificationsGraph = PXGraph.CreateInstance <KCClassificationsMappingMaint>();
                    KCIItemConversionDataMaint conversionGraph         = PXGraph.CreateInstance <KCIItemConversionDataMaint>();
                    KCMapInventoryItem itemMapper = new KCMapInventoryItem(relationshipGraph, classificationsGraph, graph, conversionGraph, _store, logger.LoggerProperties);

                    foreach (KeyValuePair <string, InventoryItem> product in items)
                    {
                        InventoryItem inventoryItem = product.Value;
                        var key = inventoryItem.InventoryCD;

                        KCAPIInventoryItem apiProduct = itemMapper.GetAPIInventoryItem(inventoryItem);
                        if (MSMQPrices != null)
                        {
                            apiProduct = SetPrices(apiProduct, MSMQPrices[key]);
                        }

                        List <string> labels = HandleLabels(inventoryItem, graph);
                        List <(string imagePlacement, string imageUrl)> images = HandleImages(inventoryItem, graph);

                        APIUpdates quantityUpdates;
                        if (MSMQQuantityUpdates?.ContainsKey(key) == true)
                        {
                            quantityUpdates = new APIUpdates()
                            {
                                UpdateType = "InStock",
                                Updates    = MSMQQuantityUpdates[key]
                            };
                        }
                        else
                        {
                            quantityUpdates = HandleQuantities(graph, inventoryItem);
                        }

                        string formattedLabels           = FormatLabels(labels);
                        string formattedImages           = FormatPictureUrls(images);
                        string formattedBundleComponents = FormatBundleComponents(apiProduct?.BundleComponents);
                        string formattedQuantities       = FormatQuantities(quantityUpdates, graph);

                        apiProduct.Labels              = formattedLabels;
                        apiProduct.PictureUrls         = formattedImages;
                        apiProduct.FtpBundleComponents = formattedBundleComponents;
                        apiProduct.DCQuantity          = formattedQuantities;
                        apiProduct.QuantityUpdateType  = "InStock";

                        lock (locker)
                        {
                            dtos.Add(new Tuple <string, InventoryItem, KCBulkProduct>(product.Key, inventoryItem, new KCBulkProduct(apiProduct, HandleAttributes(inventoryItem))));
                        }

                        SetSyncDateTime(inventoryItem, graph);
                        graph.Actions.PressSave();
                    }
                }, cancellationToken);
            }

            tasks.StartAndWaitAll(cancellationToken);
            Thread.Sleep((int)KCConstants.SYNC_DELAY_SECONDS * 1000);

            dtos.Sort(new KCProductTypeComparer());

            List <KCBulkProduct> list = dtos.Select(x => x.Item3).ToList();


            return(list);
        }
        private void SendInventoryUpdateMessage(SyncType syncType, string inventoryId, JToken baseMessage, JToken insertedToken, JToken deletedToken, string warehouseId)
        {
            var inventoryID = int.Parse(insertedToken.SelectToken("InventoryID_2").ToString());

            insertedToken[nameof(KCMSMQInventoryQuantity.Updates)] = JToken.FromObject(KCMapInventoryItem.GetAPIQuantity(inventoryID).Value.Updates);

            SendUpdateMessage(syncType, inventoryId, baseMessage, insertedToken, deletedToken, warehouseId);
        }
        public void ProcessMessageFTP(List <KCPriceAndInventoryMessage> messages, CancellationToken cancellationToken)
        {
            KCDataExchangeMaint      masterGraph = PXGraph.CreateInstance <KCDataExchangeMaint>();
            KCPriceAndInventoryMaint graph       = PXGraph.CreateInstance <KCPriceAndInventoryMaint>();


            var MSMQQuantityUpdates = new Dictionary <string, List <KCAPIQuantity> >();
            var MSMQPrices          = new Dictionary <string, KCAPIInventoryItem>();

            var productsForExportPrice    = new List <KeyValuePair <string, InventoryItem> >();
            var productsForExportQuantity = new Dictionary <string, KeyValuePair <string, InventoryItem> >();

            PushNotificationsHook pricePN    = graph.PushNotification.SelectSingle(KCMSMQQueueHelper.GetSyncName(SyncType.InventoryPrice));
            PushNotificationsHook quantityPN = graph.PushNotification.SelectSingle(KCMSMQQueueHelper.GetSyncName(SyncType.InventoryQuantity));
            PushNotificationsHook vendorPN   = graph.PushNotification.SelectSingle(KCMSMQQueueHelper.GetSyncName(SyncType.VendorQuantity));

            KCMSMQueueReader price    = null;
            KCMSMQueueReader quantity = null;
            KCMSMQueueReader vendor   = null;

            try
            {
                price    = new KCMSMQueueReader(pricePN.Address);
                quantity = new KCMSMQueueReader(quantityPN.Address);
                vendor   = new KCMSMQueueReader(vendorPN.Address);

                foreach (KCPriceAndInventoryMessage msg in messages)
                {
                    var syncType = KCMSMQQueueHelper.ParseSyncQueueName(msg.Address);
                    if (syncType == SyncType.InventoryQuantity || syncType == SyncType.VendorQuantity)
                    {
                        List <object> insertedMessages = null;
                        if (syncType == SyncType.InventoryQuantity && quantity.TryReceiveMessage(msg.MessageID, out var invMessage))
                        {
                            insertedMessages = invMessage.Inserted;
                        }
                        if (syncType == SyncType.VendorQuantity && vendor.TryReceiveMessage(msg.MessageID, out var vendorMessage))
                        {
                            insertedMessages = vendorMessage.Inserted;
                        }

                        if (insertedMessages != null)
                        {
                            foreach (object item in insertedMessages)
                            {
                                KCMSMQInventoryQuantity quantityProduct = JsonConvert.DeserializeObject <KCMSMQInventoryQuantity>(item.ToString());
                                InventoryItem           inventoryItem   = masterGraph.ProductByInvCd.Select(quantityProduct.InventoryID.Trim());
                                KNSIKCInventoryItem     kcProduct       = masterGraph.KCInventoryItem.SelectSingle(inventoryItem.InventoryID);

                                if (kcProduct.UsrKCCAID != null)
                                {
                                    var key = inventoryItem.InventoryCD;

                                    if (!MSMQQuantityUpdates.ContainsKey(key))
                                    {
                                        MSMQQuantityUpdates.Add(key, quantityProduct.Updates);
                                    }

                                    if (!productsForExportQuantity.ContainsKey(key))
                                    {
                                        InventoryItemPCExt inventoryItemPCExt = inventoryItem.GetExtension <InventoryItemPCExt>();

                                        productsForExportQuantity.Add(inventoryItem.InventoryCD, new KeyValuePair <string, InventoryItem>(inventoryItemPCExt.UsrKNCompositeType, inventoryItem));
                                    }
                                }
                            }
                        }
                    }
                    else if (syncType == SyncType.InventoryPrice)
                    {
                        if (price.TryReceiveMessage(msg.MessageID, out var message))
                        {
                            foreach (object item in message.Inserted)
                            {
                                KCMSMQInventoryPrice priceProduct       = JsonConvert.DeserializeObject <KCMSMQInventoryPrice>(item.ToString());
                                InventoryItem        inventoryItem      = masterGraph.ProductByInvCd.Select(priceProduct.InventoryID.Trim());
                                InventoryItemPCExt   inventoryItemPCExt = inventoryItem.GetExtension <InventoryItemPCExt>();

                                productsForExportPrice.Add(new KeyValuePair <string, InventoryItem>(inventoryItemPCExt.UsrKNCompositeType, inventoryItem));
                                MSMQPrices.Add(inventoryItem.InventoryCD, KCMapInventoryItem.GetAPIMSMQInventoryPrice(priceProduct));
                            }
                        }
                    }
                }
            }
            finally
            {
                price?.Dispose();
                quantity?.Dispose();
                vendor?.Dispose();
            }

            Export(masterGraph, productsForExportPrice, cancellationToken, MSMQPrices);
            Export(masterGraph, productsForExportQuantity.Values.ToList(), cancellationToken, null, MSMQQuantityUpdates);
        }