Esempio n. 1
0
        public void FixupWalmartPrices(IUnitOfWork db)
        {
            _log.Info("FixupWalmartPrices");
            var today = _time.GetAppNowTime().Date;

            var fromDate         = _time.GetAppNowTime().AddHours(-8);
            var requestedActions = _actionService.GetUnprocessedByType(db, SystemActionType.ListingPriceRecalculation, fromDate, null);

            var listingIds         = requestedActions.Select(i => StringHelper.TryGetLong(i.Tag)).Where(i => i.HasValue).ToList();
            var dbListingsToUpdate = db.Listings.GetAll().Where(i => listingIds.Contains(i.Id)).ToList();
            var updatedListingIds  = new List <string>();

            //51082
            foreach (var dbListing in dbListingsToUpdate)
            {
                var newPrice = GetNewPrice(db, dbListing.Id);
                if (newPrice.HasValue)
                {
                    if (dbListing.CurrentPrice != newPrice)
                    {
                        _log.Info("Changing price for SKU=" + dbListing.SKU + ", " + dbListing.CurrentPrice + " => " + newPrice + ", IsFBA=" + dbListing.IsFBA + ", IsPrime=" + dbListing.IsPrime + ", Market=" + (int)dbListing.Market);

                        LogListingPrice(db,
                                        PriceChangeSourceType.SetByAutoPrice,
                                        dbListing.Id,
                                        dbListing.SKU,
                                        newPrice.Value,
                                        dbListing.CurrentPrice,
                                        _time.GetAppNowTime(),
                                        null);

                        dbListing.CurrentPrice         = newPrice.Value;
                        dbListing.PriceUpdateRequested = true;
                    }
                    updatedListingIds.Add(dbListing.Id.ToString());
                }
                else
                {
                    _log.Info("Unbale to calculate new price for " + dbListing.SKU);
                }
            }

            db.Commit();

            var actionsSuccess = requestedActions.Where(i => updatedListingIds.Contains(i.Tag)).ToList();

            foreach (var actionToUpdate in actionsSuccess)
            {
                _actionService.SetResult(db, actionToUpdate.Id, SystemActionStatus.Done, null);
            }

            var actionFails = requestedActions.Where(i => !updatedListingIds.Contains(i.Tag)).ToList();

            foreach (var actionToUpdate in actionFails)
            {
                _actionService.SetResult(db, actionToUpdate.Id, SystemActionStatus.Fail, null);
            }
            db.Commit();
        }
        public void ProcessSystemAction(ISystemActionService actionService,
                                        string feedDirectory)
        {
            using (var db = _dbFactory.GetRWDb())
            {
                var toProcessActions = actionService.GetUnprocessedByType(db, SystemActionType.ProcessUploadOrderFeed, null, null);

                foreach (var action in toProcessActions)
                {
                    _log.Info("Find action: " + action.Id);
                    var actionStatus = SystemActionStatus.None;
                    var output       = new PublishFeedOutput();
                    try
                    {
                        var inputData = SystemActionHelper.FromStr <PublishFeedInput>(action.InputData);

                        var filepath = Path.Combine(feedDirectory, inputData.FileName);

                        var uploadResult = UploadFeed(filepath,
                                                      (MarketType)(inputData.Market ?? (int)MarketType.OfflineOrders),
                                                      inputData.MarketplaceId,
                                                      (PublishFeedModes)(inputData.Mode ?? (int)PublishFeedModes.Publish),
                                                      inputData.IsPrime);

                        output.ProgressPercent = 100;
                        output.IsSuccess       = true;
                        if (uploadResult != null)
                        {
                            output.MatchedCount             = uploadResult.MatchedCount;
                            output.ParsedCount              = uploadResult.ParsedCount;
                            output.Processed1OperationCount = uploadResult.Processed1Count;
                            output.Processed2OperationCount = uploadResult.Processed2Count;
                        }

                        actionStatus = SystemActionStatus.Done;
                        _log.Info("Sale feed processed: " + filepath + ", actionId=" + action.Id);
                    }
                    catch (Exception ex)
                    {
                        actionStatus = SystemActionStatus.Fail;

                        _log.Error("Fail quantity distributed, actionId=" + action.Id + ", status=" + actionStatus, ex);
                    }

                    actionService.SetResult(db,
                                            action.Id,
                                            actionStatus,
                                            output,
                                            null);
                }

                db.Commit();
            }
        }
        public void ProcessRestartActions()
        {
            using (var db = _dbFactory.GetRWDb())
            {
                var restartActions = _actionService.GetUnprocessedByType(db, SystemActionType.RestartService, null, null);
                foreach (var action in restartActions)
                {
                    Restart("Ccen.Dws.Full.Sync.Service");

                    _actionService.SetResult(db, action.Id, SystemActionStatus.Done, null);

                    db.Commit();
                }
            }
        }
