public long AddAction(IUnitOfWork db, SystemActionType type, string tag, ISystemActionInput inputData, long?parentActionId, long?by, SystemActionStatus?status = SystemActionStatus.None) { var input = JsonConvert.SerializeObject(inputData); _logService.Info("AddAction, type=" + type + ", inputData=" + input); var newAction = new SystemActionDTO() { ParentId = parentActionId, Status = (int)status, Type = (int)type, Tag = tag, InputData = input, CreateDate = _time.GetUtcTime(), CreatedBy = by, }; db.SystemActions.AddAction(newAction); return(newAction.Id); }
public void UpdateAllShippedOrderStatus(TrackingManager trackingService, ITime time, IUnitOfWork db, ITrackingProvider trackingProvider, CompanyDTO company) { var carrierNames = ShippingServiceUtils.GetRelatedCarrierNames(trackingProvider.Carrier); var shippings = db.Orders.GetUnDeliveredMailInfoes(time.GetUtcTime(), true, null) .OrderBy(o => o.OrderDate) //NOTE: first reprocess old trackings .Where(sh => carrierNames.Contains(sh.Carrier)) .Take(500) .ToList(); shippings.AddRange(db.Orders.GetUnDeliveredShippingInfoes(time.GetUtcTime(), true, null) .OrderBy(o => o.OrderDate) //NOTE: first reprocess old trackings .Where(sh => carrierNames.Contains(sh.Carrier)) .Take(500) .ToList()); trackingService.UpdateOrderTracking(db, company, shippings, trackingProvider); }
public void SyncBegin(int?count) { if (_syncHistoryId.HasValue) { return; } using (var db = _dbFactory.GetRWDb()) { var history = new SyncHistory { StartDate = _time.GetUtcTime(), Type = (int)_syncType, Market = (int)_market, MarketplaceId = _marketplaceId, AdditionalData = _additionalData, PingDate = _time.GetUtcTime(), Status = (int)SyncStatus.InProgresss, CountToProcess = count }; db.SyncHistory.Add(history); db.Commit(); _syncHistoryId = history.Id; _withErrors = new List <string>(); _withWarning = new List <string>(); _orderList = new SynchronizedCollection <string>(); _logger.Info("[Sync] start, type=" + _syncType + ", market=" + _market + ", marketplaceId=" + _marketplaceId + ", id=" + _syncHistoryId); } }
public void ReProcessTrackNotifications(IDbFactory dbFactory) { var from = _time.GetAppNowTime().AddDays(-42); //NOTE: Possible/not sure: After 42 days USPS not update/keep info var orderFrom = _time.GetAppNowTime().AddDays(-90); using (var db = dbFactory.GetRWDb()) { var shippings = db.Orders.GetUnDeliveredShippingInfoes(_time.GetUtcTime(), false, null) .Where(o => (!o.TrackingStateDate.HasValue || o.TrackingStateDate.Value > from) && o.OrderDate > orderFrom) .OrderBy(o => o.OrderDate) .ToList(); shippings.AddRange(db.Orders.GetUnDeliveredMailInfoes(_time.GetUtcTime(), false, null) .Where(o => (!o.TrackingStateDate.HasValue || o.TrackingStateDate.Value > from) && o.OrderDate > orderFrom) .OrderBy(o => o.OrderDate) .ToList()); var actionService = new SystemActionService(_log, _time); var companyAddress = new CompanyAddressService(_company); var addressService = new AddressService(null, companyAddress.GetReturnAddress(MarketIdentifier.Empty()), companyAddress.GetPickupAddress(MarketIdentifier.Empty())); var notificationService = new NotificationService(_log, _time, dbFactory); var ruleList = new List <ITrackingRule>() { //new NeverShippedTrackingRule(_log, notificationService, _time), //new GetStuckTrackingRule(_log, notificationService, _time), //new NoticeLeftTrackingRule(actionService, _log) }; var trackingService = new TrackingManager(_log, actionService, addressService, _emailService, _time, ruleList); foreach (var shipping in shippings) { trackingService.CheckRules(db, shipping, shipping.TrackingStateEvent, shipping.TrackingStateDate, new List <TrackingRecord>() { new TrackingRecord() { Date = shipping.TrackingStateDate, Message = shipping.TrackingStateEvent, } }, ruleList); } } }
public void UpdateMyPrice(AmazonApi api, IUnitOfWork db) { var lastUpdate = _time.GetUtcTime().AddHours(-12); var allItems = db.Listings .GetAll() .Where(p => p.Market == (int)api.Market && p.MarketplaceId == api.MarketplaceId && !p.IsRemoved && (!p.PriceFromMarketUpdatedDate.HasValue || p.PriceFromMarketUpdatedDate < lastUpdate)) .ToList(); var index = 0; var stepSize = 20; var stepSleeper = new StepSleeper(TimeSpan.FromSeconds(1), 5); while (index < allItems.Count) { try { var itemsToUpdate = allItems.Skip(index).Take(stepSize).ToList(); var skuList = itemsToUpdate.Select(i => i.SKU).ToList(); var items = api.GetMyPriceBySKU(skuList); foreach (var item in items) { var toUpdate = itemsToUpdate.FirstOrDefault(pi => pi.SKU == item.SKU); if (toUpdate != null) { toUpdate.ListingPriceFromMarket = item.ListingPriceFromMarket; toUpdate.ShippingPriceFromMarket = item.ShippingPriceFromMarket; toUpdate.ReqularPriceFromMarket = item.ReqularPriceFromMarket; toUpdate.PriceFromMarketUpdatedDate = _time.GetUtcTime(); } } } catch (Exception ex) { _log.Error("Error when updating rank for index: " + index, ex); } index += stepSize; db.Commit(); stepSleeper.NextStep(); } }
private bool IsPrintLabelsInProgress(IUnitOfWork db, ISystemActionService actionService, ITime time) { var after = time.GetUtcTime().AddHours(-1); var printInProgressList = actionService.GetInProgressByType(db, SystemActionType.PrintBatch, after); return(printInProgressList.Any()); }
private void AddActions(IUnitOfWork db, ParentItemDTO parentItemDto) { foreach (var item in parentItemDto.Variations) { var actions = new List <SystemActionType>() { SystemActionType.UpdateOnMarketProductRelationship, SystemActionType.UpdateOnMarketProductImage, }; foreach (var actionType in actions) { var newAction = new SystemActionDTO() { ParentId = null, Status = (int)SystemActionStatus.None, Type = (int)actionType, Tag = item.Id.ToString(), InputData = null, CreateDate = _time.GetUtcTime(), CreatedBy = null, }; db.SystemActions.AddAction(newAction); } } db.Commit(); }
public IList <ItemDTO> CheckItemsSizeMappingIssue() { IList <ItemDTO> newSizeIssues = new List <ItemDTO>(); using (var db = _dbFactory.GetRWDb()) { var existListingWithIssues = db.ListingSizeIssues.GetAll().ToList(); var allListingWithIssues = db.Items.GetAllWithSizeMappingIssues().ToList(); var existListingIds = existListingWithIssues.Select(i => i.ListingId).ToList(); newSizeIssues = allListingWithIssues .Where(l => l.ListingEntityId.HasValue && !existListingIds.Contains(l.ListingEntityId.Value)) .ToList(); foreach (var sizeIssue in newSizeIssues) { db.ListingSizeIssues.Add(new ListingSizeIssue() { ListingId = sizeIssue.ListingEntityId.Value, AmazonSize = sizeIssue.Size, StyleSize = sizeIssue.StyleSize, IsActual = true, ReCheckDate = _time.GetUtcTime(), CreateDate = _time.GetUtcTime(), }); } db.Commit(); foreach (var existIssue in existListingWithIssues) { var listingIssue = allListingWithIssues.FirstOrDefault(l => l.ListingEntityId == existIssue.ListingId); if (listingIssue == null) { existIssue.IsActual = false; } else { existIssue.IsActual = true; } existIssue.ReCheckDate = _time.GetUtcTime(); } } return(newSizeIssues.OrderByDescending(l => l.OpenDate).ToList()); }
public CheckResult Check(IUnitOfWork db, DTOMarketOrder order, IList <ListingOrderDTO> items) { var result = DuplicateValidatorCheck(db, order, items); _log.Info("CheckDuplicate, result=" + result.IsSuccess + ", message=" + result.Message); if (!result.IsSuccess) { db.OrderNotifies.Add( ComposeNotify(order.Id, (int)OrderNotifyType.Duplicate, 1, result.Message, _time.GetAppNowTime())); db.Commit(); var emailInfo = new DuplicateEmailInfo(_emailService.AddressService, order.CustomerOrderId, (MarketType)order.Market, new DuplicateOrdersDTO { Items = items, OrderNumbers = result.AdditionalData }, order.BuyerName, order.BuyerEmail); _emailService.SendEmail(emailInfo, CallSource.Service); _log.Info("Send duplicated order email, orderId=" + order.Id); db.OrderEmailNotifies.Add(new OrderEmailNotify() { OrderNumber = order.OrderId, Reason = "System emailed, found duplicate", Type = (int)OrderEmailNotifyType.OutputDuplicateAlertEmail, CreateDate = _time.GetUtcTime(), }); db.OrderComments.Add(new OrderComment() { OrderId = order.Id, Message = "[System] Duplicate order alert email sent", Type = (int)CommentType.OutputEmail, CreateDate = _time.GetAppNowTime(), UpdateDate = _time.GetAppNowTime() }); db.Commit(); } return(result); }
public IList <TrackingState> TrackShipments(IList <TrackingNumberToCheckDto> trackingNumbers) { var results = new List <TrackingState>(); var trackingNumberList = trackingNumbers.Select(t => t.TrackingNumber).ToList(); foreach (var trackingNumber in trackingNumberList) { _log.Info("Begin get CA track info=" + trackingNumber); var perOneTrackingResult = _api.GetTrackingField(new List <string>() { trackingNumber }); if (perOneTrackingResult.Status == CallStatus.Fail) { _log.Info(String.Format("Error, tracking number={0}: {1}", trackingNumber, perOneTrackingResult.Message)); results.Add(new TrackingState() { TrackingNumber = trackingNumber, Records = new List <TrackingRecord>() { new TrackingRecord() { Message = TrackingHelper.BuildUndefinedMessage(perOneTrackingResult.Message), Date = _time.GetUtcTime(), } } }); } else { foreach (var result in perOneTrackingResult.Data) { _log.Info("CA tracking result=" + result.TrackingNumber + ", last status=" + (result.Records != null && result.Records.Any() ? result.Records[0].Message + " at " + result.Records[0].Date : "")); } results.AddRange(perOneTrackingResult.Data); } } foreach (var info in results) { if (info.Records != null) { info.Records.ForEach(r => r.Source = TrackingStatusSources.CanadaPost); } } return(results); }
public void Import(string filename) { var lines = File.ReadAllLines(filename); using (var db = _dbFactory.GetRWDb()) { var existBarcodes = db.CustomBarcodes.GetAllAsDto().ToList(); var index = 0; var existIndex = 0; foreach (var line in lines) { if (String.IsNullOrEmpty(line)) { continue; } var barcode = line.Trim(); var exist = existBarcodes.FirstOrDefault(b => b.Barcode == barcode); if (exist == null) { var newBarcode = new CustomBarcode() { Barcode = barcode, CreateDate = _time.GetUtcTime() }; db.CustomBarcodes.Add(newBarcode); existBarcodes.Add(new CustomBarcodeDTO() { Barcode = barcode }); index++; _log.Info("Added: " + index); } else { existIndex++; _log.Info("Exist: " + existIndex); } if (index % 200 == 0) { db.Commit(); } } } }
public void ProcessResult(CheckResult result, Order dbOrder, DTOOrder order, IList <ListingOrderDTO> orderItems) { if (result.IsSuccess) { _log.Info("Send sign confirmation request order email, orderId=" + order.Id); var alreadySend = _db.OrderEmailNotifies.IsExist(order.OrderId, OrderEmailNotifyType.OutputSignConfirmationEmail); if (alreadySend) { return; } var emailInfo = new SignConfirmationRequestEmailInfo(_emailService.AddressService, null, order.OrderId, (MarketType)order.Market, orderItems, //NOTE: make sense only express or not ShippingUtils.IsServiceNextDay(order.InitialServiceType) ? ShippingTypeCode.PriorityExpress : ShippingTypeCode.Standard, order.BuyerName, order.BuyerEmail); _emailService.SendEmail(emailInfo, CallSource.Service); _db.OrderEmailNotifies.Add(new OrderEmailNotify() { OrderNumber = order.OrderId, Reason = "System emailed, request signconfirmation", Type = (int)OrderEmailNotifyType.OutputSignConfirmationEmail, CreateDate = _time.GetUtcTime(), }); _db.OrderComments.Add(new OrderComment() { OrderId = order.Id, Message = "[System] Sign Confirmation email sent", Type = (int)CommentType.Address, CreateDate = _time.GetAppNowTime(), UpdateDate = _time.GetAppNowTime() }); _db.Commit(); } }
public void CheckOrders() { var from = _time.GetAppNowTime().AddDays(-2); using (var invDb = _dbFactory.GetInventoryRWDb()) { var ordersToCheck = invDb.Orders.GetAll().Where(o => o.OrderDate > from && !o.LastCheckedDate.HasValue).ToList(); foreach (var order in ordersToCheck) { if (order.OrderDate < _time.GetUtcTime().AddHours(-2)) { _log.Info("Checking order: " + order.OrderDate); using (var db = _dbFactory.GetRDb()) { var items = db.Scanned.GetScanItemAsDto() .Where(i => i.OrderId == order.Id) .OrderBy(i => i.Barcode) .ToList(); var woStyleItemIds = items.Where(i => !i.StyleItemId.HasValue).ToList(); if (woStyleItemIds.Any()) { _log.Info("Send notification, orderDate=" + order.OrderDate + ", barcodes=" + woStyleItemIds.Count); SendWoStyleNotification(order.OrderDate, order.Description, woStyleItemIds.Select(i => i.Barcode).ToList()); } else { _log.Info("All barcodes have styles"); } order.LastCheckedDate = _time.GetAppNowTime(); invDb.Commit(); } } } } }
public override void SetLastSyncDate(ISettingsService settings, MarketType market, string marketplaceId, DateTime?when) { settings.SetListingsReadDate(_time.GetUtcTime(), market, marketplaceId); settings.SetListingsManualSyncRequest(false, market, marketplaceId); }
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); } } }
public IList <CheckResult <AddressDTO> > CheckAddress(CallSource callSource, IUnitOfWork db, AddressDTO address, long?orderId, out AddressDTO addressWithCorrection) { if (orderId.HasValue && orderId.Value == 0) { throw new ArgumentOutOfRangeException("order.Id", "Should be non zero"); } addressWithCorrection = null; var checkResults = _addressService.CheckAddress(callSource, address); OrderNotify dbStampsOrderNotify = null; foreach (var subResult in checkResults) { //Stamps if (subResult.AdditionalData?[0] == OrderNotifyType.AddressCheckStamps.ToString()) { if (orderId.HasValue) { dbStampsOrderNotify = new OrderNotify() { OrderId = orderId.Value, Type = (int)OrderNotifyType.AddressCheckStamps, Message = StringHelper.Substring(subResult.Message, 512), Status = (int)subResult.Status, CreateDate = _time.GetAppNowTime() }; db.OrderNotifies.Add(dbStampsOrderNotify); } } //Previous correction address if (subResult.AdditionalData?[0] == OrderNotifyType.AddressCheckWithPerviousCorrection.ToString()) { addressWithCorrection = subResult.Data; if (orderId.HasValue) { db.OrderNotifies.Add(new OrderNotify() { OrderId = orderId.Value, Type = (int)OrderNotifyType.AddressCheckWithPerviousCorrection, Message = StringHelper.Substring(subResult.Message, 512), Status = subResult.Status, CreateDate = _time.GetUtcTime() }); } if (subResult.Status < (int)AddressValidationStatus.Invalid && subResult.Status != (int)AddressValidationStatus.None) { if (addressWithCorrection != null && String.IsNullOrEmpty(addressWithCorrection.Address1) && String.IsNullOrEmpty(addressWithCorrection.Address2) && String.IsNullOrEmpty(addressWithCorrection.City) && String.IsNullOrEmpty(addressWithCorrection.State) && String.IsNullOrEmpty(addressWithCorrection.Country) && String.IsNullOrEmpty(addressWithCorrection.Zip) && String.IsNullOrEmpty(addressWithCorrection.ZipAddon)) { addressWithCorrection = null; } if (addressWithCorrection != null) { /* * Похоже идея автоматически менять адрес на предыдущий не совсем хорошая, есть клиент например который хотел послать посылку на новый адрес а мы послали на старый 110-4229580-1843404 * Давай теперь вместо автоматического исправления адреса просто писать коммент, «previous delivery to %Old_Address% was successful” */ if (orderId.HasValue) { var addressString = AddressHelper.ToString(addressWithCorrection, ", "); db.OrderComments.Add(new OrderComment() { OrderId = orderId.Value, Message = String.Format("[System] Previous delivery to \"{0}\" was successful", addressString), Type = (int)CommentType.Address, CreateDate = _time.GetUtcTime() }); } //NOTE: Previous correction address uses only to create order comment addressWithCorrection = null; } } } if (subResult.AdditionalData?[0] == OrderNotifyType.AddressCheckMelissa.ToString()) { //Nothing } if (subResult.AdditionalData?[0] == OrderNotifyType.AddressCheckGoogleGeocode.ToString()) { if (orderId.HasValue) { db.OrderNotifies.Add(new OrderNotify() { OrderId = orderId.Value, Type = (int)OrderNotifyType.AddressCheckGoogleGeocode, Message = StringHelper.Substring(subResult.Message, 512), Status = subResult.Status, CreateDate = _time.GetUtcTime() }); } } if (subResult.AdditionalData?[0] == OrderNotifyType.AddressCheckFedex.ToString()) { if (orderId.HasValue) { db.OrderNotifies.Add(new OrderNotify() { OrderId = orderId.Value, Type = (int)OrderNotifyType.AddressCheckFedex, Message = StringHelper.Substring(subResult.Message, 512), Status = subResult.Status, CreateDate = _time.GetUtcTime() }); } var stampsResult = checkResults.FirstOrDefault(r => r.AdditionalData[0] == OrderNotifyType.AddressCheckStamps.ToString()); if (stampsResult != null && stampsResult.Status >= (int)AddressValidationStatus.Invalid) { if (subResult.Status < (int)AddressValidationStatus.Invalid) { if (addressWithCorrection == null && subResult.Data != null) { var correctionCandidate = subResult.Data; correctionCandidate.FullName = address.FullName; //TASK: If stamps verify it replace it, and don’t show errors. var addressCandidateResults = _addressService.CheckAddress(callSource, correctionCandidate, new Core.Models.Settings.AddressProviderType[] { Core.Models.Settings.AddressProviderType.Stamps }); var stampsCandidateResult = addressCandidateResults.FirstOrDefault(r => r.AdditionalData[0] == OrderNotifyType.AddressCheckStamps.ToString()); if (stampsCandidateResult.Status < (int)AddressValidationStatus.Invalid) { _log.Info("Replacing address to Fedex Effective address"); stampsResult.Status = stampsCandidateResult.Status; if (dbStampsOrderNotify != null) { dbStampsOrderNotify.Status = stampsCandidateResult.Status; } if (orderId.HasValue) { db.OrderComments.Add(new OrderComment() { OrderId = orderId.Value, Message = String.Format("[System] Address was replaced by Fedex \"Effective address\""), Type = (int)CommentType.Address, CreateDate = _time.GetUtcTime() }); } addressWithCorrection = subResult.Data; } } } } } } return(checkResults); }
public void Process(IUnitOfWork db, EmailReadingResult result) { if (result.Status == EmailMatchingResultStatus.New && result.HasMatches) { var noHtml = StringHelper.TrimTags(result.Email.Message ?? ""); var message = StringHelper.Substring(noHtml, 70).ToLower(); //to remove the signature confirmation var removeSignConfirmation = message.IndexOf("remove signature confirmation", StringComparison.OrdinalIgnoreCase) >= 0 || message.IndexOf("remove signature", StringComparison.OrdinalIgnoreCase) >= 0 || message.IndexOf("remove the signature", StringComparison.OrdinalIgnoreCase) >= 0; if (removeSignConfirmation) { var orderNumber = result.MatchedIdList.FirstOrDefault(); _log.Info("Received RemoveSignatureConfirmation request, orderNumber=" + orderNumber); if (!String.IsNullOrEmpty(orderNumber)) { var isExistRemoveSignConfirmation = db.OrderEmailNotifies.IsExist(orderNumber, OrderEmailNotifyType.InputRemoveSignConfirmationEmail); if (!isExistRemoveSignConfirmation) //NOTE: First remove sign confirmation request { result.WasEmailProcessed = true; _log.Info("RemoveSignatureEmailRule, WasEmailProcessed=" + result.WasEmailProcessed); var comment = String.Empty; var order = db.Orders.GetByOrderNumber(orderNumber); //var now = _time.GetAppNowTime(); //var isWeekday = db.Dates.IsWorkday(_time.GetAppNowTime()); if (order.OrderStatus == OrderStatusEnumEx.Shipped //|| (isWeekday && now.Hour > 15) ) { //comment = "Skipped. Order already shipped or request came after 3PM on weekday"; var commentText = ""; if (order.OrderStatus == OrderStatusEnumEx.Shipped) { commentText = "[System] Remove signature confirmation request came after the order shipped"; comment = "Skipped. Order already shipped"; } //if (isWeekday && now.Hour > 15) //{ // commentText = "[System] Remove signature confirmation request came after 3PM on weekday"; // comment = "Skipped. Request came after 3PM on weekday"; //} db.OrderComments.Add(new OrderComment() { OrderId = order.Id, Message = commentText, Type = (int)CommentType.Address, CreateDate = _time.GetAppNowTime(), UpdateDate = _time.GetAppNowTime() }); var emailInfo = new RejectRemoveSignConfirmationEmailInfo(_emailService.AddressService, null, orderNumber, (MarketType)order.Market, order.BuyerName, order.BuyerEmail); _emailService.SendEmail(emailInfo, CallSource.Service); } else { //Tring to remove signature if (order.OrderStatus == OrderStatusEnumEx.Unshipped || order.OrderStatus == OrderStatusEnumEx.PartiallyShipped || order.OrderStatus == OrderStatusEnumEx.Pending) { if (order.IsSignConfirmation) { order.IsSignConfirmation = false; _log.Info("Updated IsSignConfirmation=false, orderNumber=" + order.AmazonIdentifier); db.OrderComments.Add(new OrderComment() { OrderId = order.Id, Message = "[System] Signature confirmation was removed per buyer request", Type = (int)CommentType.Address, CreateDate = _time.GetAppNowTime(), UpdateDate = _time.GetAppNowTime() }); _actionService.AddAction(db, SystemActionType.UpdateRates, order.AmazonIdentifier, new UpdateRatesInput() { OrderId = order.Id }, null, null); var orderItems = db.Listings.GetOrderItems(order.Id); var emailInfo = new AcceptRemoveSignConfirmationEmailInfo(_emailService.AddressService, null, orderNumber, (MarketType)order.Market, orderItems, order.BuyerName, order.BuyerEmail); _emailService.SendEmail(emailInfo, CallSource.Service); comment = "Sign confirmation removed + emailed"; } else { db.OrderComments.Add(new OrderComment() { OrderId = order.Id, Message = "[System] Remove signature confirmation request skipped. Signature confirmation was already removed", Type = (int)CommentType.Address, CreateDate = _time.GetAppNowTime(), UpdateDate = _time.GetAppNowTime() }); comment = "Skipped. Already removed"; } } else { //NOTE: If OrderStatus=Canceled comment = "Skipped. Order status=" + order.OrderStatus; } } var dbBuyer = db.Buyers.GetFiltered(b => b.Email == result.Email.From).FirstOrDefault(); if (dbBuyer != null) { dbBuyer.RemoveSignConfirmation = true; dbBuyer.RemoveSignConfirmationDate = _time.GetUtcTime(); _log.Info("Set RemoveSignConfirmation=true, buyerEmail=" + result.Email.From); } else { _log.Info("Can't find buyerEmail=" + result.Email.From); } db.OrderEmailNotifies.Add(new OrderEmailNotify() { OrderNumber = orderNumber, Type = (int)OrderEmailNotifyType.InputRemoveSignConfirmationEmail, Reason = comment, CreateDate = _time.GetUtcTime() }); db.Commit(); } else { _log.Info("Repeated RemoveSignConfirmation email, no action"); } } else { _log.Info("Can't RemoveSignConfirmation, no matching orders!"); } } } }
public void ProcessNewListingsWithItems(IUnitOfWork db, IMarketApi api, ITime time, IList <ItemDTO> items) { _log.Debug("Begin process new items"); foreach (var dtoItem in items) { try { if (dtoItem.IsExistOnAmazon == true) { _syncInfo.AddSuccess(dtoItem.ASIN, "New listing item was filled by Amazon"); if (String.IsNullOrEmpty(dtoItem.ParentASIN)) { _syncInfo.AddWarning(dtoItem.ASIN, "Empty ParentASIN"); } dtoItem.IsAmazonParentASIN = !String.IsNullOrEmpty(dtoItem.ParentASIN); dtoItem.LastUpdateFromAmazon = time.GetUtcTime(); //Add new item, no need to additional check dtoItem.StyleString = SkuHelper.RetrieveStyleIdFromSKU(db, dtoItem.SKU, dtoItem.Name); var dbItem = db.Items.StoreItemIfNotExist(_itemHistoryService, "ListingLineProcessing", dtoItem, api.Market, api.MarketplaceId, _companyId, time.GetAppNowTime()); //NOTE: fresh size (for some reason can start came emtpy) dtoItem.Size = dbItem.Size; if (!dbItem.StyleItemId.HasValue) { //Keep exists styleId dtoItem.StyleId = dbItem.StyleId; var styleItem = FindOrCreateStyleItem(db, dtoItem); if (styleItem != null) { if (styleItem.StyleItemId > 0) { dbItem.StyleId = styleItem.StyleId; dbItem.StyleItemId = styleItem.StyleItemId; } else { if (!dbItem.StyleId.HasValue) { dbItem.StyleId = styleItem.StyleId; } } _log.Debug(String.Format("Set for ASIN={0}, styleId={1}, styleItemId={2}", dtoItem.ASIN, styleItem.StyleId, styleItem.StyleItemId)); } db.Commit(); } if (!String.IsNullOrEmpty(dtoItem.Barcode) && dbItem.StyleItemId.HasValue) { _styleManager.StoreOrUpdateBarcode(db, dbItem.StyleItemId.Value, dtoItem.Barcode); } var dbListing = db.Listings.StoreOrUpdate(dtoItem, dbItem, api.Market, api.MarketplaceId, time.GetAppNowTime()); dtoItem.IsDefault = dbListing.IsDefault; _syncInfo.AddSuccess(dtoItem.ASIN, "New listing item was stored"); _log.Debug("Store item:" + dbItem.ASIN + ", parentASIN=" + dbItem.ParentASIN + ", SKU=" + dtoItem.SKU + ", StyleString=" + dbItem.StyleString + ", quantity=" + dtoItem.RealQuantity); } else { _syncInfo.AddWarning(dtoItem.ASIN, "Item is not filled by Amazon (new listing item)"); _log.Warn("Item is not filled by Amazon (new listing item), item=" + dtoItem.ASIN); } } catch (Exception ex) { _syncInfo.AddError(dtoItem.ASIN, "Error while creating item", ex); _log.Error(string.Format("Error while creating item, asin={0}", dtoItem.ASIN), ex); } } _log.Debug("End process new items"); }
private void CancelOrder(IUnitOfWork db, EmailReadingResult result, string orderNumber, Order order) { if (!String.IsNullOrEmpty(orderNumber)) { var itemId = EmailHelper.ExtractWalmartItemId(result.Email.Message); _log.Info("ItemId=" + itemId); var existCancellationActions = _systemAction.GetByTypeAndTag(db, SystemActionType.UpdateOnMarketCancelOrder, orderNumber); var isExistCancelRequest = existCancellationActions.Any(); if (existCancellationActions.Any() && order != null && (order.Market == (int)MarketType.Walmart || order.Market == (int)MarketType.WalmartCA)) //NOTE: for Walmart checking by item cancallation { var existItemCancallation = false; foreach (var action in existCancellationActions) { var data = JsonConvert.DeserializeObject <CancelOrderInput>(action.InputData); if (data.ItemId == itemId) { existItemCancallation = true; } } isExistCancelRequest = existItemCancallation; } if (!isExistCancelRequest) { result.WasEmailProcessed = true; _log.Info("CancellationEmailRule, WasEmailProcessed=" + result.WasEmailProcessed); var comment = ""; //NOTE: "system to cancel that order if it wasn’t shipped and it’s not assigned to Active Batch yet, and send client an email" //NOTE: if no order in system if (order == null || ((order.OrderStatus == OrderStatusEnumEx.Unshipped || order.OrderStatus == OrderStatusEnumEx.Pending || order.OrderStatus == OrderStatusEnumEx.Canceled) && !order.BatchId.HasValue)) { _log.Info("Order status was changed to Canceled, orderNumber=" + orderNumber); SystemActionHelper.AddCancelationActionSequences(db, _systemAction, order.Id, orderNumber, itemId, result.Email.Id, result.Email.From, (order != null && (order.Market == (int)MarketType.Walmart || order.Market == (int)MarketType.WalmartCA)) ? result.Email.Subject : null, EmailHelper.ExtractShortMessageBody(result.Email.Message, 200, true), null, CancelReasonType.PerBuyerRequest); if (order != null && order.Market != (int)MarketType.Walmart && order.Market != (int)MarketType.WalmartCA) //NOTE: Exclude Walmart, cancellation happen only for one item { order.OrderStatus = OrderStatusEnumEx.Canceled; } //if (order != null && (order.Market == (int) MarketType.Walmart || order.Market == (int)MarketType.WalmartCA)) //{ // if (!order.BatchId.HasValue) //Only when not in batch // { // var orderItemLineCount = db.OrderItems.GetByOrderIdAsDto(order.Id).Count(); // if (orderItemLineCount > 1) // { // _log.Info("Walmart Order set OnHold, in case it has more then one item line = " + orderItemLineCount); // order.OnHold = true; // db.OrderComments.Add(new OrderComment() // { // OrderId = order.Id, // Message = String.Format("[System] Partial email cancellation request, 1 / {0} order lines", orderItemLineCount), // Type = (int)CommentType.ReturnExchange, // LinkedEmailId = result.Email.Id, // CreateDate = _time.GetAppNowTime(), // UpdateDate = _time.GetAppNowTime(), // }); // } // } //} if (order != null) { comment = "Marked as cancelled + emailed"; db.OrderNotifies.Add(new OrderNotify() { OrderId = order.Id, Status = 1, Type = (int)OrderNotifyType.CancellationRequest, Params = itemId, Message = "Email cancelation request in progress", CreateDate = _time.GetAppNowTime(), }); } } else { var commentText = "[System] Email cancelation request wasn't processed. Order already shipped."; if (order.OrderStatus != OrderStatusEnumEx.Shipped) { db.OrderNotifies.Add(new OrderNotify() { OrderId = order.Id, Status = 1, Type = (int)OrderNotifyType.CancellationRequest, Params = itemId, Message = "Email cancelation request, order in batch", CreateDate = _time.GetAppNowTime(), }); } else { _systemAction.AddAction(db, SystemActionType.SendEmail, orderNumber, new SendEmailInput() { EmailType = EmailTypes.RejectOrderCancellationToBuyer, OrderId = orderNumber, ReplyToEmail = result.Email.From, ReplyToSubject = result.Email.Subject, }, null, null); commentText += " Email was sent to customer."; } db.OrderComments.Add(new OrderComment() { OrderId = order.Id, Message = commentText, Type = (int)CommentType.ReturnExchange, LinkedEmailId = result.Email.Id, CreateDate = _time.GetAppNowTime(), UpdateDate = _time.GetAppNowTime(), }); comment = "Cancellation skipped"; } db.OrderEmailNotifies.Add(new OrderEmailNotify() { OrderNumber = orderNumber, Type = (int)OrderEmailNotifyType.InputOrderCancelledEmail, Reason = comment, CreateDate = _time.GetUtcTime() }); db.Commit(); } else { _log.Info("Repeated OrderCancellation email, no action"); } } else { _log.Info("Can't OrderCancellation, no order number!"); } }
private void ProcessItems(IUnitOfWork db, IMarketApi api, ITime time, IList <ItemDTO> listings) { var syncInfo = Context.SyncInformer; Log.Debug("ProcessItems begin"); var allDbListings = db.Listings.GetAll().Where(l => l.Market == (int)api.Market && (l.MarketplaceId == api.MarketplaceId || String.IsNullOrEmpty(api.MarketplaceId))) .ToList(); var allDbItems = db.Items.GetAll().Where(l => l.Market == (int)api.Market && (l.MarketplaceId == api.MarketplaceId || String.IsNullOrEmpty(api.MarketplaceId))) .ToList(); var updateItemIds = new List <long>(); var existsListingSKUs = new List <string>(); //STEP 1. Update listings ASINs Log.Debug("Update ASINs begin"); foreach (var listing in listings) { var dbListing = allDbListings.FirstOrDefault(l => l.SKU == listing.SKU); if (dbListing != null) { existsListingSKUs.Add(listing.SKU); if (dbListing.ListingId != listing.ListingId) { dbListing.ListingId = listing.ListingId; } if (dbListing.ASIN != listing.ASIN) { dbListing.ASIN = listing.ASIN; } if (dbListing.AmazonRealQuantity != listing.RealQuantity) { Log.Debug("Price changed: " + dbListing.SKU + ": " + dbListing.AmazonRealQuantity + "=>" + listing.RealQuantity); dbListing.AmazonRealQuantity = listing.RealQuantity; dbListing.AmazonRealQuantityUpdateDate = time.GetAppNowTime(); } if (dbListing.AmazonCurrentPrice != listing.CurrentPrice) { Log.Debug("Price changed: " + dbListing.SKU + ": " + dbListing.AmazonCurrentPrice + "=>" + listing.CurrentPrice); dbListing.AmazonCurrentPrice = listing.CurrentPrice; dbListing.AmazonCurrentPriceUpdateDate = time.GetAppNowTime(); } var dbItem = allDbItems.FirstOrDefault(i => i.Id == dbListing.ItemId); if (dbItem != null) { if (dbItem.ASIN != listing.ASIN) { Log.Debug("Item ASIN changed: " + dbItem.Id + ": " + dbItem.ASIN + " => " + listing.ASIN); dbItem.ASIN = listing.ASIN; } if (dbItem.SourceMarketId != listing.ASIN) { dbItem.SourceMarketId = listing.ASIN; } if (dbItem.ItemPublishedStatusFromMarket != listing.PublishedStatus) { dbItem.ItemPublishedStatusFromMarket = listing.PublishedStatus; dbItem.ItemPublishedStatusFromMarketDate = time.GetAppNowTime(); } if (listing.PublishedStatus == (int)PublishedStatuses.Published) { dbItem.ItemPublishedStatusBeforeRepublishing = dbItem.ItemPublishedStatus; dbItem.ItemPublishedStatus = listing.PublishedStatus; dbItem.ItemPublishedStatusReason = "Listings report"; dbItem.ItemPublishedStatusDate = time.GetAppNowTime(); } updateItemIds.Add(dbItem.Id); } } } db.Commit(); Log.Debug("Update ASINs end"); //STEP 1.2. Market all not exists as unpublished Log.Debug("Update items Unpublished begin"); var notUpdatedItems = allDbItems.Where(i => !updateItemIds.Contains(i.Id)).ToList(); Log.Debug("Not updated items: " + notUpdatedItems.Count()); foreach (var dbItem in notUpdatedItems) { if (dbItem.ItemPublishedStatus == (int)PublishedStatuses.Published) { Log.Debug("Status changes for: " + dbItem.ASIN + " - " + dbItem.ItemPublishedStatus + "=>" + PublishedStatuses.New); dbItem.ItemPublishedStatusBeforeRepublishing = dbItem.ItemPublishedStatus; dbItem.ItemPublishedStatusReason = "System Warning: the listing has the Published status, but it does not appear in the listing report."; dbItem.ItemPublishedStatusDate = time.GetAppNowTime(); dbItem.ItemPublishedStatus = (int)PublishedStatuses.New; dbItem.IsAmazonParentASIN = false; dbItem.IsExistOnAmazon = false; } } db.Commit(); Log.Debug("Update items Unpublished end"); //STEP 2. Update ParentASINs Log.Debug("Update ParentASINs begin"); var newListingsWithError = new List <ItemDTO>(); try { api.FillWithAdditionalInfo(Log, time, listings, IdType.SKU, ItemFillMode.Defualt, out newListingsWithError); } catch (Exception ex) //Can continue if only part of records was filled { syncInfo.AddError("", "Can't fill new listing items with additional info", ex); Log.Error("Can't fill new listing items with additional info", ex); } var allDbParents = db.ParentItems.GetAll().Where(pi => pi.Market == (int)api.Market && (pi.MarketplaceId == api.MarketplaceId || String.IsNullOrEmpty(api.MarketplaceId))).ToList(); var updatedParentIds = new List <long>(); foreach (var listing in listings) { var dbListing = allDbListings.FirstOrDefault(l => l.SKU == listing.SKU); var dbItem = dbListing == null ? null : allDbItems.FirstOrDefault(i => i.Id == dbListing.ItemId); var dbParentItem = dbItem == null ? null : allDbParents.FirstOrDefault(pi => pi.ASIN == dbItem.ParentASIN); if (dbItem != null && dbItem.IsExistOnAmazon != listing.IsExistOnAmazon) { Log.Debug("IsExistOnAmazon: " + listing.ASIN + ": " + dbItem.IsExistOnAmazon + "=>" + listing.IsExistOnAmazon); dbItem.IsExistOnAmazon = listing.IsExistOnAmazon; } var parentASIN = listing.ParentASIN; if (String.IsNullOrEmpty(parentASIN)) { parentASIN = listing.ASIN; } if (dbItem != null && dbItem.IsExistOnAmazon == true) { dbItem.IsAmazonParentASIN = !String.IsNullOrEmpty(listing.ParentASIN); dbItem.LastUpdateFromAmazon = time.GetUtcTime(); } if (dbParentItem != null && listing.IsExistOnAmazon == true) { var allItemsForParentItem = allDbItems.Where(i => i.ParentASIN == dbParentItem.ASIN).ToList(); if (dbParentItem.ASIN != parentASIN) { Log.Debug("ParentItem ASIN: " + dbParentItem.ASIN + "=>" + parentASIN); dbParentItem.ASIN = parentASIN; allItemsForParentItem.ForEach(i => i.ParentASIN = parentASIN); //UPDATE for all, in case it may have different Parents on Amazon (us last one for all) } if (listing.ParentASIN != dbParentItem.ASIN) { dbParentItem.IsAmazonUpdated = false; } else { dbParentItem.IsAmazonUpdated = listing.IsExistOnAmazon; } } } db.Commit(); Log.Debug("Update ParentASINs end"); //2.1 Update not exist parent asins var notUpdatedParents = allDbParents.Where(pi => !updatedParentIds.Contains(pi.Id)).ToList(); Log.Debug("Not exist parent items: " + notUpdatedParents.Count()); foreach (var dbParentItem in notUpdatedParents) { Log.Debug("Mark as not processed: " + dbParentItem.ASIN); dbParentItem.IsAmazonUpdated = false; } db.Commit(); //3.0 Set to inactive not exist listings var notExistListings = listings.Where(l => !existsListingSKUs.Contains(l.SKU)).ToList(); foreach (var notExistListing in notExistListings) { Log.Debug("Request qty=0 for SKU=" + notExistListing.SKU); if (Context.ActionService != null) { Context.ActionService.AddAction(db, SystemActionType.UpdateOnMarketProductQuantity, notExistListing.SKU, new UpdateQtyInput() { Market = api.Market, MarketplaceId = api.MarketplaceId, ListingId = null, SKU = notExistListing.SKU, SourceMarketId = notExistListing.SourceMarketId, NewQty = 0, }, null, null); } } Log.Debug("ProcessItems end"); }
public void ReadItemsInfo(SupplieroasisApi api) { _log.Info("Begin ReadItemsInfo"); var itemsWithError = new List <string>(); var items = api.GetItems(_log, _time, null, ItemFillMode.Defualt, out itemsWithError); using (var db = _dbFactory.GetRWDb()) { _log.Info("Total items=" + items.Count()); //Create var allItems = db.Items.GetAllViewAsDto().Where(m => m.Market == (int)api.Market && (m.MarketplaceId == api.MarketplaceId || String.IsNullOrEmpty(api.MarketplaceId))).ToList(); foreach (var item in items) { foreach (var variation in item.Variations) { var existItem = allItems.FirstOrDefault(i => StringHelper.IsEqualNoCase(i.SKU, variation.SKU)); if (existItem == null) { _log.Info("Add new item, MarketItemId=" + variation.SourceMarketId); var exampleItem = db.Items.GetAllViewAsDto().FirstOrDefault(i => i.Market == (int)MarketType.Amazon && i.MarketplaceId == MarketplaceKeeper.AmazonComMarketplaceId && i.SKU == variation.SKU); if (exampleItem == null) { exampleItem = db.Items.GetAllViewAsDto().OrderByDescending(i => i.CreateDate).FirstOrDefault(i => i.SKU == variation.SKU); } var styleString = SkuHelper.RetrieveStyleIdFromSKU(db, variation.SKU, null); if (String.IsNullOrEmpty(styleString)) { styleString = variation.SKU; } if (String.IsNullOrEmpty(styleString)) { _log.Info("StyleString is empty for: " + variation.SKU + ", itemSKU=" + item.SKU); continue; } var parentItem = db.ParentItems.GetAll().FirstOrDefault(pi => pi.ASIN == styleString && pi.Market == (int)MarketType.OverStock); if (parentItem == null) { parentItem = new ParentItem() { ASIN = styleString, SourceMarketId = styleString, Market = item.Market, MarketplaceId = item.MarketplaceId, CreateDate = _time.GetAmazonNowTime() }; db.ParentItems.Add(parentItem); db.Commit(); } if (exampleItem == null) { exampleItem = new DTO.ItemDTO(); var style = db.Styles.GetAll().FirstOrDefault(st => st.StyleID == styleString); if (style != null) { exampleItem.StyleId = style.Id; } var size = SkuHelper.RetrieveSizeFromSKU(variation.SKU); if (style != null) { var styleItem = db.StyleItems.GetAll().FirstOrDefault(si => si.StyleId == style.Id && si.Size == size); if (styleItem != null) { exampleItem.StyleItemId = styleItem.Id; } } } var newItem = new Item() { ASIN = item.ASIN, ParentASIN = parentItem.ASIN, Market = item.Market, MarketplaceId = item.MarketplaceId, Barcode = variation.Barcode, SourceMarketId = item.SourceMarketId, ItemPublishedStatus = variation.PublishedStatus, StyleId = exampleItem?.StyleId, StyleItemId = exampleItem?.StyleItemId, CreateDate = _time.GetAmazonNowTime() }; db.Items.Add(newItem); db.Commit(); var newListing = new Listing() { ItemId = newItem.Id, SKU = variation.SKU, ListingId = variation.SKU, Market = variation.Market, MarketplaceId = variation.MarketplaceId, CreateDate = _time.GetAmazonNowTime(), AmazonRealQuantity = variation.AmazonRealQuantity, }; db.Listings.Add(newListing); db.Commit(); } } } //Update var updatedItemIds = new List <long>(); foreach (var item in items) { foreach (var variation in item.Variations) { _log.Info("Read info for SKU=" + variation.SKU); var dbListing = db.Listings.GetAll().FirstOrDefault(m => m.Market == (int)api.Market && (m.MarketplaceId == api.MarketplaceId || String.IsNullOrEmpty(api.MarketplaceId)) && m.SKU == variation.SKU); if (dbListing == null) { _log.Info("Unable to find item for, SKU=" + variation.SKU); continue; } var dbItem = db.Items.GetAll().FirstOrDefault(i => i.Id == dbListing.ItemId); if (dbItem == null) { _log.Info("Unable to find item for itemId=" + dbListing.ItemId); continue; } updatedItemIds.Add(dbItem.Id); if (dbItem.ItemPublishedStatus != variation.PublishedStatus) { dbItem.ItemPublishedStatus = variation.PublishedStatus; dbItem.ItemPublishedStatusDate = _time.GetAppNowTime(); dbItem.ItemPublishedStatusReason = "Derived from market"; } dbItem.Barcode = variation.Barcode; //dbListing.AmazonCurrentPrice = variation.AmazonCurrentPrice; //dbListing.AmazonCurrentPriceUpdateDate = _time.GetAppNowTime(); dbListing.AmazonRealQuantity = variation.AmazonRealQuantity; dbListing.AmazonRealQuantityUpdateDate = _time.GetAppNowTime(); } } db.Commit(); //Remove not exists var toRemoveItems = db.Items.GetAll().Where(i => i.Market == (int)api.Market && (i.MarketplaceId == api.MarketplaceId || String.IsNullOrEmpty(api.MarketplaceId)) && !updatedItemIds.Contains(i.Id) && i.ItemPublishedStatus == (int)PublishedStatuses.Published); _log.Info("Items to unpublish, count=" + toRemoveItems.Count()); foreach (var toRemoveItem in toRemoveItems) { toRemoveItem.ItemPublishedStatusBeforeRepublishing = toRemoveItem.ItemPublishedStatus; toRemoveItem.ItemPublishedStatus = (int)PublishedStatuses.Unpublished; toRemoveItem.ItemPublishedStatusDate = _time.GetUtcTime(); } db.Commit(); } _log.Info("End ReadItemsInfo"); }
public CheckResult Check(IUnitOfWork db, DTOMarketOrder order, IList <ListingOrderDTO> items, AddressValidationStatus addressValidationStatus) { if (order.Id == 0) { throw new ArgumentOutOfRangeException("order.Id", "Should be non zero"); } if (order.OrderStatus == OrderStatusEnumEx.Pending) { throw new ArgumentException("order.OrderStatus", "Not supported status Pending"); } //International order has issue with PersonName if (ShippingUtils.IsInternational(order.FinalShippingCountry)) { if (String.IsNullOrEmpty(order.FinalShippingPhone)) { var emailInfo = new PhoneMissingEmailInfo(_emailService.AddressService, null, order.OrderId, (MarketType)order.Market, items, order.BuyerName, order.BuyerEmail); _emailService.SendEmail(emailInfo, CallSource.Service); _log.Info("Send phone missing email, orderId=" + order.Id); db.OrderEmailNotifies.Add(new OrderEmailNotify() { OrderNumber = order.OrderId, Reason = "System emailed, missing phone number", Type = (int)OrderEmailNotifyType.OutputPhoneMissingEmail, CreateDate = _time.GetUtcTime(), }); db.OrderComments.Add(new OrderComment() { OrderId = order.Id, Message = "[System] Missing phone email sent", Type = (int)CommentType.Address, CreateDate = _time.GetAppNowTime(), UpdateDate = _time.GetAppNowTime() }); db.Commit(); return(new CheckResult() { IsSuccess = false }); } } return(new CheckResult() { IsSuccess = true }); }
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"); } }
public void Process(IUnitOfWork db, EmailReadingResult result) { if (result.Status == EmailMatchingResultStatus.New && result.HasMatches) { var subject = (result.Email.Subject ?? ""); var today = _time.GetAppNowTime().Date; //TASK: 1. Emails which have these in subjects: "Order delivery inquiry" or " Where's My Stuff?” //CHANGE: When client sends an email with subject “Package didn’t arrive..” like 113-7086092-7521857, process it same way as emails with subject “Lost Package”… var isWhereMyStaff = subject.StartsWith("Order delivery inquiry", StringComparison.OrdinalIgnoreCase) || subject.IndexOf("Where's My Stuff?", StringComparison.OrdinalIgnoreCase) >= 0 || subject.IndexOf("Where's My Stuff ?", StringComparison.OrdinalIgnoreCase) >= 0 || subject.IndexOf("Package didn’t arrive:", StringComparison.OrdinalIgnoreCase) >= 0 || subject.IndexOf("Package didn?t arrive", StringComparison.OrdinalIgnoreCase) >= 0 || subject.IndexOf("Shipping inquiry", StringComparison.InvariantCultureIgnoreCase) >= 0; //NOTE: actually came with ? instead of ' if (isWhereMyStaff) { _log.Info("Received 'Where my stuff'"); var orderNumber = result.MatchedIdList.FirstOrDefault(); if (!String.IsNullOrEmpty(orderNumber)) { //TASK: 2. Which were successfully delivered to client. var order = db.Orders.GetByOrderNumber(orderNumber); var shippingInfos = db.OrderShippingInfos.GetByOrderIdAsDto(order.Id).Where(sh => sh.IsActive).ToList(); //a. delivered to client (not returned to us) var delivered = shippingInfos.Any() && shippingInfos.All(sh => sh.DeliveredStatus == (int)DeliveredStatusEnum.Delivered); var deliveryDate = shippingInfos.Select(sh => sh.ActualDeliveryDate).FirstOrDefault(); //b. Delivered within last 2 month. if (delivered && deliveryDate.HasValue && deliveryDate > today.AddMonths(-2)) { _log.Info("Package was delivered, withing last 2 month"); var alreadySendLostTemplate = db.OrderEmailNotifies.IsExist(order.AmazonIdentifier, OrderEmailNotifyType.OutputLostPackageEmail); //3. To which we didn’t answer yet with Lost Package template if (!alreadySendLostTemplate) { _log.Info("Not send package lost template"); var orderEmails = db.Emails.GetAllByOrderId(order.AmazonIdentifier) .Select(m => new { m.Id, m.ReceiveDate, m.Subject }).ToList(); var isAnyOtherSimilarEmails = orderEmails.Any(e => e.Id != result.Email.Id && (e.ReceiveDate <= result.Email.ReceiveDate && e.Subject.Contains("Where's My Stuff?") || e.Subject.Contains("Order delivery inquiry"))); var isAnyOtherEmailAfterDelivery = deliveryDate.HasValue && orderEmails.Any(e => e.Id != result.Email.Id && e.ReceiveDate >= deliveryDate.Value); //4. If it’s the first email with that subject ("Order delivery inquiry" or " Where's My Stuff?”) if (!isAnyOtherSimilarEmails && !isAnyOtherEmailAfterDelivery) { _log.Info("Pass to Order Delivery Inquiry Rule"); OrderShippingInfoDTO shippingInfo = null; ShippingMethodDTO shippingMethod = null; if (shippingInfos.Any()) { shippingInfo = shippingInfos.OrderByDescending(sh => sh.ActualDeliveryDate) .FirstOrDefault(i => i.IsActive); if (shippingInfo != null) { shippingMethod = db.ShippingMethods.GetByIdAsDto(shippingInfo.ShippingMethodId); } } var emailInfo = new LostPackageEmailInfo(_emailService.AddressService, null, order.AmazonIdentifier, (MarketType)order.Market, shippingInfo != null ? shippingInfo.ActualDeliveryDate : null, shippingInfo != null ? shippingInfo.TrackingStateEvent : null, shippingMethod != null ? shippingMethod.CarrierName : null, shippingInfo != null ? shippingInfo.TrackingNumber : null, order.GetAddressDto(), order.BuyerName, order.BuyerEmail); _emailService.SendEmail(emailInfo, CallSource.Service); db.OrderEmailNotifies.Add(new OrderEmailNotify() { OrderNumber = order.CustomerOrderId, Type = (int)OrderEmailNotifyType.OutputLostPackageEmail, Reason = "Email: " + StringHelper.Substring(subject, 40), CreateDate = _time.GetUtcTime() }); db.OrderComments.Add(new OrderComment() { OrderId = order.Id, Type = (int)CommentType.OutputEmail, Message = "[System] \"Lost Package\" email sent", CreateDate = _time.GetAppNowTime(), }); db.Commit(); result.WasEmailProcessed = true; } else { if (isAnyOtherSimilarEmails) { _log.Info("Similar email was found"); } if (isAnyOtherEmailAfterDelivery) { _log.Info("Other email was found after delivery"); } } } else { _log.Info("Already sent Lost Package template"); } } else { _log.Info("Package not yet delivered"); } } } } }
private void SetItemFieldsIfExistOnAmazon(IUnitOfWork db, ItemDTO dtoItem, Item dbItem) { //NOTE: Skip any ParentASIN updates //NOTE: updates for childs only when we change ParentItem objects //NOTE: to keep source relationships //if (!String.IsNullOrEmpty(dtoItem.ParentASIN)) //{ // dbItem.ParentASIN = dtoItem.ParentASIN; //} //NOTE: only when no ParentASIN if (String.IsNullOrEmpty(dbItem.ParentASIN) && !String.IsNullOrEmpty(dtoItem.ParentASIN)) { dbItem.ParentASIN = dtoItem.ParentASIN; } if (dbItem.ASIN != dtoItem.ASIN) { _log.Info("For SKU=" + dtoItem.SKU + "(id: " + dbItem.Id + ")" + ", ASIN=" + dbItem.ASIN + "=>" + dtoItem.ASIN); dbItem.ASIN = dtoItem.ASIN; } if (dbItem.ItemPublishedStatus == (int)PublishedStatuses.New || dbItem.ItemPublishedStatus == (int)PublishedStatuses.PublishedInactive || dbItem.ItemPublishedStatus == (int)PublishedStatuses.PublishedInProgress || dbItem.ItemPublishedStatus == (int)PublishedStatuses.PublishingErrors || dbItem.ItemPublishedStatus == (int)PublishedStatuses.None || dbItem.ItemPublishedStatus == (int)PublishedStatuses.HasPublishRequest) //NOTE: should be excluded HasUnpublishdRequest { dbItem.ItemPublishedStatus = (int)PublishedStatuses.Published; dbItem.ItemPublishedStatusReason = ""; dbItem.ItemPublishedStatusDate = _time.GetAppNowTime(); } dbItem.ItemPublishedStatusFromMarket = (int)PublishedStatuses.Published; dbItem.ItemPublishedStatusFromMarketDate = _time.GetAppNowTime(); dbItem.IsAmazonParentASIN = dtoItem.ParentASIN == dbItem.ParentASIN; dbItem.SourceMarketId = dtoItem.SourceMarketId; dbItem.MarketParentASIN = dtoItem.ParentASIN; if (dbItem.OnMarketTemplateName != dtoItem.OnMarketTemplateName) { _log.Debug("Template changed: " + dbItem.OnMarketTemplateName + "=>" + dtoItem.OnMarketTemplateName); } dbItem.OnMarketTemplateName = dtoItem.OnMarketTemplateName; //Updates size if came not null if (!String.IsNullOrEmpty(dtoItem.Size)) { var newSize = StringHelper.Substring(dtoItem.Size, 50); if (dbItem.Size != newSize) { if (_itemHistoryService != null) { _itemHistoryService.AddRecord(dbItem.Id, ItemHistoryHelper.SizeKey, dbItem.Size, "ListingLineProcessing.SetItemFieldsIfExistOnAmazon", newSize, null, null); } dbItem.Size = newSize; } } else { dtoItem.Size = dbItem.Size; //NOTE: item DTO size using in below code (should be actual) } dbItem.IsExistOnAmazon = true; dbItem.LastUpdateFromAmazon = _time.GetUtcTime(); //Set style string if (String.IsNullOrEmpty(dbItem.StyleString)) { dtoItem.StyleString = SkuHelper.RetrieveStyleIdFromSKU(db, dtoItem.SKU, dtoItem.Name); _log.Debug(string.Format("StyleString updated from={0}, to={1}", dbItem.StyleString, dtoItem.StyleString)); dbItem.StyleString = dtoItem.StyleString; } else { dtoItem.StyleString = dbItem.StyleString; } //Additional Fields dbItem.Title = dtoItem.Name; if (!String.IsNullOrEmpty(dtoItem.ImageUrl)) { dbItem.PrimaryImage = dtoItem.ImageUrl; } dbItem.BrandName = dtoItem.BrandName; dbItem.Type = StringHelper.Substring(dtoItem.Type, 50); dbItem.ListPrice = dtoItem.ListPrice; dbItem.Color = StringHelper.Substring(dtoItem.Color, 50); dbItem.Department = dtoItem.Department; dbItem.AdditionalImages = dtoItem.AdditionalImages; if (!String.IsNullOrEmpty(dtoItem.Features)) { dbItem.Features = dtoItem.Features; } if (!String.IsNullOrEmpty(dtoItem.SearchKeywords)) { dbItem.SearchKeywords = dtoItem.SearchKeywords; } if (!String.IsNullOrEmpty(dtoItem.Barcode)) { dbItem.Barcode = dtoItem.Barcode; } //Setting styleId, create style, styleItem if not exist if (!dbItem.StyleItemId.HasValue) { //Kepp exists styleId dtoItem.StyleId = dbItem.StyleId; _log.Info("FindOrCreateStyleItem"); var styleItem = FindOrCreateStyleItem(db, dtoItem); if (styleItem != null) { if (styleItem.StyleItemId > 0) { _styleHistoryService.AddRecord(styleItem.StyleId, StyleHistoryHelper.AttachListingKey, dbItem.StyleItemId, dbItem.Market + ":" + dbItem.MarketplaceId, styleItem.StyleItemId, dbItem.Id.ToString() + ":" + dbItem.ASIN, null); dbItem.StyleId = styleItem.StyleId; dbItem.StyleItemId = styleItem.StyleItemId; } else { if (!dbItem.StyleId.HasValue) { dbItem.StyleId = styleItem.StyleId; } } _log.Debug(String.Format("Set for ASIN={0}, styleId={1}, styleItemId={2}", dtoItem.ASIN, styleItem.StyleId, styleItem.StyleItemId)); } else { _log.Info("Empty StyleItem"); } } //Update style image if (dbItem.StyleId.HasValue && !String.IsNullOrEmpty(dbItem.PrimaryImage)) { _styleManager.UpdateStyleImageIfEmpty(db, dbItem.StyleId.Value, dbItem.PrimaryImage); } if (dtoItem.Weight.HasValue && dbItem.StyleItemId.HasValue) { var dbStyleItem = db.StyleItems.Get(dbItem.StyleItemId.Value); if (!dbStyleItem.Weight.HasValue) { dbStyleItem.Weight = dtoItem.Weight; } } if (!String.IsNullOrEmpty(dtoItem.Barcode) && dbItem.StyleItemId.HasValue) { _styleManager.StoreOrUpdateBarcode(db, dbItem.StyleItemId.Value, dtoItem.Barcode); } }
public IList <TrackingState> UpdateOrderTracking( IUnitOfWork db, CompanyDTO company, IList <OrderToTrackDTO> shippings, ITrackingProvider trackingProvider) { _log.Info("UpdateOrderTracking, shippings=" + shippings.Count); try { var ruleList = _ruleList; var trackingList = shippings .Where(o => !String.IsNullOrEmpty(o.TrackingNumber)) .Select(o => new TrackingNumberToCheckDto() { TrackingNumber = o.TrackingNumber, ToCountry = o.ShippingAddress != null ? o.ShippingAddress.FinalCountry : null, }).ToList(); var stateList = trackingProvider.TrackShipments(trackingList); var today = _time.GetAppNowTime(); _log.Info("UpdateOrderTracking, track count get back=" + stateList.Count); var processedShipmentIds = new List <long>(); var processedMailInfoIds = new List <long>(); foreach (var state in stateList) { //NOTE: Fedex has delivery records not as last record (ex.: 393418292108) var deliveredRecord = state.Records != null?state.Records.FirstOrDefault(r => _deliveryEventList.Contains(r.Message ?? "") || (r.Message ?? "").ToLower().StartsWith("delivered")) : null; var lastRecord = deliveredRecord != null ? deliveredRecord : (state.Records != null ? state.Records.FirstOrDefault() : null); var isBack = lastRecord != null?_addressService.IsMine(lastRecord.AsAddressDto()) : false; var shippingDto = shippings.FirstOrDefault(sh => sh.TrackingNumber == state.TrackingNumber); if (shippingDto != null) { var hasStateChanges = false; if (lastRecord == null) { hasStateChanges = false; shippingDto.TrackingRequestAttempts = shippingDto.TrackingRequestAttempts + 1; shippingDto.LastTrackingRequestDate = _time.GetUtcTime(); _log.Warn("UpdateOrderTracking, empty Records!"); } else { _log.Info("UpdateOrderTracking, o=" + shippingDto.OrderNumber + ", tr=" + shippingDto.TrackingNumber + ", at=" + shippingDto.OrderDate + ", new state=" + lastRecord.Message + " at=" + lastRecord.Date); var newStateEvent = StringHelper.Substring(lastRecord.Message, 100); hasStateChanges = shippingDto.TrackingStateDate != lastRecord.Date || shippingDto.TrackingStateEvent != newStateEvent; shippingDto.TrackingStateSource = (int)lastRecord.Source; shippingDto.TrackingStateDate = lastRecord.Date; shippingDto.TrackingStateEvent = newStateEvent; shippingDto.TrackingLocation = lastRecord.Country + ", " + lastRecord.State + ", " + lastRecord.City + ", " + lastRecord.Zip; if (_deliveryEventList.Contains(lastRecord.Message) || lastRecord.Message.ToLower().StartsWith("delivered") || (lastRecord.Message.ToLower().Contains("shipment picked up") && (state.Records.Count > 5 && lastRecord.Date < today.AddDays(-2)))) //NOTE: temporary solution for "Shipment Picked Up", every shipment may have transit status with that name (not final) { shippingDto.DeliveredStatus = isBack ? (int)DeliveredStatusEnum.DeliveredToSender : (int)DeliveredStatusEnum.Delivered; shippingDto.IsDelivered = true; shippingDto.ActualDeliveryDate = lastRecord.Date; } else { //May happend like with refused tracking number https://tools.usps.com/go/TrackConfirmAction!input.action?tRef=qt&tLc=1&tLabels=9400116901495496872649 //Order #1577164597317 shippingDto.DeliveredStatus = (int)DeliveredStatusEnum.None; shippingDto.IsDelivered = false; shippingDto.ActualDeliveryDate = null; } //For DHL if (lastRecord.Message.ToLower().StartsWith("Returned to shipper")) { shippingDto.DeliveredStatus = (int)DeliveredStatusEnum.DeliveredToSender; shippingDto.IsDelivered = true; shippingDto.ActualDeliveryDate = lastRecord.Date; } shippingDto.LastTrackingRequestDate = _time.GetUtcTime(); if (!hasStateChanges) { shippingDto.TrackingRequestAttempts = shippingDto.TrackingRequestAttempts + 1; } else { shippingDto.TrackingRequestAttempts = 1; } //NOTE: If state no changes for a long time => no requests if (lastRecord.Date < _time.GetAppNowTime().AddDays(-50) || (shippingDto.OrderDate < _time.GetAppNowTime().AddDays(-90) && lastRecord.Message.StartsWith(TrackingHelper.UndefinedPrefix))) { shippingDto.TrackingRequestAttempts = 10000; if (lastRecord.Message.StartsWith(TrackingHelper.UndefinedPrefix)) { _log.Info("Info Unavailable, message=" + lastRecord.Message); shippingDto.DeliveredStatus = (int)DeliveredStatusEnum.InfoUnavailable; } _log.Info("Last attempt (= 10000)"); } } if (shippingDto.ShipmentInfoId.HasValue) { if (processedShipmentIds.Any(sh => sh == shippingDto.ShipmentInfoId.Value)) { _log.Info("Shipment with that Id already processed: " + shippingDto.ShipmentInfoId.Value); } else { processedShipmentIds.Add(shippingDto.ShipmentInfoId.Value); var changeFields = new List <Expression <Func <OrderShippingInfo, object> > >() { p => p.LastTrackingRequestDate, p => p.TrackingRequestAttempts }; if (hasStateChanges) { changeFields.Add(p => p.TrackingStateSource); changeFields.Add(p => p.TrackingStateDate); changeFields.Add(p => p.TrackingStateEvent); changeFields.Add(p => p.TrackingLocation); changeFields.Add(p => p.DeliveredStatus); changeFields.Add(p => p.IsDelivered); changeFields.Add(p => p.ActualDeliveryDate); } db.OrderShippingInfos.TrackItem(new OrderShippingInfo() { Id = shippingDto.ShipmentInfoId.Value, TrackingStateSource = shippingDto.TrackingStateSource, TrackingStateDate = shippingDto.TrackingStateDate, TrackingStateEvent = shippingDto.TrackingStateEvent, TrackingLocation = shippingDto.TrackingLocation, DeliveredStatus = shippingDto.DeliveredStatus, IsDelivered = shippingDto.IsDelivered, ActualDeliveryDate = shippingDto.ActualDeliveryDate, LastTrackingRequestDate = shippingDto.LastTrackingRequestDate, TrackingRequestAttempts = shippingDto.TrackingRequestAttempts ?? 1 }, changeFields); } } if (shippingDto.MailInfoId.HasValue) { if (processedMailInfoIds.Any(sh => sh == shippingDto.MailInfoId.Value)) { _log.Info("Shipment with that Id already processed: " + shippingDto.MailInfoId.Value); } else { processedMailInfoIds.Add(shippingDto.MailInfoId.Value); var changeFields = new List <Expression <Func <MailLabelInfo, object> > >() { p => p.LastTrackingRequestDate, p => p.TrackingRequestAttempts }; if (hasStateChanges) { changeFields.Add(p => p.TrackingStateSource); changeFields.Add(p => p.TrackingStateDate); changeFields.Add(p => p.TrackingStateEvent); changeFields.Add(p => p.TrackingLocation); changeFields.Add(p => p.DeliveredStatus); changeFields.Add(p => p.IsDelivered); changeFields.Add(p => p.ActualDeliveryDate); } db.MailLabelInfos.TrackItem(new MailLabelInfo() { Id = shippingDto.MailInfoId.Value, TrackingStateSource = shippingDto.TrackingStateSource, TrackingStateDate = shippingDto.TrackingStateDate, TrackingStateEvent = shippingDto.TrackingStateEvent, TrackingLocation = shippingDto.TrackingLocation, DeliveredStatus = shippingDto.DeliveredStatus, IsDelivered = shippingDto.IsDelivered, ActualDeliveryDate = shippingDto.ActualDeliveryDate, LastTrackingRequestDate = shippingDto.LastTrackingRequestDate, TrackingRequestAttempts = shippingDto.TrackingRequestAttempts ?? 1 }, changeFields); } } //NOTE: if do checks only when state changed, the rules based on calculate business day were never activated //if (hasStateChanges) if (lastRecord != null) { CheckRules(db, shippingDto, lastRecord.Message, lastRecord.Date, state.Records, ruleList); } } } db.Commit(); return(stateList); } catch (Exception ex) { _log.Error("UpdateOrderTracking", ex); } return(null); }
public void ReadEmails(string folder, DateTime?fromDate, IList <string> acceptingToAddresses, IList <string> acceptingFromAddresses, CancellationToken?cancel) { _emailProcessResultList = new List <EmailReadingResult>(); using (var imap = new ImapClient(_settings.ImapHost, _settings.ImapPort, _settings.ImapUsername, _settings.ImapPassword, AuthMethod.Login, ssl: true)) { //var uids = new List<uint>(ImapClient.Search(SearchCondition.SentSince(sentSince).Or(SearchCondition.GreaterThan(lastUid)), mailbox)); //var uids = new List<uint>(ImapClient.Search(SearchCondition.From("*****@*****.**"), _mailbox)); //var uids = new List<uint> {lastUid};// 14559 }; //var uids = new List<uint>(ImapClient.Search(SearchCondition.SentSince(new DateTime(2013, 12, 3)).Or(SearchCondition.GreaterThan(105748)), mailbox));//.SentSince(sentSince.AddHours(-12)), mailbox)); var sentSince = fromDate ?? _time.GetUtcTime().AddDays(-2); using (var db = _dbFactory.GetRWDb()) { DateTime?maxEmailDate = db.Emails.GetAll().Max(e => e.ReceiveDate); if (maxEmailDate.HasValue) { sentSince = maxEmailDate.Value.AddHours(-5); } } uint lastUid = 0; //_log.Info(String.Join("; ", imap.ListMailboxes())); //var uids = new List<uint>(imap.Search(SearchCondition.SentSince(sentSince).Or(SearchCondition.GreaterThan(lastUid)), "INBOX")); var uids = new List <uint>(); if (_settings.IsDebug) { uids = new List <uint>() { 30456 }; // imap.Search(SearchCondition.Subject("kimlimu_cecku3g5 sent a message about Peppa Pig Little Girls"), folder).ToList();} } else { SearchCondition toCriteria = null; if (acceptingToAddresses != null && acceptingToAddresses.Any()) { foreach (var to in acceptingToAddresses) { toCriteria = toCriteria == null?SearchCondition.To(to) : toCriteria.Or(SearchCondition.To(to)); } } SearchCondition fromCriteria = null; if (acceptingFromAddresses != null && acceptingFromAddresses.Any()) { foreach (var from in acceptingFromAddresses) { fromCriteria = fromCriteria == null?SearchCondition.From(from) : fromCriteria.Or(SearchCondition.From(from)); } } var searchCriteria = SearchCondition.SentSince(sentSince); if (toCriteria != null) { searchCriteria = searchCriteria.And(toCriteria); } if (fromCriteria != null) { searchCriteria = searchCriteria.And(fromCriteria); } uids = new List <uint>(imap.Search(searchCriteria, folder)); } foreach (var uid in uids) { if (cancel.HasValue && cancel.Value.IsCancellationRequested) { _log.Info("Cancellation Requested!"); cancel.Value.ThrowIfCancellationRequested(); } _log.Info("Begin check uid: " + uid); var emailProcessingThread = new Thread(() => GetEmail(_dbFactory, imap, _time.GetUtcTime(), uid, folder)); emailProcessingThread.Priority = ThreadPriority.Highest; emailProcessingThread.Start(); if (_settings.IsDebug) { emailProcessingThread.Join(); } else { if (!emailProcessingThread.Join(_settings.ProcessMessageThreadTimeout)) { emailProcessingThread.Abort(); throw new Exception("Timeout exceeded while processing email. Uid:" + uid); } } } Console.WriteLine(uids.Count); } }
public CheckResult Check(IUnitOfWork db, DTOMarketOrder order, IList <ListingOrderDTO> items, AddressValidationStatus addressValidationStatus) { //NOTE: Skipping valid addresses if (addressValidationStatus < AddressValidationStatus.Invalid) { return(new CheckResult() { IsSuccess = true }); } var checkUSPSService = new PersonatorAddressCheckService(_log, _htmlScraper, null); var address = order.GetAddressDto(); var addressCheckResult = checkUSPSService.ScrappingCheckAddress(address); var result = new CheckResult() { IsSuccess = !addressCheckResult.IsNotServedByUSPSNote }; _log.Info("AddressNotServedByUSPSChecker, hasNote=" + addressCheckResult.IsNotServedByUSPSNote); if (addressCheckResult.IsNotServedByUSPSNote) { var existNotifier = db.OrderEmailNotifies.IsExist(order.OrderId, OrderEmailNotifyType.OutputAddressNotServedByUSPSEmail); if (!existNotifier) { var emailInfo = new AddressNotServedByUSPSEmailInfo(_emailService.AddressService, null, order.OrderId, (MarketType)order.Market, address, order.BuyerName, order.BuyerEmail, order.EarliestShipDate ?? (order.OrderDate ?? DateTime.Today).AddDays(1)); _emailService.SendEmail(emailInfo, CallSource.Service); _log.Info("Send address not served by USPS email, orderId=" + order.Id); db.OrderEmailNotifies.Add(new OrderEmailNotify() { OrderNumber = order.OrderId, Reason = "Address isn’t served by USPS", Type = (int)OrderEmailNotifyType.OutputAddressNotServedByUSPSEmail, CreateDate = _time.GetUtcTime(), }); } db.OrderComments.Add(new OrderComment() { OrderId = order.Id, Message = "Address isn’t served by USPS. Address verification email sent.", Type = (int)CommentType.OutputEmail, CreateDate = _time.GetAppNowTime(), UpdateDate = _time.GetAppNowTime() }); db.Commit(); } return(result); }
public IList <TrackingState> TrackShipments(IList <TrackingNumberToCheckDto> trackingNumbers) { var index = 0; var stepSize = 10; var results = new List <TrackingState>(); while (index < trackingNumbers.Count) { var requestTrackingList = trackingNumbers.Select(t => t.TrackingNumber).Skip(index).Take(stepSize).ToList(); var trackingResult = _api.GetTrackingField(requestTrackingList); //If one tracking from batch request fail whole request fail if (trackingResult.Status == CallStatus.Success) { results.AddRange(trackingResult.Data); } else { //After batch request fail, make per item request foreach (var trackingNumber in requestTrackingList) { var perOneTrackingResult = _api.GetTrackingField(new List <string>() { trackingNumber }); if (perOneTrackingResult.Status == CallStatus.Fail) { _log.Info(String.Format("Error, tracking number={0}: {1}", trackingNumber, perOneTrackingResult.Message)); results.Add(new TrackingState() { TrackingNumber = trackingNumber, Records = new List <TrackingRecord>() { new TrackingRecord() { Message = TrackingHelper.BuildUndefinedMessage(perOneTrackingResult.Message), Date = _time.GetUtcTime(), } } }); } else { results.AddRange(perOneTrackingResult.Data); } } _log.Info("Error: " + trackingResult.Message); } index += stepSize; } foreach (var info in results) { if (info.Records != null) { info.Records.ForEach(r => r.Source = TrackingStatusSources.USPS); } } return(results); }
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); } } }