/// <summary> /// Charges the specified payment info. /// </summary> /// <param name="financialGateway"></param> /// <param name="paymentInfo">The payment info.</param> /// <param name="errorMessage">The error message.</param> /// <returns></returns> public override FinancialTransaction Charge(FinancialGateway financialGateway, PaymentInfo paymentInfo, out string errorMessage) { var financialTransaction = base.Charge(financialGateway, paymentInfo, out errorMessage); // Handle issues with the "Original transaction ID not found" error more gracefully if (paymentInfo is ReferencePaymentInfo && errorMessage == "[19] Original transaction ID not found") { // First delete the saved account--it is worthless var rockContext = new RockContext(); var savedAccountService = new FinancialPersonSavedAccountService(rockContext); var savedAccount = savedAccountService.Queryable() .Where(s => s.TransactionCode == (( ReferencePaymentInfo )paymentInfo).TransactionCode && s.FinancialGatewayId.HasValue && s.FinancialGatewayId.Value == financialGateway.Id) .FirstOrDefault(); if (savedAccount != null) { savedAccountService.Delete(savedAccount); rockContext.SaveChanges(); errorMessage = "The previously saved payment method is no longer valid. Please select a different method."; } } return(financialTransaction); }
/// <summary> /// Handles the Click event of the btnSavePaymentInfo control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void btnSavePaymentInfo_Click(object sender, EventArgs e) { var accountService = new FinancialPersonSavedAccountService(); var configValues = (Dictionary <string, object>)Session["CachedMergeFields"]; string accountNickname = txtPaymentNick.Text; Person person = FindPerson(); var account = accountService.Queryable().Where(a => a.Name == accountNickname && a.PersonId == person.Id).FirstOrDefault(); if (account == null) { account = new FinancialPersonSavedAccount(); accountService.Add(account, person.Id); } account.Name = accountNickname; // #TODO WITH GATEWAY CALL account.TransactionCode = "Unknown"; account.PersonId = person.Id; account.MaskedAccountNumber = configValues["PaymentLastFour"].ToString(); if (!string.IsNullOrEmpty(txtCreditCard.Text)) { account.PaymentMethod = PaymentMethod.CreditCard; } else if (!string.IsNullOrEmpty(txtAccountNumber.Text)) { account.PaymentMethod = PaymentMethod.ACH; } accountService.Save(account, person.Id); divPaymentNick.Visible = false; }
/// <summary> /// Binds the saved account list. /// </summary> private void BindSavedAccountList() { var rockContext = new RockContext(); var financialPersonSavedAccountService = new FinancialPersonSavedAccountService(rockContext); var savedAccountList = financialPersonSavedAccountService .Queryable() .Where(a => a.PersonAliasId == this.Person.PrimaryAliasId.Value && a.FinancialPaymentDetail != null) .ToList(); rptSavedAccounts.DataSource = savedAccountList; rptSavedAccounts.DataBind(); pnlSavedAccounts.Visible = savedAccountList.Any(); }
/// <summary> /// Binds the saved payments if there are any. /// </summary> protected void BindSavedPayments() { var savedAccountService = new FinancialPersonSavedAccountService(); var person = FindPerson(); var accountsQueryable = savedAccountService.Queryable().Where(a => a.PersonId == person.Id); if (accountsQueryable.Count() > 0) { var ccCurrencyType = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD)); if (accountsQueryable.Where(a => a.FinancialTransaction.CurrencyTypeValueId == ccCurrencyType.Id).Any()) { var savedCreditCard = accountsQueryable.Where(a => a.FinancialTransaction.CurrencyTypeValueId == ccCurrencyType.Id) .ToDictionary(a => "Use " + a.Name + " ending in *************" + a.MaskedAccountNumber, a => a.Id); savedCreditCard.Add("Use a different card", 0); rblSavedCard.DataSource = savedCreditCard; rblSavedCard.DataValueField = "Value"; rblSavedCard.DataTextField = "Key"; rblSavedCard.DataBind(); divSavedCard.Visible = true; divNewCard.Style["display"] = "none"; } var achCurrencyType = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH)); if (accountsQueryable.Where(a => a.FinancialTransaction.CurrencyTypeValueId == achCurrencyType.Id).Any()) { var savedACH = accountsQueryable.Where(a => a.FinancialTransaction.CurrencyTypeValueId == achCurrencyType.Id) .ToDictionary(a => "Use " + a.Name + " account ending in *************" + a.MaskedAccountNumber, a => a.Id); savedACH.Add("Use a different account", 0); rblSavedCheck.DataSource = savedACH; rblSavedCheck.DataValueField = "Value"; rblSavedCheck.DataTextField = "Key"; rblSavedCheck.DataBind(); divSavedCheck.Visible = true; divNewCheck.Style["display"] = "none"; } } else { divSavedCard.Visible = false; divSavedCheck.Visible = false; txtCreditCard.Required = true; mypExpiration.Required = true; txtCVV.Required = true; txtCardName.Required = true; txtBankName.Required = true; txtRoutingNumber.Required = true; txtAccountNumber.Required = true; } }
/// <summary> /// Binds the saved payments if there are any. /// </summary> protected void BindSavedPayments() { var savedAccountService = new FinancialPersonSavedAccountService(); var person = FindPerson(); var accountsQueryable = savedAccountService.Queryable().Where(a => a.PersonId == person.Id); if (accountsQueryable.Count() > 0) { if (accountsQueryable.Where(a => a.PaymentMethod == PaymentMethod.CreditCard).Any()) { var savedCreditCard = accountsQueryable.Where(a => a.PaymentMethod == PaymentMethod.CreditCard) .ToDictionary(a => "Use " + a.Name + " ending in *************" + a.MaskedAccountNumber, a => a.Id); savedCreditCard.Add("Use a different card", 0); rblSavedCard.DataSource = savedCreditCard; rblSavedCard.DataValueField = "Value"; rblSavedCard.DataTextField = "Key"; rblSavedCard.DataBind(); divSavedCard.Visible = true; divNewCard.Style["display"] = "none"; } if (accountsQueryable.Where(a => a.PaymentMethod == PaymentMethod.ACH).Any()) { var savedACH = accountsQueryable.Where(a => a.PaymentMethod == PaymentMethod.ACH) .ToDictionary(a => "Use " + a.Name + " account ending in *************" + a.MaskedAccountNumber, a => a.Id); savedACH.Add("Use a different account", 0); rblSavedCheck.DataSource = savedACH; rblSavedCheck.DataValueField = "Value"; rblSavedCheck.DataTextField = "Key"; rblSavedCheck.DataBind(); divSavedCheck.Visible = true; divNewCheck.Style["display"] = "none"; } } else { divSavedCard.Visible = false; divSavedCheck.Visible = false; txtCreditCard.Required = true; mypExpiration.Required = true; txtCVV.Required = true; txtCardName.Required = true; txtBankName.Required = true; txtRoutingNumber.Required = true; txtAccountNumber.Required = true; } }
/// <summary> /// Handles the Click event of the btnMigrateSavedAccounts control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void btnMigrateSavedAccounts_Click(object sender, EventArgs e) { BinaryFile binaryFile = null; var rockContext = new RockContext(); var binaryFileService = new BinaryFileService(rockContext); var binaryFileId = fuCustomerVaultImportFile.BinaryFileId; if (binaryFileId.HasValue) { binaryFile = binaryFileService.Get(binaryFileId.Value); } Dictionary <string, string> nmiToPiCustomerIdLookup = null; var importData = binaryFile.ContentsToString(); StringReader stringReader = new StringReader(importData); CsvReader csvReader = new CsvReader(stringReader); csvReader.Configuration.HasHeaderRecord = false; nmiToPiCustomerIdLookup = csvReader.GetRecords <CustomerVaultImportRecord>().ToDictionary(k => k.NMICustomerId, v => v.PiCustomerId); var financialGatewayService = new FinancialGatewayService(rockContext); var nmiFinancialGatewayID = ddlNMIGateway.SelectedValue.AsInteger(); var nmiFinancialGateway = financialGatewayService.Get(nmiFinancialGatewayID); var nmiGatewayComponent = nmiFinancialGateway.GetGatewayComponent(); var piFinancialGatewayId = ddlPiGateway.SelectedValue.AsInteger(); var piFinancialGateway = financialGatewayService.Get(piFinancialGatewayId); var piGatewayComponent = piFinancialGateway.GetGatewayComponent() as IHostedGatewayComponent; var financialPersonSavedAccountService = new FinancialPersonSavedAccountService(rockContext); var nmiPersonSavedAccountList = financialPersonSavedAccountService.Queryable().Where(a => a.FinancialGatewayId == nmiFinancialGatewayID).ToList(); var personSavedAccountResultsBuilder = new StringBuilder(); var nmiPersonSavedAccountListCount = nmiPersonSavedAccountList.Count(); foreach (var nmiPersonSavedAccount in nmiPersonSavedAccountList) { var nmiCustomerId = nmiPersonSavedAccount.GatewayPersonIdentifier ?? nmiPersonSavedAccount.ReferenceNumber; var piCustomerId = nmiToPiCustomerIdLookup.GetValueOrNull(nmiCustomerId); nmiPersonSavedAccount.GatewayPersonIdentifier = piCustomerId; nmiPersonSavedAccount.FinancialGatewayId = piFinancialGatewayId; // NOTE: NMI Customer IDs created after the Vault import file was created won't have a piCustomerId personSavedAccountResultsBuilder.AppendFormat( "FinancialPersonSavedAccount.Id: {0} NMI CustomerId: '{1}', NMI GatewayPersonIdentifier: '{2}', NMI ReferenceNumber: '{3}', Pi CustomerId: '{4}'" + Environment.NewLine, nmiPersonSavedAccount.Id, nmiCustomerId, nmiPersonSavedAccount.GatewayPersonIdentifier, nmiPersonSavedAccount.ReferenceNumber, piCustomerId ); } rockContext.SaveChanges(); string resultSummary = string.Format("Migrated {0} Saved Accounts", nmiPersonSavedAccountList.Count()); personSavedAccountResultsBuilder.AppendLine(resultSummary); if (!nmiPersonSavedAccountList.Any()) { nbMigrateSavedAccounts.NotificationBoxType = Rock.Web.UI.Controls.NotificationBoxType.Warning; nbMigrateSavedAccounts.Text = "No NMI Saved Accounts Found"; } else { nbMigrateSavedAccounts.Title = "Success"; nbMigrateSavedAccounts.NotificationBoxType = Rock.Web.UI.Controls.NotificationBoxType.Success; nbMigrateSavedAccounts.Text = resultSummary; } nbMigrateSavedAccounts.Visible = true; nbMigrateSavedAccounts.Details = personSavedAccountResultsBuilder.ToString(); this.SetBlockUserPreference("MigrateSavedAccountsResultSummary", nbMigrateSavedAccounts.Text); this.SetBlockUserPreference("MigrateSavedAccountsResultDetails", personSavedAccountResultsBuilder.ToString()); }
public HttpResponseMessage ConfigureTextToGive(int personId, [FromBody] ConfigureTextToGiveArgs args) { // Validate the person var person = Service.Get(personId); if (person == null) { return(ControllerContext.Request.CreateResponse(HttpStatusCode.NotFound, "The person ID is not valid")); } // Load the person's saved accounts var rockContext = Service.Context as RockContext; var savedAccountService = new FinancialPersonSavedAccountService(rockContext); var personsSavedAccounts = savedAccountService.Queryable() .Include(sa => sa.PersonAlias) .Where(sa => sa.PersonAlias.PersonId == personId) .ToList(); // Loop through each saved account. Set default to false unless the args dictate that it is the default var foundDefaultAccount = false; foreach (var savedAccount in personsSavedAccounts) { if (!foundDefaultAccount && savedAccount.Id == args.FinancialPersonSavedAccountId) { savedAccount.IsDefault = true; foundDefaultAccount = true; } else { savedAccount.IsDefault = false; } } // If the args specified an account to be default but it was not found, then return an error if (args.FinancialPersonSavedAccountId.HasValue && !foundDefaultAccount) { return(ControllerContext.Request.CreateResponse(HttpStatusCode.NotFound, "The saved account ID is not valid")); } // Validate the account if it is being set if (args.ContributionFinancialAccountId.HasValue) { var accountService = new FinancialAccountService(rockContext); var account = accountService.Get(args.ContributionFinancialAccountId.Value); if (account == null) { return(ControllerContext.Request.CreateResponse(HttpStatusCode.NotFound, "The financial account ID is not valid")); } if (!account.IsActive) { return(ControllerContext.Request.CreateResponse(HttpStatusCode.BadRequest, "The financial account is not active")); } if (account.IsPublic.HasValue && !account.IsPublic.Value) { return(ControllerContext.Request.CreateResponse(HttpStatusCode.BadRequest, "The financial account is not public")); } } // Set the person's contribution account ID person.ContributionFinancialAccountId = args.ContributionFinancialAccountId; // Success rockContext.SaveChanges(); return(ControllerContext.Request.CreateResponse(HttpStatusCode.OK)); }
/// <summary> /// Enables processing of HTTP Web requests by a custom <see langword="HttpHandler" /> that implements the <see cref="T:System.Web.IHttpHandler" /> interface. /// </summary> /// <param name="context">An <see cref="T:System.Web.HttpContext" /> object that provides references to the intrinsic server objects (for example, <see langword="Request" />, <see langword="Response" />, <see langword="Session" />, and <see langword="Server" />) used to service HTTP requests.</param> public void ProcessRequest(HttpContext context) { // see https://sandbox.gotnpgateway.com/docs/webhooks/#core-webhook-response-format for example payload HttpRequest request = context.Request; var response = context.Response; response.ContentType = "text/plain"; // Signature https://sandbox.gotnpgateway.com/docs/webhooks/#security // see signature @ https://sandbox.fluidpay.com/merchant/settings/webhooks/search var postedSignature = request.Headers["Signature"]; string postedData = string.Empty; using (var reader = new StreamReader(request.InputStream)) { postedData = reader.ReadToEnd(); } var cardSyncWebhookResponse = postedData.FromJsonOrNull <CardSyncWebhookResponse>(); if (cardSyncWebhookResponse == null) { response.StatusCode = ( int )HttpStatusCode.BadRequest; response.StatusDescription = "Unable to determine response format."; return; } var paymentMethodData = cardSyncWebhookResponse.PaymentMethodData; if (paymentMethodData == null) { response.StatusCode = ( int )HttpStatusCode.BadRequest; response.StatusDescription = "Unable to determine payment method 'data'."; return; } var rockContext = new RockContext(); FinancialPersonSavedAccountService financialPersonSavedAccountService = new FinancialPersonSavedAccountService(rockContext); var financialPersonSavedAccountQuery = financialPersonSavedAccountService.Queryable() .Where(a => a.GatewayPersonIdentifier == paymentMethodData.RecordId || a.FinancialPaymentDetail.GatewayPersonIdentifier == paymentMethodData.RecordId); var savedAccounts = financialPersonSavedAccountQuery.Include(a => a.FinancialPaymentDetail).Include(a => a.FinancialGateway).ToList(); // There probably is only one saved account for the GatewayPersonIdentifier, but just in case, we'll loop thru. foreach (var savedAccount in savedAccounts) { var financialGateway = savedAccount.FinancialGateway; var myWellGateway = savedAccount.FinancialGateway?.GetGatewayComponent() as MyWellGateway; if (myWellGateway == null) { ExceptionLogService.LogException(new MyWellGatewayException($"Unable to determine Gateway for CardSync GatewayPersonIdentifier: {paymentMethodData.RecordId} and FinancialGatewayId: {savedAccount.FinancialGatewayId}")); response.StatusCode = ( int )HttpStatusCode.BadRequest; response.StatusDescription = $"Unable to find matching financial gateway record for recordId: {paymentMethodData.RecordId}"; return; } financialGateway.LoadAttributes(); var validSignature = myWellGateway.VerifySignature(financialGateway, postedSignature, postedData); if (!validSignature) { ExceptionLogService.LogException(new MyWellGatewayException($"Invalid WebHook signature included in header. (PostedData for RecordId: {paymentMethodData.RecordId} and FinancialGatewayId: {savedAccount.FinancialGatewayId})")); response.StatusCode = ( int )HttpStatusCode.Forbidden; response.StatusDescription = "Invalid WebHook signature included in header"; return; } var financialPaymentDetail = savedAccount.FinancialPaymentDetail; if (financialPaymentDetail == null) { // shouldn't happen continue; } if (paymentMethodData.ExpirationDate.IsNotNullOrWhiteSpace() && paymentMethodData.ExpirationDate.Length == 5) { // now that we validated this is a 5 char string (MM/YY), extract MM and YY as integers financialPaymentDetail.ExpirationMonth = paymentMethodData.ExpirationDate.Substring(0, 2).AsIntegerOrNull(); financialPaymentDetail.ExpirationYear = paymentMethodData.ExpirationDate.Substring(3, 2).AsIntegerOrNull(); // ToDo: See if they send us the CreditCardType (visa, mastercard) // ?? financialPaymentDetail.CreditCardTypeValueId } financialPaymentDetail.AccountNumberMasked = paymentMethodData.MaskedNumber; rockContext.SaveChanges(); } // NOTE: If it takes us more than 5 seconds to respond, they'll retry. // Otherwise, if we respond with a 200, they'll assume we processed it. // See https://sandbox.gotnpgateway.com/docs/webhooks/#acknowledge-and-retry for additional details response.StatusCode = ( int )HttpStatusCode.OK; }