/// <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> /// Gets the saved accounts. /// </summary> /// <returns></returns> private List <FinancialPersonSavedAccount> GetSavedAccounts() { if (_savedAccounts == null) { var person = GetPerson(); if (person != null) { var supportedGatewayIds = GetSupportedGatewayIds(); if (supportedGatewayIds != null && supportedGatewayIds.Any()) { var rockContext = GetRockContext(); var service = new FinancialPersonSavedAccountService(rockContext); _savedAccounts = service .GetByPersonId(person.Id) .Include(sa => sa.FinancialPaymentDetail) .AsNoTracking() .Where(sa => sa.FinancialGatewayId.HasValue && supportedGatewayIds.Contains(sa.FinancialGatewayId.Value)) .OrderBy(sa => sa.IsDefault) .ThenByDescending(sa => sa.CreatedDateTime) .ToList(); } } } return(_savedAccounts); }
/// <summary> /// Gets the existing saved account. /// </summary> /// <param name="giveParameters">The give parameters.</param> /// <param name="person">The person.</param> /// <param name="rockContext">The rock context.</param> /// <returns></returns> private FinancialPersonSavedAccount GetExistingSavedAccount(GiveParameters giveParameters, Person person, RockContext rockContext) { if (!giveParameters.SourceAccountId.HasValue) { return(null); } var savedAccount = new FinancialPersonSavedAccountService(rockContext).Get(giveParameters.SourceAccountId.Value); if (savedAccount == null) { GenerateResponse(HttpStatusCode.BadRequest, "The SourceAccountId passed is invalid"); return(null); } if (!savedAccount.PersonAliasId.HasValue) { GenerateResponse(HttpStatusCode.BadRequest, "The SourceAccount doesn't belong to anyone"); return(null); } if (person.Aliases.All(a => a.Id != savedAccount.PersonAliasId.Value)) { GenerateResponse(HttpStatusCode.BadRequest, "The SourceAccount doesn't belong to the passed PersonId"); return(null); } return(savedAccount); }
/// <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 person saved accounts. /// </summary> private void BindPersonSavedAccounts() { var rockContext = new RockContext(); var scheduledTransaction = this.GetFinancialScheduledTransaction(rockContext); var targetPersonId = scheduledTransaction.AuthorizedPersonAlias.PersonId; var personSavedAccountsQuery = new FinancialPersonSavedAccountService(rockContext) .GetByPersonId(targetPersonId) .Where(a => !a.IsSystem) .AsNoTracking(); DefinedValueCache[] allowedCurrencyTypes = { DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD.AsGuid()), DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH.AsGuid()) }; int[] allowedCurrencyTypeIds = allowedCurrencyTypes.Select(a => a.Id).ToArray(); var financialGateway = this.FinancialGateway; if (financialGateway == null) { return; } personSavedAccountsQuery = personSavedAccountsQuery.Where(a => a.FinancialGatewayId == financialGateway.Id && (a.FinancialPaymentDetail.CurrencyTypeValueId != null) && allowedCurrencyTypeIds.Contains(a.FinancialPaymentDetail.CurrencyTypeValueId.Value)); var personSavedAccountList = personSavedAccountsQuery.OrderBy(a => a.Name).AsNoTracking().Select(a => new { a.Id, a.Name, a.GatewayPersonIdentifier, a.FinancialPaymentDetail.AccountNumberMasked, }).ToList(); ddlPersonSavedAccount.Items.Clear(); foreach (var personSavedAccount in personSavedAccountList) { var displayName = string.Format("{0} ({1})", personSavedAccount.Name, personSavedAccount.AccountNumberMasked); ddlPersonSavedAccount.Items.Add(new ListItem(displayName, personSavedAccount.Id.ToString())); } string errorMessage; var financialGateComponent = this.FinancialGatewayComponent; var gatewayPersonIdentifier = (financialGateComponent as GatewayComponent).GetReferenceNumber(scheduledTransaction, out errorMessage); int?selectedSavedAccountId = personSavedAccountList.Where(a => a.GatewayPersonIdentifier == gatewayPersonIdentifier).Select(a => ( int? )a.Id).FirstOrDefault(); ddlPersonSavedAccount.SetValue(selectedSavedAccountId); }
public void RockCleanup_Execute_ShouldUpdatePeopleWithFinancialPersonSavedAccountToAccountProtectionProfileHigh() { var personGuid = Guid.NewGuid(); var personWithFinancialPersonBankAccount = new Person { FirstName = "Test", LastName = personGuid.ToString(), Email = $"{personGuid}@test.com", Guid = personGuid }; using (var rockContext = new RockContext()) { var personService = new PersonService(rockContext); personService.Add(personWithFinancialPersonBankAccount); rockContext.SaveChanges(); personWithFinancialPersonBankAccount = personService.Get(personWithFinancialPersonBankAccount.Id); var financialGateway = new FinancialGatewayService(rockContext).Get("6432D2D2-32FF-443D-B5B3-FB6C8414C3AD".AsGuid()); var creditCardTypeValue = DefinedTypeCache.Get(SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE.AsGuid()).DefinedValues.OrderBy(a => Guid.NewGuid()).First().Id; var currencyTypeValue = DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD.AsGuid()).Id; var definedValueService = new DefinedValueService(rockContext); var financialPersonSavedAccount = new FinancialPersonSavedAccount { Name = "Test Saved Account", PersonAliasId = personWithFinancialPersonBankAccount.PrimaryAliasId.Value, FinancialGateway = financialGateway, FinancialPaymentDetail = new FinancialPaymentDetail { AccountNumberMasked = "1111", CreditCardTypeValue = definedValueService.Get(creditCardTypeValue), CurrencyTypeValue = definedValueService.Get(currencyTypeValue), NameOnCard = "Test User" } }; var service = new FinancialPersonSavedAccountService(rockContext); service.Add(financialPersonSavedAccount); rockContext.SaveChanges(); } ExecuteRockCleanupJob(); using (var rockContext = new RockContext()) { var actualPerson = new PersonService(rockContext).Get(personGuid); Assert.That.AreEqual(AccountProtectionProfile.High, actualPerson.AccountProtectionProfile); } }
/// <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 account list. /// </summary> private void BindSavedAccountList() { var rockContext = new RockContext(); var financialPersonSavedAccountService = new FinancialPersonSavedAccountService(rockContext); var savedAccountList = financialPersonSavedAccountService .GetByPersonId(this.Person.Id) .Where(a => a.FinancialPaymentDetail != null) .ToList(); rptSavedAccounts.DataSource = savedAccountList; rptSavedAccounts.DataBind(); pnlSavedAccounts.Visible = savedAccountList.Any(); }
/// <summary> /// Removes any expired saved accounts (if <see cref="AttributeKey.RemovedExpiredSavedAccountDays"/> is set) /// </summary> /// <param name="context">The context.</param> private FinancialPersonSavedAccountService.RemoveExpiredSavedAccountsResult RemoveExpiredSavedAccounts(IJobExecutionContext context) { var dataMap = context.JobDetail.JobDataMap; int?removedExpiredSavedAccountDays = dataMap.GetString(AttributeKey.RemovedExpiredSavedAccountDays).AsIntegerOrNull(); if (!removedExpiredSavedAccountDays.HasValue) { return(new FinancialPersonSavedAccountService.RemoveExpiredSavedAccountsResult()); } var service = new FinancialPersonSavedAccountService(new RockContext()); return(service.RemoveExpiredSavedAccounts(removedExpiredSavedAccountDays.Value)); }
/// <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> /// Gets the saved accounts. /// </summary> /// <returns></returns> private List <FinancialPersonSavedAccount> GetSavedAccounts() { var financialGateway = this.FinancialGateway; if (financialGateway == null) { return(new List <FinancialPersonSavedAccount>()); } var rockContext = new RockContext(); var scheduledTransaction = this.GetFinancialScheduledTransaction(rockContext); var targetPersonId = scheduledTransaction.AuthorizedPersonAlias.PersonId; if (targetPersonId != CurrentPersonId) { if (GetAttributeValue(AttributeKey.ImpersonatorCanSeeSavedAccounts).AsBoolean() == false) { return(new List <FinancialPersonSavedAccount>()); } } var personSavedAccountsQuery = new FinancialPersonSavedAccountService(rockContext) .GetByPersonId(targetPersonId) .Where(a => !a.IsSystem) .AsNoTracking(); DefinedValueCache[] allowedCurrencyTypes = { DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD.AsGuid()), DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH.AsGuid()) }; int[] allowedCurrencyTypeIds = allowedCurrencyTypes.Select(a => a.Id).ToArray(); personSavedAccountsQuery = personSavedAccountsQuery.Where(a => a.FinancialGatewayId == financialGateway.Id && (a.FinancialPaymentDetail.CurrencyTypeValueId != null) && allowedCurrencyTypeIds.Contains(a.FinancialPaymentDetail.CurrencyTypeValueId.Value)); var personSavedAccountList = personSavedAccountsQuery.OrderBy(a => a.Name).Include(a => a.FinancialPaymentDetail).AsNoTracking().ToList(); return(personSavedAccountList); }
/// <summary> /// Create a new payment processor to handle a single automated payment. /// </summary> /// <param name="currentPersonAliasId">The current user's person alias ID. Possibly the REST user.</param> /// <param name="automatedPaymentArgs">The arguments describing how to charge the payment and store the resulting transaction</param> /// <param name="rockContext">The context to use for loading and saving entities</param> /// <param name="enableDuplicateChecking">If false, the payment will be charged even if there is a similar transaction for the same person /// within a short time period.</param> /// <param name="enableScheduleAdherenceProtection">If false and a schedule is indicated in the args, the payment will be charged even if /// the schedule has already been processed according to it's frequency.</param> public AutomatedPaymentProcessor(int?currentPersonAliasId, AutomatedPaymentArgs automatedPaymentArgs, RockContext rockContext, bool enableDuplicateChecking = true, bool enableScheduleAdherenceProtection = true) { _rockContext = rockContext; _automatedPaymentArgs = automatedPaymentArgs; _currentPersonAliasId = currentPersonAliasId; _enableDuplicateChecking = enableDuplicateChecking; _enableScheduleAdherenceProtection = enableScheduleAdherenceProtection; _futureTransaction = null; _personAliasService = new PersonAliasService(_rockContext); _financialGatewayService = new FinancialGatewayService(_rockContext); _financialAccountService = new FinancialAccountService(_rockContext); _financialPersonSavedAccountService = new FinancialPersonSavedAccountService(_rockContext); _financialBatchService = new FinancialBatchService(_rockContext); _financialTransactionService = new FinancialTransactionService(_rockContext); _financialScheduledTransactionService = new FinancialScheduledTransactionService(_rockContext); _payment = null; }
private List <PersonSavedAccountInfo> GetSavedAccounts() { var financialGateway = this.FinancialGateway; if (financialGateway == null) { return(new List <PersonSavedAccountInfo>()); } var rockContext = new RockContext(); var scheduledTransaction = this.GetFinancialScheduledTransaction(rockContext); var targetPersonId = scheduledTransaction.AuthorizedPersonAlias.PersonId; var personSavedAccountsQuery = new FinancialPersonSavedAccountService(rockContext) .GetByPersonId(targetPersonId) .Where(a => !a.IsSystem) .AsNoTracking(); DefinedValueCache[] allowedCurrencyTypes = { DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD.AsGuid()), DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH.AsGuid()) }; int[] allowedCurrencyTypeIds = allowedCurrencyTypes.Select(a => a.Id).ToArray(); personSavedAccountsQuery = personSavedAccountsQuery.Where(a => a.FinancialGatewayId == financialGateway.Id && (a.FinancialPaymentDetail.CurrencyTypeValueId != null) && allowedCurrencyTypeIds.Contains(a.FinancialPaymentDetail.CurrencyTypeValueId.Value)); List <PersonSavedAccountInfo> personSavedAccountList = personSavedAccountsQuery.OrderBy(a => a.Name).AsNoTracking().Select(a => new PersonSavedAccountInfo { Id = a.Id, Name = a.Name, GatewayPersonIdentifier = a.GatewayPersonIdentifier, AccountNumberMasked = a.FinancialPaymentDetail.AccountNumberMasked, }).ToList(); return(personSavedAccountList); }
/// <summary> /// Event when the user clicks to delete the saved accounts /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void rptSavedAccounts_Delete(object sender, CommandEventArgs e) { var bankAccountGuid = e.CommandArgument.ToStringSafe().AsGuid(); var rockContext = new RockContext(); var financialPersonSavedAccountService = new FinancialPersonSavedAccountService(rockContext); var financialPersonSavedAccount = financialPersonSavedAccountService.Get(bankAccountGuid); if (financialPersonSavedAccount != null) { string errorMessage; if (!financialPersonSavedAccountService.CanDelete(financialPersonSavedAccount, out errorMessage)) { mdWarningAlert.Show(errorMessage, ModalAlertType.Information); return; } financialPersonSavedAccountService.Delete(financialPersonSavedAccount); rockContext.SaveChanges(); } ShowDetail(); }
/// <summary> /// Handles the Delete event of the gSavedAccounts control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RowEventArgs"/> instance containing the event data.</param> protected void gSavedAccounts_Delete(object sender, RowEventArgs e) { var rockContext = new RockContext(); var service = new FinancialPersonSavedAccountService(rockContext); var savedAccount = service.Get(e.RowKeyId); string errorMessage; if (savedAccount == null) { return; } if (!service.CanDelete(savedAccount, out errorMessage)) { mdGridWarning.Show(errorMessage, ModalAlertType.Information); return; } service.Delete(savedAccount); rockContext.SaveChanges(); BindGrid(); }
/// <summary> /// Handles the Click event of the btnSaveAccount 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 SaveNewFinancialPersonSavedAccount(FinancialScheduledTransaction financialScheduledTransaction) { var rockContext = new RockContext(); var scheduledTransaction = this.GetFinancialScheduledTransaction(rockContext); var targetPerson = scheduledTransaction.AuthorizedPersonAlias.Person; var financialGatewayComponent = this.FinancialGatewayComponent; var financialGateway = this.FinancialGateway; var savedAccount = new FinancialPersonSavedAccount(); var paymentDetail = financialScheduledTransaction.FinancialPaymentDetail; savedAccount.PersonAliasId = targetPerson.PrimaryAliasId; savedAccount.ReferenceNumber = paymentDetail.GatewayPersonIdentifier; savedAccount.Name = tbSaveAccount.Text; savedAccount.TransactionCode = financialScheduledTransaction.TransactionCode; savedAccount.GatewayPersonIdentifier = paymentDetail.GatewayPersonIdentifier; savedAccount.FinancialGatewayId = financialGateway.Id; savedAccount.FinancialPaymentDetail = new FinancialPaymentDetail(); savedAccount.FinancialPaymentDetail.AccountNumberMasked = paymentDetail.AccountNumberMasked; savedAccount.FinancialPaymentDetail.CurrencyTypeValueId = paymentDetail.CurrencyTypeValueId; savedAccount.FinancialPaymentDetail.CreditCardTypeValueId = paymentDetail.CreditCardTypeValueId; savedAccount.FinancialPaymentDetail.NameOnCard = paymentDetail.NameOnCard; savedAccount.FinancialPaymentDetail.ExpirationMonth = paymentDetail.ExpirationMonth; savedAccount.FinancialPaymentDetail.ExpirationYear = paymentDetail.ExpirationYear; savedAccount.FinancialPaymentDetail.BillingLocationId = paymentDetail.BillingLocationId; var savedAccountService = new FinancialPersonSavedAccountService(rockContext); savedAccountService.Add(savedAccount); rockContext.SaveChanges(); savedAccount.FinancialPaymentDetail.FinancialPersonSavedAccountId = savedAccount.Id; }
/// <summary> /// Create a new payment processor to handle a single automated payment from a future transaction (probably generated from text-to-give). /// </summary> /// <param name="futureTransaction">The transaction with a FutureProcessingDateTime</param> /// <param name="rockContext">The context to use for loading and saving entities</param> public AutomatedPaymentProcessor(FinancialTransaction futureTransaction, RockContext rockContext) { _rockContext = rockContext; _automatedPaymentArgs = null; _currentPersonAliasId = futureTransaction.CreatedByPersonAliasId; _futureTransaction = futureTransaction; // The job charging these future transactions could have a variable run frequency and be charging a days worth at a time, so the duplicate // checking could very easily provide false positives. Therefore, we rely on the "dry-run" to have previously validated _enableDuplicateChecking = false; // These future transactions should have already had a "dry-run" and been validated. _enableScheduleAdherenceProtection = false; // These future transactions should have already had a "dry-run" and been validated _personAliasService = new PersonAliasService(_rockContext); _financialGatewayService = new FinancialGatewayService(_rockContext); _financialAccountService = new FinancialAccountService(_rockContext); _financialPersonSavedAccountService = new FinancialPersonSavedAccountService(_rockContext); _financialBatchService = new FinancialBatchService(rockContext); _financialTransactionService = new FinancialTransactionService(_rockContext); _financialScheduledTransactionService = new FinancialScheduledTransactionService(_rockContext); _payment = null; CopyFutureTransactionToArgs(); }
/// <summary> /// Updates the scheduled payment. /// </summary> /// <param name="usePaymentToken">if set to <c>true</c> [use payment token].</param> /// <param name="paymentToken">The payment token.</param> protected void UpdateScheduledPayment(bool usePaymentToken, string paymentToken = null) { var giftTerm = this.GetAttributeValue(AttributeKey.GiftTerm); if (dtpStartDate.SelectedDate <= RockDateTime.Today) { nbUpdateScheduledPaymentWarning.Visible = true; nbUpdateScheduledPaymentWarning.Text = string.Format("When scheduling a {0}, make sure the starting date is in the future (after today)", giftTerm.ToLower()); return; } var rockContext = new RockContext(); var financialScheduledTransactionService = new FinancialScheduledTransactionService(rockContext); int scheduledTransactionId = hfScheduledTransactionId.Value.AsInteger(); var financialScheduledTransaction = financialScheduledTransactionService.Get(scheduledTransactionId); financialScheduledTransaction.StartDate = dtpStartDate.SelectedDate.Value; financialScheduledTransaction.TransactionFrequencyValueId = ddlFrequency.SelectedValue.AsInteger(); ReferencePaymentInfo referencePaymentInfo; var person = financialScheduledTransaction.AuthorizedPersonAlias.Person; string errorMessage; var financialGateway = this.FinancialGateway; var financialGatewayComponent = this.FinancialGatewayComponent; if (usePaymentToken) { referencePaymentInfo = new ReferencePaymentInfo(); referencePaymentInfo.FirstName = person.FirstName; referencePaymentInfo.LastName = person.LastName; referencePaymentInfo.UpdateAddressFieldsFromAddressControl(acBillingAddress); referencePaymentInfo.ReferenceNumber = paymentToken; var customerToken = financialGatewayComponent.CreateCustomerAccount(this.FinancialGateway, referencePaymentInfo, out errorMessage); if (errorMessage.IsNotNullOrWhiteSpace() || customerToken.IsNullOrWhiteSpace()) { nbMessage.NotificationBoxType = NotificationBoxType.Danger; nbMessage.Text = errorMessage ?? "Unknown Error"; nbMessage.Visible = true; return; } referencePaymentInfo.GatewayPersonIdentifier = customerToken; } else { var savedAccountId = ddlPersonSavedAccount.SelectedValue.AsInteger(); var savedAccount = new FinancialPersonSavedAccountService(rockContext).Get(savedAccountId); if (savedAccount != null) { referencePaymentInfo = savedAccount.GetReferencePayment(); } else { throw new Exception("Unable to determine Saved Account"); } } var selectedAccountAmounts = caapPromptForAccountAmounts.AccountAmounts.Where(a => a.Amount.HasValue && a.Amount.Value != 0).Select(a => new { a.AccountId, Amount = a.Amount.Value }).ToArray(); referencePaymentInfo.Amount = selectedAccountAmounts.Sum(a => a.Amount); var successfullyUpdated = financialGatewayComponent.UpdateScheduledPayment(financialScheduledTransaction, referencePaymentInfo, out errorMessage); if (!successfullyUpdated) { nbMessage.NotificationBoxType = NotificationBoxType.Danger; nbMessage.Text = errorMessage ?? "Unknown Error"; nbMessage.Visible = true; return; } financialScheduledTransaction.FinancialPaymentDetail.SetFromPaymentInfo(referencePaymentInfo, financialGatewayComponent as GatewayComponent, rockContext); var selectedAccountIds = selectedAccountAmounts.Select(a => a.AccountId).ToArray(); var deletedTransactionDetails = financialScheduledTransaction.ScheduledTransactionDetails.ToList().Where(a => selectedAccountIds.Contains(a.AccountId)).ToList(); foreach (var deletedTransactionDetail in deletedTransactionDetails) { financialScheduledTransaction.ScheduledTransactionDetails.Remove(deletedTransactionDetail); } foreach (var selectedAccountAmount in selectedAccountAmounts) { var scheduledTransactionDetail = financialScheduledTransaction.ScheduledTransactionDetails.FirstOrDefault(a => a.AccountId == selectedAccountAmount.AccountId); if (scheduledTransactionDetail == null) { scheduledTransactionDetail = new FinancialScheduledTransactionDetail(); scheduledTransactionDetail.AccountId = selectedAccountAmount.AccountId; financialScheduledTransaction.ScheduledTransactionDetails.Add(scheduledTransactionDetail); } scheduledTransactionDetail.Amount = selectedAccountAmount.Amount; } rockContext.SaveChanges(); var mergeFields = LavaHelper.GetCommonMergeFields(this.RockPage, this.CurrentPerson, new CommonMergeFieldsOptions { GetLegacyGlobalMergeFields = false }); var finishLavaTemplate = this.GetAttributeValue(AttributeKey.FinishLavaTemplate); mergeFields.Add("Transaction", financialScheduledTransaction); mergeFields.Add("Person", financialScheduledTransaction.AuthorizedPersonAlias.Person); mergeFields.Add("PaymentDetail", financialScheduledTransaction.FinancialPaymentDetail); mergeFields.Add("BillingLocation", financialScheduledTransaction.FinancialPaymentDetail.BillingLocation); pnlPromptForChanges.Visible = false; pnlTransactionSummary.Visible = true; lTransactionSummaryHTML.Text = finishLavaTemplate.ResolveMergeFields(mergeFields); }
/// <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) { errorMessage = string.Empty; Response ppResponse = null; var invoice = GetInvoice(paymentInfo); // add in spark reference code BrowserInfo browser = new BrowserInfo(); browser.ButtonSource = "SparkDevelopmentNetwork_SP"; invoice.BrowserInfo = browser; var tender = GetTender(paymentInfo); if (tender != null) { if (paymentInfo is ReferencePaymentInfo) { var reference = paymentInfo as ReferencePaymentInfo; var ppTransaction = new ReferenceTransaction("Sale", reference.TransactionCode, GetUserInfo(financialGateway), GetConnection(financialGateway), invoice, tender, PayflowUtility.RequestId); ppResponse = ppTransaction.SubmitTransaction(); } else { var ppTransaction = new SaleTransaction(GetUserInfo(financialGateway), GetConnection(financialGateway), invoice, tender, PayflowUtility.RequestId); ppResponse = ppTransaction.SubmitTransaction(); } } else { errorMessage = "Could not create tender from PaymentInfo"; } if (ppResponse != null) { TransactionResponse txnResponse = ppResponse.TransactionResponse; if (txnResponse != null) { if (txnResponse.Result == 0) // Success { var transaction = new FinancialTransaction(); transaction.TransactionCode = txnResponse.Pnref; // Get the stored payment method that was used so we can update it // with the latest transaction code. We do this because Paypal // will only let us use the same transaction code in reference // transactions for up to 12 months. if (paymentInfo is ReferencePaymentInfo) { var reference = paymentInfo as ReferencePaymentInfo; var rockContext = new RockContext(); var savedAccount = new FinancialPersonSavedAccountService(rockContext) .Queryable() .Where(s => s.TransactionCode == reference.TransactionCode && s.FinancialGatewayId.HasValue && s.FinancialGatewayId.Value == financialGateway.Id) .FirstOrDefault(); if (savedAccount != null) { savedAccount.TransactionCode = txnResponse.Pnref; rockContext.SaveChanges(); } } return(transaction); } else { errorMessage = string.Format("[{0}] {1}", txnResponse.Result, txnResponse.RespMsg); } } else { errorMessage = "Invalid transaction response from the financial gateway"; } } else { errorMessage = "Invalid response from the financial gateway."; } return(null); }
/// <summary> /// Removes any expired saved accounts (if <see cref="AttributeKey.RemovedExpiredSavedAccountDays"/> is set) /// </summary> /// <param name="context">The context.</param> private RemoveExpiredSavedAccountsResult RemoveExpiredSavedAccounts(IJobExecutionContext context) { var dataMap = context.JobDetail.JobDataMap; int?removedExpiredSavedAccountDays = dataMap.GetString(AttributeKey.RemovedExpiredSavedAccountDays).AsIntegerOrNull(); if (!removedExpiredSavedAccountDays.HasValue) { return(new RemoveExpiredSavedAccountsResult()); } var financialPersonSavedAccountQry = new FinancialPersonSavedAccountService(new RockContext()).Queryable() .Where(a => a.FinancialPaymentDetail.ExpirationMonthEncrypted != null) .Where(a => a.PersonAliasId.HasValue || a.GroupId.HasValue) .Where(a => a.FinancialPaymentDetailId.HasValue) .Where(a => a.IsSystem == false) .OrderBy(a => a.Id); var savedAccountInfoList = financialPersonSavedAccountQry.Select(a => new SavedAccountInfo { Id = a.Id, FinancialPaymentDetail = a.FinancialPaymentDetail }).ToList(); DateTime now = DateTime.Now; int currentMonth = now.Month; int currentYear = now.Year; var result = new RemoveExpiredSavedAccountsResult() { // if today is 3/16/2020 and removedExpiredSavedAccountDays is 90, only delete card if it expired before 12/17/2019 DeleteIfExpiredBeforeDate = RockDateTime.Today.AddDays(-removedExpiredSavedAccountDays.Value) }; foreach (var savedAccountInfo in savedAccountInfoList) { int?expirationMonth = savedAccountInfo.FinancialPaymentDetail.ExpirationMonth; int?expirationYear = savedAccountInfo.FinancialPaymentDetail.ExpirationYear; if (!expirationMonth.HasValue || !expirationMonth.HasValue) { continue; } if (expirationMonth.Value < 1 || expirationMonth.Value > 12 || expirationYear <= DateTime.MinValue.Year || expirationYear >= DateTime.MaxValue.Year) { // invalid month (or year) continue; } // a credit card with an expiration of April 2020 would be expired on May 1st, 2020 var cardExpirationDate = new DateTime(expirationYear.Value, expirationMonth.Value, 1).AddMonths(1); /* Example: * Today's Date: 2020-3-16 * removedExpiredSavedAccountDays: 90 * Expired Before Date: 2019-12-17 (Today (2020-3-16) - removedExpiredSavedAccountDays) * Cards that expired before 2019-12-17 should be deleted * Delete 04/20 (Expires 05/01/2020) card? No * Delete 05/20 (Expires 06/01/2020) card? No * Delete 01/20 (Expires 03/01/2020) card? No * Delete 12/19 (Expires 01/01/2020) card? No * Delete 11/19 (Expires 12/01/2019) card? Yes * Delete 10/19 (Expires 11/01/2019) card? Yes * * Today's Date: 2020-3-16 * removedExpiredSavedAccountDays: 0 * Expired Before Date: 2019-03-16 (Today (2020-3-16) - 0) * Cards that expired before 2019-03-16 should be deleted * Delete 04/20 (Expires 05/01/2020) card? No * Delete 05/20 (Expires 06/01/2020) card? No * Delete 01/20 (Expires 03/01/2020) card? Yes * Delete 12/19 (Expires 01/01/2020) card? Yes * Delete 11/19 (Expires 12/01/2019) card? Yes * Delete 10/19 (Expires 11/01/2019) card? Yes */ if (cardExpirationDate >= result.DeleteIfExpiredBeforeDate) { // We want to only delete cards that expired more than X days ago, so if this card expiration day is after that, skip continue; } // Card expiration date is older than X day ago, so delete it. // Wrapping the following in a try/catch so a single deletion failure doesn't end the process for all deletion candidates. try { using (var savedAccountRockContext = new RockContext()) { var financialPersonSavedAccountService = new FinancialPersonSavedAccountService(savedAccountRockContext); var financialPersonSavedAccount = financialPersonSavedAccountService.Get(savedAccountInfo.Id); if (financialPersonSavedAccount != null) { if (financialPersonSavedAccountService.CanDelete(financialPersonSavedAccount, out _)) { financialPersonSavedAccountService.Delete(financialPersonSavedAccount); savedAccountRockContext.SaveChanges(); result.AccountsDeletedCount++; } } } } catch (Exception ex) { // Provide better identifying context in case the caught exception is too vague. var exception = new Exception($"Unable to delete FinancialPersonSavedAccount (ID = {savedAccountInfo.Id}).", ex); result.AccountRemovalExceptions.Add(exception); } } return(result); }
public SaveFinancialAccountFormResult SaveFinancialAccount(Guid gatewayGuid, [FromBody] SaveFinancialAccountFormArgs args) { // Validate the args if (args?.TransactionCode.IsNullOrWhiteSpace() != false) { return(new SaveFinancialAccountFormResult { Title = "Sorry", Detail = "The account information cannot be saved as there's not a valid transaction code to reference", IsSuccess = false }); } if (args.SavedAccountName.IsNullOrWhiteSpace()) { return(new SaveFinancialAccountFormResult { Title = "Missing Account Name", Detail = "Please enter a name to use for this account", IsSuccess = false }); } var currentPerson = GetPerson(); var isAnonymous = currentPerson == null; using (var rockContext = new RockContext()) { if (isAnonymous) { if (args.Username.IsNullOrWhiteSpace() || args.Password.IsNullOrWhiteSpace()) { return(new SaveFinancialAccountFormResult { Title = "Missing Information", Detail = "A username and password are required when saving an account", IsSuccess = false }); } var userLoginService = new UserLoginService(rockContext); if (userLoginService.GetByUserName(args.Username) != null) { return(new SaveFinancialAccountFormResult { Title = "Invalid Username", Detail = "The selected Username is already being used. Please select a different Username", IsSuccess = false }); } if (!UserLoginService.IsPasswordValid(args.Password)) { return(new SaveFinancialAccountFormResult { Title = "Invalid Password", Detail = UserLoginService.FriendlyPasswordRules(), IsSuccess = false }); } } // Load the gateway from the database var financialGatewayService = new FinancialGatewayService(rockContext); var financialGateway = financialGatewayService.Get(gatewayGuid); var gateway = financialGateway?.GetGatewayComponent(); if (gateway is null) { return(new SaveFinancialAccountFormResult { Title = "Invalid Gateway", Detail = "Sorry, the financial gateway information is not valid.", IsSuccess = false }); } // Load the transaction from the database var financialTransactionService = new FinancialTransactionService(rockContext); var transaction = financialTransactionService.GetByTransactionCode(financialGateway.Id, args.TransactionCode); var transactionPersonAlias = transaction?.AuthorizedPersonAlias; var transactionPerson = transactionPersonAlias?.Person; var paymentDetail = transaction?.FinancialPaymentDetail; if (transactionPerson is null || paymentDetail is null) { return(new SaveFinancialAccountFormResult { Title = "Invalid Transaction", Detail = "Sorry, the account information cannot be saved as there's not a valid transaction to reference", IsSuccess = false }); } // Create the login if needed if (isAnonymous) { var user = UserLoginService.Create( rockContext, transactionPerson, AuthenticationServiceType.Internal, EntityTypeCache.Get(SystemGuid.EntityType.AUTHENTICATION_DATABASE.AsGuid()).Id, args.Username, args.Password, false); var mergeFields = Lava.LavaHelper.GetCommonMergeFields(null, currentPerson); // TODO mergeFields.Add( "ConfirmAccountUrl", RootPath + "ConfirmAccount" ); mergeFields.Add("Person", transactionPerson); mergeFields.Add("User", user); var emailMessage = new RockEmailMessage(SystemGuid.SystemCommunication.SECURITY_CONFIRM_ACCOUNT.AsGuid()); emailMessage.AddRecipient(new RockEmailMessageRecipient(transactionPerson, mergeFields)); // TODO emailMessage.AppRoot = ResolveRockUrl( "~/" ); // TODO emailMessage.ThemeRoot = ResolveRockUrl( "~~/" ); emailMessage.CreateCommunicationRecord = false; emailMessage.Send(); } var savedAccount = new FinancialPersonSavedAccount { PersonAliasId = transactionPersonAlias.Id, ReferenceNumber = args.TransactionCode, GatewayPersonIdentifier = args.GatewayPersonIdentifier, Name = args.SavedAccountName, TransactionCode = args.TransactionCode, FinancialGatewayId = financialGateway.Id, FinancialPaymentDetail = new FinancialPaymentDetail { AccountNumberMasked = paymentDetail.AccountNumberMasked, CurrencyTypeValueId = paymentDetail.CurrencyTypeValueId, CreditCardTypeValueId = paymentDetail.CreditCardTypeValueId, NameOnCard = paymentDetail.NameOnCard, ExpirationMonth = paymentDetail.ExpirationMonth, ExpirationYear = paymentDetail.ExpirationYear, BillingLocationId = paymentDetail.BillingLocationId } }; var financialPersonSavedAccountService = new FinancialPersonSavedAccountService(rockContext); financialPersonSavedAccountService.Add(savedAccount); rockContext.SaveChanges(); return(new SaveFinancialAccountFormResult { Title = "Success", Detail = "The account has been saved for future use", IsSuccess = true }); } }
/// <summary> /// Executes the specified workflow. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="action">The action.</param> /// <param name="entity">The entity.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> public override bool Execute(RockContext rockContext, WorkflowAction action, Object entity, out List <string> errorMessages) { errorMessages = new List <string>(); var continueOnError = GetAttributeValue(action, "ContinueOnError").AsBoolean(); // Get the gateway var gateway = GetEntityFromAttributeValue <FinancialGateway>(action, "FinancialGateway", true, rockContext); if (gateway == null) { errorMessages.Add("The gateway is not valid"); } // Get the person var person = GetPersonFromAttributeValue(action, "Person", true, rockContext); if (person == null || !person.PrimaryAliasId.HasValue) { errorMessages.Add("A valid person was not provided."); } // If there are any errors accumulated, exit if (errorMessages.Any()) { return(HandleExit(action, errorMessages, continueOnError)); } // Find the saved account var savedAccountQry = new FinancialPersonSavedAccountService(rockContext) .GetByPersonId(person.Id) .AsNoTracking() .Where(sa => sa.FinancialGatewayId == gateway.Id); var savedAccount = savedAccountQry.FirstOrDefault(sa => sa.IsDefault) ?? savedAccountQry.FirstOrDefault(); // Log the result and set the result attribute if (savedAccount == null) { action.AddLogEntry(string.Format( "{0} does not have a saved account for {1}", person.FullName, gateway.Name)); var attribute = SetWorkflowAttributeValue(action, "ResultAttribute", ( int? )null); if (attribute != null) { action.AddLogEntry(string.Format("Set '{0}' attribute to null.", attribute.Name)); } } else { action.AddLogEntry(string.Format( "{0} has a saved account with ID {1} for {2}", person.FullName, savedAccount.Id, gateway.Name)); var attribute = SetWorkflowAttributeValue(action, "ResultAttribute", savedAccount.Id); if (attribute != null) { action.AddLogEntry(string.Format("Set '{0}' attribute to '{1}'.", attribute.Name, savedAccount.Id)); } } return(HandleExit(action, errorMessages, continueOnError)); }
/// <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()); }
/// <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; }
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> /// Gets the saved financial accounts associated with the specified /// person and returns the view models that represent those accounts. /// </summary> /// <param name="personId">The person identifier whose accounts should be retrieved.</param> /// <param name="options">The options for filtering and limiting the results.</param> /// <returns>A list of <see cref="SavedFinancialAccountListItemViewModel"/> objects that represent the accounts.</returns> public List <SavedFinancialAccountListItemViewModel> GetSavedFinancialAccountsForPersonAsAccountListItems(int personId, SavedFinancialAccountOptions options = null) { var financialPersonSavedAccountService = new FinancialPersonSavedAccountService(RockContext); options = options ?? DefaultSavedFinancialAccountOptions; var queryOptions = options.ToQueryOptions(); // Limit the query to just the one person we are interested in. queryOptions.PersonIds = new List <int> { personId }; // Build the query to get all the matching saved accounts for // the specified person. var savedAccountsQuery = financialPersonSavedAccountService .GetFinancialPersonSavedAccountsQuery(queryOptions); // Get the data from the database, pulling in only the bits we need. var savedAccounts = savedAccountsQuery .Select(a => new { a.Guid, a.Name, a.FinancialPaymentDetail.ExpirationMonth, a.FinancialPaymentDetail.ExpirationYear, a.FinancialPaymentDetail.AccountNumberMasked, a.FinancialPaymentDetail.CurrencyTypeValueId, a.FinancialPaymentDetail.CreditCardTypeValueId }) .ToList(); // Note: We don't perform a security check because saved accounts // don't have explicit security. It is implied that the matching // person identifier is enough security check. // Translate the saved accounts into something that will be // recognized by the client. return(savedAccounts .Select(a => { string image = null; string expirationDate = null; if (a.ExpirationMonth.HasValue && a.ExpirationYear.HasValue) { // ExpirationYear returns 4 digits, but just in case, // check if it is 4 digits before just getting the last 2. string expireYY = a.ExpirationYear.Value.ToString(); if (expireYY.Length == 4) { expireYY = expireYY.Substring(2); } expirationDate = $"{a.ExpirationMonth.Value:00}/{expireYY:00}"; } // Determine the descriptive text to associate with this account. string description = a.AccountNumberMasked != null && a.AccountNumberMasked.Length >= 4 ? $"Ending in {a.AccountNumberMasked.Right( 4 )} and Expires {expirationDate}" : $"Expires {expirationDate}"; // Determine the image to use for this account. if (a.CreditCardTypeValueId.HasValue) { var creditCardTypeValueCache = DefinedValueCache.Get(a.CreditCardTypeValueId.Value); image = creditCardTypeValueCache?.GetAttributeValue(SystemKey.CreditCardTypeAttributeKey.IconImage); } return new SavedFinancialAccountListItemViewModel { Value = a.Guid.ToString(), Text = a.Name, Description = description, Image = image }; }) .OrderBy(a => a.Text) .ToList()); }
/// <summary> /// Updates the scheduled payment. /// </summary> /// <param name="usePaymentToken">if set to <c>true</c> [use payment token].</param> /// <param name="paymentToken">The payment token.</param> protected void UpdateScheduledPayment(bool usePaymentToken, string paymentToken = null) { var giftTerm = this.GetAttributeValue(AttributeKey.GiftTerm); if (dtpStartDate.SelectedDate <= RockDateTime.Today) { nbUpdateScheduledPaymentWarning.Visible = true; nbUpdateScheduledPaymentWarning.Text = string.Format("When scheduling a {0}, make sure the starting date is in the future (after today)", giftTerm.ToLower()); return; } var rockContext = new RockContext(); var financialScheduledTransactionService = new FinancialScheduledTransactionService(rockContext); var financialScheduledTransactionDetailService = new FinancialScheduledTransactionDetailService(rockContext); Guid scheduledTransactionGuid = hfScheduledTransactionGuid.Value.AsGuid(); var financialScheduledTransaction = financialScheduledTransactionService.Get(scheduledTransactionGuid); financialScheduledTransaction.StartDate = dtpStartDate.SelectedDate.Value; financialScheduledTransaction.TransactionFrequencyValueId = ddlFrequency.SelectedValue.AsInteger(); ReferencePaymentInfo referencePaymentInfo; var person = financialScheduledTransaction.AuthorizedPersonAlias.Person; string errorMessage; var financialGateway = this.FinancialGateway; var financialGatewayComponent = this.FinancialGatewayComponent; var existingPaymentOrPersonSavedAccountId = rblExistingPaymentOrPersonSavedAccount.SelectedValue.AsInteger(); bool useExistingPaymentMethod = pnlUseExistingPaymentNoSavedAccounts.Visible || existingPaymentOrPersonSavedAccountId == 0; bool useSavedAccount = pnlUseExistingPaymentWithSavedAccounts.Visible && existingPaymentOrPersonSavedAccountId > 0; if (usePaymentToken) { referencePaymentInfo = new ReferencePaymentInfo(); referencePaymentInfo.FirstName = person.FirstName; referencePaymentInfo.LastName = person.LastName; referencePaymentInfo.UpdateAddressFieldsFromAddressControl(acBillingAddress); referencePaymentInfo.ReferenceNumber = paymentToken; var customerToken = financialGatewayComponent.CreateCustomerAccount(this.FinancialGateway, referencePaymentInfo, out errorMessage); if (errorMessage.IsNotNullOrWhiteSpace() || customerToken.IsNullOrWhiteSpace()) { nbMessage.NotificationBoxType = NotificationBoxType.Danger; nbMessage.Text = errorMessage ?? "Unknown Error"; nbMessage.Visible = true; return; } referencePaymentInfo.GatewayPersonIdentifier = customerToken; } else if (useExistingPaymentMethod) { // use save payment method as original transaction referencePaymentInfo = new ReferencePaymentInfo(); referencePaymentInfo.GatewayPersonIdentifier = financialScheduledTransaction.FinancialPaymentDetail.GatewayPersonIdentifier; referencePaymentInfo.FinancialPersonSavedAccountId = financialScheduledTransaction.FinancialPaymentDetail.FinancialPersonSavedAccountId; } else if (useSavedAccount) { var savedAccount = new FinancialPersonSavedAccountService(rockContext).Get(existingPaymentOrPersonSavedAccountId); if (savedAccount != null) { referencePaymentInfo = savedAccount.GetReferencePayment(); } else { // shouldn't happen throw new Exception("Unable to determine Saved Account"); } } else { // shouldn't happen throw new Exception("Unable to determine payment method"); } var selectedAccountAmounts = caapPromptForAccountAmounts.AccountAmounts.Where(a => a.Amount.HasValue && a.Amount.Value != 0).Select(a => new { a.AccountId, Amount = a.Amount.Value }).ToArray(); referencePaymentInfo.Amount = selectedAccountAmounts.Sum(a => a.Amount); var originalGatewayScheduleId = financialScheduledTransaction.GatewayScheduleId; try { financialScheduledTransaction.FinancialPaymentDetail.ClearPaymentInfo(); var successfullyUpdated = financialGatewayComponent.UpdateScheduledPayment(financialScheduledTransaction, referencePaymentInfo, out errorMessage); if (!successfullyUpdated) { nbMessage.NotificationBoxType = NotificationBoxType.Danger; nbMessage.Text = errorMessage ?? "Unknown Error"; nbMessage.Visible = true; return; } financialScheduledTransaction.FinancialPaymentDetail.SetFromPaymentInfo(referencePaymentInfo, financialGatewayComponent as GatewayComponent, rockContext); var selectedAccountIds = selectedAccountAmounts.Select(a => a.AccountId).ToArray(); var deletedTransactionDetails = financialScheduledTransaction.ScheduledTransactionDetails.ToList().Where(a => !selectedAccountIds.Contains(a.AccountId)).ToList(); foreach (var deletedTransactionDetail in deletedTransactionDetails) { financialScheduledTransaction.ScheduledTransactionDetails.Remove(deletedTransactionDetail); financialScheduledTransactionDetailService.Delete(deletedTransactionDetail); } foreach (var selectedAccountAmount in selectedAccountAmounts) { var scheduledTransactionDetail = financialScheduledTransaction.ScheduledTransactionDetails.FirstOrDefault(a => a.AccountId == selectedAccountAmount.AccountId); if (scheduledTransactionDetail == null) { scheduledTransactionDetail = new FinancialScheduledTransactionDetail(); scheduledTransactionDetail.AccountId = selectedAccountAmount.AccountId; financialScheduledTransaction.ScheduledTransactionDetails.Add(scheduledTransactionDetail); } scheduledTransactionDetail.Amount = selectedAccountAmount.Amount; } rockContext.SaveChanges(); Task.Run(() => ScheduledGiftWasModifiedMessage.PublishScheduledTransactionEvent(financialScheduledTransaction.Id, ScheduledGiftEventTypes.ScheduledGiftUpdated)); } catch (Exception) { // if the GatewayScheduleId was updated, but there was an exception, // make sure we save the financialScheduledTransaction record with the updated GatewayScheduleId so we don't orphan it if (financialScheduledTransaction.GatewayScheduleId.IsNotNullOrWhiteSpace() && (originalGatewayScheduleId != financialScheduledTransaction.GatewayScheduleId)) { rockContext.SaveChanges(); } throw; } var mergeFields = LavaHelper.GetCommonMergeFields(this.RockPage, this.CurrentPerson, new CommonMergeFieldsOptions { GetLegacyGlobalMergeFields = false }); var finishLavaTemplate = this.GetAttributeValue(AttributeKey.FinishLavaTemplate); // re-fetch financialScheduledTransaction with a new RockContext from database to ensure that lazy loaded fields will be populated using (var rockContextForSummary = new RockContext()) { if (pnlHostedPaymentControl.Visible && hfSaveNewAccount.Value.AsInteger() == 1 && tbSaveAccount.Text.IsNotNullOrWhiteSpace()) { SaveNewFinancialPersonSavedAccount(financialScheduledTransaction); } financialScheduledTransaction = new FinancialScheduledTransactionService(rockContextForSummary).Get(scheduledTransactionGuid); mergeFields.Add("Transaction", financialScheduledTransaction); mergeFields.Add("Person", financialScheduledTransaction.AuthorizedPersonAlias.Person); mergeFields.Add("PaymentDetail", financialScheduledTransaction.FinancialPaymentDetail); mergeFields.Add("BillingLocation", financialScheduledTransaction.FinancialPaymentDetail.BillingLocation); pnlPromptForChanges.Visible = false; pnlTransactionSummary.Visible = true; lTransactionSummaryHTML.Text = finishLavaTemplate.ResolveMergeFields(mergeFields); } }