public List <MessageString> Validate(IUnitOfWork db, ILogService log, DateTime when) { var messages = new List <MessageString>(); var emailType = this.EmailType; if (ReplyToEmailId.HasValue) { var replyToEmail = db.Emails.Get(ReplyToEmailId.Value); if (replyToEmail.Type == (int)IncomeEmailTypes.CancellationRequest) { log.Info("Add message: Cancellation emails usually processed by system automatically. Are you sure you would like to send the response?"); messages.Add(new MessageString() { Message = "Cancellation emails usually processed by system automatically. Are you sure you would like to send the response?", Status = MessageStatus.Info, }); } } if (!String.IsNullOrEmpty(OrderNumber) && emailType == EmailTypes.LostPackage) { var emailNotify = db.OrderEmailNotifies .GetAll() .OrderByDescending(o => o.CreateDate) .FirstOrDefault(o => o.OrderNumber == OrderNumber && o.Type == (int)OrderEmailNotifyType.OutputLostPackageEmail); if (emailNotify != null) { log.Info("Add message: Lost template was already sent for this order on " + DateHelper.ToDateString(emailNotify.CreateDate) + ", are you sure you want to send it again?"); messages.Add(new MessageString() { Message = "Lost template was already sent for this order on " + DateHelper.ToDateString(emailNotify.CreateDate) + ", are you sure you want to send it again?", Status = MessageStatus.Info, }); } } if (!String.IsNullOrEmpty(OrderNumber) && emailType == EmailTypes.LostPackage) { var order = db.Orders.GetByOrderIdAsDto(OrderNumber); if (order != null) { var labels = db.Labels.GetByOrderIdAsDto(order.Id).ToList(); OrderShippingInfoDTO label = null; if (labels.Any()) { label = labels.OrderByDescending(sh => sh.LabelPurchaseDate).FirstOrDefault(i => i.IsActive); } if (label == null || label.DeliveredStatus != (int)DeliveredStatusEnum.Delivered) { log.Info("Add message: The order isn't marked yet as delivered, are you sure you want to send this message?"); messages.Add(new MessageString() { Message = "The order isn't marked yet as delivered, are you sure you want to send this message?", Status = MessageStatus.Info, }); } } } if (!String.IsNullOrEmpty(OrderNumber) && emailType == EmailTypes.ReturnInstructions) { var order = db.Orders.GetByOrderIdAsDto(OrderNumber); if (order != null && order.OrderDate.HasValue) { var orderShippings = db.OrderShippingInfos .GetByOrderIdAsDto(order.Id) .Where(sh => sh.IsActive) .ToList(); var returnRequestToLate = OrderHelper.AcceptReturnRequest(order.OrderDate.Value, order.EarliestDeliveryDate, orderShippings.Max(sh => sh.ActualDeliveryDate), when, when); if (returnRequestToLate) { log.Info("Add message: The order was placed over 30 days ago, are you sure you want to send this message?"); messages.Add(new MessageString() { Message = "The order was placed over 30 days ago, are you sure you want to send this message?", Status = MessageStatus.Info, }); } } } return(messages); }
public void Process(IUnitOfWork db, EmailReadingResult result) { if (result.Status != EmailMatchingResultStatus.New || !result.HasMatches) { return; } var subject = result.Email.Subject ?? ""; var returnRequest = subject.StartsWith("Return authorization request for order") || subject.StartsWith("Return authorisation request for order") || subject.StartsWith("Return authorisation notification for order") || subject.StartsWith("Return authorization notification for order"); if (returnRequest) { result.WasEmailProcessed = true; //NOTE: skipped comment added to other Rules _log.Info("ReturnRequsetEmailRule, WasEmailProcessed=" + result.WasEmailProcessed); var orderNumber = result.MatchedIdList.FirstOrDefault(); _log.Info("Received Return authorization request, orderNumber=" + orderNumber); if (_existanceCheck) { var existReturn = db.ReturnRequests.GetAll().FirstOrDefault(r => r.OrderNumber == orderNumber); if (existReturn != null) { //Already exist return; } } var order = db.Orders.GetByOrderNumber(orderNumber); var orderItems = db.Listings.GetOrderItems(order.Id); var orderShippings = db.OrderShippingInfos.GetByOrderIdAsDto(order.Id).Where(sh => sh.IsActive).ToList(); //Return codes: https://sellercentral.amazon.com/gp/help/help-page.html/ref=ag_200453320_cont_scsearch?ie=UTF8&itemID=200453320&language=en_CA /*Order ID: # 112-4884600-1049826 * Item: Toy Story Woody Buzz Boys 4 pc Cotton Pajamas Set (6) * Quantity: 1 * Return reason: Too small * Customer comments: I need 5T or 6T sizes. (Optional) * Details: ... (Optional) * Request received: February 27, 2016*/ /* * Order ID: # 114-8683360-8244230 * Item: Shopkins Girls' Little Girls' Luxe Plush 2-Piece Pajama Snuggle Set, Pink, 6 * Quantity: 1 * Return reason: Too small * * Item: Shopkins Girls' Little Girls' 2-Piece Fleece Pajama Set, Pink, 6 * Quantity: 1 * Return reason: Too small */ var messages = result.Email.Message.Split(new string[] { "<br />", "<br>", "<br/>", "/r/n" }, StringSplitOptions.RemoveEmptyEntries); // var regex = new Regex(@"Order ID: # (?<OrderId>.*) // ([\s\S]+)Item: (?<ItemName>.*) // ([\s\S]+)Quantity: (?<Quantity>.*) // ([\s\S]+)Return reason: (?<Reason>.*) // ([\s\S]+)Request received: (?<Date>.*)"); // var match = regex.Match(message); // string receiveDate = match.Groups["Date"].Value; // string orderId = match.Groups["OrderId"].Value; // string itemName = match.Groups["ItemName"].Value; // string quantity = match.Groups["Quantity"].Value; // string reasonText = match.Groups["Reason"].Value; var returns = new List <ReturnRequestDTO>(); ReturnRequestDTO currentReturn = null; foreach (var message in messages) { if (message.StartsWith("Item: ")) { currentReturn = new ReturnRequestDTO(); returns.Add(currentReturn); currentReturn.ItemName = message.Replace("Item: ", ""); } if (currentReturn != null) { if (message.StartsWith("Return reason: ")) { currentReturn.Reason = StringHelper.Substring(message.Replace("Return reason: ", ""), 255); } if (message.StartsWith("Quantity: ")) { currentReturn.Quantity = StringHelper.TryGetInt(message.Replace("Quantity: ", "")); } if (message.StartsWith("Request received:")) { currentReturn.ReceiveDate = DateHelper.FromDateString(message.Replace("Request received: ", "")); } if (message.StartsWith("Customer comments:")) { currentReturn.CustomerComments = StringHelper.Substring(message.Replace("Customer comments: ", ""), 255); } if (message.StartsWith("Details:")) { currentReturn.Details = StringHelper.Substring(message.Replace("Details: ", ""), 255); } } } //var reason = ReasonCode.None; //ListingOrderDTO itemToCheck = null; //var itemsToExchange = new List<StyleItemCache>(); foreach (var ret in returns) { var itemToCheck = orderItems.FirstOrDefault(i => i.Title == ret.ItemName); //If not found check all items if (itemToCheck == null && orderItems.Count == 1) { itemToCheck = orderItems.FirstOrDefault(); } _log.Info("Item to check=" + (itemToCheck != null ? itemToCheck.SKU : "[null}")); if (itemToCheck != null) { ret.StyleId = itemToCheck.StyleId; ret.StyleItemId = itemToCheck.StyleItemId; ret.SKU = itemToCheck.SKU; ret.StyleString = itemToCheck.StyleID; } } foreach (var ret in returns) { var requestDb = new ReturnRequest() { ItemName = StringHelper.Substring(ret.ItemName, 255), OrderNumber = orderNumber, Quantity = ret.Quantity, Reason = ret.Reason, CustomerComments = StringHelper.Substring(ret.CustomerComments, 255), Details = StringHelper.Substring(ret.Details, 255), ReceiveDate = ret.ReceiveDate, CreateDate = _time.GetAppNowTime(), StyleId = ret.StyleId, StyleItemId = ret.StyleItemId, SKU = ret.SKU, }; db.ReturnRequests.Add(requestDb); db.Commit(); } _log.Info("Request saved into DB"); if (!_enableSendEmail) { //Skip logic with composing comment / email message return; } if (ShippingUtils.IsInternational(order.ShippingCountry)) { //Don't offer exchange to international order return; } var comments = new List <string>(); foreach (var request in returns) { var reason = GetReasonCode(request.Reason); var itemsToExchange = GetItemsToExchange(db, request); if (reason == ReasonCode.TooSmall || reason == ReasonCode.TooLarge) { var itemsToExchangeWithQty = itemsToExchange.Where(i => i.RemainingQuantity > 0).ToList(); //TASK: Don’t send those emails to orders which can’t be returned already, because more than 30 days passed like order 105-5461372-1374643. //TASK: orders, which were placed Nov 1-Jan 31, can be returned/exchanged by January 31 var returnRequestToLate = false; if (order.OrderDate.HasValue) { returnRequestToLate = OrderHelper.AcceptReturnRequest(order.OrderDate.Value, order.EstDeliveryDate, orderShippings.Max(sh => sh.ActualDeliveryDate), result.Email.ReceiveDate, _time.GetAppNowTime()); } if (returnRequestToLate) { var message = String.Format("Return request received (reason: {0}, style: {1}). Return request came too late. No email was sent to client by the system.", request.Reason, request.StyleString); comments.Add(message); } else { //TASK: don’t send Too small/big emails to clients who already purchased bigger/smaller size of same pajama, like this client - 105-1300286-6499443. var alreadyPurchasedOrdersByCustomer = db.Orders.GetAll().Where(o => o.OrderStatus == OrderStatusEnumEx.Unshipped && o.BuyerEmail == order.BuyerEmail) .Select(o => o.Id).ToList(); var alreadyPurchasedItems = db.OrderItems.GetWithListingInfo() .Where(oi => alreadyPurchasedOrdersByCustomer.Contains(oi.OrderId.Value)) .ToList(); var alreadyPurchasedAnotherSize = false; if (request.StyleId.HasValue) { alreadyPurchasedAnotherSize = alreadyPurchasedItems.Any(i => i.StyleEntityId == request.StyleId && i.StyleItemId != request.StyleItemId); } if (alreadyPurchasedAnotherSize) { var message = String.Format("Return request received (reason: {0}, style: {1}). Customer already purchased bigger/smaller size of same pajama. No email was sent to client by the system.", request.Reason, request.StyleString); comments.Add(message); } else { if (itemsToExchangeWithQty.Any()) { var sizeList = itemsToExchangeWithQty .OrderBy(i => SizeHelper.GetSizeIndex(i.Size)) .Select(i => i.Size) .ToList(); var sizeString = String.Join(" or ", sizeList); _log.Info("Send email for customer: " + reason + ", sizes=" + sizeString); var commentText = String.Format("Return request received (reason: {0}, style: {1}).", request.Reason, request.StyleString, reason == ReasonCode.TooLarge ? "smaller" : "bigger"); comments.Add(commentText); //TEMP: Disabled email //var commentText = String.Format("Return request received (reason: {0}, style: {1}). System offered client {2} size. Exchange request email sent.", // request.Reason, // request.StyleString, // reason == ReasonCode.TooLarge ? "smaller" : "bigger"); //comments.Add(commentText); //var emailInfoToBuyer = new AcceptReturnRequestEmailInfo(null, // orderNumber, // (MarketType) order.Market, // reason == ReasonCode.TooLarge, // sizeString, // order.BuyerName, // order.BuyerEmail); //_emailService.SendEmail(emailInfoToBuyer, CallSource.Service); } else { var sizeList = itemsToExchange .OrderBy(i => SizeHelper.GetSizeIndex(i.Size)) .Select(i => i.Size) .ToList(); var sizeString = String.Join(", ", sizeList); var message = String.Format("Return request received (reason: {0}). System didn't find any items to offer exchange (style: {1}, size: {2}). No email was sent to client by the system.", request.Reason, request?.StyleString ?? "[null]", sizeString); comments.Add(message); } } } db.Commit(); } } if (comments.Any()) { db.OrderComments.Add(new OrderComment() { OrderId = order.Id, Message = "[System] " + String.Join(", ", comments), Type = (int)CommentType.ReturnExchange, CreateDate = _time.GetAppNowTime(), UpdateDate = _time.GetAppNowTime() }); } } }