/// <summary> /// Publishes the expiring card and cardholder details /// </summary> /// <param name="person"></param> /// <param name="financialPaymentDetail"></param> /// <param name="financialScheduledTransactions"></param> public static void Publish(Person person, FinancialPaymentDetail financialPaymentDetail, List <int> financialScheduledTransactions) { if (!RockMessageBus.IsRockStarted) { // Don't publish events until Rock is all the way started const string logMessage = "'Credit Card Is Expiring Message' message was not published because Rock is not fully started yet."; var elapsedSinceProcessStarted = RockDateTime.Now - RockInstanceConfig.ApplicationStartedDateTime; if (elapsedSinceProcessStarted.TotalSeconds > RockMessageBus.MAX_SECONDS_SINCE_STARTTIME_LOG_ERROR) { RockLogger.Log.Error(RockLogDomains.Bus, logMessage); ExceptionLogService.LogException(new BusException(logMessage)); } else { RockLogger.Log.Debug(RockLogDomains.Bus, logMessage); } return; } var cardHolder = new CardHolder() { CommunicationPreference = (int)person.CommunicationPreference, Email = person.Email, FirstName = person.FirstName, Id = person.Id, LastName = person.LastName, MiddleName = person.MiddleName, NickName = person.NickName }; var message = new CreditCardIsExpiringMessage { AccountNumberMasked = financialPaymentDetail.AccountNumberMasked, BillingLocation = financialPaymentDetail.BillingLocation?.GetFullStreetAddress(), CardExpirationDate = financialPaymentDetail.CardExpirationDate, CreatedDateTime = financialPaymentDetail.CreatedDateTime, CreditCardTypeValue = financialPaymentDetail.CreditCardTypeValue?.Value, ExpirationDate = financialPaymentDetail.ExpirationDate, ExpirationMonth = financialPaymentDetail.ExpirationMonth, ExpirationYear = financialPaymentDetail.ExpirationYear, FinancialPersonSavedAccountName = financialPaymentDetail.FinancialPersonSavedAccount?.Name, Id = financialPaymentDetail.Id, NameOnCard = financialPaymentDetail.NameOnCard, Person = cardHolder, FinancialScheduledTransactions = financialScheduledTransactions }; _ = RockMessageBus.PublishAsync <ExpiringCardEventQueue, CreditCardIsExpiringMessage>(message); RockLogger.Log.Debug(RockLogDomains.Bus, "Published 'Credit Card Is Expiring Message' message."); }
/// <summary> /// Creates the payment detail. /// </summary> /// <param name="parameters">The parameters.</param> /// <param name="person">The person.</param> /// <param name="billingLocationId">The billing location identifier.</param> /// <param name="rockContext">The rock context.</param> /// <returns></returns> private FinancialPaymentDetail CreatePaymentDetail(PaymentParameters parameters, Person person, int billingLocationId, RockContext rockContext) { if (string.IsNullOrWhiteSpace(parameters.AccountNumber)) { GenerateResponse(HttpStatusCode.BadRequest, "AccountNumber is required"); return(null); } if (string.IsNullOrWhiteSpace(parameters.AccountType)) { GenerateResponse(HttpStatusCode.BadRequest, "AccountType is required"); return(null); } var accountType = parameters.AccountType.ToLower(); var allowedTypes = new String[] { "checking", "savings", "credit" }; if (!allowedTypes.Contains(accountType)) { GenerateResponse(HttpStatusCode.BadRequest, "AccountType must be one of " + string.Join(", ", allowedTypes)); return(null); } var maskedAccountNumber = Mask(parameters.AccountNumber); var nameOnCard = (parameters.FirstName ?? person.FirstName) + " " + (parameters.LastName ?? person.LastName); var paymentDetail = new FinancialPaymentDetail { AccountNumberMasked = maskedAccountNumber, NameOnCardEncrypted = Rock.Security.Encryption.EncryptString(nameOnCard), BillingLocationId = billingLocationId }; if (parameters.AccountType.ToLower() == "credit") { paymentDetail.ExpirationMonthEncrypted = Rock.Security.Encryption.EncryptString(parameters.ExpirationMonth.ToString()); paymentDetail.ExpirationYearEncrypted = Rock.Security.Encryption.EncryptString(parameters.ExpirationYear.ToString()); } new FinancialPaymentDetailService(rockContext).Add(paymentDetail); rockContext.SaveChanges(); return(paymentDetail); }
private static FinancialPaymentDetail CreateFinancialPaymentDetail( int?currencyTypeId, int?cardTypeId, DateTime transactionDateTime) { var payment = new FinancialPaymentDetail { CurrencyTypeValueId = currencyTypeId, CreditCardTypeValueId = cardTypeId, Guid = Guid.NewGuid(), CreatedDateTime = transactionDateTime, ModifiedDateTime = RockDateTime.Now }; _paymentService.Add(payment); _rockContext.SaveChanges(true); return(payment); }
/// <summary> /// Handles the Click event of the btnConfirmationNext 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 btnPayPalConfirmationNext_Click(object sender, EventArgs e) { string errorMessage = string.Empty; var transaction = _payPalExpressGatewayComponent.Charge(_payPalExpressGateway, GetPaymentInfo(), out errorMessage); if (errorMessage != string.Empty) { ShowMessage(NotificationBoxType.Danger, "Payment Processing Error", errorMessage); return; } if (transaction == null) { ShowMessage(NotificationBoxType.Danger, "Payment Error", "Invalid Transaction"); return; } Person person = GetPerson(GetPaymentInfo(), true); RockContext rockContext = new RockContext(); SaveTransaction(_payPalExpressGateway, _payPalExpressGatewayComponent, person, GetPaymentInfo(), transaction, rockContext); FinancialPaymentDetail paymentDetail = transaction.FinancialPaymentDetail.Clone(false); ShowSuccess(_payPalExpressGatewayComponent, person, GetPaymentInfo(), null, paymentDetail, rockContext); }
/// <summary> /// Gets the payment information. /// </summary> /// <param name="parameters">The parameters.</param> /// <param name="person">The person.</param> /// <param name="rockContext">The rock context.</param> /// <param name="totalAmount">The total amount.</param> /// <param name="paymentDetail">The payment detail.</param> /// <returns></returns> private PaymentInfo GetPaymentInfo( PaymentParameters parameters, Person person, RockContext rockContext, decimal totalAmount, FinancialPaymentDetail paymentDetail ) { PaymentInfo paymentInfo = null; if ( parameters.AccountType.ToLower() == "credit" ) { if ( parameters.ExpirationMonth < 1 || parameters.ExpirationMonth > 12 ) { GenerateResponse( HttpStatusCode.BadRequest, "ExpirationMonth is required and must be between 1 and 12 for credit transactions" ); } var currentDate = DateTime.Now; var maxYear = currentDate.Year + 30; if ( parameters.ExpirationYear < currentDate.Year || parameters.ExpirationYear > maxYear ) { GenerateResponse( HttpStatusCode.BadRequest, string.Format( "ExpirationYear is required and must be between {0} and {1} for credit transactions", currentDate.Year, maxYear ) ); } if ( parameters.ExpirationYear <= currentDate.Year && parameters.ExpirationMonth < currentDate.Month ) { GenerateResponse( HttpStatusCode.BadRequest, "The ExpirationMonth and ExpirationYear combination must not have already elapsed for credit transactions" ); } if ( string.IsNullOrWhiteSpace( parameters.Street1 ) || string.IsNullOrWhiteSpace( parameters.City ) || string.IsNullOrWhiteSpace( parameters.State ) || string.IsNullOrWhiteSpace( parameters.PostalCode ) ) { GenerateResponse( HttpStatusCode.BadRequest, "Street1, City, State, and PostalCode are required for credit transactions" ); } paymentInfo = new CreditCardPaymentInfo() { Number = parameters.AccountNumber, Code = parameters.CCV ?? string.Empty, ExpirationDate = new DateTime( parameters.ExpirationYear, parameters.ExpirationMonth, 1 ), BillingStreet1 = parameters.Street1 ?? string.Empty, BillingStreet2 = parameters.Street2 ?? string.Empty, BillingCity = parameters.City ?? string.Empty, BillingState = parameters.State ?? string.Empty, BillingPostalCode = parameters.PostalCode ?? string.Empty, BillingCountry = parameters.Country ?? "USA" }; } else { if ( string.IsNullOrWhiteSpace( parameters.RoutingNumber ) ) { GenerateResponse( HttpStatusCode.BadRequest, "RoutingNumber is required for ACH transactions" ); return null; } paymentInfo = new ACHPaymentInfo() { BankRoutingNumber = parameters.RoutingNumber, BankAccountNumber = parameters.AccountNumber, AccountType = parameters.AccountType.ToLower() == "checking" ? BankAccountType.Checking : BankAccountType.Savings }; } paymentInfo.Amount = totalAmount; paymentInfo.FirstName = parameters.FirstName ?? person.FirstName; paymentInfo.LastName = parameters.LastName ?? person.LastName; paymentInfo.Email = parameters.Email ?? person.Email; paymentInfo.Phone = parameters.PhoneNumber ?? string.Empty; paymentInfo.Street1 = parameters.Street1 ?? string.Empty; paymentInfo.Street2 = parameters.Street2 ?? string.Empty; paymentInfo.City = parameters.City ?? string.Empty; paymentInfo.State = parameters.State ?? string.Empty; paymentInfo.PostalCode = parameters.PostalCode ?? string.Empty; paymentInfo.Country = parameters.Country ?? "USA"; if ( paymentInfo.CreditCardTypeValue != null ) { paymentDetail.CreditCardTypeValueId = paymentInfo.CreditCardTypeValue.Id; } if ( paymentInfo.CurrencyTypeValue != null ) { paymentDetail.CurrencyTypeValueId = paymentInfo.CurrencyTypeValue.Id; } return paymentInfo; }
/// <summary> /// Creates the saved account. /// </summary> /// <param name="parameters">The parameters.</param> /// <param name="paymentDetail">The payment detail.</param> /// <param name="financialGateway">The financial gateway.</param> /// <param name="person">The person.</param> /// <param name="rockContext">The rock context.</param> /// <returns></returns> private FinancialPersonSavedAccount CreateSavedAccount( PaymentParameters parameters, FinancialPaymentDetail paymentDetail, FinancialGateway financialGateway, Person person, RockContext rockContext) { var lastFour = paymentDetail.AccountNumberMasked.Substring(paymentDetail.AccountNumberMasked.Length - 4); var name = string.Empty; if ( parameters.AccountType.ToLower() != "credit" ) { if ( string.IsNullOrWhiteSpace( parameters.RoutingNumber ) ) { GenerateResponse( HttpStatusCode.BadRequest, "RoutingNumber is required for ACH transactions" ); return null; } if ( string.IsNullOrWhiteSpace( parameters.AccountNumber ) ) { GenerateResponse( HttpStatusCode.BadRequest, "AccountNumber is required" ); return null; } name = "Bank card ***" + lastFour; var bankAccountService = new FinancialPersonBankAccountService( rockContext ); var accountNumberSecured = FinancialPersonBankAccount.EncodeAccountNumber( parameters.RoutingNumber, parameters.AccountNumber ); var bankAccount = bankAccountService.Queryable().Where( a => a.AccountNumberSecured == accountNumberSecured && a.PersonAliasId == person.PrimaryAliasId.Value ).FirstOrDefault(); if ( bankAccount == null ) { bankAccount = new FinancialPersonBankAccount(); bankAccount.PersonAliasId = person.PrimaryAliasId.Value; bankAccount.AccountNumberMasked = paymentDetail.AccountNumberMasked; bankAccount.AccountNumberSecured = accountNumberSecured; bankAccountService.Add( bankAccount ); } } else { name = "Credit card ***" + lastFour; } var savedAccount = new FinancialPersonSavedAccount { PersonAliasId = person.PrimaryAliasId, FinancialGatewayId = financialGateway.Id, Name = name, FinancialPaymentDetailId = paymentDetail.Id }; new FinancialPersonSavedAccountService(rockContext).Add( savedAccount ); rockContext.SaveChanges(); return savedAccount; }
/// <summary> /// Creates the payment detail. /// </summary> /// <param name="parameters">The parameters.</param> /// <param name="person">The person.</param> /// <param name="billingLocationId">The billing location identifier.</param> /// <param name="rockContext">The rock context.</param> /// <returns></returns> private FinancialPaymentDetail CreatePaymentDetail( PaymentParameters parameters, Person person, int billingLocationId, RockContext rockContext ) { if ( string.IsNullOrWhiteSpace( parameters.AccountNumber ) ) { GenerateResponse( HttpStatusCode.BadRequest, "AccountNumber is required" ); return null; } if ( string.IsNullOrWhiteSpace( parameters.AccountType ) ) { GenerateResponse( HttpStatusCode.BadRequest, "AccountType is required" ); return null; } var accountType = parameters.AccountType.ToLower(); var allowedTypes = new String[] { "checking", "savings", "credit" }; if (!allowedTypes.Contains(accountType) ) { GenerateResponse( HttpStatusCode.BadRequest, "AccountType must be one of " + string.Join(", ", allowedTypes) ); return null; } var maskedAccountNumber = Mask( parameters.AccountNumber ); var nameOnCard = ( parameters.FirstName ?? person.FirstName ) + " " + ( parameters.LastName ?? person.LastName ); var paymentDetail = new FinancialPaymentDetail { AccountNumberMasked = maskedAccountNumber, NameOnCardEncrypted = Rock.Security.Encryption.EncryptString(nameOnCard), BillingLocationId = billingLocationId }; if ( parameters.AccountType.ToLower() == "credit" ) { paymentDetail.ExpirationMonthEncrypted = Rock.Security.Encryption.EncryptString( parameters.ExpirationMonth.ToString() ); paymentDetail.ExpirationYearEncrypted = Rock.Security.Encryption.EncryptString( parameters.ExpirationYear.ToString() ); } new FinancialPaymentDetailService( rockContext ).Add( paymentDetail ); rockContext.SaveChanges(); return paymentDetail; }
/// <summary> /// Maps the contribution. /// </summary> /// <param name="tableData">The table data.</param> /// <param name="selectedColumns">The selected columns.</param> private void MapContribution( IQueryable<Row> tableData, List<string> selectedColumns = null ) { var lookupContext = new RockContext(); int transactionEntityTypeId = EntityTypeCache.Read( "Rock.Model.FinancialTransaction" ).Id; var transactionTypeContributionId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ), lookupContext ).Id; var currencyTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE ) ); int currencyTypeACH = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ) ) ).Id; int currencyTypeCash = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH ) ) ).Id; int currencyTypeCheck = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK ) ) ).Id; int currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ) ) ).Id; int? currencyTypeNonCash = currencyTypes.DefinedValues.Where( dv => dv.Value.Equals( "Non-Cash" ) ).Select( dv => (int?)dv.Id ).FirstOrDefault(); if ( currencyTypeNonCash == null ) { var newTenderNonCash = new DefinedValue(); newTenderNonCash.Value = "Non-Cash"; newTenderNonCash.Description = "Non-Cash"; newTenderNonCash.DefinedTypeId = currencyTypes.Id; lookupContext.DefinedValues.Add( newTenderNonCash ); lookupContext.SaveChanges(); currencyTypeNonCash = newTenderNonCash.Id; } var creditCardTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE ) ).DefinedValues; int sourceTypeOnsite = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_ONSITE_COLLECTION ), lookupContext ).Id; int sourceTypeWebsite = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE ), lookupContext ).Id; int sourceTypeKiosk = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_KIOSK ), lookupContext ).Id; var refundReasons = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON ), lookupContext ).DefinedValues; var accountList = new FinancialAccountService( lookupContext ).Queryable().AsNoTracking().ToList(); int? defaultBatchId = null; if ( ImportedBatches.ContainsKey( 0 ) ) { defaultBatchId = ImportedBatches[0]; } // Get all imported contributions var importedContributions = new FinancialTransactionService( lookupContext ).Queryable().AsNoTracking() .Where( c => c.ForeignId != null ) .ToDictionary( t => (int)t.ForeignId, t => (int?)t.Id ); // List for batching new contributions var newTransactions = new List<FinancialTransaction>(); int completed = 0; int totalRows = tableData.Count(); int percentage = ( totalRows - 1 ) / 100 + 1; ReportProgress( 0, string.Format( "Verifying contribution import ({0:N0} found, {1:N0} already exist).", totalRows, importedContributions.Count ) ); foreach ( var row in tableData.Where( r => r != null ) ) { int? individualId = row["Individual_ID"] as int?; int? householdId = row["Household_ID"] as int?; int? contributionId = row["ContributionID"] as int?; if ( contributionId != null && !importedContributions.ContainsKey( (int)contributionId ) ) { var transaction = new FinancialTransaction(); transaction.CreatedByPersonAliasId = ImportPersonAliasId; transaction.ModifiedByPersonAliasId = ImportPersonAliasId; transaction.TransactionTypeValueId = transactionTypeContributionId; transaction.ForeignKey = contributionId.ToString(); transaction.ForeignId = contributionId; int? giverAliasId = null; var personKeys = GetPersonKeys( individualId, householdId ); if ( personKeys != null && personKeys.PersonAliasId > 0 ) { giverAliasId = personKeys.PersonAliasId; transaction.CreatedByPersonAliasId = giverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } string summary = row["Memo"] as string; if ( summary != null ) { transaction.Summary = summary; } int? batchId = row["BatchID"] as int?; if ( batchId != null && ImportedBatches.Any( b => b.Key.Equals( batchId ) ) ) { transaction.BatchId = ImportedBatches.FirstOrDefault( b => b.Key.Equals( batchId ) ).Value; } else { // use the default batch for any non-matching transactions transaction.BatchId = defaultBatchId; } DateTime? receivedDate = row["Received_Date"] as DateTime?; if ( receivedDate != null ) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; transaction.ModifiedDateTime = ImportDateTime; } string cardType = row["Card_Type"] as string; string cardLastFour = row["Last_Four"] as string; string contributionType = row["Contribution_Type_Name"].ToStringSafe().ToLower(); if ( contributionType != null ) { // set default source to onsite, exceptions listed below transaction.SourceTypeValueId = sourceTypeOnsite; int? paymentCurrencyTypeId = null, creditCardTypeId = null; if ( contributionType == "cash" ) { paymentCurrencyTypeId = currencyTypeCash; } else if ( contributionType == "check" ) { paymentCurrencyTypeId = currencyTypeCheck; } else if ( contributionType == "ach" ) { paymentCurrencyTypeId = currencyTypeACH; transaction.SourceTypeValueId = sourceTypeWebsite; } else if ( contributionType == "credit card" ) { paymentCurrencyTypeId = currencyTypeCreditCard; transaction.SourceTypeValueId = sourceTypeWebsite; if ( cardType != null ) { creditCardTypeId = creditCardTypes.Where( t => t.Value.Equals( cardType ) ).Select( t => (int?)t.Id ).FirstOrDefault(); } } else { paymentCurrencyTypeId = currencyTypeNonCash; } var paymentDetail = new FinancialPaymentDetail(); paymentDetail.CreatedDateTime = receivedDate; paymentDetail.CreatedByPersonAliasId = giverAliasId; paymentDetail.ModifiedDateTime = ImportDateTime; paymentDetail.ModifiedByPersonAliasId = giverAliasId; paymentDetail.CurrencyTypeValueId = paymentCurrencyTypeId; paymentDetail.CreditCardTypeValueId = creditCardTypeId; paymentDetail.AccountNumberMasked = cardLastFour; paymentDetail.ForeignKey = contributionId.ToString(); paymentDetail.ForeignId = contributionId; transaction.FinancialPaymentDetail = paymentDetail; } string checkNumber = row["Check_Number"] as string; // if the check number is valid, put it in the transaction code if ( checkNumber.AsType<int?>() != null ) { transaction.TransactionCode = checkNumber; } // check for SecureGive kiosk transactions else if ( !string.IsNullOrEmpty( checkNumber ) && checkNumber.StartsWith( "SG" ) ) { transaction.SourceTypeValueId = sourceTypeKiosk; } string fundName = row["Fund_Name"] as string; string subFund = row["Sub_Fund_Name"] as string; string fundGLAccount = row["Fund_GL_Account"] as string; string subFundGLAccount = row["Sub_Fund_GL_Account"] as string; Boolean? isFundActive = row["Fund_Is_active"] as Boolean?; decimal? statedValue = row["Stated_Value"] as decimal?; decimal? amount = row["Amount"] as decimal?; if ( fundName != null & amount != null ) { int transactionAccountId; var parentAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName ) && a.CampusId == null ); if ( parentAccount == null ) { parentAccount = AddAccount( lookupContext, fundName, fundGLAccount, null, null, isFundActive ); accountList.Add( parentAccount ); } if ( subFund != null ) { int? campusFundId = null; // assign a campus if the subfund is a campus fund var campusFund = CampusList.FirstOrDefault( c => subFund.StartsWith( c.Name ) || subFund.StartsWith( c.ShortCode ) ); if ( campusFund != null ) { // use full campus name as the subfund subFund = campusFund.Name; campusFundId = campusFund.Id; } // add info to easily find/assign this fund in the view subFund = string.Format( "{0} {1}", subFund, fundName ); var childAccount = accountList.FirstOrDefault( c => c.Name.Equals( subFund ) && c.ParentAccountId == parentAccount.Id ); if ( childAccount == null ) { // create a child account with a campusId if it was set childAccount = AddAccount( lookupContext, subFund, subFundGLAccount, campusFundId, parentAccount.Id, isFundActive ); accountList.Add( childAccount ); } transactionAccountId = childAccount.Id; } else { transactionAccountId = parentAccount.Id; } if ( amount == 0 && statedValue != null && statedValue != 0 ) { amount = statedValue; } var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = (decimal)amount; transactionDetail.CreatedDateTime = receivedDate; transactionDetail.AccountId = transactionAccountId; transaction.TransactionDetails.Add( transactionDetail ); if ( amount < 0 ) { transaction.RefundDetails = new FinancialTransactionRefund(); transaction.RefundDetails.CreatedDateTime = receivedDate; transaction.RefundDetails.RefundReasonValueId = refundReasons.Where( dv => summary != null && dv.Value.Contains( summary ) ) .Select( dv => (int?)dv.Id ).FirstOrDefault(); transaction.RefundDetails.RefundReasonSummary = summary; } } newTransactions.Add( transaction ); completed++; if ( completed % percentage < 1 ) { int percentComplete = completed / percentage; ReportProgress( percentComplete, string.Format( "{0:N0} contributions imported ({1}% complete).", completed, percentComplete ) ); } else if ( completed % ReportingNumber < 1 ) { SaveContributions( newTransactions ); newTransactions.Clear(); ReportPartialProgress(); } } } if ( newTransactions.Any() ) { SaveContributions( newTransactions ); } ReportProgress( 100, string.Format( "Finished contribution import: {0:N0} contributions imported.", completed ) ); }
/// <summary> /// Uploads the scanned item. /// </summary> /// <param name="scannedDocInfo">The scanned document information.</param> public static void UploadScannedItem(ScannedDocInfo scannedDocInfo) { RockRestClient client = EnsureUploadScanRestClient(); // upload image of front of doc (if was successfully scanned) int?frontImageBinaryFileId = null; if (scannedDocInfo.FrontImageData != null) { string frontImageFileName = string.Format("image1_{0}.png", DateTime.Now.ToString("o").RemoveSpecialCharacters()); frontImageBinaryFileId = client.UploadBinaryFile(frontImageFileName, Rock.Client.SystemGuid.BinaryFiletype.CONTRIBUTION_IMAGE.AsGuid(), scannedDocInfo.FrontImagePngBytes, false); } // upload image of back of doc (if it exists) int?backImageBinaryFileId = null; if (scannedDocInfo.BackImageData != null) { // upload image of back of doc string backImageFileName = string.Format("image2_{0}.png", DateTime.Now.ToString("o").RemoveSpecialCharacters()); backImageBinaryFileId = client.UploadBinaryFile(backImageFileName, Rock.Client.SystemGuid.BinaryFiletype.CONTRIBUTION_IMAGE.AsGuid(), scannedDocInfo.BackImagePngBytes, false); } FinancialPaymentDetail financialPaymentDetail = new FinancialPaymentDetail(); financialPaymentDetail.CurrencyTypeValueId = scannedDocInfo.CurrencyTypeValue.Id; financialPaymentDetail.Guid = Guid.NewGuid(); var financialPaymentDetailId = client.PostData <FinancialPaymentDetail>("api/FinancialPaymentDetails", financialPaymentDetail).AsIntegerOrNull(); FinancialTransaction financialTransaction = new FinancialTransaction(); financialTransaction.BatchId = batchPage.SelectedFinancialBatch.Id; financialTransaction.TransactionCode = string.Empty; financialTransaction.Summary = string.Empty; financialTransaction.Guid = Guid.NewGuid(); financialTransaction.TransactionDateTime = batchPage.SelectedFinancialBatch.BatchStartDateTime; financialTransaction.FinancialPaymentDetailId = financialPaymentDetailId; financialTransaction.SourceTypeValueId = scannedDocInfo.SourceTypeValue.Id; financialTransaction.TransactionTypeValueId = transactionTypeValueContribution.Id; var accounts = scannedDocInfo.AccountAmountCaptureList; if (accounts != null) { var accountsWithValues = accounts.Where(a => a.Amount > 0).ToList(); if (accountsWithValues != null && accountsWithValues.Count() > 0) { AddFinancialTransactionDetailForEachAccount(accountsWithValues, financialTransaction); } } int?uploadedTransactionId; if (scannedDocInfo.IsCheck) { financialTransaction.TransactionCode = scannedDocInfo.CheckNumber; financialTransaction.MICRStatus = scannedDocInfo.BadMicr ? MICRStatus.Fail : MICRStatus.Success; FinancialTransactionScannedCheck financialTransactionScannedCheck = new FinancialTransactionScannedCheck(); // Rock server will encrypt CheckMicrPlainText to this since we can't have the DataEncryptionKey in a RestClient financialTransactionScannedCheck.FinancialTransaction = financialTransaction; financialTransactionScannedCheck.ScannedCheckMicrData = scannedDocInfo.ScannedCheckMicrData; financialTransactionScannedCheck.ScannedCheckMicrParts = scannedDocInfo.ScannedCheckMicrParts; uploadedTransactionId = client.PostData <FinancialTransactionScannedCheck>("api/FinancialTransactions/PostScanned", financialTransactionScannedCheck).AsIntegerOrNull(); } else { //FinancialTransactionDetail uploadedTransactionId = client.PostData <FinancialTransaction>("api/FinancialTransactions", financialTransaction as FinancialTransaction).AsIntegerOrNull(); } // upload FinancialTransactionImage records for front/back if (frontImageBinaryFileId.HasValue) { FinancialTransactionImage financialTransactionImageFront = new FinancialTransactionImage(); financialTransactionImageFront.BinaryFileId = frontImageBinaryFileId.Value; financialTransactionImageFront.TransactionId = uploadedTransactionId.Value; financialTransactionImageFront.Order = 0; financialTransactionImageFront.Guid = Guid.NewGuid(); client.PostData <FinancialTransactionImage>("api/FinancialTransactionImages", financialTransactionImageFront); } if (backImageBinaryFileId.HasValue) { FinancialTransactionImage financialTransactionImageBack = new FinancialTransactionImage(); financialTransactionImageBack.BinaryFileId = backImageBinaryFileId.Value; financialTransactionImageBack.TransactionId = uploadedTransactionId.Value; financialTransactionImageBack.Order = 1; financialTransactionImageBack.Guid = Guid.NewGuid(); client.PostData <FinancialTransactionImage>("api/FinancialTransactionImages", financialTransactionImageBack); } scannedDocInfo.TransactionId = uploadedTransactionId; financialTransaction.Id = uploadedTransactionId ?? 0; financialTransaction.CreatedDateTime = financialTransaction.CreatedDateTime ?? DateTime.Now; batchPage.SelectedFinancialBatch.Transactions.Add(financialTransaction); var transactionList = batchPage.grdBatchItems.DataContext as BindingList <FinancialTransaction>; transactionList.Insert(0, financialTransaction); ItemsUploaded++; }
public HttpResponseMessage Give([FromBody] GiveParameters giveParameters) { var rockContext = new RockContext(); try { rockContext.WrapTransaction(() => { int?locationId = null; FinancialPaymentDetail paymentDetail = null; PaymentInfo paymentInfo = null; FinancialPersonSavedAccount savedAccount = null; bool newSavedAccount = true; var gatewayComponent = GatewayContainer.GetComponent(gatewayName); if (gatewayComponent == null) { GenerateResponse(HttpStatusCode.InternalServerError, "There was a problem creating the gateway component"); } var financialGateway = new FinancialGatewayService(rockContext).Queryable().FirstOrDefault(g => g.EntityTypeId == gatewayComponent.EntityType.Id); if (financialGateway == null) { GenerateResponse(HttpStatusCode.InternalServerError, "There was a problem creating the financial gateway"); } var totalAmount = CalculateTotalAmount(giveParameters, rockContext); var person = GetExistingPerson(giveParameters.PersonId, rockContext); if (person == null) { // New person locationId = CreateLocation(giveParameters, rockContext); person = CreatePerson(giveParameters, locationId.Value, rockContext); } else { // Existing person savedAccount = GetExistingSavedAccount(giveParameters, person, rockContext); if (savedAccount != null) { locationId = savedAccount.FinancialPaymentDetail.BillingLocationId; newSavedAccount = false; } } if (!locationId.HasValue) { locationId = CreateLocation(giveParameters, rockContext); } if (savedAccount == null) { paymentDetail = CreatePaymentDetail(giveParameters, person, locationId.Value, rockContext); savedAccount = CreateSavedAccount(giveParameters, paymentDetail, financialGateway, person, rockContext); newSavedAccount = true; paymentInfo = GetPaymentInfo(giveParameters, person, rockContext, totalAmount.Value, paymentDetail); } else { paymentDetail = savedAccount.FinancialPaymentDetail; locationId = paymentDetail.BillingLocationId; paymentInfo = savedAccount.GetReferencePayment(); UpdatePaymentInfoForSavedAccount(giveParameters, paymentInfo, person, rockContext, locationId.Value, totalAmount.Value); } SaveLocationToFamilyIfNone(person, locationId.Value, rockContext); string errorMessage; var transaction = gatewayComponent.Charge(financialGateway, paymentInfo, out errorMessage); if (transaction == null || !string.IsNullOrWhiteSpace(errorMessage)) { GenerateResponse(HttpStatusCode.InternalServerError, errorMessage ?? "The gateway had a problem and/or did not create a transaction as expected"); } transaction.FinancialPaymentDetail = null; transaction.SourceTypeValueId = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE)).Id; transaction.TransactionDateTime = RockDateTime.Now; transaction.AuthorizedPersonAliasId = person.PrimaryAliasId; transaction.AuthorizedPersonAlias = person.PrimaryAlias; transaction.FinancialGatewayId = financialGateway.Id; transaction.TransactionTypeValueId = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION)).Id; transaction.FinancialPaymentDetailId = paymentDetail.Id; savedAccount.TransactionCode = transaction.TransactionCode; foreach (var accountAmount in giveParameters.AmountDetails) { transaction.TransactionDetails.Add(new FinancialTransactionDetail() { Amount = accountAmount.Amount, AccountId = accountAmount.TargetAccountId }); } new FinancialTransactionService(rockContext).Add(transaction); rockContext.SaveChanges(); if (newSavedAccount) { var newReferenceNumber = gatewayComponent.GetReferenceNumber(transaction, out errorMessage); savedAccount.ReferenceNumber = newReferenceNumber; } rockContext.SaveChanges(); }); } catch (HttpResponseException exception) { return(exception.Response); } catch (Exception exception) { var response = new HttpResponseMessage(HttpStatusCode.InternalServerError); response.Content = new StringContent(exception.Message); return(response); } return(new HttpResponseMessage(HttpStatusCode.NoContent)); }
private void ShowSuccess( GatewayComponent gatewayComponent, Person person, PaymentInfo paymentInfo, PaymentSchedule schedule, FinancialPaymentDetail paymentDetail, RockContext rockContext ) { tdTransactionCodeReceipt.Description = TransactionCode; tdTransactionCodeReceipt.Visible = !string.IsNullOrWhiteSpace( TransactionCode ); tdScheduleId.Description = ScheduleId; tdScheduleId.Visible = !string.IsNullOrWhiteSpace( ScheduleId ); tdNameReceipt.Description = paymentInfo.FullName; tdPhoneReceipt.Description = paymentInfo.Phone; tdEmailReceipt.Description = paymentInfo.Email; tdAddressReceipt.Description = string.Format( "{0} {1}, {2} {3}", paymentInfo.Street1, paymentInfo.City, paymentInfo.State, paymentInfo.PostalCode ); rptAccountListReceipt.DataSource = SelectedAccounts.Where( a => a.Amount != 0 ); rptAccountListReceipt.DataBind(); tdTotalReceipt.Description = paymentInfo.Amount.ToString( "C" ); tdPaymentMethodReceipt.Description = paymentInfo.CurrencyTypeValue.Description; string acctNumber = paymentInfo.MaskedNumber; if ( string.IsNullOrWhiteSpace( acctNumber ) && paymentDetail != null && !string.IsNullOrWhiteSpace( paymentDetail.AccountNumberMasked ) ) { acctNumber = paymentDetail.AccountNumberMasked; } tdAccountNumberReceipt.Description = acctNumber; tdAccountNumberReceipt.Visible = !string.IsNullOrWhiteSpace( acctNumber ); tdWhenReceipt.Description = schedule != null ? schedule.ToString() : "Today"; // If there was a transaction code returned and this was not already created from a previous saved account, // show the option to save the account. if ( !( paymentInfo is ReferencePaymentInfo ) && !string.IsNullOrWhiteSpace( TransactionCode ) && gatewayComponent.SupportsSavedAccount( paymentInfo.CurrencyTypeValue ) ) { cbSaveAccount.Visible = true; pnlSaveAccount.Visible = true; txtSaveAccount.Visible = true; // If current person does not have a login, have them create a username and password phCreateLogin.Visible = !new UserLoginService( rockContext ).GetByPersonId( person.Id ).Any(); } else { pnlSaveAccount.Visible = false; } }
/// <summary> /// Maps the contribution. /// </summary> /// <param name="csvData">The table data.</param> private int MapContribution(CSVInstance csvData) { var lookupContext = new RockContext(); var currencyTypes = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE)); var currencyTypeACH = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH))).Id; var currencyTypeCash = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH))).Id; var currencyTypeCheck = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK))).Id; var currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD))).Id; var currencyTypeNonCash = currencyTypes.DefinedValues.Where(dv => dv.Value.Equals("Non-Cash")).Select(dv => (int?)dv.Id).FirstOrDefault(); if (currencyTypeNonCash == null) { var newTenderNonCash = new DefinedValue { Value = "Non-Cash", Description = "Non-Cash", DefinedTypeId = currencyTypes.Id }; lookupContext.DefinedValues.Add(newTenderNonCash); lookupContext.SaveChanges(); currencyTypeNonCash = newTenderNonCash.Id; } var creditCardTypes = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE)).DefinedValues; var sourceTypeOnsite = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_ONSITE_COLLECTION), lookupContext).Id; var sourceTypeWebsite = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE), lookupContext).Id; var sourceTypeKiosk = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_KIOSK), lookupContext).Id; var refundReasons = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON), lookupContext).DefinedValues; var accountList = new FinancialAccountService(lookupContext).Queryable().AsNoTracking().ToList(); int?defaultBatchId = null; if (ImportedBatches.ContainsKey(0)) { defaultBatchId = ImportedBatches[0]; } // Look for custom attributes in the Contribution file var allFields = csvData.TableNodes.FirstOrDefault().Children.Select((node, index) => new { node = node, index = index }).ToList(); var customAttributes = allFields .Where(f => f.index > ContributionCreditCardType) .ToDictionary(f => f.index, f => f.node.Name); // Get all imported contributions var importedContributions = new FinancialTransactionService(lookupContext).Queryable().AsNoTracking() .Where(c => c.ForeignId != null) .Select(t => (int)t.ForeignId) .OrderBy(t => t).ToList(); // List for batching new contributions var newTransactions = new List <FinancialTransaction>(); var completed = 0; ReportProgress(0, $"Verifying contribution import ({importedContributions.Count:N0} already exist)."); string[] row; // Uses a look-ahead enumerator: this call will move to the next record immediately while ((row = csvData.Database.FirstOrDefault()) != null) { var individualIdKey = row[IndividualID]; var contributionIdKey = row[ContributionID]; var contributionId = contributionIdKey.AsType <int?>(); if (contributionId != null && !importedContributions.Contains((int)contributionId)) { var transaction = new FinancialTransaction { CreatedByPersonAliasId = ImportPersonAliasId, ModifiedByPersonAliasId = ImportPersonAliasId, TransactionTypeValueId = TransactionTypeContributionId, ForeignKey = contributionId.ToString(), ForeignId = contributionId }; int?giverAliasId = null; var personKeys = GetPersonKeys(individualIdKey); if (personKeys != null && personKeys.PersonAliasId > 0) { giverAliasId = personKeys.PersonAliasId; transaction.CreatedByPersonAliasId = giverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } else if (AnonymousGiverAliasId != null && AnonymousGiverAliasId > 0) { giverAliasId = AnonymousGiverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } var summary = row[Memo] as string; if (!string.IsNullOrWhiteSpace(summary)) { transaction.Summary = summary; } var batchIdKey = row[ContributionBatchID]; var batchId = batchIdKey.AsType <int?>(); if (batchId != null && ImportedBatches.Any(b => b.Key.Equals(batchId))) { transaction.BatchId = ImportedBatches.FirstOrDefault(b => b.Key.Equals(batchId)).Value; } else { // use the default batch for any non-matching transactions transaction.BatchId = defaultBatchId; } var receivedDateKey = row[ReceivedDate]; var receivedDate = receivedDateKey.AsType <DateTime?>(); if (receivedDate != null) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; transaction.ModifiedDateTime = ImportDateTime; } var contributionType = row[ContributionTypeName]; var creditCardType = row[ContributionCreditCardType]; if (!string.IsNullOrWhiteSpace(contributionType)) { // set default source to onsite, exceptions listed below transaction.SourceTypeValueId = sourceTypeOnsite; int?paymentCurrencyTypeId = null, creditCardTypeId = null; if (contributionType.Equals("cash", StringComparison.CurrentCultureIgnoreCase)) { paymentCurrencyTypeId = currencyTypeCash; } else if (contributionType.Equals("check", StringComparison.CurrentCultureIgnoreCase)) { paymentCurrencyTypeId = currencyTypeCheck; } else if (contributionType.Equals("ach", StringComparison.CurrentCultureIgnoreCase)) { paymentCurrencyTypeId = currencyTypeACH; transaction.SourceTypeValueId = sourceTypeWebsite; } else if (contributionType.Equals("credit card", StringComparison.CurrentCultureIgnoreCase)) { paymentCurrencyTypeId = currencyTypeCreditCard; transaction.SourceTypeValueId = sourceTypeWebsite; // Determine CC Type if (!string.IsNullOrWhiteSpace(creditCardType)) { creditCardTypeId = creditCardTypes.Where(c => c.Value.StartsWith(creditCardType, StringComparison.CurrentCultureIgnoreCase) || c.Description.StartsWith(creditCardType, StringComparison.CurrentCultureIgnoreCase)) .Select(c => c.Id).FirstOrDefault(); } } else { paymentCurrencyTypeId = currencyTypeNonCash; } var paymentDetail = new FinancialPaymentDetail { CreatedDateTime = receivedDate, CreatedByPersonAliasId = giverAliasId, ModifiedDateTime = ImportDateTime, ModifiedByPersonAliasId = giverAliasId, CurrencyTypeValueId = paymentCurrencyTypeId, CreditCardTypeValueId = creditCardTypeId, ForeignKey = contributionId.ToString(), ForeignId = contributionId }; transaction.FinancialPaymentDetail = paymentDetail; } var transactionCode = row[CheckNumber] as string; // if transaction code provided, put it in the transaction code if (!string.IsNullOrEmpty(transactionCode)) { transaction.TransactionCode = transactionCode; // check for SecureGive kiosk transactions if (transactionCode.StartsWith("SG")) { transaction.SourceTypeValueId = sourceTypeKiosk; } } var fundName = row[FundName] as string; var subFund = row[SubFundName] as string; var fundGLAccount = row[FundGLAccount] as string; var subFundGLAccount = row[SubFundGLAccount] as string; var isFundActiveKey = row[FundIsActive]; var isFundActive = isFundActiveKey.AsType <bool?>(); var isSubFundActiveKey = row[SubFundIsActive]; var isSubFundActive = isSubFundActiveKey.AsType <bool?>(); var statedValueKey = row[StatedValue]; var statedValue = statedValueKey.AsType <decimal?>(); var amountKey = row[Amount]; var amount = amountKey.AsType <decimal?>(); if (!string.IsNullOrWhiteSpace(fundName) & amount != null) { int transactionAccountId; var parentAccount = accountList.FirstOrDefault(a => a.Name.Equals(fundName.Truncate(50))); if (parentAccount == null) { parentAccount = AddAccount(lookupContext, fundName, fundGLAccount, null, null, isFundActive, null, null, null, null, "", "", null); accountList.Add(parentAccount); } if (!string.IsNullOrWhiteSpace(subFund)) { int?campusFundId = null; // assign a campus if the subfund is a campus fund var campusFund = CampusList.FirstOrDefault(c => subFund.Contains(c.Name) || subFund.Contains(c.ShortCode)); if (campusFund != null) { campusFundId = campusFund.Id; } // add info to easily find/assign this fund in the view subFund = $"{fundName} {subFund}"; var childAccount = accountList.FirstOrDefault(c => c.Name.Equals(subFund.Truncate(50)) && c.ParentAccountId == parentAccount.Id); if (childAccount == null) { // create a child account with a campusId if it was set childAccount = AddAccount(lookupContext, subFund, subFundGLAccount, campusFundId, parentAccount.Id, isSubFundActive, null, null, null, null, "", "", null); accountList.Add(childAccount); } transactionAccountId = childAccount.Id; } else { transactionAccountId = parentAccount.Id; } if (amount == 0 && statedValue != null && statedValue != 0) { amount = statedValue; } var transactionDetail = new FinancialTransactionDetail { Amount = (decimal)amount, CreatedDateTime = receivedDate, AccountId = transactionAccountId }; transaction.TransactionDetails.Add(transactionDetail); if (amount < 0) { transaction.RefundDetails = new FinancialTransactionRefund(); transaction.RefundDetails.CreatedDateTime = receivedDate; transaction.RefundDetails.RefundReasonValueId = refundReasons.Where(dv => summary != null && dv.Value.Contains(summary)) .Select(dv => (int?)dv.Id).FirstOrDefault(); transaction.RefundDetails.RefundReasonSummary = summary; } } newTransactions.Add(transaction); completed++; if (completed % (ReportingNumber * 10) < 1) { ReportProgress(0, $"{completed:N0} contributions imported."); } else if (completed % ReportingNumber < 1) { SaveContributions(newTransactions); newTransactions.Clear(); ReportPartialProgress(); } } } if (newTransactions.Any()) { SaveContributions(newTransactions); } ReportProgress(100, $"Finished contribution import: {completed:N0} contributions imported."); return(completed); }
/// <summary> /// Maps the contribution. /// </summary> /// <param name="csvData">The table data.</param> private int MapContribution( CSVInstance csvData ) { var lookupContext = new RockContext(); int transactionEntityTypeId = EntityTypeCache.Read( "Rock.Model.FinancialTransaction" ).Id; var transactionTypeContributionId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ), lookupContext ).Id; var currencyTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE ) ); int currencyTypeACH = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ) ) ).Id; int currencyTypeCash = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH ) ) ).Id; int currencyTypeCheck = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK ) ) ).Id; int currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ) ) ).Id; int? currencyTypeNonCash = currencyTypes.DefinedValues.Where( dv => dv.Value.Equals( "Non-Cash" ) ).Select( dv => ( int? )dv.Id ).FirstOrDefault(); if ( currencyTypeNonCash == null ) { var newTenderNonCash = new DefinedValue(); newTenderNonCash.Value = "Non-Cash"; newTenderNonCash.Description = "Non-Cash"; newTenderNonCash.DefinedTypeId = currencyTypes.Id; lookupContext.DefinedValues.Add( newTenderNonCash ); lookupContext.SaveChanges(); currencyTypeNonCash = newTenderNonCash.Id; } var creditCardTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE ) ).DefinedValues; int sourceTypeOnsite = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_ONSITE_COLLECTION ), lookupContext ).Id; int sourceTypeWebsite = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE ), lookupContext ).Id; int sourceTypeKiosk = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_KIOSK ), lookupContext ).Id; var refundReasons = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON ), lookupContext ).DefinedValues; var accountList = new FinancialAccountService( lookupContext ).Queryable().AsNoTracking().ToList(); int? defaultBatchId = null; if ( ImportedBatches.ContainsKey( 0 ) ) { defaultBatchId = ImportedBatches[0]; } // Get all imported contributions var importedContributions = new FinancialTransactionService( lookupContext ).Queryable().AsNoTracking() .Where( c => c.ForeignId != null ) .ToDictionary( t => ( int )t.ForeignId, t => ( int? )t.Id ); // List for batching new contributions var newTransactions = new List<FinancialTransaction>(); int completed = 0; ReportProgress( 0, string.Format( "Verifying contribution import ({0:N0} already exist).", importedContributions.Count ) ); string[] row; // Uses a look-ahead enumerator: this call will move to the next record immediately while ( (row = csvData.Database.FirstOrDefault()) != null ) { string individualIdKey = row[IndividualID]; int? individualId = individualIdKey.AsType<int?>(); string contributionIdKey = row[ContributionID]; int? contributionId = contributionIdKey.AsType<int?>(); if ( contributionId != null && !importedContributions.ContainsKey( ( int )contributionId ) ) { var transaction = new FinancialTransaction(); transaction.CreatedByPersonAliasId = ImportPersonAliasId; transaction.ModifiedByPersonAliasId = ImportPersonAliasId; transaction.TransactionTypeValueId = transactionTypeContributionId; transaction.ForeignKey = contributionId.ToString(); transaction.ForeignId = contributionId; int? giverAliasId = null; var personKeys = GetPersonKeys( individualId ); if ( personKeys != null && personKeys.PersonAliasId > 0 ) { giverAliasId = personKeys.PersonAliasId; transaction.CreatedByPersonAliasId = giverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } else if ( AnonymousGiverAliasId != null && AnonymousGiverAliasId > 0 ) { giverAliasId = AnonymousGiverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } string summary = row[Memo] as string; if ( !String.IsNullOrWhiteSpace( summary ) ) { transaction.Summary = summary; } string batchIdKey = row[ContributionBatchID]; int? batchId = batchIdKey.AsType<int?>(); if ( batchId != null && ImportedBatches.Any( b => b.Key.Equals( batchId ) ) ) { transaction.BatchId = ImportedBatches.FirstOrDefault( b => b.Key.Equals( batchId ) ).Value; } else { // use the default batch for any non-matching transactions transaction.BatchId = defaultBatchId; } string receivedDateKey = row[ReceivedDate]; DateTime? receivedDate = receivedDateKey.AsType<DateTime?>(); if ( receivedDate != null ) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; transaction.ModifiedDateTime = ImportDateTime; } string contributionType = row[ContributionTypeName].ToStringSafe().ToLower(); if ( !String.IsNullOrWhiteSpace( contributionType ) ) { // set default source to onsite, exceptions listed below transaction.SourceTypeValueId = sourceTypeOnsite; int? paymentCurrencyTypeId = null, creditCardTypeId = null; if ( contributionType == "cash" ) { paymentCurrencyTypeId = currencyTypeCash; } else if ( contributionType == "check" ) { paymentCurrencyTypeId = currencyTypeCheck; } else if ( contributionType == "ach" ) { paymentCurrencyTypeId = currencyTypeACH; transaction.SourceTypeValueId = sourceTypeWebsite; } else if ( contributionType == "credit card" ) { paymentCurrencyTypeId = currencyTypeCreditCard; transaction.SourceTypeValueId = sourceTypeWebsite; } else { paymentCurrencyTypeId = currencyTypeNonCash; } var paymentDetail = new FinancialPaymentDetail(); paymentDetail.CreatedDateTime = receivedDate; paymentDetail.CreatedByPersonAliasId = giverAliasId; paymentDetail.ModifiedDateTime = ImportDateTime; paymentDetail.ModifiedByPersonAliasId = giverAliasId; paymentDetail.CurrencyTypeValueId = paymentCurrencyTypeId; paymentDetail.CreditCardTypeValueId = creditCardTypeId; paymentDetail.ForeignKey = contributionId.ToString(); paymentDetail.ForeignId = contributionId; transaction.FinancialPaymentDetail = paymentDetail; } string checkNumber = row[CheckNumber] as string; // if the check number is valid, put it in the transaction code if ( checkNumber.AsType<int?>() != null ) { transaction.TransactionCode = checkNumber; } // check for SecureGive kiosk transactions else if ( !string.IsNullOrEmpty( checkNumber ) && checkNumber.StartsWith( "SG" ) ) { transaction.SourceTypeValueId = sourceTypeKiosk; } string fundName = row[FundName] as string; string subFund = row[SubFundName] as string; string fundGLAccount = row[FundGLAccount] as string; string subFundGLAccount = row[SubFundGLAccount] as string; string isFundActiveKey = row[FundIsActive]; Boolean? isFundActive = isFundActiveKey.AsType<Boolean?>(); string isSubFundActiveKey = row[SubFundIsActive]; Boolean? isSubFundActive = isSubFundActiveKey.AsType<Boolean?>(); string statedValueKey = row[StatedValue]; decimal? statedValue = statedValueKey.AsType<decimal?>(); string amountKey = row[Amount]; decimal? amount = amountKey.AsType<decimal?>(); if ( !String.IsNullOrWhiteSpace( fundName ) & amount != null ) { int transactionAccountId; var parentAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName.Truncate( 50 ) ) && a.CampusId == null ); if ( parentAccount == null ) { parentAccount = AddAccount( lookupContext, fundName, fundGLAccount, null, null, isFundActive ); accountList.Add( parentAccount ); } if ( !String.IsNullOrWhiteSpace( subFund ) ) { int? campusFundId = null; // assign a campus if the subfund is a campus fund var campusFund = CampusList.FirstOrDefault( c => subFund.StartsWith( c.Name ) || subFund.StartsWith( c.ShortCode ) ); if ( campusFund != null ) { // use full campus name as the subfund subFund = campusFund.Name; campusFundId = campusFund.Id; } // add info to easily find/assign this fund in the view subFund = string.Format( "{0} {1}", subFund, fundName ); var childAccount = accountList.FirstOrDefault( c => c.Name.Equals( subFund.Truncate( 50 ) ) && c.ParentAccountId == parentAccount.Id ); if ( childAccount == null ) { // create a child account with a campusId if it was set childAccount = AddAccount( lookupContext, subFund, subFundGLAccount, campusFundId, parentAccount.Id, isSubFundActive ); accountList.Add( childAccount ); } transactionAccountId = childAccount.Id; } else { transactionAccountId = parentAccount.Id; } if ( amount == 0 && statedValue != null && statedValue != 0 ) { amount = statedValue; } var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = ( decimal )amount; transactionDetail.CreatedDateTime = receivedDate; transactionDetail.AccountId = transactionAccountId; transaction.TransactionDetails.Add( transactionDetail ); if ( amount < 0 ) { transaction.RefundDetails = new FinancialTransactionRefund(); transaction.RefundDetails.CreatedDateTime = receivedDate; transaction.RefundDetails.RefundReasonValueId = refundReasons.Where( dv => summary != null && dv.Value.Contains( summary ) ) .Select( dv => ( int? )dv.Id ).FirstOrDefault(); transaction.RefundDetails.RefundReasonSummary = summary; } } newTransactions.Add( transaction ); completed++; if ( completed % (ReportingNumber * 10) < 1 ) { ReportProgress( 0, string.Format( "{0:N0} contributions imported.", completed ) ); } else if ( completed % ReportingNumber < 1 ) { SaveContributions( newTransactions ); newTransactions.Clear(); ReportPartialProgress(); } } } if ( newTransactions.Any() ) { SaveContributions( newTransactions ); } ReportProgress( 100, string.Format( "Finished contribution import: {0:N0} contributions imported.", completed ) ); return completed; }
/// <summary> /// Gets the payment information. /// </summary> /// <param name="parameters">The parameters.</param> /// <param name="person">The person.</param> /// <param name="rockContext">The rock context.</param> /// <param name="totalAmount">The total amount.</param> /// <param name="paymentDetail">The payment detail.</param> /// <returns></returns> private PaymentInfo GetPaymentInfo(PaymentParameters parameters, Person person, RockContext rockContext, decimal totalAmount, FinancialPaymentDetail paymentDetail) { PaymentInfo paymentInfo = null; if (parameters.AccountType.ToLower() == "credit") { if (parameters.ExpirationMonth < 1 || parameters.ExpirationMonth > 12) { GenerateResponse(HttpStatusCode.BadRequest, "ExpirationMonth is required and must be between 1 and 12 for credit transactions"); } var currentDate = DateTime.Now; var maxYear = currentDate.Year + 30; if (parameters.ExpirationYear < currentDate.Year || parameters.ExpirationYear > maxYear) { GenerateResponse(HttpStatusCode.BadRequest, string.Format("ExpirationYear is required and must be between {0} and {1} for credit transactions", currentDate.Year, maxYear)); } if (parameters.ExpirationYear <= currentDate.Year && parameters.ExpirationMonth < currentDate.Month) { GenerateResponse(HttpStatusCode.BadRequest, "The ExpirationMonth and ExpirationYear combination must not have already elapsed for credit transactions"); } if (string.IsNullOrWhiteSpace(parameters.Street1) || string.IsNullOrWhiteSpace(parameters.City) || string.IsNullOrWhiteSpace(parameters.State) || string.IsNullOrWhiteSpace(parameters.PostalCode)) { GenerateResponse(HttpStatusCode.BadRequest, "Street1, City, State, and PostalCode are required for credit transactions"); } paymentInfo = new CreditCardPaymentInfo() { Number = parameters.AccountNumber, Code = parameters.CCV ?? string.Empty, ExpirationDate = new DateTime(parameters.ExpirationYear, parameters.ExpirationMonth, 1), BillingStreet1 = parameters.Street1 ?? string.Empty, BillingStreet2 = parameters.Street2 ?? string.Empty, BillingCity = parameters.City ?? string.Empty, BillingState = parameters.State ?? string.Empty, BillingPostalCode = parameters.PostalCode ?? string.Empty, BillingCountry = parameters.Country ?? "USA" }; } else { if (string.IsNullOrWhiteSpace(parameters.RoutingNumber)) { GenerateResponse(HttpStatusCode.BadRequest, "RoutingNumber is required for ACH transactions"); return(null); } paymentInfo = new ACHPaymentInfo() { BankRoutingNumber = parameters.RoutingNumber, BankAccountNumber = parameters.AccountNumber, AccountType = parameters.AccountType.ToLower() == "checking" ? BankAccountType.Checking : BankAccountType.Savings }; } paymentInfo.Amount = totalAmount; paymentInfo.FirstName = parameters.FirstName ?? person.FirstName; paymentInfo.LastName = parameters.LastName ?? person.LastName; paymentInfo.Email = parameters.Email ?? person.Email; paymentInfo.Phone = parameters.PhoneNumber ?? string.Empty; paymentInfo.Street1 = parameters.Street1 ?? string.Empty; paymentInfo.Street2 = parameters.Street2 ?? string.Empty; paymentInfo.City = parameters.City ?? string.Empty; paymentInfo.State = parameters.State ?? string.Empty; paymentInfo.PostalCode = parameters.PostalCode ?? string.Empty; paymentInfo.Country = parameters.Country ?? "USA"; if (paymentInfo.CreditCardTypeValue != null) { paymentDetail.CreditCardTypeValueId = paymentInfo.CreditCardTypeValue.Id; } if (paymentInfo.CurrencyTypeValue != null) { paymentDetail.CurrencyTypeValueId = paymentInfo.CurrencyTypeValue.Id; } return(paymentInfo); }
/// <summary> /// Creates the saved account. /// </summary> /// <param name="parameters">The parameters.</param> /// <param name="paymentDetail">The payment detail.</param> /// <param name="financialGateway">The financial gateway.</param> /// <param name="person">The person.</param> /// <param name="rockContext">The rock context.</param> /// <returns></returns> private FinancialPersonSavedAccount CreateSavedAccount(PaymentParameters parameters, FinancialPaymentDetail paymentDetail, FinancialGateway financialGateway, Person person, RockContext rockContext) { var lastFour = paymentDetail.AccountNumberMasked.Substring(paymentDetail.AccountNumberMasked.Length - 4); var name = string.Empty; if (parameters.AccountType.ToLower() != "credit") { if (string.IsNullOrWhiteSpace(parameters.RoutingNumber)) { GenerateResponse(HttpStatusCode.BadRequest, "RoutingNumber is required for ACH transactions"); return(null); } if (string.IsNullOrWhiteSpace(parameters.AccountNumber)) { GenerateResponse(HttpStatusCode.BadRequest, "AccountNumber is required"); return(null); } name = "Bank card ***" + lastFour; var bankAccountService = new FinancialPersonBankAccountService(rockContext); var accountNumberSecured = FinancialPersonBankAccount.EncodeAccountNumber(parameters.RoutingNumber, parameters.AccountNumber); var bankAccount = bankAccountService.Queryable().Where(a => a.AccountNumberSecured == accountNumberSecured && a.PersonAliasId == person.PrimaryAliasId.Value).FirstOrDefault(); if (bankAccount == null) { bankAccount = new FinancialPersonBankAccount(); bankAccount.PersonAliasId = person.PrimaryAliasId.Value; bankAccount.AccountNumberMasked = paymentDetail.AccountNumberMasked; bankAccount.AccountNumberSecured = accountNumberSecured; bankAccountService.Add(bankAccount); } } else { name = "Credit card ***" + lastFour; } var savedAccount = new FinancialPersonSavedAccount { PersonAliasId = person.PrimaryAliasId, FinancialGatewayId = financialGateway.Id, Name = name, FinancialPaymentDetailId = paymentDetail.Id }; new FinancialPersonSavedAccountService(rockContext).Add(savedAccount); rockContext.SaveChanges(); return(savedAccount); }
private void ShowSuccess(GatewayComponent gatewayComponent, Person person, PaymentInfo paymentInfo, PaymentSchedule schedule, FinancialPaymentDetail paymentDetail, RockContext rockContext) { tdTransactionCodeReceipt.Description = TransactionCode; tdTransactionCodeReceipt.Visible = !string.IsNullOrWhiteSpace(TransactionCode); tdScheduleId.Description = ScheduleId.ToString(); tdScheduleId.Visible = ScheduleId.HasValue; tdNameReceipt.Description = paymentInfo.FullName; tdPhoneReceipt.Description = paymentInfo.Phone; tdEmailReceipt.Description = paymentInfo.Email; tdAddressReceipt.Description = string.Format("{0} {1}, {2} {3}", paymentInfo.Street1, paymentInfo.City, paymentInfo.State, paymentInfo.PostalCode); rptAccountListReceipt.DataSource = GetSelectedAccounts().Where(a => a.Amount != 0); rptAccountListReceipt.DataBind(); tdTotalReceipt.Description = paymentInfo.Amount.ToString("C"); tdPaymentMethodReceipt.Description = paymentInfo.CurrencyTypeValue.Description; string acctNumber = paymentInfo.MaskedNumber; if (string.IsNullOrWhiteSpace(acctNumber) && paymentDetail != null && !string.IsNullOrWhiteSpace(paymentDetail.AccountNumberMasked)) { acctNumber = paymentDetail.AccountNumberMasked; } tdAccountNumberReceipt.Description = acctNumber; tdAccountNumberReceipt.Visible = !string.IsNullOrWhiteSpace(acctNumber); tdWhenReceipt.Description = schedule != null?schedule.ToString() : "Today"; pnlConfirmation.Visible = false; pnlSuccess.Visible = true; }
/// <summary> /// Maps the contribution. /// </summary> /// <param name="tableData">The table data.</param> /// <param name="selectedColumns">The selected columns.</param> private void MapContribution(IQueryable <Row> tableData, List <string> selectedColumns = null) { var lookupContext = new RockContext(); int transactionEntityTypeId = EntityTypeCache.Read("Rock.Model.FinancialTransaction").Id; var transactionTypeContributionId = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION), lookupContext).Id; var currencyTypes = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE)); int currencyTypeACH = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH))).Id; int currencyTypeCash = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH))).Id; int currencyTypeCheck = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK))).Id; int currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD))).Id; int?currencyTypeNonCash = currencyTypes.DefinedValues.Where(dv => dv.Value.Equals("Non-Cash")).Select(dv => (int?)dv.Id).FirstOrDefault(); if (currencyTypeNonCash == null) { var newTenderNonCash = new DefinedValue(); newTenderNonCash.Value = "Non-Cash"; newTenderNonCash.Description = "Non-Cash"; newTenderNonCash.DefinedTypeId = currencyTypes.Id; lookupContext.DefinedValues.Add(newTenderNonCash); lookupContext.SaveChanges(); currencyTypeNonCash = newTenderNonCash.Id; } var creditCardTypes = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE)).DefinedValues; int sourceTypeOnsite = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_ONSITE_COLLECTION), lookupContext).Id; int sourceTypeWebsite = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE), lookupContext).Id; int sourceTypeKiosk = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_KIOSK), lookupContext).Id; var refundReasons = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON), lookupContext).DefinedValues; var accountList = new FinancialAccountService(lookupContext).Queryable().AsNoTracking().ToList(); int?defaultBatchId = null; if (ImportedBatches.ContainsKey(0)) { defaultBatchId = ImportedBatches[0]; } // Get all imported contributions var importedContributions = new FinancialTransactionService(lookupContext).Queryable().AsNoTracking() .Where(c => c.ForeignId != null) .ToDictionary(t => (int)t.ForeignId, t => (int?)t.Id); // List for batching new contributions var newTransactions = new List <FinancialTransaction>(); int completed = 0; int totalRows = tableData.Count(); int percentage = (totalRows - 1) / 100 + 1; ReportProgress(0, string.Format("Verifying contribution import ({0:N0} found, {1:N0} already exist).", totalRows, importedContributions.Count)); foreach (var row in tableData.Where(r => r != null)) { int?individualId = row["Individual_ID"] as int?; int?householdId = row["Household_ID"] as int?; int?contributionId = row["ContributionID"] as int?; if (contributionId != null && !importedContributions.ContainsKey((int)contributionId)) { var transaction = new FinancialTransaction(); transaction.CreatedByPersonAliasId = ImportPersonAliasId; transaction.ModifiedByPersonAliasId = ImportPersonAliasId; transaction.TransactionTypeValueId = transactionTypeContributionId; transaction.ForeignKey = contributionId.ToString(); transaction.ForeignId = contributionId; int?giverAliasId = null; var personKeys = GetPersonKeys(individualId, householdId); if (personKeys != null && personKeys.PersonAliasId > 0) { giverAliasId = personKeys.PersonAliasId; transaction.CreatedByPersonAliasId = giverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } string summary = row["Memo"] as string; if (summary != null) { transaction.Summary = summary; } int?batchId = row["BatchID"] as int?; if (batchId != null && ImportedBatches.Any(b => b.Key.Equals(batchId))) { transaction.BatchId = ImportedBatches.FirstOrDefault(b => b.Key.Equals(batchId)).Value; } else { // use the default batch for any non-matching transactions transaction.BatchId = defaultBatchId; } DateTime?receivedDate = row["Received_Date"] as DateTime?; if (receivedDate != null) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; transaction.ModifiedDateTime = ImportDateTime; } string cardType = row["Card_Type"] as string; string cardLastFour = row["Last_Four"] as string; string contributionType = row["Contribution_Type_Name"].ToStringSafe().ToLower(); if (contributionType != null) { // set default source to onsite, exceptions listed below transaction.SourceTypeValueId = sourceTypeOnsite; int?paymentCurrencyTypeId = null, creditCardTypeId = null; if (contributionType == "cash") { paymentCurrencyTypeId = currencyTypeCash; } else if (contributionType == "check") { paymentCurrencyTypeId = currencyTypeCheck; } else if (contributionType == "ach") { paymentCurrencyTypeId = currencyTypeACH; transaction.SourceTypeValueId = sourceTypeWebsite; } else if (contributionType == "credit card") { paymentCurrencyTypeId = currencyTypeCreditCard; transaction.SourceTypeValueId = sourceTypeWebsite; if (cardType != null) { creditCardTypeId = creditCardTypes.Where(t => t.Value.Equals(cardType)).Select(t => (int?)t.Id).FirstOrDefault(); } } else { paymentCurrencyTypeId = currencyTypeNonCash; } var paymentDetail = new FinancialPaymentDetail(); paymentDetail.CreatedDateTime = receivedDate; paymentDetail.CreatedByPersonAliasId = giverAliasId; paymentDetail.ModifiedDateTime = ImportDateTime; paymentDetail.ModifiedByPersonAliasId = giverAliasId; paymentDetail.CurrencyTypeValueId = paymentCurrencyTypeId; paymentDetail.CreditCardTypeValueId = creditCardTypeId; paymentDetail.AccountNumberMasked = cardLastFour; paymentDetail.ForeignKey = contributionId.ToString(); paymentDetail.ForeignId = contributionId; transaction.FinancialPaymentDetail = paymentDetail; } string checkNumber = row["Check_Number"] as string; // if the check number is valid, put it in the transaction code if (checkNumber.AsType <int?>() != null) { transaction.TransactionCode = checkNumber; } // check for SecureGive kiosk transactions else if (!string.IsNullOrEmpty(checkNumber) && checkNumber.StartsWith("SG")) { transaction.SourceTypeValueId = sourceTypeKiosk; } string fundName = row["Fund_Name"] as string; string subFund = row["Sub_Fund_Name"] as string; string fundGLAccount = row["Fund_GL_Account"] as string; string subFundGLAccount = row["Sub_Fund_GL_Account"] as string; Boolean?isFundActive = row["Fund_Is_active"] as Boolean?; decimal?statedValue = row["Stated_Value"] as decimal?; decimal?amount = row["Amount"] as decimal?; if (fundName != null & amount != null) { int transactionAccountId; var parentAccount = accountList.FirstOrDefault(a => a.Name.Equals(fundName) && a.CampusId == null); if (parentAccount == null) { parentAccount = AddAccount(lookupContext, fundName, fundGLAccount, null, null, isFundActive); accountList.Add(parentAccount); } if (subFund != null) { int?campusFundId = null; // assign a campus if the subfund is a campus fund var campusFund = CampusList.FirstOrDefault(c => subFund.StartsWith(c.Name) || subFund.StartsWith(c.ShortCode)); if (campusFund != null) { // use full campus name as the subfund subFund = campusFund.Name; campusFundId = campusFund.Id; } // add info to easily find/assign this fund in the view subFund = string.Format("{0} {1}", subFund, fundName); var childAccount = accountList.FirstOrDefault(c => c.Name.Equals(subFund) && c.ParentAccountId == parentAccount.Id); if (childAccount == null) { // create a child account with a campusId if it was set childAccount = AddAccount(lookupContext, subFund, subFundGLAccount, campusFundId, parentAccount.Id, isFundActive); accountList.Add(childAccount); } transactionAccountId = childAccount.Id; } else { transactionAccountId = parentAccount.Id; } if (amount == 0 && statedValue != null && statedValue != 0) { amount = statedValue; } var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = (decimal)amount; transactionDetail.CreatedDateTime = receivedDate; transactionDetail.AccountId = transactionAccountId; transaction.TransactionDetails.Add(transactionDetail); if (amount < 0) { transaction.RefundDetails = new FinancialTransactionRefund(); transaction.RefundDetails.CreatedDateTime = receivedDate; transaction.RefundDetails.RefundReasonValueId = refundReasons.Where(dv => summary != null && dv.Value.Contains(summary)) .Select(dv => (int?)dv.Id).FirstOrDefault(); transaction.RefundDetails.RefundReasonSummary = summary; } } newTransactions.Add(transaction); completed++; if (completed % percentage < 1) { int percentComplete = completed / percentage; ReportProgress(percentComplete, string.Format("{0:N0} contributions imported ({1}% complete).", completed, percentComplete)); } else if (completed % ReportingNumber < 1) { SaveContributions(newTransactions); newTransactions.Clear(); ReportPartialProgress(); } } } if (newTransactions.Any()) { SaveContributions(newTransactions); } ReportProgress(100, string.Format("Finished contribution import: {0:N0} contributions imported.", completed)); }
/// <summary> /// Maps the contribution. /// </summary> /// <param name="csvData">The table data.</param> private int MapContribution(CSVInstance csvData) { var lookupContext = new RockContext(); int transactionEntityTypeId = EntityTypeCache.Read("Rock.Model.FinancialTransaction").Id; var transactionTypeContributionId = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION), lookupContext).Id; var currencyTypes = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE)); int currencyTypeACH = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH))).Id; int currencyTypeCash = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH))).Id; int currencyTypeCheck = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK))).Id; int currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD))).Id; int?currencyTypeNonCash = currencyTypes.DefinedValues.Where(dv => dv.Value.Equals("Non-Cash")).Select(dv => (int?)dv.Id).FirstOrDefault(); if (currencyTypeNonCash == null) { var newTenderNonCash = new DefinedValue(); newTenderNonCash.Value = "Non-Cash"; newTenderNonCash.Description = "Non-Cash"; newTenderNonCash.DefinedTypeId = currencyTypes.Id; lookupContext.DefinedValues.Add(newTenderNonCash); lookupContext.SaveChanges(); currencyTypeNonCash = newTenderNonCash.Id; } var creditCardTypes = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE)).DefinedValues; int sourceTypeOnsite = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_ONSITE_COLLECTION), lookupContext).Id; int sourceTypeWebsite = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE), lookupContext).Id; int sourceTypeKiosk = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_KIOSK), lookupContext).Id; var refundReasons = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON), lookupContext).DefinedValues; var accountList = new FinancialAccountService(lookupContext).Queryable().AsNoTracking().ToList(); int?defaultBatchId = null; if (ImportedBatches.ContainsKey(0)) { defaultBatchId = ImportedBatches[0]; } // Get all imported contributions var importedContributions = new FinancialTransactionService(lookupContext).Queryable().AsNoTracking() .Where(c => c.ForeignId != null) .ToDictionary(t => (int)t.ForeignId, t => (int?)t.Id); // List for batching new contributions var newTransactions = new List <FinancialTransaction>(); int completed = 0; ReportProgress(0, string.Format("Verifying contribution import ({0:N0} already exist).", importedContributions.Count)); string[] row; // Uses a look-ahead enumerator: this call will move to the next record immediately while ((row = csvData.Database.FirstOrDefault()) != null) { string individualIdKey = row[IndividualID]; int? individualId = individualIdKey.AsType <int?>(); string contributionIdKey = row[ContributionID]; int? contributionId = contributionIdKey.AsType <int?>(); if (contributionId != null && !importedContributions.ContainsKey((int)contributionId)) { var transaction = new FinancialTransaction(); transaction.CreatedByPersonAliasId = ImportPersonAliasId; transaction.ModifiedByPersonAliasId = ImportPersonAliasId; transaction.TransactionTypeValueId = transactionTypeContributionId; transaction.ForeignKey = contributionId.ToString(); transaction.ForeignId = contributionId; int?giverAliasId = null; var personKeys = GetPersonKeys(individualId); if (personKeys != null && personKeys.PersonAliasId > 0) { giverAliasId = personKeys.PersonAliasId; transaction.CreatedByPersonAliasId = giverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } string summary = row[Memo] as string; if (summary != null) { transaction.Summary = summary; } string batchIdKey = row[ContributionBatchID]; int? batchId = batchIdKey.AsType <int?>(); if (batchId != null && ImportedBatches.Any(b => b.Key.Equals(batchId))) { transaction.BatchId = ImportedBatches.FirstOrDefault(b => b.Key.Equals(batchId)).Value; } else { // use the default batch for any non-matching transactions transaction.BatchId = defaultBatchId; } string receivedDateKey = row[ReceivedDate]; DateTime?receivedDate = receivedDateKey.AsType <DateTime?>(); if (receivedDate != null) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; transaction.ModifiedDateTime = ImportDateTime; } string contributionType = row[ContributionTypeName].ToStringSafe().ToLower(); if (contributionType != null) { // set default source to onsite, exceptions listed below transaction.SourceTypeValueId = sourceTypeOnsite; int?paymentCurrencyTypeId = null, creditCardTypeId = null; if (contributionType == "cash") { paymentCurrencyTypeId = currencyTypeCash; } else if (contributionType == "check") { paymentCurrencyTypeId = currencyTypeCheck; } else if (contributionType == "ach") { paymentCurrencyTypeId = currencyTypeACH; transaction.SourceTypeValueId = sourceTypeWebsite; } else if (contributionType == "credit card") { paymentCurrencyTypeId = currencyTypeCreditCard; transaction.SourceTypeValueId = sourceTypeWebsite; } else { paymentCurrencyTypeId = currencyTypeNonCash; } var paymentDetail = new FinancialPaymentDetail(); paymentDetail.CreatedDateTime = receivedDate; paymentDetail.CreatedByPersonAliasId = giverAliasId; paymentDetail.ModifiedDateTime = ImportDateTime; paymentDetail.ModifiedByPersonAliasId = giverAliasId; paymentDetail.CurrencyTypeValueId = paymentCurrencyTypeId; paymentDetail.CreditCardTypeValueId = creditCardTypeId; paymentDetail.ForeignKey = contributionId.ToString(); paymentDetail.ForeignId = contributionId; transaction.FinancialPaymentDetail = paymentDetail; } string checkNumber = row[CheckNumber] as string; // if the check number is valid, put it in the transaction code if (checkNumber.AsType <int?>() != null) { transaction.TransactionCode = checkNumber; } // check for SecureGive kiosk transactions else if (!string.IsNullOrEmpty(checkNumber) && checkNumber.StartsWith("SG")) { transaction.SourceTypeValueId = sourceTypeKiosk; } string fundName = row[FundName] as string; string subFund = row[SubFundName] as string; string fundGLAccount = row[FundGLAccount] as string; string subFundGLAccount = row[SubFundGLAccount] as string; string isFundActiveKey = row[FundIsActive]; Boolean?isFundActive = isFundActiveKey.AsType <Boolean?>(); string statedValueKey = row[StatedValue]; decimal?statedValue = statedValueKey.AsType <decimal?>(); string amountKey = row[Amount]; decimal?amount = amountKey.AsType <decimal?>(); if (fundName != null & amount != null) { int transactionAccountId; var parentAccount = accountList.FirstOrDefault(a => a.Name.Equals(fundName) && a.CampusId == null); if (parentAccount == null) { parentAccount = AddAccount(lookupContext, fundName, fundGLAccount, null, null, isFundActive); accountList.Add(parentAccount); } if (!String.IsNullOrWhiteSpace(subFund)) { int?campusFundId = null; // assign a campus if the subfund is a campus fund var campusFund = CampusList.FirstOrDefault(c => subFund.StartsWith(c.Name) || subFund.StartsWith(c.ShortCode)); if (campusFund != null) { // use full campus name as the subfund subFund = campusFund.Name; campusFundId = campusFund.Id; } // add info to easily find/assign this fund in the view subFund = string.Format("{0} {1}", subFund, fundName); var childAccount = accountList.FirstOrDefault(c => c.Name.Equals(subFund) && c.ParentAccountId == parentAccount.Id); if (childAccount == null) { // create a child account with a campusId if it was set childAccount = AddAccount(lookupContext, subFund, subFundGLAccount, campusFundId, parentAccount.Id, isFundActive); accountList.Add(childAccount); } transactionAccountId = childAccount.Id; } else { transactionAccountId = parentAccount.Id; } if (amount == 0 && statedValue != null && statedValue != 0) { amount = statedValue; } var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = (decimal)amount; transactionDetail.CreatedDateTime = receivedDate; transactionDetail.AccountId = transactionAccountId; transaction.TransactionDetails.Add(transactionDetail); if (amount < 0) { transaction.RefundDetails = new FinancialTransactionRefund(); transaction.RefundDetails.CreatedDateTime = receivedDate; transaction.RefundDetails.RefundReasonValueId = refundReasons.Where(dv => summary != null && dv.Value.Contains(summary)) .Select(dv => (int?)dv.Id).FirstOrDefault(); transaction.RefundDetails.RefundReasonSummary = summary; } } newTransactions.Add(transaction); completed++; if (completed % (ReportingNumber * 10) < 1) { ReportProgress(0, string.Format("{0:N0} contributions imported.", completed)); } else if (completed % ReportingNumber < 1) { SaveContributions(newTransactions); newTransactions.Clear(); ReportPartialProgress(); } } } if (newTransactions.Any()) { SaveContributions(newTransactions); } ReportProgress(100, string.Format("Finished contribution import: {0:N0} contributions imported.", completed)); return(completed); }
/// <summary> /// Maps the contribution. /// </summary> /// <param name="tableData">The table data.</param> /// <param name="totalRows">The total rows.</param> private void MapContribution(IQueryable <Row> tableData, long totalRows = 0) { var lookupContext = new RockContext(); var transactionTypeContributionId = DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid(), lookupContext).Id; var currencyTypes = DefinedTypeCache.Get(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE)); var currencyTypeACH = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH))).Id; var currencyTypeCash = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH))).Id; var currencyTypeCheck = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK))).Id; var currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD))).Id; var currencyTypeNonCash = currencyTypes.DefinedValues.Where(dv => dv.Value.Equals("Non-Cash")).Select(dv => ( int? )dv.Id).FirstOrDefault(); if (currencyTypeNonCash == null) { var newTenderNonCash = new DefinedValue { Value = "Non-Cash", Description = "Non-Cash", DefinedTypeId = currencyTypes.Id }; lookupContext.DefinedValues.Add(newTenderNonCash); lookupContext.SaveChanges(); currencyTypeNonCash = newTenderNonCash.Id; } var creditCardTypes = DefinedTypeCache.Get(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE)).DefinedValues; var refundReasons = DefinedTypeCache.Get(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON), lookupContext).DefinedValues; var accountList = new FinancialAccountService(lookupContext).Queryable().AsNoTracking().ToList(); int?defaultBatchId = null; if (ImportedBatches.ContainsKey(0)) { defaultBatchId = ImportedBatches[0]; } // Get all imported contributions var importedContributions = new FinancialTransactionService(lookupContext).Queryable().AsNoTracking() .Where(c => c.ForeignId != null) .ToDictionary(t => ( int )t.ForeignId, t => ( int? )t.Id); // List for batching new contributions var newTransactions = new List <FinancialTransaction>(); if (totalRows == 0) { totalRows = tableData.Count(); } var completedItems = 0; var percentage = (totalRows - 1) / 100 + 1; ReportProgress(0, $"Verifying contribution import ({totalRows:N0} found, {importedContributions.Count:N0} already exist)."); foreach (var row in tableData.Where(r => r != null)) { var individualId = row["Individual_ID"] as int?; var householdId = row["Household_ID"] as int?; var contributionId = row["ContributionID"] as int?; if (contributionId.HasValue && !importedContributions.ContainsKey(( int )contributionId)) { var transaction = new FinancialTransaction { CreatedByPersonAliasId = ImportPersonAliasId, ModifiedByPersonAliasId = ImportPersonAliasId, TransactionTypeValueId = transactionTypeContributionId, ForeignKey = contributionId.ToString(), ForeignId = contributionId }; int?giverAliasId = null; var personKeys = GetPersonKeys(individualId, householdId); if (personKeys != null && personKeys.PersonAliasId > 0) { giverAliasId = personKeys.PersonAliasId; transaction.CreatedByPersonAliasId = giverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } var summary = row["Memo"] as string; if (!string.IsNullOrWhiteSpace(summary)) { transaction.Summary = summary; } var batchId = row["BatchID"] as int?; if (batchId.HasValue && ImportedBatches.Any(b => b.Key.Equals(batchId))) { transaction.BatchId = ImportedBatches.FirstOrDefault(b => b.Key.Equals(batchId)).Value; } else { // use the default batch for any non-matching transactions transaction.BatchId = defaultBatchId; } var receivedDate = row["Received_Date"] as DateTime?; if (receivedDate.HasValue) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; transaction.ModifiedDateTime = ImportDateTime; } var contributionFields = row.Columns.Select(c => c.Name).ToList(); var cardType = contributionFields.Contains("Card_Type") ? row["Card_Type"] as string : string.Empty; var cardLastFour = contributionFields.Contains("Last_Four") ? row["Last_Four"] as string : string.Empty; var contributionType = contributionFields.Contains("Contribution_Type_Name") ? row["Contribution_Type_Name"] as string : string.Empty; if (!string.IsNullOrWhiteSpace(contributionType)) { // set default source to onsite, exceptions listed below transaction.SourceTypeValueId = TransactionSourceTypeOnsiteId; int?paymentCurrencyTypeId = null, creditCardTypeId = null; switch (contributionType.ToLower()) { case "cash": paymentCurrencyTypeId = currencyTypeCash; break; case "check": paymentCurrencyTypeId = currencyTypeCheck; break; case "ach": paymentCurrencyTypeId = currencyTypeACH; transaction.SourceTypeValueId = TransactionSourceTypeWebsiteId; break; case "credit card": paymentCurrencyTypeId = currencyTypeCreditCard; transaction.SourceTypeValueId = TransactionSourceTypeWebsiteId; if (!string.IsNullOrWhiteSpace(cardType)) { creditCardTypeId = creditCardTypes.Where(t => t.Value.Equals(cardType, StringComparison.OrdinalIgnoreCase)) .Select(t => ( int? )t.Id).FirstOrDefault(); } break; default: paymentCurrencyTypeId = currencyTypeNonCash; break; } var paymentDetail = new FinancialPaymentDetail { CreatedDateTime = receivedDate, CreatedByPersonAliasId = giverAliasId, ModifiedDateTime = ImportDateTime, ModifiedByPersonAliasId = giverAliasId, CurrencyTypeValueId = paymentCurrencyTypeId, CreditCardTypeValueId = creditCardTypeId, AccountNumberMasked = cardLastFour, ForeignKey = contributionId.ToString(), ForeignId = contributionId }; transaction.FinancialPaymentDetail = paymentDetail; } var checkNumber = row["Check_Number"] as string; // if the check number is valid, put it in the transaction code if (checkNumber.AsType <int?>().HasValue) { transaction.TransactionCode = checkNumber; } // check for SecureGive kiosk transactions else if (!string.IsNullOrWhiteSpace(checkNumber) && checkNumber.StartsWith("SG")) { transaction.SourceTypeValueId = TransactionSourceTypeKioskId; } var fundName = contributionFields.Contains("Fund_Name") ? row["Fund_Name"] as string : string.Empty; var fundType = contributionFields.Contains("Fund_type") ? row["Fund_type"] as string : string.Empty; var subFund = contributionFields.Contains("Sub_Fund_Name") ? row["Sub_Fund_Name"] as string : string.Empty; var fundGLAccount = contributionFields.Contains("Fund_GL_Account") ? row["Fund_GL_Account"] as string : string.Empty; var subFundGLAccount = contributionFields.Contains("Sub_Fund_GL_Account") ? row["Sub_Fund_GL_Account"] as string : string.Empty; var isFundActive = contributionFields.Contains("Fund_Is_active") ? row["Fund_Is_active"] as string : null; var statedValue = row["Stated_Value"] as decimal?; var amount = row["Amount"] as decimal?; if (!string.IsNullOrWhiteSpace(fundName) && amount.HasValue) { int transactionAccountId; var parentAccount = accountList.FirstOrDefault(a => !a.CampusId.HasValue && a.Name.Equals(fundName.Truncate(50), StringComparison.OrdinalIgnoreCase)); if (parentAccount == null) { int?accountTypeDefinedTypeId = null; if (!string.IsNullOrWhiteSpace(fundType)) { accountTypeDefinedTypeId = LoadAccountTypeDefinedValue(lookupContext, fundType); } parentAccount = AddFinancialAccount(lookupContext, fundName, $"{fundName} imported {ImportDateTime}", fundGLAccount, null, null, isFundActive.AsBooleanOrNull(), receivedDate, fundName.RemoveSpecialCharacters(), accountTypeValueId: accountTypeDefinedTypeId); accountList.Add(parentAccount); } if (!string.IsNullOrWhiteSpace(subFund)) { int?campusFundId = null; // assign a campus if the subfund is a campus fund var campusFund = CampusList.FirstOrDefault(c => subFund.StartsWith(c.Name, StringComparison.OrdinalIgnoreCase) || subFund.StartsWith(c.ShortCode, StringComparison.OrdinalIgnoreCase)); if (campusFund != null) { // use full campus name as the subfund subFund = campusFund.Name; campusFundId = campusFund.Id; } // add info to easily find/assign this fund in the view subFund = $"{subFund} {fundName}"; var childAccount = accountList.FirstOrDefault(c => c.ParentAccountId == parentAccount.Id && c.Name.Equals(subFund.Truncate(50), StringComparison.OrdinalIgnoreCase)); if (childAccount == null) { // create a child account with a campusId if it was set childAccount = AddFinancialAccount(lookupContext, subFund, $"{subFund} imported {ImportDateTime}", subFundGLAccount, campusFundId, parentAccount.Id, isFundActive.AsBooleanOrNull(), receivedDate, subFund.RemoveSpecialCharacters(), accountTypeValueId: parentAccount.AccountTypeValueId); accountList.Add(childAccount); } transactionAccountId = childAccount.Id; } else { transactionAccountId = parentAccount.Id; } if (amount == 0 && statedValue.HasValue && statedValue != 0) { amount = statedValue; } var transactionDetail = new FinancialTransactionDetail { Amount = ( decimal )amount, CreatedDateTime = receivedDate, AccountId = transactionAccountId }; transaction.TransactionDetails.Add(transactionDetail); if (amount < 0) { transaction.RefundDetails = new FinancialTransactionRefund(); transaction.RefundDetails.CreatedDateTime = receivedDate; transaction.RefundDetails.RefundReasonValueId = refundReasons.Where(dv => summary != null && dv.Value.Contains(summary)) .Select(dv => ( int? )dv.Id).FirstOrDefault(); transaction.RefundDetails.RefundReasonSummary = summary; } } newTransactions.Add(transaction); completedItems++; if (completedItems % percentage < 1) { var percentComplete = completedItems / percentage; ReportProgress(percentComplete, $"{completedItems:N0} contributions imported ({percentComplete}% complete)."); } if (completedItems % ReportingNumber < 1) { SaveContributions(newTransactions); newTransactions.Clear(); ReportPartialProgress(); } } } if (newTransactions.Any()) { SaveContributions(newTransactions); } ReportProgress(100, $"Finished contribution import: {completedItems:N0} contributions imported."); }
public HttpResponseMessage ScheduleGiving([FromBody] ScheduleParameters scheduleParameters) { var rockContext = new RockContext(); try { rockContext.WrapTransaction(() => { var person = GetExistingPerson(scheduleParameters.PersonId, rockContext); if (person == null) { GenerateResponse(HttpStatusCode.BadRequest, "An existing person is required to schedule giving"); } var totalAmount = CalculateTotalAmount(scheduleParameters, rockContext); var paymentSchedule = GetPaymentSchedule(scheduleParameters, person); var gatewayComponent = GatewayContainer.GetComponent(gatewayName); if (gatewayComponent == null) { GenerateResponse(HttpStatusCode.InternalServerError, "There was a problem creating the gateway component"); } var financialGateway = new FinancialGatewayService(rockContext).Queryable().FirstOrDefault(g => g.EntityTypeId == gatewayComponent.EntityType.Id); if (financialGateway == null) { GenerateResponse(HttpStatusCode.InternalServerError, "There was a problem creating the financial gateway"); } var savedAccount = GetExistingSavedAccount(scheduleParameters, person, rockContext); FinancialPaymentDetail paymentDetail = null; PaymentInfo paymentInfo = null; int?locationId = null; if (savedAccount == null) { locationId = CreateLocation(scheduleParameters, rockContext); paymentDetail = CreatePaymentDetail(scheduleParameters, person, locationId.Value, rockContext); savedAccount = CreateSavedAccount(scheduleParameters, paymentDetail, financialGateway, person, rockContext); paymentInfo = GetPaymentInfo(scheduleParameters, person, rockContext, totalAmount.Value, paymentDetail); } else { paymentDetail = savedAccount.FinancialPaymentDetail; locationId = paymentDetail.BillingLocationId; paymentInfo = savedAccount.GetReferencePayment(); UpdatePaymentInfoForSavedAccount(scheduleParameters, paymentInfo, person, rockContext, paymentDetail.BillingLocationId.Value, totalAmount.Value); } SaveLocationToFamilyIfNone(person, locationId.Value, rockContext); string errorMessage; var schedule = gatewayComponent.AddScheduledPayment(financialGateway, paymentSchedule, paymentInfo, out errorMessage); if (schedule == null || !string.IsNullOrWhiteSpace(errorMessage)) { GenerateResponse(HttpStatusCode.InternalServerError, errorMessage ?? "The gateway had a problem and/or did not create a transaction as expected"); } schedule.TransactionFrequencyValueId = paymentSchedule.TransactionFrequencyValue.Id; if (person.PrimaryAliasId.HasValue) { schedule.AuthorizedPersonAliasId = person.PrimaryAliasId.Value; } schedule.FinancialPaymentDetail = paymentDetail; schedule.FinancialPaymentDetail.CurrencyTypeValueId = paymentInfo.CurrencyTypeValue.Id; if (paymentInfo.CreditCardTypeValue != null) { schedule.FinancialPaymentDetail.CreditCardTypeValueId = paymentInfo.CreditCardTypeValue.Id; } foreach (var accountAmount in scheduleParameters.AmountDetails) { schedule.ScheduledTransactionDetails.Add(new FinancialScheduledTransactionDetail() { Amount = accountAmount.Amount, AccountId = accountAmount.TargetAccountId }); } new FinancialScheduledTransactionService(rockContext).Add(schedule); rockContext.SaveChanges(); }); } catch (HttpResponseException exception) { return(exception.Response); } catch (Exception exception) { var response = new HttpResponseMessage(HttpStatusCode.InternalServerError); response.Content = new StringContent(exception.Message); return(response); } return(new HttpResponseMessage(HttpStatusCode.NoContent)); }