/// <summary>
        /// Adds a redemption reward for the transaction in the context.
        /// </summary>
        internal void AddRedemptionRewards()
        {
            RedeemedDealInfo redeemedDealInfo = (RedeemedDealInfo)Context[Key.RedeemedDealInfo];

            if (Context.Config.EnableRedemptionRewards == true && (ReimbursementTender)redeemedDealInfo.ReimbursementTenderId == ReimbursementTender.MicrosoftEarn)
            {
                IRewardOperations rewardOperations = CommerceOperationsFactory.RewardOperations(Context);
                Context[Key.RewardId] = Context.Config.FirstEarnRewardId;
                Context[Key.FirstEarnRewardAmount]      = Context.Config.FirstEarnRewardAmount;
                Context[Key.FirstEarnRewardExplanation] = Context.Config.FirstEarnRewardExplanation;
                ConcurrentDictionary <string, string> payload = new ConcurrentDictionary <string, string>();
                IScheduler scheduler = PartnerFactory.Scheduler(Context.Config.SchedulerQueueName,
                                                                Context.Config.SchedulerTableName,
                                                                Context.Config);
                if (rewardOperations.AddRedemptionReward() == ResultCode.Success)
                {
                    // Add a job to potentially reward user for their first Earn.
                    payload[Key.RewardPayoutId.ToString()]        = ((Guid)Context[Key.RewardPayoutId]).ToString();
                    payload[Key.PartnerCardId.ToString()]         = (string)Context[Key.PartnerCardId];
                    payload[Key.PartnerRedeemedDealId.ToString()] = redeemedDealInfo.PartnerRedeemedDealId;
                    payload[Key.RewardId.ToString()] = Context.Config.FirstEarnRewardId.ToString();
                    ScheduledJobDetails scheduledJobDetails = new ScheduledJobDetails
                    {
                        JobId          = Guid.NewGuid(),
                        JobType        = ScheduledJobType.ApplyRedemptionReward,
                        JobDescription = redeemedDealInfo.GlobalUserId.ToString(),
                        Orchestrated   = true,
                        Payload        = payload
                    };
                    scheduler.ScheduleJobAsync(scheduledJobDetails).Wait();
                }

                // Add a job to potentially reward the person who referred this user for this user's first Earn.
                Context[Key.RedeemedDealId] = ((RedeemedDeal)Context[Key.RedeemedDeal]).Id;
                Guid globalUserId = ((RedeemedDealInfo)Context[Key.RedeemedDealInfo]).GlobalUserId;
                Context[Key.GlobalUserId] = globalUserId;
                string userId = globalUserId.ToString();
                if (rewardOperations.AddReferredRedemptionReward() == ResultCode.Success)
                {
                    payload[Key.GlobalUserId.ToString()]  = userId;
                    payload[Key.ReferralEvent.ToString()] = ReferralEvent.Signup.ToString();
                    ScheduledJobDetails scheduledJobDetails = new ScheduledJobDetails
                    {
                        JobId          = Guid.NewGuid(),
                        JobType        = ScheduledJobType.ApplyReferralReward,
                        JobDescription = userId,
                        Orchestrated   = true,
                        StartTime      = DateTime.UtcNow,
                        Payload        = payload
                    };
                    scheduler.ScheduleJobAsync(scheduledJobDetails).Wait();
                }
            }
        }
        /// <summary>
        /// Updates analytics with information about the transaction in the context.
        /// </summary>
        private void UpdateAnalytics()
        {
            RedeemedDealInfo redeemedDealInfo = (RedeemedDealInfo)Context[Key.RedeemedDealInfo];
            SharedUserLogic  sharedUserLogic  = new SharedUserLogic(Context, CommerceOperationsFactory.UserOperations(Context));

            Context[Key.GlobalUserId] = redeemedDealInfo.GlobalUserId;
            User         user         = sharedUserLogic.RetrieveUser();
            RedeemedDeal redeemedDeal = (RedeemedDeal)Context[Key.RedeemedDeal];

            Analytics.AddRedemptionEvent(redeemedDealInfo.GlobalUserId, redeemedDeal.AnalyticsEventId, user.AnalyticsEventId,
                                         redeemedDealInfo.ParentDealId, redeemedDealInfo.Currency,
                                         redeemedDeal.AuthorizationAmount, redeemedDealInfo.DiscountAmount,
                                         redeemedDealInfo.GlobalId, (string)Context[Key.PartnerMerchantId],
                                         CommerceWorkerConfig.Instance);
        }