Esempio n. 4
0
        public void ProcessPrintBatchActions(Action startPrintCallback)
        {
            using (var db = _dbFactory.GetRWDb())
            {
                var printActions = _actionService.GetUnprocessedByType(db, SystemActionType.PrintBatch, null, null)
                                   .OrderByDescending(a => a.CreateDate)
                                   .ToList();
                _log.Info("Unprocessed actions: " + printActions.Count);

                foreach (var action in printActions)
                {
                    if (action.Status == (int)SystemActionStatus.None)
                    {
                        startPrintCallback?.Invoke();

                        _actionService.SetResult(db, action.Id, SystemActionStatus.InProgress, null);

                        var input = JsonConvert.DeserializeObject <PrintBatchInput>(action.InputData);

                        var result = PrintBatch(input.BatchId, input.CompanyId, input.UserId);

                        _actionService.SetResult(db, action.Id, SystemActionStatus.Done, new PrintBatchOutput()
                        {
                            IsProcessed = true,
                            Messages    = result.Messages,
                            FilePath    = result.Url,
                            PrintPackId = result.PrintPackId,
                            PickupInfo  = result.PickupInfo,
                        });

                        _log.Debug(String.Format(
                                       "Print label action was done, batchId={0}, companyId={1}, userId={2}",
                                       input.BatchId,
                                       input.CompanyId,
                                       input.UserId));
                    }
                }
                db.Commit();
            }
        }
        public void ProcessCancellations(IUnitOfWork db, string filterTag)
        {
            //NOTE: reprocess cancel request every 2 hours
            var maxLastAttemptDate = _time.GetUtcTime().AddHours(-2);

            var cancelActions    = _actionService.GetUnprocessedByType(db, SystemActionType.UpdateOnMarketCancelOrder, maxLastAttemptDate, null);
            var actionOutputList = new Dictionary <long, CancelOrderOutput>();

            if (!String.IsNullOrEmpty(filterTag))
            {
                cancelActions = cancelActions.Where(a => a.Tag == filterTag).ToList();
            }

            foreach (var action in cancelActions)
            {
                try
                {
                    var data   = JsonConvert.DeserializeObject <CancelOrderInput>(action.InputData);
                    var orders = db.Orders.GetAllByCustomerOrderNumber(data.OrderNumber);
                    if (!orders.Any())
                    {
                        _log.Info(_api.Market + "_" + _api.MarketplaceId + ": Can't find orderId=" + data.OrderNumber);
                        continue;
                    }

                    if (orders[0].Market != (int)_api.Market ||
                        (!String.IsNullOrEmpty(_api.MarketplaceId) &&
                         orders[0].MarketplaceId != _api.MarketplaceId))
                    {
                        //_log.Info("skip order=" + data.OrderNumber + ", market=" + order.Market + ", marketplace=" + order.MarketplaceId);
                        continue;
                    }

                    _log.Info("Order to cancel: " + _api.Market + "_" + _api.MarketplaceId + ", actionId=" + action.Id +
                              ", orderId=" + data.OrderNumber + ", itemId=" + data.ItemId);

                    var itemIdList        = (data.ItemId ?? "").Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                    var orderIdList       = orders.Select(o => o.Id).ToList();
                    var allOrderItems     = db.OrderItems.GetWithListingInfo().Where(i => i.OrderId.HasValue && orderIdList.Contains(i.OrderId.Value)).ToList();
                    var orderItemToCancel = itemIdList.Any() ? allOrderItems.Where(i => itemIdList.Contains(i.SourceMarketId)).ToList() : allOrderItems;

                    CallResult <DTOOrder> result;
                    if (orderItemToCancel.Count >= 1)
                    {
                        var orderToCancel = orders.FirstOrDefault(o => o.Id == orderItemToCancel[0].OrderId);
                        result = _api.CancelOrder(orderToCancel.MarketOrderId, orderItemToCancel);
                    }
                    else
                    {
                        result = CallResult <DTOOrder> .Fail("No items to cancel", null);
                    }


                    if (result.IsSuccess)
                    {
                        var output = new CancelOrderOutput()
                        {
                            IsProcessed   = true,
                            ResultMessage = "Cancelled by API"
                        };
                        _actionService.SetResult(db, action.Id, SystemActionStatus.Done, output);
                        db.Commit();
                    }
                    else
                    {
                        var output = new CancelOrderOutput()
                        {
                            IsProcessed   = true,
                            ResultMessage = "Fail: " + result.Message
                        };
                        _actionService.SetResult(db, action.Id, SystemActionStatus.None, output);
                    }
                }
                catch (Exception ex)
                {
                    if (action.AttemptNumber > 10)
                    {
                        var output = new CancelOrderOutput()
                        {
                            IsProcessed   = true,
                            ResultMessage = ex.Message
                        };
                        _actionService.SetResult(db, action.Id, SystemActionStatus.Fail, output);
                        db.Commit();
                    }

                    _log.Error("OrderCancellation.Process", ex);
                }
            }
        }
