/// <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);
        }
        /// <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);
        }
        /// <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>
        /// 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);
                    }
                }
            }
        }