예제 #3
0
        /// <summary>
        /// Checks if this transaction has earned any discount amount in order to send a notification
        /// </summary>
        /// <returns>If we have to send a notification for the transaction or not</returns>
        private bool TransactionMetNotificationThreshold()
        {
            Context.Log.Verbose("Checking if the discount amount for the transaction is good enough for a notification");
            //By default make it true. It's better to send a notification wrongly than not to send one.
            bool transactionMetNotificationThreshold = true;

            const int thresholdAmount = 0; //No point in sending a notification where the customer did not save anything

            RedeemedDealInfo redeemedDealInfo = (RedeemedDealInfo)Context[Key.RedeemedDealInfo];

            if (redeemedDealInfo.DiscountAmount <= thresholdAmount)
            {
                Context.Log.Verbose("Discount amount {0) is too small/has not met the threshold limit of {1} to send notification", redeemedDealInfo.DiscountAmount, thresholdAmount);
                //Do not send a notification if the discount has not met the threshold
                transactionMetNotificationThreshold = false;
            }

            return(transactionMetNotificationThreshold);
        }
        /// <summary>
        /// Adds the Authorization to the data store and logs accordingly.
        /// </summary>
        /// <returns>
        /// The ResultCode corresponding to the result of the operation.
        /// </returns>
        public ResultCode AddAuthorization()
        {
            ResultCode result;

            // Add the redemption event info to the data store.
            Context.Log.Verbose("Attempting to add the authorization to the data store.");
            result = AuthorizationOperations.AddAuthorization();
            Context.Log.Verbose("ResultCode after adding the authorization to the data store: {0}", result);

//TODO: Shouldn't this be in the CardLink layer?
            // If the authorization was successfully created, complete populating redeemed deal into fields.
            if (result == ResultCode.Created)
            {
                RedeemedDealInfo redeeemedDealInfo = (RedeemedDealInfo)Context[Key.RedeemedDealInfo];
                int    redemptionAmt = redeeemedDealInfo.DiscountAmount;
                double actualSavings = (double)redemptionAmt / 100;
                redeeemedDealInfo.DiscountText = String.Format("${0:F2}", actualSavings);
            }

            return(result);
        }
        /// <summary>
        ///     Executes processing of the request.
        /// </summary>
        public ResultCode Execute()
        {
            ResultCode                  result  = ResultCode.None;
            EndPointMessageRequest      request = (EndPointMessageRequest)Context[Key.Request];
            Dictionary <String, String> messageElementCollectionDictionary = new Dictionary <string, string>();

            foreach (MessageElementsCollection c in request.MessageElementsCollection)
            {
                messageElementCollectionDictionary.Add(c.Key, c.Value);
            }

            String requestType = messageElementCollectionDictionary[VisaEPMConstants.EventEventType];

            if (string.Equals(requestType, VisaEPMConstants.OnClearEventTypeValue, StringComparison.OrdinalIgnoreCase))
            {
                Dictionary <String, String> userDefinedFieldsCollectionDictionary = new Dictionary <string, string>();
                foreach (UserDefinedFieldsCollection c in request.UserDefinedFieldsCollection)
                {
                    userDefinedFieldsCollectionDictionary.Add(c.Key, c.Value);
                }

                String cardId     = request.CardId;
                String merchantId = messageElementCollectionDictionary[VisaEPMConstants.TransactionVisaMerchantId];
                String storeId    = messageElementCollectionDictionary[VisaEPMConstants.TransactionVisaStoreId];

                // Marshal the redeem deal request into a RedeemedDeal object.
                RedeemedDeal redeemedDeal = new RedeemedDeal()
                {
                    AnalyticsEventId = Guid.NewGuid()
                };
                Context[Key.RedeemedDeal] = redeemedDeal;

                redeemedDeal.CallbackEvent = RedemptionEvent.Settlement;
                redeemedDeal.PartnerRedeemedDealScopeId = messageElementCollectionDictionary[VisaEPMConstants.TransactionVipTransactionId];
                redeemedDeal.PartnerRedeemedDealId      =
                    messageElementCollectionDictionary[VisaEPMConstants.TransactionTransactionID];
                String time = messageElementCollectionDictionary[VisaEPMConstants.TransactionTimeStampYYMMDD];
                // UTC Time: 2013-12-05T07:25:06
                redeemedDeal.PurchaseDateTime = DateTime.Parse(time);
                redeemedDeal.PurchaseDateTime = DateTime.SpecifyKind(redeemedDeal.PurchaseDateTime, DateTimeKind.Utc);
                String amount = messageElementCollectionDictionary[VisaEPMConstants.TransactionClearingAmount];
                redeemedDeal.AuthorizationAmount = AmexUtilities.ParseAuthAmount(amount);
                redeemedDeal.Currency            = VisaConstants.CurrencyUSD;

                Context[Key.PartnerCardId]           = cardId;
                Context[Key.PartnerClaimedDealId]    = null; // could be the BingOfferDealId
                Context[Key.PartnerMerchantId]       = string.Format("{0};{1}", merchantId, storeId);
                Context[Key.OutletPartnerMerchantId] = null; // storedId;
                Context[Key.CreditStatus]            = CreditStatus.ClearingReceived;

                string merchantCity       = messageElementCollectionDictionary.NullIfNotExist(VisaEPMConstants.MerchantCityString);
                string merchantState      = messageElementCollectionDictionary.NullIfNotExist(VisaEPMConstants.MerchantStateString);
                var    merchantPostalCode = messageElementCollectionDictionary.NullIfNotExist(VisaEPMConstants.MerchantPostalCodeString);

                KeyTransactionData keyTransactionData = new KeyTransactionData
                {
                    MerchantCity       = merchantCity,
                    MerchantState      = merchantState,
                    MerchantPostalCode = merchantPostalCode
                };

                Context[Key.PartnerData] = keyTransactionData.XmlSerialize();

                LogRedeedmedDealRequestParameters(redeemedDeal);

                result = AddRedeemedDeal();
                Context[Key.ResultCode] = result;

                // If the deal was successfully redeemed, apply any applicable rewards.
                if (result == ResultCode.Created)
                {
                    RedeemedDealInfo redeemedDealInfo = (RedeemedDealInfo)Context[Key.RedeemedDealInfo];
                    if (redeemedDealInfo != null)
                    {
                        // Update analytics.
                        SharedUserLogic sharedUserLogic = new SharedUserLogic(Context,
                                                                              CommerceOperationsFactory.UserOperations(
                                                                                  Context));
                        Context[Key.GlobalUserId] = redeemedDealInfo.GlobalUserId;
                        User user = sharedUserLogic.RetrieveUser();
                        if (user != null)
                        {
                            Analytics.AddRedemptionEvent(redeemedDealInfo.GlobalUserId, redeemedDeal.AnalyticsEventId,
                                                         user.AnalyticsEventId,
                                                         redeemedDealInfo.ParentDealId, redeemedDealInfo.Currency,
                                                         redeemedDeal.AuthorizationAmount,
                                                         redeemedDealInfo.DiscountAmount,
                                                         redeemedDealInfo.GlobalId, (string)Context[Key.PartnerMerchantId]);
                        }

                        // Add rewards for any active rewards program.
                        AddRedemptionRewards();
                    }
                }
            }
            return(result);
        }
