/// <summary> /// Marshals information from the MasterCard clearing data record into the RedeemedDeal object in the context. /// </summary> /// <param name="clearingData"> /// The clearing data record to marshal. /// </param> /// <exception cref="ArgumentNullException"> /// Parameter clearingData cannot be null. /// </exception> public void MarshalRedeemDeal(ClearingData clearingData) { if (clearingData == null) { throw new ArgumentNullException("clearingData", "Parameter clearingData cannot be null."); } RedeemedDeal redeemedDeal = (RedeemedDeal)Context[Key.RedeemedDeal]; redeemedDeal.CallbackEvent = RedemptionEvent.Settlement; redeemedDeal.PurchaseDateTime = clearingData.TransactionDate; redeemedDeal.AuthorizationAmount = (int)(clearingData.TransactionAmount * 100); redeemedDeal.Currency = "USD"; redeemedDeal.PartnerRedeemedDealScopeId = clearingData.BankNetRefNumber; KeyClearingData keyClearingData = new KeyClearingData { BankCustomerNumber = clearingData.BankCustomerNumber, BankNetRefNumber = clearingData.BankNetRefNumber, MerchantId = clearingData.MerchantId, IssuerIca = clearingData.IssuerIca }; Context[Key.PartnerData] = keyClearingData.XmlSerialize(); Context[Key.PartnerCardId] = clearingData.BankCustomerNumber; Context[Key.PartnerMerchantId] = clearingData.LocationId; Context[Key.PartnerMerchantIdType] = PartnerMerchantIdType.SettlementOnly; Context[Key.CreditStatus] = CreditStatus.ClearingReceived; Context[Key.PartnerReferenceNumber] = clearingData.TransactionSequenceNumber; }
/// <summary> /// Processes the clearing file. /// </summary> public async virtual Task Process() { // Deserialize clearing file into a Clearing object. ClearingParser clearingParser = new ClearingParser(Context.Log); Clearing clearing = clearingParser.Parse(FileName, Stream); if (clearing != null) { foreach (ClearingData clearingData in clearing.DataRecords) { if (clearingData != null) { // Add a redeemed deal record to the data store for the transaction. RedeemedDeal redeemedDeal = new RedeemedDeal(); ResultCode result = AddRedeemedDealRecord(clearingData, redeemedDeal); // If the redeemed deal record was added successfully, update rewards. if (result == ResultCode.Created) { await AddRedemptionRewards(redeemedDeal.Id).ConfigureAwait(false); } } } } }
/// <summary> /// Adds a RedeemedDeal record to the data store for the specified ClearingData record. /// </summary> /// <param name="clearingData"> /// The ClearingData record for which to add a redeemed deal record. /// </param> /// <param name="redeemedDeal"> /// The RedeemedDeal object to use when committing the redeemed deal record. /// </param> /// <returns> /// The ResultCode corresponding to the result of the operation. /// </returns> private ResultCode AddRedeemedDealRecord(ClearingData clearingData, RedeemedDeal redeemedDeal) { ResultCode result = ResultCode.NoApplicableDealFound; redeemedDeal.AnalyticsEventId = Guid.NewGuid(); Context[Key.RedeemedDeal] = redeemedDeal; new MasterCard(Context).MarshalRedeemDeal(clearingData); Context[Key.Partner] = Partner.MasterCard; result = RedeemedDealOperations.AddRedeemedDeal(); return(result); }
/// <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> /// Marshal Transaction Log File Record into a RedeemedDeal Record /// </summary> /// <param name="detail"> /// Transaction Log File Detail Record /// </param> private void MarshalRedeemDeal(TransactionLogDetail detail) { RedeemedDeal redeemedDeal = (RedeemedDeal)Context[Key.RedeemedDeal]; redeemedDeal.CallbackEvent = RedemptionEvent.Settlement; redeemedDeal.PurchaseDateTime = detail.TransactionDate; redeemedDeal.AuthorizationAmount = (int)(detail.TransactionAmount * 100); redeemedDeal.Currency = "USD"; redeemedDeal.PartnerRedeemedDealScopeId = detail.TransactionId; //redeemedDeal.PartnerRedeemedDealId = detail.TransactionId; Context[Key.PartnerDealId] = detail.OfferId; Context[Key.PartnerCardId] = detail.CardToken; Context[Key.PartnerMerchantId] = detail.MerchantNumber; Context[Key.CreditStatus] = CreditStatus.ClearingReceived; }
/// <summary> /// Taken down the parameters used to call the addReedemedDeal stored procedure /// </summary> /// <param name="redeemedDeal">RedeemedDeal just populated</param> private void LogRedeedmedDealRequestParameters(RedeemedDeal redeemedDeal) { String request = String.Format("ReededmedDealRequest: {0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10}, {11}, {12}, {13}", redeemedDeal.Id, (int)Context[Key.Partner], Context[Key.PartnerDealId], Context[Key.PartnerCardId], Context[Key.PartnerClaimedDealId], Context[Key.PartnerMerchantId], Context[Key.OutletPartnerMerchantId], (int)(redeemedDeal.CallbackEvent), redeemedDeal.PurchaseDateTime.ToString(), redeemedDeal.AuthorizationAmount, redeemedDeal.Currency, redeemedDeal.PartnerRedeemedDealId, redeemedDeal.AnalyticsEventId, Context[Key.CreditStatus]); Context.Log.Verbose(request); }
/// <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); } } } }