Esempio n. 6
0
        public void ProcessSystemAction(CancellationToken cancelToken)
        {
            var syncInfo = new EmptySyncInformer(_log, SyncType.Orders);

            using (var db = _dbFactory.GetRWDb())
            {
                var updateRateActions = _actionService.GetUnprocessedByType(db, SystemActionType.UpdateRates, null, null);

                foreach (var action in updateRateActions)
                {
                    if (cancelToken.IsCancellationRequested)
                    {
                        return;
                    }

                    var actionStatus = SystemActionStatus.None;
                    try
                    {
                        var inputData = SystemActionHelper.FromStr <UpdateRatesInput>(action.InputData);
                        var orderId   = inputData.OrderId;
                        if (!orderId.HasValue && !String.IsNullOrEmpty(inputData.OrderNumber))
                        {
                            var order = db.Orders.GetByOrderNumber(inputData.OrderNumber);
                            orderId = order.Id;
                        }

                        if (orderId.HasValue)
                        {
                            var orderIdList            = new long[] { orderId.Value };
                            IList <DTOOrder> dtoOrders = db.ItemOrderMappings.GetSelectedOrdersWithItems(_weightService, orderIdList, includeSourceItems: true).ToList();

                            foreach (var dtoOrder in dtoOrders)
                            {
                                //Ignore shipped orders
                                if ((dtoOrder.Market != (int)MarketType.eBay &&
                                     ShippingUtils.IsOrderShipped(dtoOrder.OrderStatus)) ||
                                    dtoOrder.ShippingInfos.Any(s => !String.IsNullOrEmpty(s.LabelPath))

                                    || dtoOrder.BatchId.HasValue) //NOTE: SKip orders in batch
                                {
                                    actionStatus = SystemActionStatus.Skipped;
                                }
                                else
                                {
                                    var markets = new MarketplaceKeeper(_dbFactory, false);
                                    markets.Init();
                                    var companyAddress = new CompanyAddressService(_company, markets.GetAll());
                                    var synchronizer   = new AmazonOrdersSynchronizer(_log,
                                                                                      _company,
                                                                                      syncInfo,
                                                                                      _rateProviders,
                                                                                      companyAddress,
                                                                                      _time,
                                                                                      _weightService,
                                                                                      _messageService);
                                    if (!synchronizer.UIUpdate(db, dtoOrder, false, false, keepCustomShipping: false, switchToMethodId: null))
                                    {
                                        actionStatus = SystemActionStatus.Fail;
                                    }
                                    else
                                    {
                                        actionStatus = SystemActionStatus.Done;
                                    }
                                }
                            }

                            _log.Info("Order rates was recalculated, actionId=" + action.Id + ", status=" + actionStatus);
                        }
                        else
                        {
                            actionStatus = SystemActionStatus.NotFoundEntity;
                            _log.Info("Can't find order, actionId=" + action.Id + ", orderId=" + inputData.OrderId + ", orderNumber=" + inputData.OrderNumber);
                        }
                    }
                    catch (Exception ex)
                    {
                        _log.Error("Fail recalculate order rates action, actionId=" + action.Id, ex);
                        actionStatus = SystemActionStatus.Fail;
                    }

                    _actionService.SetResult(db,
                                             action.Id,
                                             actionStatus,
                                             null,
                                             null);
                }

                db.Commit();
            }
        }