예제 #6
0
        /// <summary>
        /// Send email and sms
        /// </summary>
        /// <param name="userId">
        /// User Id to send notification to
        /// </param>
        /// <param name="environment">
        /// Environment for which notification needs to be sent
        /// </param>
        internal void Send(Guid userId, string environment)
        {
            try
            {
                Users.Dal.DataModel.User user = RetrieveUser(userId);

                //By default, enable both email and phone notification
                TransactionNotificationPreference transactionNotificationPreference =
                    TransactionNotificationPreference.Email | TransactionNotificationPreference.Phone;

                if (user.Info != null && user.Info.Preferences != null)
                {
                    transactionNotificationPreference = user.Info.Preferences.TransactionNotificationMedium;
                }


                if (transactionNotificationPreference == TransactionNotificationPreference.None)
                {
                    Context.Log.Verbose("User has turned off both SMS & Email auth notification");
                    return;
                }

                INotificationContentCreator creator          = NotificationContentCreatorFactory.NotificationContentCreator(Context);
                RedeemedDealInfo            redeemedDealInfo = (RedeemedDealInfo)Context[Key.RedeemedDealInfo];
                Context.Log.Verbose("Credit Amount : {0}", redeemedDealInfo.DiscountText);
                Context.Log.Verbose("DiscountSummary : {0}", redeemedDealInfo.DiscountSummary);
                Context.Log.Verbose("LastFourDigits : {0}", redeemedDealInfo.LastFourDigits);
                Context.Log.Verbose("MerchantName : {0}", redeemedDealInfo.MerchantName);
                Context.Log.Verbose("UserName : {0}", SalutationName);
                Context.Log.Verbose("ReimbursementTender : {0}", redeemedDealInfo.ReimbursementTenderId);

                AuthEmailNotificationData authEmailNotificationData = new AuthEmailNotificationData()
                {
                    CreditAmount      = redeemedDealInfo.DiscountText,
                    DiscountSummary   = redeemedDealInfo.DiscountSummary,
                    LastFourDigits    = redeemedDealInfo.LastFourDigits,
                    MerchantName      = redeemedDealInfo.MerchantName,
                    UserName          = SalutationName,
                    UserId            = userId.ToString(),
                    DealId            = redeemedDealInfo.ParentDealId.ToString(),
                    DiscountId        = redeemedDealInfo.GlobalId.ToString(),
                    TransactionDate   = redeemedDealInfo.TransactionDate.ToLongDateString(),
                    TransactionId     = redeemedDealInfo.TransactionId,
                    PartnerId         = redeemedDealInfo.PartnerId.ToString(CultureInfo.InvariantCulture),
                    PartnerMerchantId = redeemedDealInfo.PartnerMerchantId,
                    Percent           = (float)Math.Round(redeemedDealInfo.Percent, 2)
                };

                NotificationContent content;
                if ((transactionNotificationPreference & TransactionNotificationPreference.Email) == TransactionNotificationPreference.Email)
                {
                    EnvironmentType environmentType;
                    if (Enum.TryParse(environment, true, out environmentType))
                    {
                        authEmailNotificationData.PopulateAuthStatusAndEmailLink(user, UsersDal, environmentType);
                    }


                    bool isEarn = true;
                    if (redeemedDealInfo.ReimbursementTenderId == (int)ReimbursementTender.MicrosoftEarn)
                    {
                        content =
                            creator.CreateAuthEmailContentAsync(authEmailNotificationData, authEmailSubjectEarn,
                                                                authEmailTemplatePathEarn).Result;
                    }
                    else if (redeemedDealInfo.ReimbursementTenderId == (int)ReimbursementTender.MicrosoftBurn)
                    {
                        content =
                            creator.CreateAuthEmailContentAsync(authEmailNotificationData, authEmailSubjectBurn,
                                                                authEmailTemplatePathBurn).Result;
                    }
                    else
                    {
                        isEarn  = false;
                        content =
                            creator.CreateAuthEmailContentAsync(authEmailNotificationData, authEmailSubjectClo).Result;
                    }

                    Context.Log.Verbose("About to send Email Auth notification");
                    SendEmailNotification(user.Email, content, isEarn);
                    Context.Log.Verbose("Email notification sent");
                }
                else
                {
                    Context.Log.Verbose("User has turned off Email Auth notification");
                }

                if ((transactionNotificationPreference & TransactionNotificationPreference.Phone) ==
                    TransactionNotificationPreference.Phone)
                {
                    AuthSmsNotificationData authSmsNotificationData = new AuthSmsNotificationData()
                    {
                        DiscountSummary = redeemedDealInfo.DiscountSummary,
                        MerchantName    = redeemedDealInfo.MerchantName,
                        Percent         = (float)Math.Round(redeemedDealInfo.Percent, 2),
                        CreditAmount    = redeemedDealInfo.DiscountText
                    };

                    if (redeemedDealInfo.ReimbursementTenderId == (int)ReimbursementTender.MicrosoftEarn)
                    {
                        content =
                            creator.CreateAuthSmsContentAsync(authSmsNotificationData, authSmsTemplatePathEarn).Result;
                    }
                    else if (redeemedDealInfo.ReimbursementTenderId == (int)ReimbursementTender.MicrosoftBurn)
                    {
                        content =
                            creator.CreateAuthSmsContentAsync(authSmsNotificationData, authSmsTemplatePathBurn).Result;
                    }
                    else
                    {
                        content = creator.CreateAuthSmsContentAsync(authSmsNotificationData).Result;
                    }

                    Context.Log.Verbose("About to send SMS Auth notification");
                    SendSmsNotification(userId, content.TextBody);
                    Context.Log.Verbose("SMS Notification sent");
                }
                else
                {
                    Context.Log.Verbose("User has turned off SMS Auth notification");
                }
            }
            catch (Exception exception)
            {
                // catch all exception, log them as warning.
                // but continue sending other notifications if needed
                Context.Log.Warning("Sending notification resulted in error. User Id : {0}", exception, userId);
            }
        }
        /// <summary>
        /// Executes processing of the deal redemption request.
        /// </summary>
        public ResultCode Execute()
        {
            ResultCode result;

            // Marshal the First Data redeem deal request into a RedeemedDeal object.
            RedeemedDeal redeemedDeal = new RedeemedDeal()
            {
                AnalyticsEventId = Guid.NewGuid()
            };

            Context[Key.RedeemedDeal] = redeemedDeal;
            FirstData firstData = new FirstData(Context);

            firstData.MarshalRedeemDeal();

            // If the purchase date and time was valid, Add the RedeemedDeal to the data store.
            if (redeemedDeal.PurchaseDateTime != DateTime.MinValue)
            {
                string disallowedReason = Context[Key.DisallowedReason] as string;
                if (String.IsNullOrWhiteSpace(disallowedReason) == true)
                {
                    result = AddRedeemedDeal();
                }
                else
                {
                    Context.Log.Warning("Transaction is disallowed because tender type was: {0}.", disallowedReason);
                    Context[Key.RedeemedDealInfo] = new RedeemedDealInfo
                    {
                        PartnerDealId        = (string)Context[Key.PartnerDealId],
                        PartnerClaimedDealId = (string)Context[Key.PartnerClaimedDealId]
                    };
                    result = ResultCode.TransactionDisallowed;
                }
            }
            else
            {
                result = ResultCode.InvalidPurchaseDateTime;
            }

            // Build the response to send back to First Data based on the result of adding the RedeemedDeal.
            Context[Key.ResultCode] = result;
            firstData.BuildRedeemedDealResponse();

            // If the deal was successfully redeemed, send user notification and update analytics.
            if (result == ResultCode.Created)
            {
                RedeemedDealInfo redeemedDealInfo = (RedeemedDealInfo)Context[Key.RedeemedDealInfo];

                // Send notification.
                NotifyAuthorization notifyAuthorization = new NotifyAuthorization(Context);
                Task.Run(new Action(notifyAuthorization.SendNotification));

                // Update analytics.
                SharedUserLogic sharedUserLogic = new SharedUserLogic(Context,
                                                                      CommerceOperationsFactory.UserOperations(Context));
                Context[Key.GlobalUserId] = redeemedDealInfo.GlobalUserId;
                User user = sharedUserLogic.RetrieveUser();
                Analytics.AddRedemptionEvent(redeemedDealInfo.GlobalUserId, redeemedDeal.AnalyticsEventId, user.AnalyticsEventId,
                                             redeemedDealInfo.ParentDealId, redeemedDealInfo.Currency,
                                             redeemedDeal.AuthorizationAmount, redeemedDealInfo.DiscountAmount,
                                             redeemedDealInfo.GlobalId, (string)Context[Key.PartnerMerchantId]);
            }

            return(result);
        }
        /// <summary>
        /// Adds the authorization in the context to the data store.
        /// </summary>
        /// <returns>
        /// The ResultCode corresponding to the result of the operation.
        /// </returns>
        public ResultCode AddAuthorization()
        {
            int?offset = GetPartnerMerchantTimeZoneOffset();

            ResultCode    result;
            Authorization authorization = (Authorization)Context[Key.Authorization];

            // TEMPORARY: Determine if the allow list forces transaction rejection.
            if (PhysStoreFilter() == true)
            {
//Context.Log.Critical("AuthorizationId: {0}\r\nPartnerId: {1}\r\nPartnerDealId: {2}\r\nPartnerCardId: {3}\r\nPartnerMerchantId: {4}\r\nPurchaseDateTime: {5}\r\nAuthorizationAmount: {6}\r\nTransactionScopeId: {7}" +
//                     "TransactionId: {8}\r\nCurrency: {9}\r\nPartnerData: {10}\r\noffset: {11}", null,
//                     authorization.Id, (int)Context[Key.Partner], Context[Key.PartnerDealId], Context[Key.PartnerCardId], Context[Key.PartnerMerchantId], authorization.PurchaseDateTime, authorization.AuthorizationAmount, authorization.TransactionScopeId,
//                     authorization.TransactionId, authorization.Currency, Context[Key.PartnerData], offset);


                result = SqlProcedure("AddAuthorization",
                                      new Dictionary <string, object>
                {
                    { "@authorizationId", authorization.Id },
                    { "@partnerId", (int)Context[Key.Partner] },
                    { "@recommendedPartnerDealId", Context[Key.PartnerDealId] },
                    { "@partnerCardId", Context[Key.PartnerCardId] },
                    { "@partnerMerchantId", Context[Key.PartnerMerchantId] },
                    { "@purchaseDateTime", authorization.PurchaseDateTime },
                    { "@authAmount", authorization.AuthorizationAmount },
                    { "@transactionScopeId", authorization.TransactionScopeId },
                    { "@transactionId", authorization.TransactionId },
                    { "@currency", authorization.Currency },
                    { "@partnerData", Context[Key.PartnerData] },
                    { "@timeZoneOffset", offset }
                },

                                      (sqlDataReader) =>
                {
                    if (sqlDataReader.Read() == true)
                    {
                        RedeemedDealInfo redeemedDealInfo = new RedeemedDealInfo
                        {
                            GlobalId              = sqlDataReader.GetGuid(sqlDataReader.GetOrdinal("GlobalDealId")),
                            Currency              = sqlDataReader.GetString(sqlDataReader.GetOrdinal("Currency")),
                            Amount                = sqlDataReader.GetInt32(sqlDataReader.GetOrdinal("Amount")),
                            Percent               = sqlDataReader.GetDecimal(sqlDataReader.GetOrdinal("Percent")),
                            MinimumPurchase       = sqlDataReader.GetInt32(sqlDataReader.GetOrdinal("MinimumPurchase")),
                            GlobalUserId          = sqlDataReader.GetGuid(sqlDataReader.GetOrdinal("GlobalUserId")),
                            PartnerDealId         = sqlDataReader.GetString(sqlDataReader.GetOrdinal("PartnerDealId")),
                            PartnerClaimedDealId  = sqlDataReader.IsDBNull(sqlDataReader.GetOrdinal("PartnerClaimedDealId")) ? null : sqlDataReader.GetString(sqlDataReader.GetOrdinal("PartnerClaimedDealId")),
                            PartnerRedeemedDealId = authorization.PartnerRedeemedDealId,
                            DiscountSummary       = sqlDataReader.GetString(sqlDataReader.GetOrdinal("DiscountSummary")),
                            LastFourDigits        = sqlDataReader.GetString(sqlDataReader.GetOrdinal("LastFourDigits")),
                            DiscountAmount        = sqlDataReader.GetInt32(sqlDataReader.GetOrdinal("DiscountAmount")),
                            PartnerMerchantId     = (string)Context[Key.PartnerMerchantId],
                            TransactionId         = authorization.TransactionId,
                            TransactionDate       = authorization.PurchaseDateTime,
                            PartnerId             = (int)Context[Key.Partner],
                            ReimbursementTenderId = sqlDataReader.GetInt32(sqlDataReader.GetOrdinal("ReimbursementTenderId"))
                        };

                        // Function based partner claimed deal id is not stored (comes as null or empty string). Generate it.
                        if (string.IsNullOrEmpty(redeemedDealInfo.PartnerClaimedDealId))
                        {
                            int cardId = sqlDataReader.GetInt32(sqlDataReader.GetOrdinal("CardId"));
                            int dealId = sqlDataReader.GetInt32(sqlDataReader.GetOrdinal("DealId"));
                            redeemedDealInfo.PartnerClaimedDealId = General.TwoIntegersToHexString(cardId, dealId);
                        }

                        // Add nullable items.
                        int merchantNameColumnId = sqlDataReader.GetOrdinal("MerchantName");
                        if (sqlDataReader.IsDBNull(merchantNameColumnId) == false)
                        {
                            redeemedDealInfo.MerchantName = sqlDataReader.GetString(merchantNameColumnId);
                        }

                        int parentDealIdColumnId = sqlDataReader.GetOrdinal("ParentDealId");
                        if (sqlDataReader.IsDBNull(parentDealIdColumnId) == false)
                        {
                            redeemedDealInfo.ParentDealId = sqlDataReader.GetGuid(parentDealIdColumnId);
                        }

                        // Populate the context.
                        Context[Key.RedeemedDealInfo] = redeemedDealInfo;
                    }
                });
            }
            // TEMPORARY: Log the disallowed transaction.
            else
            {
                result = ResultCode.NoApplicableDealFound;
                Context.Log.Warning("Transaction disallowed. Card / Allow list mismatch.");
            }

            if (result == ResultCode.Success)
            {
                result = ResultCode.Created;
            }

            return(result);
        }
        /// <summary>
        /// Process the transaction log file
        /// </summary>
        /// <returns>
        /// Async Task Wrapper
        /// </returns>
        public async Task Process()
        {
            TransactionLogParser transactionLogParser = new TransactionLogParser(Context.Log);
            TransactionLogFile   transactionLogFile   = transactionLogParser.Parse(TransactionLogFileName, TransactionLogFileStream);

            if (transactionLogFile != null)
            {
                foreach (TransactionLogDetail detail in transactionLogFile.TransactionLogRecords)
                {
                    // block the reversed transactions
                    if (TransactionIdSet.Contains(detail.TransactionId) || detail.TransactionAmount <= 0)
                    {
                        continue;
                    }

                    TransactionIdSet.Add(detail.TransactionId);

                    // 1. process the detail record here -> Insert as redeemed deal
                    RedeemedDeal redeemedDeal = new RedeemedDeal()
                    {
                        AnalyticsEventId = Guid.NewGuid()
                    };
                    Context[Key.RedeemedDeal] = redeemedDeal;
                    MarshalRedeemDeal(detail);
                    ResultCode result = RedeemedDealOperations.AddRedeemedDeal();

                    //2. If the record was processed successfully, attempt to add a redemption reward if applicable and analytics
                    if (result == ResultCode.Created)
                    {
                        RedeemedDealInfo redemptionInfo = (RedeemedDealInfo)Context[Key.RedeemedDealInfo];
                        // First add a redemption reward to the redeeming user if they're enabled.
                        if (EnableRedemptionRewards)
                        {
                            if (WorkerActions.RewardRedemption(RewardOperations, Context) == ResultCode.Success)
                            {
                                // Add job to process the reward payout.
                                ConcurrentDictionary <string, string> payload = new ConcurrentDictionary <string, string>();
                                payload[Key.RewardPayoutId.ToString()]        = ((Guid)Context[Key.RewardPayoutId]).ToString();
                                payload[Key.PartnerCardId.ToString()]         = (string)Context[Key.PartnerCardId];
                                payload[Key.PartnerRedeemedDealId.ToString()] = redemptionInfo.PartnerRedeemedDealId;

                                IScheduler scheduler = PartnerFactory.Scheduler(CommerceWorkerConfig.Instance.SchedulerQueueName,
                                                                                CommerceWorkerConfig.Instance.SchedulerTableName,
                                                                                CommerceWorkerConfig.Instance);
                                ScheduledJobDetails scheduledJobDetails = new ScheduledJobDetails
                                {
                                    JobId          = Guid.NewGuid(),
                                    JobType        = ScheduledJobType.ApplyRedemptionReward,
                                    JobDescription = redemptionInfo.GlobalUserId.ToString(),
                                    Orchestrated   = true,
                                    Payload        = payload
                                };

                                await scheduler.ScheduleJobAsync(scheduledJobDetails).ConfigureAwait(false);
                            }
                        }

                        // Then add a referred redemption reward to the user who referred the redeeming user.
                        Context[Key.RedeemedDealId] = ((RedeemedDeal)Context[Key.RedeemedDeal]).Id;
                        Context[Key.GlobalUserId]   = ((RedeemedDealInfo)Context[Key.RedeemedDealInfo]).GlobalUserId;
                        WorkerActions.RewardReferredRedemption(RewardOperations, Context);

                        // Update analytics.
                        // For FDC this happens at AUTH time
                        // Butfor Amex flow, we put analytics at the time of Transaction File Processing
                        SharedUserLogic sharedUserLogic = new SharedUserLogic(Context,
                                                                              CommerceOperationsFactory.UserOperations(Context));
                        Context[Key.GlobalUserId] = redemptionInfo.GlobalUserId;
                        User user = sharedUserLogic.RetrieveUser();
                        Analytics.AddRedemptionEvent(redemptionInfo.GlobalUserId, redeemedDeal.AnalyticsEventId, user.AnalyticsEventId,
                                                     redemptionInfo.ParentDealId, redemptionInfo.Currency,
                                                     redeemedDeal.AuthorizationAmount, redemptionInfo.DiscountAmount,
                                                     redemptionInfo.GlobalId, (string)Context[Key.PartnerMerchantId],
                                                     CommerceWorkerConfig.Instance);
                    }
                }
            }
        }