Esempio n. 1
0
        /// <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);
        }
Esempio n. 2
0
        /// <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();
        }
Esempio n. 4
0
        /// <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;
            }
        }
Esempio n. 5
0
        /// <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));
        }
Esempio n. 8
0
        /// <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;
        }