Esempio n. 7
0
        public void SendItemUpdates(Action <StyleImageDTO> prepareStyleImageCallback,
                                    Func <ParentItemDTO, bool, IList <ItemExDTO>, IList <StyleEntireDto>, IList <StyleImageDTO>, IList <StyleFeatureValueDTO>, IList <DropShipperDTO>, CallResult <ParentItemDTO> > itemPublishCallback,
                                    MarketType market,
                                    string marketplaceId,
                                    IList <long> styleIds)
        {
            _log.Info("Begin ItemUpdates");

            IList <SystemActionDTO> updateActions = null;

            using (var db = _dbFactory.GetRWDb())
            {
                IList <string> parentASINList;

                if (styleIds == null)
                {
                    DateTime?maxLastAttemptDate = _time.GetUtcTime().AddHours(-4);

                    updateActions = _actionService.GetUnprocessedByType(db,
                                                                        SystemActionType.UpdateOnMarketProductData,
                                                                        maxLastAttemptDate,
                                                                        null);

                    var parentItemIds = updateActions.Select(i => StringHelper.TryGetInt(i.Tag))
                                        .Where(i => i.HasValue)
                                        .ToList();

                    parentASINList = (from pi in db.ParentItems.GetAll()
                                      where parentItemIds.Contains(pi.Id) &&
                                      pi.Market == (int)market &&
                                      pi.MarketplaceId == marketplaceId
                                      select pi.ASIN).Distinct().ToList();
                }
                else
                {
                    parentASINList = (from i in db.Items.GetAll()
                                      join l in db.Listings.GetAll() on i.Id equals l.ItemId
                                      join st in db.Styles.GetAll() on i.StyleId equals st.Id
                                      where !st.Deleted &&
                                      !l.IsRemoved &&
                                      styleIds.Contains(st.Id) &&
                                      i.Market == (int)market &&
                                      (i.MarketplaceId == marketplaceId || String.IsNullOrEmpty(marketplaceId)) &&
                                      i.StyleItemId.HasValue
                                      select i.ParentASIN).Distinct().ToList();
                }

                //NOTE: Need to submit items with group, otherwise we have incorrect color variations calculation, and sometimes image calculation
                var allItemList = db.Items.GetAllActualExAsDto()
                                  .Where(i => parentASINList.Contains(i.ParentASIN) &&
                                         i.Market == (int)market &&
                                         (i.MarketplaceId == marketplaceId || String.IsNullOrEmpty(marketplaceId))).ToList();

                _log.Info("Parent ASIN Count to submit=" + parentASINList.Count + ", item count=" + allItemList.Count);

                //Refresh parentASIN list, exclude asins with not actual items
                parentASINList = allItemList.Select(i => i.ParentASIN).Distinct().ToList();


                var allParentItemList = db.ParentItems.GetAllAsDto().Where(p => parentASINList.Contains(p.ASIN) &&
                                                                           p.Market == (int)market &&
                                                                           (p.MarketplaceId == marketplaceId || String.IsNullOrEmpty(marketplaceId)))
                                        .ToList();

                var allStyleIdList     = allItemList.Where(i => i.StyleId.HasValue).Select(i => i.StyleId.Value).ToList();
                var allStyleList       = db.Styles.GetAllAsDtoEx().Where(s => allStyleIdList.Contains(s.Id)).ToList();
                var allStyleImageList  = db.StyleImages.GetAllAsDto().Where(sim => allStyleIdList.Contains(sim.StyleId)).ToList();
                var allFeatures        = db.StyleFeatureValues.GetAllFeatureValuesByStyleIdAsDto(allStyleIdList).ToList();
                var allDropShipperList = db.DropShippers.GetAllAsDto().ToList();
                allFeatures.AddRange(db.StyleFeatureTextValues.GetAllFeatureTextValuesByStyleIdAsDto(allStyleIdList));
                allFeatures = allFeatures.OrderBy(fv => fv.SortOrder).ToList();

                foreach (var item in allItemList)
                {
                    var parent = allParentItemList.FirstOrDefault(p => p.ASIN == item.ParentASIN);
                    if (parent != null)
                    {
                        item.OnHold = parent.OnHold;
                    }
                }

                //Exclude OnHold (after ParentItem onHold was applied)
                allItemList = allItemList.Where(i => !i.OnHold).ToList();

                foreach (var styleImage in allStyleImageList)
                {
                    try
                    {
                        prepareStyleImageCallback(styleImage);
                    }
                    catch (Exception ex)
                    {
                        _log.Info("PrepareStyleImage error, image=" + styleImage.Image, ex);
                    }
                }

                if (allItemList.Any())
                {
                    _log.Info("Items to update=" + String.Join(", ", allItemList.Select(i => i.SKU).ToList()));

                    foreach (var parentItem in allParentItemList)
                    {
                        var groupItems       = allItemList.Where(i => i.ParentASIN == parentItem.ASIN).ToList();
                        var groupStyleIdList =
                            groupItems.Where(i => i.StyleId.HasValue).Select(i => i.StyleId).Distinct().ToList();
                        var styles        = allStyleList.Where(s => groupStyleIdList.Contains(s.Id)).ToList();
                        var styleFeatures = allFeatures.Where(f => groupStyleIdList.Contains(f.StyleId)).ToList();

                        var enableColorVariation = (parentItem != null && parentItem.ForceEnableColorVariations) ||
                                                   groupItems.GroupBy(i => i.Size)
                                                   .Select(g => new
                        {
                            Count = g.Count(),
                            Size  = g.Key,
                        })
                                                   .Count(g => g.Count > 1) > 0;

                        var styleImages = allStyleImageList
                                          .Where(im => groupStyleIdList.Contains(im.StyleId) && !im.IsSystem)
                                          .OrderBy(im => im.StyleId)
                                          .ThenByDescending(im => im.IsDefault)
                                          .ThenBy(im => im.Id)
                                          .ToList();

                        if (_mode == PublishingMode.Report ||
                            _mode == PublishingMode.ReportAll)
                        {
                            itemPublishCallback(parentItem,
                                                enableColorVariation,
                                                groupItems,
                                                styles,
                                                styleImages,
                                                styleFeatures,
                                                allDropShipperList);
                        }

                        if (_mode == PublishingMode.PerItem)
                        {
                            //SEND
                            var result = itemPublishCallback(parentItem,
                                                             enableColorVariation,
                                                             groupItems,
                                                             styles,
                                                             styleImages,
                                                             styleFeatures,
                                                             allDropShipperList);

                            var parentItemIdStr = parentItem.Id.ToString();
                            var dbSystemActions = db.SystemActions.GetAll()
                                                  .Where(a => a.Tag == parentItemIdStr &&
                                                         a.Type == (int)SystemActionType.UpdateOnMarketProductData)
                                                  .ToList();

                            if (result.IsSuccess)
                            {
                                var dbParentItem = db.ParentItems.GetAll().FirstOrDefault(pi => parentItem.Id == pi.Id);
                                dbParentItem.SourceMarketId  = result.Data.SourceMarketId;
                                dbParentItem.SourceMarketUrl = result.Data.SourceMarketUrl;

                                var itemIds = groupItems.Select(i => i.Id).ToList();
                                var dbItems = db.Items.GetAll().Where(i => itemIds.Contains(i.Id)).ToList();
                                foreach (var groupItem in groupItems)
                                {
                                    var resultItem = result.Data.Variations?.FirstOrDefault(v => v.SKU == groupItem.SKU);
                                    var dbItem     = dbItems.FirstOrDefault(i => i.Id == groupItem.Id);
                                    if (dbItem != null && resultItem != null)
                                    {
                                        dbItem.SourceMarketId          = resultItem.SourceMarketId;
                                        dbItem.SourceMarketUrl         = resultItem.SourceMarketUrl;
                                        dbItem.ItemPublishedStatus     = (int)PublishedStatuses.Published;
                                        dbItem.ItemPublishedStatusDate = _time.GetAppNowTime();
                                    }
                                }

                                foreach (var dbSystemAction in dbSystemActions)
                                {
                                    dbSystemAction.Status = (int)SystemActionStatus.Done;
                                }
                            }
                            else
                            {
                                foreach (var dbSystemAction in dbSystemActions)
                                {
                                    dbSystemAction.AttemptDate = _time.GetAppNowTime();
                                    dbSystemAction.AttemptNumber++;
                                    if (dbSystemAction.AttemptNumber > 3)
                                    {
                                        dbSystemAction.Status = (int)SystemActionStatus.Fail;
                                    }
                                }
                            }

                            db.Commit();
                        }
                    }
                }
                else
                {
                    if (updateActions != null && updateActions.Any())
                    {
                        foreach (var updateAction in updateActions)
                        {
                            _actionService.SetResult(db, updateAction.Id, SystemActionStatus.Fail, null);
                        }
                    }
                }
                _log.Info("End ItemUpdates");
            }
        }
Esempio n. 8
0
        public void ProcessRefunds(IUnitOfWork db, string tag)
        {
            //NOTE: reprocess cancel request every 2 hours
            DateTime?maxLastAttemptDate = _time.GetUtcTime().AddHours(-4);
            var      maxAttempts        = 10;

            var returnActions = _actionService.GetUnprocessedByType(db,
                                                                    SystemActionType.UpdateOnMarketReturnOrder,
                                                                    maxLastAttemptDate,
                                                                    tag);

            foreach (var action in returnActions)
            {
                Order     order        = null;
                decimal   refundAmount = 0M;
                Exception exception    = null;
                try
                {
                    var data = JsonConvert.DeserializeObject <ReturnOrderInput>(action.InputData);
                    order = db.Orders.GetByOrderNumber(data.OrderNumber);
                    if (order == null)
                    {
                        _log.Info(_api.Market + "_" + _api.MarketplaceId + ": Can't find orderId=" + data.OrderNumber);
                        continue;
                    }

                    if (order.Market != (int)_api.Market ||
                        (!String.IsNullOrEmpty(_api.MarketplaceId) &&
                         order.MarketplaceId != _api.MarketplaceId))
                    {
                        //_log.Info("skip order=" + data.OrderNumber + ", market=" + order.Market + ", marketplace=" + order.MarketplaceId);
                        continue;
                    }

                    _log.Info("Order to refund: " + _api.Market + "_" + _api.MarketplaceId
                              + ", actionId=" + action.Id
                              + ", orderId=" + data.OrderNumber);

                    data.MarketOrderId        = order.MarketOrderId;
                    data.Id                   = action.Id;
                    data.PaymentTransactionId = order.PaymentInfo;

                    #region Prepare Fee Data

                    var orderIds = new List <long>()
                    {
                        order.Id
                    };
                    var orderItems      = db.OrderItems.GetAllAsDto().Where(oi => orderIds.Contains(oi.OrderId)).ToList();
                    var previousRefunds = db.SystemActions.GetAllAsDto().Where(a => a.Type == (int)SystemActionType.UpdateOnMarketReturnOrder &&
                                                                               a.Tag == data.OrderNumber &&
                                                                               a.Id != action.Id)
                                          .ToList();
                    var previousRefundDataList = previousRefunds.Select(i => JsonConvert.DeserializeObject <ReturnOrderInput>(i.InputData)).ToList();

                    foreach (var orderItem in orderItems)
                    {
                        var refundItem = data.Items.FirstOrDefault(oi => oi.ItemOrderId == orderItem.ItemOrderIdentifier);
                        if (refundItem == null)
                        {
                            if (order.Market != (int)MarketType.Walmart) //NOTE: Skip Walmart, builded based on return request
                            {
                                data.Items.Add(new ReturnOrderItemInput()
                                {
                                    ItemOrderId = orderItem.ItemOrderIdentifier,
                                    Quantity    = 0,
                                });
                            }
                        }
                        else
                        {
                            if (refundItem.RefundItemPrice > 0)
                            {
                                decimal alreadyRefundedItemSum = 0;
                                foreach (var refundData in previousRefundDataList)
                                {
                                    alreadyRefundedItemSum += refundData.Items.Where(i => i.ItemOrderId == orderItem.ItemOrderIdentifier).Sum(i => i.RefundItemPrice);
                                }
                                decimal totalItemSum           = orderItems.Where(oi => oi.ItemOrderIdentifier == orderItem.ItemOrderIdentifier).Sum(oi => oi.ItemPaid ?? 0);
                                decimal requestedRefundItemSum = refundItem.RefundItemPrice;

                                var perItemPrice = (orderItem.ItemPaid ?? 0) / (decimal)orderItem.QuantityOrdered;

                                var adjustment = refundItem.RefundItemPrice -
                                                 refundItem.Quantity * perItemPrice;
                                if (adjustment > 0)
                                {
                                    refundItem.AdjustmentRefund = adjustment;
                                }
                                if (adjustment < 0)
                                {
                                    refundItem.AdjustmentFee = -adjustment;
                                }
                            }
                            else
                            {
                                refundItem.Quantity = 0;
                            }
                        }
                    }

                    //Group back for virtual styles
                    data.Items = data.Items
                                 .GroupBy(i => String.Join("_", i.ItemOrderId.Split('_').Take(2)))
                                 .Select(g => new ReturnOrderItemInput()
                    {
                        ItemOrderId            = g.Key,
                        Quantity               = g.Max(i => i.Quantity),
                        Feedback               = g.FirstOrDefault()?.Feedback,
                        Notes                  = g.FirstOrDefault()?.Notes,
                        Reason                 = g.FirstOrDefault()?.Reason,
                        TotalPaidAmount        = g.Sum(i => i.TotalPaidAmount),
                        RefundItemPrice        = g.Sum(i => i.RefundItemPrice),
                        RefundShippingPrice    = g.Sum(i => i.RefundShippingPrice),
                        DeductPrepaidLabelCost = g.Sum(i => i.DeductPrepaidLabelCost),
                        DeductShippingPrice    = g.Sum(i => i.DeductShippingPrice),
                        AdjustmentRefund       = g.Sum(i => i.AdjustmentRefund),
                        AdjustmentFee          = g.Sum(i => i.AdjustmentFee),
                    })
                                 .ToList();

                    refundAmount = data.Items.Sum(i => i.AdjustmentRefund);

                    #endregion

                    var result = _api.RefundOrder(order.AmazonIdentifier, data);

                    if (result.IsSuccess)
                    {
                        var output = new ReturnOrderOutput()
                        {
                            IsProcessed   = true,
                            ResultMessage = "Refunds by API"
                        };
                        _actionService.SetResult(db, action.Id, SystemActionStatus.Done, output);
                        db.Commit();
                    }
                    else
                    {
                        _log.Info("Refund Fail: " + result.Message);
                        var output = new ReturnOrderOutput()
                        {
                            IsProcessed   = true,
                            ResultMessage = "Fail: " + result.Message
                        };
                        _actionService.SetResult(db, action.Id, action.AttemptNumber > maxAttempts ? SystemActionStatus.Fail : SystemActionStatus.None, output);
                        db.Commit();
                    }
                }
                catch (Exception ex)
                {
                    exception = ex;
                    _log.Error("WalmartOrderRefund.Process", ex);
                }

                if (action.AttemptNumber > maxAttempts)
                {
                    var output = new ReturnOrderOutput()
                    {
                        IsProcessed   = true,
                        ResultMessage = exception != null ? exception.Message : ""
                    };
                    _actionService.SetResult(db, action.Id, SystemActionStatus.Fail, output);
                    db.Commit();

                    db.OrderComments.Add(new OrderComment()
                    {
                        OrderId    = order.Id,
                        CreateDate = _time.GetAppNowTime(),
                        Type       = (int)CommentType.ReturnExchange,
                        Message    = "Refund failed, amount: $" + PriceHelper.RoundToTwoPrecision(refundAmount)
                    });
                    db.Commit();

                    _emailService.SendSystemEmail(
                        "System can't process refund, order #" + (order != null ? order.CustomerOrderId : "n/a"),
                        "Details: " + (exception != null ? exception.Message : "-"),
                        EmailHelper.RafiEmail + ";" + EmailHelper.RaananEmail,
                        EmailHelper.SupportDgtexEmail);
                }
            }
        }
        public void ProcessCancellations(IUnitOfWork db, string tag)
        {
            //NOTE: reprocess cancel request every 2 hours
            var maxLastAttemptDate = _time.GetUtcTime().AddHours(-2);

            var cancelActions    = _actionService.GetUnprocessedByType(db, SystemActionType.UpdateOnMarketCancelOrder, maxLastAttemptDate, tag);
            var actionOutputList = new Dictionary <long, CancelOrderOutput>();

            foreach (var action in cancelActions)
            {
                try
                {
                    var data   = JsonConvert.DeserializeObject <CancelOrderInput>(action.InputData);
                    var orders = db.Orders.GetAllByCustomerOrderNumber(data.OrderNumber);
                    if (!orders.Any())
                    {
                        _log.Info(_api.Market + "_" + _api.MarketplaceId + ": Can't find orderId=" + data.OrderNumber);
                        continue;
                    }

                    if (orders[0].Market != (int)_api.Market ||
                        (!String.IsNullOrEmpty(_api.MarketplaceId) &&
                         orders[0].MarketplaceId != _api.MarketplaceId))
                    {
                        //_log.Info("skip order=" + data.OrderNumber + ", market=" + order.Market + ", marketplace=" + order.MarketplaceId);
                        continue;
                    }

                    _log.Info("Order to cancel: " + _api.Market + "_" + _api.MarketplaceId + ", actionId=" + action.Id +
                              ", orderId=" + data.OrderNumber + ", itemId=" + data.ItemId);


                    foreach (var order in orders)
                    {
                        order.OrderStatus = OrderStatusEnumEx.Canceled;
                    }
                    db.Commit();

                    var output = new CancelOrderOutput()
                    {
                        IsProcessed   = true,
                        ResultMessage = "Cancelled by API"
                    };
                    _actionService.SetResult(db, action.Id, SystemActionStatus.Done, output);
                    db.Commit();
                }
                catch (Exception ex)
                {
                    if (action.AttemptNumber > 10)
                    {
                        var output = new CancelOrderOutput()
                        {
                            IsProcessed   = true,
                            ResultMessage = ex.Message
                        };
                        _actionService.SetResult(db, action.Id, SystemActionStatus.Fail, output);
                        db.Commit();
                    }

                    _log.Error("WalmartOrderCancellation.Process", ex);
                }
            }
        }
        public void ProcessSystemAction()
        {
            using (var db = _dbFactory.GetRWDb())
            {
                var commentActions = _actionService.GetUnprocessedByType(db, SystemActionType.AddComment, null, null);

                foreach (var action in commentActions)
                {
                    var actionStatus = SystemActionStatus.None;
                    try
                    {
                        var inputData = SystemActionHelper.FromStr <AddCommentInput>(action.InputData);
                        var orderId   = inputData.OrderId;
                        if (!orderId.HasValue && !String.IsNullOrEmpty(inputData.OrderNumber))
                        {
                            var order = db.Orders.GetByCustomerOrderNumber(inputData.OrderNumber);
                            if (order == null)
                            {
                                throw new ArgumentException("Can't find order", "OrderNumber");
                            }

                            orderId = order.Id;
                        }

                        if (orderId.HasValue)
                        {
                            db.OrderComments.Add(new OrderComment()
                            {
                                OrderId       = orderId.Value,
                                Message       = inputData.Message,
                                Type          = inputData.Type,
                                LinkedEmailId = inputData.LinkedEmailId,

                                CreateDate = _time.GetAppNowTime(),
                                CreatedBy  = inputData.By,
                            });
                            db.Commit();

                            actionStatus = SystemActionStatus.Done;
                            _log.Info("Comment was added, actionId=" + action.Id);
                        }
                        else
                        {
                            actionStatus = SystemActionStatus.NotFoundEntity;
                            _log.Info("Can't find order, orderId=" + inputData.OrderId + ", orderNumber=" + inputData.OrderNumber);
                        }
                    }
                    catch (Exception ex)
                    {
                        actionStatus = SystemActionStatus.Fail;
                        if (action.CreateDate > _time.GetUtcTime().AddHours(-6))
                        {
                            actionStatus = SystemActionStatus.None;
                        }

                        _log.Error("Fail add comment action, actionId=" + action.Id + ", status=" + actionStatus, ex);
                    }

                    _actionService.SetResult(db,
                                             action.Id,
                                             actionStatus,
                                             null,
                                             null);
                }

                db.Commit();
            }
        }