protected void bbtnDelete_Click( object sender, EventArgs e ) { BootstrapButton bbtnDelete = (BootstrapButton)sender; RepeaterItem riItem = (RepeaterItem)bbtnDelete.NamingContainer; HiddenField hfScheduledTransactionId = (HiddenField)riItem.FindControl( "hfScheduledTransactionId" ); Literal content = (Literal)riItem.FindControl( "lLiquidContent" ); Button btnEdit = (Button)riItem.FindControl( "btnEdit" ); var rockContext = new Rock.Data.RockContext(); FinancialScheduledTransactionService fstService = new FinancialScheduledTransactionService( rockContext ); var currentTransaction = fstService.Get( Int32.Parse(hfScheduledTransactionId.Value) ); string errorMessage = string.Empty; if ( fstService.Cancel( currentTransaction, out errorMessage ) ) { rockContext.SaveChanges(); content.Text = String.Format( "<div class='alert alert-success'>Your recurring {0} has been deleted.</div>", GetAttributeValue( "TransactionLabel" ).ToLower() ); } else { content.Text = String.Format( "<div class='alert alert-danger'>An error occured while deleting your scheduled transation. Message: {0}</div>", errorMessage ); } bbtnDelete.Visible = false; btnEdit.Visible = false; }
private void DeleteOldTransaction( int scheduledTransactionId ) { using ( var rockContext = new Rock.Data.RockContext() ) { FinancialScheduledTransactionService fstService = new FinancialScheduledTransactionService( rockContext ); var currentTransaction = fstService.Get( scheduledTransactionId ); if ( currentTransaction != null && currentTransaction.FinancialGateway != null ) { currentTransaction.FinancialGateway.LoadAttributes( rockContext ); } string errorMessage = string.Empty; if ( fstService.Cancel( currentTransaction, out errorMessage ) ) { try { fstService.GetStatus( currentTransaction, out errorMessage ); } catch { } rockContext.SaveChanges(); //content.Text = String.Format( "<div class='alert alert-success'>Your recurring {0} has been deleted.</div>", GetAttributeValue( "TransactionLabel" ).ToLower() ); } else { //content.Text = String.Format( "<div class='alert alert-danger'>An error occured while deleting your scheduled transation. Message: {0}</div>", errorMessage ); } } }
private void SaveScheduledTransaction( FinancialGateway financialGateway, GatewayComponent gateway, Person person, PaymentInfo paymentInfo, PaymentSchedule schedule, FinancialScheduledTransaction scheduledTransaction, RockContext rockContext ) { scheduledTransaction.TransactionFrequencyValueId = schedule.TransactionFrequencyValue.Id; scheduledTransaction.StartDate = schedule.StartDate; scheduledTransaction.AuthorizedPersonAliasId = person.PrimaryAliasId.Value; scheduledTransaction.FinancialGatewayId = financialGateway.Id; if ( scheduledTransaction.FinancialPaymentDetail == null ) { scheduledTransaction.FinancialPaymentDetail = new FinancialPaymentDetail(); } scheduledTransaction.FinancialPaymentDetail.SetFromPaymentInfo( paymentInfo, gateway, rockContext ); Guid sourceGuid = Guid.Empty; if ( Guid.TryParse( GetAttributeValue( "Source" ), out sourceGuid ) ) { var source = DefinedValueCache.Read( sourceGuid ); if ( source != null ) { scheduledTransaction.SourceTypeValueId = source.Id; } } var changeSummary = new StringBuilder(); changeSummary.AppendFormat( "{0} starting {1}", schedule.TransactionFrequencyValue.Value, schedule.StartDate.ToShortDateString() ); changeSummary.AppendLine(); changeSummary.Append( paymentInfo.CurrencyTypeValue.Value ); if ( paymentInfo.CreditCardTypeValue != null ) { changeSummary.AppendFormat( " - {0}", paymentInfo.CreditCardTypeValue.Value ); } changeSummary.AppendFormat( " {0}", paymentInfo.MaskedNumber ); changeSummary.AppendLine(); foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) ) { var transactionDetail = new FinancialScheduledTransactionDetail(); transactionDetail.Amount = account.Amount; transactionDetail.AccountId = account.Id; scheduledTransaction.ScheduledTransactionDetails.Add( transactionDetail ); changeSummary.AppendFormat( "{0}: {1}", account.Name, account.Amount.FormatAsCurrency() ); changeSummary.AppendLine(); } if ( !string.IsNullOrWhiteSpace( paymentInfo.Comment1 ) ) { changeSummary.Append( paymentInfo.Comment1 ); changeSummary.AppendLine(); } var transactionService = new FinancialScheduledTransactionService( rockContext ); transactionService.Add( scheduledTransaction ); rockContext.SaveChanges(); // If this is a transfer, now we can delete the old transaction if ( _scheduledTransactionToBeTransferred != null ) { DeleteOldTransaction( _scheduledTransactionToBeTransferred.Id ); } // Add a note about the change var noteType = NoteTypeCache.Read( Rock.SystemGuid.NoteType.SCHEDULED_TRANSACTION_NOTE.AsGuid() ); if ( noteType != null ) { var noteService = new NoteService( rockContext ); var note = new Note(); note.NoteTypeId = noteType.Id; note.EntityId = scheduledTransaction.Id; note.Caption = "Created Transaction"; note.Text = changeSummary.ToString(); noteService.Add( note ); } rockContext.SaveChanges(); ScheduleId = scheduledTransaction.GatewayScheduleId; TransactionCode = scheduledTransaction.TransactionCode; }
/// <summary> /// Fetches the old (to be transferred) scheduled transaction and verifies /// that the target person is the same on the scheduled transaction. Then /// it puts it into the _scheduledTransactionToBeTransferred private field /// for use throughout the entry process so that its values can be used on /// the form for the new transaction. /// </summary> /// <param name="scheduledTransactionId">The scheduled transaction identifier.</param> private void InitializeTransfer( int? scheduledTransactionId ) { if ( scheduledTransactionId == null ) { return; } RockContext rockContext = new RockContext(); var scheduledTransaction = new FinancialScheduledTransactionService( rockContext ).Get( scheduledTransactionId.Value ); var personService = new PersonService( rockContext ); // get business giving id var givingIds = personService.GetBusinesses( _targetPerson.Id ).Select( g => g.GivingId ).ToList(); // add the person's regular giving id givingIds.Add( _targetPerson.GivingId ); // Make sure the current person is the authorized person, otherwise return if ( scheduledTransaction == null || ! givingIds.Contains( scheduledTransaction.AuthorizedPersonAlias.Person.GivingId ) ) { return; } _scheduledTransactionToBeTransferred = scheduledTransaction; // Set the frequency to be the same on the initial page build if ( !IsPostBack ) { btnFrequency.SelectedValue = scheduledTransaction.TransactionFrequencyValueId.ToString(); dtpStartDate.SelectedDate = ( scheduledTransaction.NextPaymentDate.HasValue ) ? scheduledTransaction.NextPaymentDate : RockDateTime.Today.AddDays( 1 ); } }
/// <summary> /// Processes the payment information. /// </summary> /// <param name="errorMessage">The error message.</param> /// <returns></returns> private bool ProcessPaymentInfo( out string errorMessage ) { errorMessage = string.Empty; var errorMessages = new List<string>(); // Validate that an amount was entered if ( SelectedAccounts.Sum( a => a.Amount ) <= 0 ) { errorMessages.Add( "Make sure you've entered an amount for at least one account" ); } // Validate that no negative amounts were entered if ( SelectedAccounts.Any( a => a.Amount < 0 ) ) { errorMessages.Add( "Make sure the amount you've entered for each account is a positive amount" ); } string howOften = DefinedValueCache.Read( btnFrequency.SelectedValueAsId().Value ).Name; DateTime when = DateTime.MinValue; // Make sure a repeating payment starts in the future if ( dtpStartDate.SelectedDate.HasValue && dtpStartDate.SelectedDate > DateTime.Today ) { when = dtpStartDate.SelectedDate.Value; } else { errorMessages.Add( "Make sure the Next Gift date is in the future (after today)" ); } if ( hfPaymentTab.Value == "ACH" ) { // Validate ach options if ( rblSavedAch.Items.Count > 0 && ( rblSavedAch.SelectedValueAsInt() ?? 0 ) > 0 ) { // TODO: Find saved account } else { if ( string.IsNullOrWhiteSpace( txtBankName.Text ) ) { errorMessages.Add( "Make sure to enter a bank name" ); } if ( string.IsNullOrWhiteSpace( txtRoutingNumber.Text ) ) { errorMessages.Add( "Make sure to enter a valid routing number" ); } if ( string.IsNullOrWhiteSpace( txtAccountNumber.Text ) ) { errorMessages.Add( "Make sure to enter a valid account number" ); } } } else if ( hfPaymentTab.Value == "CreditCard" ) { // validate cc options if ( rblSavedCC.Items.Count > 0 && ( rblSavedCC.SelectedValueAsInt() ?? 0 ) > 0 ) { // TODO: Find saved card } else { if ( Gateway.SplitNameOnCard ) { if ( string.IsNullOrWhiteSpace( txtCardFirstName.Text ) || string.IsNullOrWhiteSpace( txtCardLastName.Text ) ) { errorMessages.Add( "Make sure to enter a valid first and last name as it appears on your credit card" ); } } else { if ( string.IsNullOrWhiteSpace( txtCardName.Text ) ) { errorMessages.Add( "Make sure to enter a valid name as it appears on your credit card" ); } } if ( string.IsNullOrWhiteSpace( txtCreditCard.Text ) ) { errorMessages.Add( "Make sure to enter a valid credit card number" ); } var currentMonth = DateTime.Today; currentMonth = new DateTime( currentMonth.Year, currentMonth.Month, 1 ); if ( !mypExpiration.SelectedDate.HasValue || mypExpiration.SelectedDate.Value.CompareTo( currentMonth ) < 0 ) { errorMessages.Add( "Make sure to enter a valid credit card expiration date" ); } if ( string.IsNullOrWhiteSpace( txtCVV.Text ) ) { errorMessages.Add( "Make sure to enter a valid credit card security code" ); } } } if ( errorMessages.Any() ) { errorMessage = errorMessages.AsDelimited( "<br/>" ); return false; } using ( new UnitOfWorkScope() ) { FinancialScheduledTransaction scheduledTransaction = null; if ( ScheduledTransactionId.HasValue ) { scheduledTransaction = new FinancialScheduledTransactionService().Get( ScheduledTransactionId.Value ); } if ( scheduledTransaction == null ) { errorMessage = "There was a problem getting the transaction information"; return false; } if ( scheduledTransaction.AuthorizedPerson == null ) { errorMessage = "There was a problem determining the person associated with the transaction"; return false; } PaymentInfo paymentInfo = GetPaymentInfo( new PersonService(), scheduledTransaction ); if ( paymentInfo != null ) { tdName.Description = paymentInfo.FullName; tdTotal.Description = paymentInfo.Amount.ToString( "C" ); if (paymentInfo.CurrencyTypeValue != null) { tdPaymentMethod.Description = paymentInfo.CurrencyTypeValue.Description; tdPaymentMethod.Visible = true; } else { tdPaymentMethod.Visible = false; } if (string.IsNullOrWhiteSpace(paymentInfo.MaskedNumber)) { tdAccountNumber.Visible = false; } else { tdAccountNumber.Visible = true; tdAccountNumber.Description = paymentInfo.MaskedNumber; } tdWhen.Description = string.Format( "{0} starting on {1}", howOften, when.ToShortDateString()); } } rptAccountListConfirmation.DataSource = SelectedAccounts.Where( a => a.Amount != 0 ); rptAccountListConfirmation.DataBind(); string nextDate = dtpStartDate.SelectedDate.HasValue ? dtpStartDate.SelectedDate.Value.ToShortDateString() : "?"; string frequency = DefinedValueCache.Read( btnFrequency.SelectedValueAsInt() ?? 0 ).Description; tdWhen.Description = frequency + " starting on " + nextDate; return true; }
/// <summary> /// Handles the RowSelected event of the rGridGivingProfile control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RowEventArgs"/> instance containing the event data.</param> protected void rGridGivingProfile_Edit( object sender, RowEventArgs e ) { string urlEncodedKey = string.Empty; if ( TargetPerson != null ) { urlEncodedKey = TargetPerson.UrlEncodedKey; } else { var txn = new FinancialScheduledTransactionService( new RockContext() ).Get( (int)e.RowKeyValue ); if ( txn != null && txn.AuthorizedPerson != null ) { urlEncodedKey = txn.AuthorizedPerson.UrlEncodedKey; } } var parms = new Dictionary<string, string>(); parms.Add( "Txn", rGridGivingProfile.DataKeys[e.RowIndex]["id"].ToString() ); if ( !string.IsNullOrWhiteSpace( urlEncodedKey ) ) { parms.Add( "Person", urlEncodedKey ); } NavigateToLinkedPage( "EditPage", parms ); }
/// <summary> /// Processes the confirmation. /// </summary> /// <param name="errorMessage">The error message.</param> /// <returns></returns> private bool ProcessConfirmation( out string errorMessage ) { var rockContext = new RockContext(); if ( string.IsNullOrWhiteSpace( TransactionCode ) ) { GatewayComponent gateway = hfPaymentTab.Value == "ACH" ? _achGateway : _ccGateway; if ( gateway == null ) { errorMessage = "There was a problem creating the payment gateway information"; return false; } Person person = GetPerson( true ); if ( person == null ) { errorMessage = "There was a problem creating the person information"; return false; } if ( !person.PrimaryAliasId.HasValue) { errorMessage = "There was a problem creating the person's primary alias"; return false; } PaymentInfo paymentInfo = GetPaymentInfo(); if ( paymentInfo == null ) { errorMessage = "There was a problem creating the payment information"; return false; } else { paymentInfo.FirstName = person.FirstName; paymentInfo.LastName = person.LastName; } if ( paymentInfo.CreditCardTypeValue != null ) { CreditCardTypeValueId = paymentInfo.CreditCardTypeValue.Id; } PaymentSchedule schedule = GetSchedule(); if ( schedule != null ) { schedule.PersonId = person.Id; var scheduledTransaction = gateway.AddScheduledPayment( schedule, paymentInfo, out errorMessage ); if ( scheduledTransaction != null ) { scheduledTransaction.TransactionFrequencyValueId = schedule.TransactionFrequencyValue.Id; scheduledTransaction.AuthorizedPersonAliasId = person.PrimaryAliasId.Value; scheduledTransaction.GatewayEntityTypeId = EntityTypeCache.Read( gateway.TypeGuid ).Id; scheduledTransaction.CurrencyTypeValueId = paymentInfo.CurrencyTypeValue.Id; scheduledTransaction.CreditCardTypeValueId = CreditCardTypeValueId; var changeSummary = new StringBuilder(); changeSummary.AppendFormat( "{0} starting {1}", schedule.TransactionFrequencyValue.Value, schedule.StartDate.ToShortDateString() ); changeSummary.AppendLine(); changeSummary.Append( paymentInfo.CurrencyTypeValue.Value ); if (paymentInfo.CreditCardTypeValue != null) { changeSummary.AppendFormat( " - {0}", paymentInfo.CreditCardTypeValue.Value ); } changeSummary.AppendFormat( " {0}", paymentInfo.MaskedNumber ); changeSummary.AppendLine(); foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) ) { var transactionDetail = new FinancialScheduledTransactionDetail(); transactionDetail.Amount = account.Amount; transactionDetail.AccountId = account.Id; scheduledTransaction.ScheduledTransactionDetails.Add( transactionDetail ); changeSummary.AppendFormat( "{0}: {1:C2}", account.Name, account.Amount ); changeSummary.AppendLine(); } var transactionService = new FinancialScheduledTransactionService( rockContext ); transactionService.Add( scheduledTransaction ); rockContext.SaveChanges(); // Add a note about the change var noteTypeService = new NoteTypeService( rockContext ); var noteType = noteTypeService.Get( scheduledTransaction.TypeId, "Note" ); var noteService = new NoteService( rockContext ); var note = new Note(); note.NoteTypeId = noteType.Id; note.EntityId = scheduledTransaction.Id; note.Caption = "Created Transaction"; note.Text = changeSummary.ToString(); noteService.Add( note ); rockContext.SaveChanges(); ScheduleId = scheduledTransaction.GatewayScheduleId; TransactionCode = scheduledTransaction.TransactionCode; } else { return false; } } else { var transaction = gateway.Charge( paymentInfo, out errorMessage ); if ( transaction != null ) { transaction.TransactionDateTime = RockDateTime.Now; transaction.AuthorizedPersonAliasId = person.PrimaryAliasId; transaction.GatewayEntityTypeId = gateway.TypeId; transaction.TransactionTypeValueId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ) ).Id; transaction.CurrencyTypeValueId = paymentInfo.CurrencyTypeValue.Id; transaction.CreditCardTypeValueId = CreditCardTypeValueId; Guid sourceGuid = Guid.Empty; if ( Guid.TryParse( GetAttributeValue( "Source" ), out sourceGuid ) ) { transaction.SourceTypeValueId = DefinedValueCache.Read( sourceGuid ).Id; } foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) ) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = account.Amount; transactionDetail.AccountId = account.Id; transaction.TransactionDetails.Add( transactionDetail ); } var batchService = new FinancialBatchService( rockContext ); // Get the batch var batch = batchService.Get( GetAttributeValue( "BatchNamePrefix" ), paymentInfo.CurrencyTypeValue, paymentInfo.CreditCardTypeValue, transaction.TransactionDateTime.Value, gateway.BatchTimeOffset ); batch.ControlAmount += transaction.TotalAmount; transaction.BatchId = batch.Id; batch.Transactions.Add( transaction ); rockContext.SaveChanges(); TransactionCode = transaction.TransactionCode; } else { return false; } } 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; tdAccountNumberReceipt.Description = paymentInfo.MaskedNumber; 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 ) ) { 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; } return true; } else { pnlDupWarning.Visible = true; divActions.Visible = false; errorMessage = string.Empty; return false; } }
/// <summary> /// Processes the payments. /// </summary> /// <param name="gateway">The gateway.</param> /// <param name="batchNamePrefix">The batch name prefix.</param> /// <param name="payments">The payments.</param> /// <param name="batchUrlFormat">The batch URL format.</param> /// <returns></returns> public static string ProcessPayments( FinancialGateway gateway, string batchNamePrefix, List<Payment> payments, string batchUrlFormat = "" ) { int totalPayments = 0; int totalAlreadyDownloaded = 0; int totalNoScheduledTransaction = 0; int totalAdded = 0; var batches = new List<FinancialBatch>(); var batchSummary = new Dictionary<Guid, List<Payment>>(); var initialControlAmounts = new Dictionary<Guid, decimal>(); var allBatchChanges = new Dictionary<Guid, List<string>>(); var allTxnChanges = new Dictionary<Guid, List<string>>(); var txnPersonNames = new Dictionary<Guid, string>(); using ( var rockContext = new RockContext() ) { var accountService = new FinancialAccountService( rockContext ); var txnService = new FinancialTransactionService( rockContext ); var batchService = new FinancialBatchService( rockContext ); var scheduledTxnService = new FinancialScheduledTransactionService( rockContext ); var contributionTxnType = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid() ); var defaultAccount = accountService.Queryable() .Where( a => a.IsActive && !a.ParentAccountId.HasValue && ( !a.StartDate.HasValue || a.StartDate.Value <= RockDateTime.Now ) && ( !a.EndDate.HasValue || a.EndDate.Value >= RockDateTime.Now ) ) .OrderBy( a => a.Order ) .FirstOrDefault(); var batchTxnChanges = new Dictionary<Guid, List<string>>(); var batchBatchChanges = new Dictionary<Guid, List<string>>(); foreach ( var payment in payments.Where( p => p.Amount > 0.0M ) ) { totalPayments++; // Only consider transactions that have not already been added if ( txnService.GetByTransactionCode( payment.TransactionCode ) == null ) { var scheduledTransaction = scheduledTxnService.GetByScheduleId( payment.GatewayScheduleId ); if ( scheduledTransaction != null ) { scheduledTransaction.IsActive = payment.ScheduleActive; var txnChanges = new List<string>(); var transaction = new FinancialTransaction(); transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); transaction.Guid = Guid.NewGuid(); allTxnChanges.Add( transaction.Guid, txnChanges ); txnChanges.Add( "Created Transaction (Downloaded from Gateway)" ); transaction.TransactionCode = payment.TransactionCode; History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode ); transaction.TransactionDateTime = payment.TransactionDateTime; History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime ); transaction.ScheduledTransactionId = scheduledTransaction.Id; transaction.AuthorizedPersonAliasId = scheduledTransaction.AuthorizedPersonAliasId; History.EvaluateChange( txnChanges, "Person", string.Empty, scheduledTransaction.AuthorizedPersonAlias.Person.FullName ); txnPersonNames.Add( transaction.Guid, scheduledTransaction.AuthorizedPersonAlias.Person.FullName ); transaction.FinancialGatewayId = gateway.Id; History.EvaluateChange( txnChanges, "Gateway", string.Empty, gateway.Name ); transaction.TransactionTypeValueId = contributionTxnType.Id; History.EvaluateChange( txnChanges, "Type", string.Empty, contributionTxnType.Value ); var currencyTypeValue = payment.CurrencyTypeValue; var creditCardTypevalue = payment.CreditCardTypeValue; if ( scheduledTransaction.FinancialPaymentDetail != null ) { if ( currencyTypeValue == null && scheduledTransaction.FinancialPaymentDetail.CurrencyTypeValueId.HasValue ) { currencyTypeValue = DefinedValueCache.Read( scheduledTransaction.FinancialPaymentDetail.CurrencyTypeValueId.Value ); } if ( creditCardTypevalue == null && scheduledTransaction.FinancialPaymentDetail.CreditCardTypeValueId.HasValue ) { creditCardTypevalue = DefinedValueCache.Read( scheduledTransaction.FinancialPaymentDetail.CreditCardTypeValueId.Value ); } transaction.FinancialPaymentDetail.AccountNumberMasked = scheduledTransaction.FinancialPaymentDetail.AccountNumberMasked; transaction.FinancialPaymentDetail.NameOnCardEncrypted = scheduledTransaction.FinancialPaymentDetail.NameOnCardEncrypted; transaction.FinancialPaymentDetail.ExpirationMonthEncrypted = scheduledTransaction.FinancialPaymentDetail.ExpirationMonthEncrypted; transaction.FinancialPaymentDetail.ExpirationYearEncrypted = scheduledTransaction.FinancialPaymentDetail.ExpirationYearEncrypted; } if ( currencyTypeValue != null ) { transaction.FinancialPaymentDetail.CurrencyTypeValueId = currencyTypeValue.Id; History.EvaluateChange( txnChanges, "Currency Type", string.Empty, currencyTypeValue.Value ); } if ( creditCardTypevalue != null ) { transaction.FinancialPaymentDetail.CreditCardTypeValueId = creditCardTypevalue.Id; History.EvaluateChange( txnChanges, "Credit Card Type", string.Empty, creditCardTypevalue.Value ); } //transaction.SourceTypeValueId = DefinedValueCache.Read( sourceGuid ).Id; // Try to allocate the amount of the transaction based on the current scheduled transaction accounts decimal remainingAmount = payment.Amount; foreach ( var detail in scheduledTransaction.ScheduledTransactionDetails.Where( d => d.Amount != 0.0M ) ) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.AccountId = detail.AccountId; if ( detail.Amount <= remainingAmount ) { // If the configured amount for this account is less than or equal to the remaining // amount, allocate the configured amount transactionDetail.Amount = detail.Amount; remainingAmount -= detail.Amount; } else { // If the configured amount is greater than the remaining amount, only allocate // the remaining amount transaction.Summary = "Note: Downloaded transaction amount was less than the configured allocation amounts for the Scheduled Transaction."; detail.Amount = remainingAmount; detail.Summary = "Note: The downloaded amount was not enough to apply the configured amount to this account."; remainingAmount = 0.0M; } transaction.TransactionDetails.Add( transactionDetail ); History.EvaluateChange( txnChanges, detail.Account.Name, 0.0M.ToString( "C2" ), transactionDetail.Amount.ToString( "C2" ) ); History.EvaluateChange( txnChanges, "Summary", string.Empty, transactionDetail.Summary ); if ( remainingAmount <= 0.0M ) { // If there's no amount left, break out of details break; } } // If there's still amount left after allocating based on current config, add the remainder // to the account that was configured for the most amount if ( remainingAmount > 0.0M ) { transaction.Summary = "Note: Downloaded transaction amount was greater than the configured allocation amounts for the Scheduled Transaction."; var transactionDetail = transaction.TransactionDetails .OrderByDescending( d => d.Amount ) .First(); if ( transactionDetail == null && defaultAccount != null ) { transactionDetail = new FinancialTransactionDetail(); transactionDetail.AccountId = defaultAccount.Id; } if ( transactionDetail != null ) { transactionDetail.Amount += remainingAmount; transactionDetail.Summary = "Note: Extra amount was applied to this account."; } History.EvaluateChange( txnChanges, defaultAccount.Name, 0.0M.ToString( "C2" ), transactionDetail.Amount.ToString( "C2" ) ); History.EvaluateChange( txnChanges, "Summary", string.Empty, transactionDetail.Summary ); } // Get the batch var batch = batchService.Get( batchNamePrefix, currencyTypeValue, creditCardTypevalue, transaction.TransactionDateTime.Value, gateway.GetBatchTimeOffset(), batches ); var batchChanges = new List<string>(); if ( batch.Id != 0 ) { initialControlAmounts.AddOrIgnore( batch.Guid, batch.ControlAmount ); } batch.ControlAmount += transaction.TotalAmount; batch.Transactions.Add( transaction ); // Add summary if ( !batchSummary.ContainsKey( batch.Guid ) ) { batchSummary.Add( batch.Guid, new List<Payment>() ); } batchSummary[batch.Guid].Add( payment ); totalAdded++; } else { totalNoScheduledTransaction++; } } else { totalAlreadyDownloaded++; } } foreach ( var batch in batches ) { var batchChanges = new List<string>(); allBatchChanges.Add( batch.Guid, batchChanges ); if ( batch.Id == 0 ) { batchChanges.Add( "Generated the batch" ); History.EvaluateChange( batchChanges, "Batch Name", string.Empty, batch.Name ); History.EvaluateChange( batchChanges, "Status", null, batch.Status ); History.EvaluateChange( batchChanges, "Start Date/Time", null, batch.BatchStartDateTime ); History.EvaluateChange( batchChanges, "End Date/Time", null, batch.BatchEndDateTime ); } if ( initialControlAmounts.ContainsKey( batch.Guid ) ) { History.EvaluateChange( batchChanges, "Control Amount", initialControlAmounts[batch.Guid].ToString( "C2" ), batch.ControlAmount.ToString( "C2" ) ); } } rockContext.WrapTransaction( () => { rockContext.SaveChanges(); foreach ( var batch in batches ) { HistoryService.SaveChanges( rockContext, typeof( FinancialBatch ), Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), batch.Id, allBatchChanges[batch.Guid] ); foreach ( var transaction in batch.Transactions ) { if ( allTxnChanges.ContainsKey( transaction.Guid ) ) { HistoryService.SaveChanges( rockContext, typeof( FinancialBatch ), Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(), batch.Id, allTxnChanges[transaction.Guid], txnPersonNames[transaction.Guid], typeof( FinancialTransaction ), transaction.Id ); } } } rockContext.SaveChanges(); } ); } StringBuilder sb = new StringBuilder(); sb.AppendFormat( "<li>{0} {1} downloaded.</li>", totalPayments.ToString( "N0" ), ( totalPayments == 1 ? "payment" : "payments" ) ); if ( totalAlreadyDownloaded > 0 ) { sb.AppendFormat( "<li>{0} {1} previously downloaded and {2} already been added.</li>", totalAlreadyDownloaded.ToString( "N0" ), ( totalAlreadyDownloaded == 1 ? "payment was" : "payments were" ), ( totalAlreadyDownloaded == 1 ? "has" : "have" ) ); } if ( totalNoScheduledTransaction > 0 ) { sb.AppendFormat( "<li>{0} {1} could not be matched to an existing scheduled payment profile.</li>", totalNoScheduledTransaction.ToString( "N0" ), ( totalNoScheduledTransaction == 1 ? "payment" : "payments" ) ); } sb.AppendFormat( "<li>{0} {1} successfully added.</li>", totalAdded.ToString( "N0" ), ( totalAdded == 1 ? "payment was" : "payments were" ) ); foreach ( var batchItem in batchSummary ) { int items = batchItem.Value.Count; if (items > 0) { var batch = batches .Where( b => b.Guid.Equals( batchItem.Key ) ) .FirstOrDefault(); string batchName = string.Format("'{0} ({1})'", batch.Name, batch.BatchStartDateTime.Value.ToString("d")); if ( !string.IsNullOrWhiteSpace( batchUrlFormat ) ) { batchName = string.Format( "<a href='{0}'>{1}</a>", string.Format( batchUrlFormat, batch.Id ), batchName ); } decimal sum = batchItem.Value.Select( p => p.Amount ).Sum(); string summaryformat = items == 1 ? "<li>{0} transaction of {1} was added to the {2} batch.</li>" : "<li>{0} transactions totaling {1} were added to the {2} batch</li>"; sb.AppendFormat( summaryformat, items.ToString( "N0" ), sum.ToString( "C2" ), batchName ); } } return sb.ToString(); }
/// <summary> /// Processes the confirmation. /// </summary> /// <param name="errorMessage">The error message.</param> /// <returns></returns> private bool ProcessConfirmation( out string errorMessage ) { if ( string.IsNullOrWhiteSpace( TransactionCode ) ) { GatewayComponent gateway = hfPaymentTab.Value == "ACH" ? _achGateway : _ccGateway; if ( gateway == null ) { errorMessage = "There was a problem creating the payment gateway information"; return false; } Person person = GetPerson( true ); if ( person == null ) { errorMessage = "There was a problem creating the person information"; return false; } PaymentInfo paymentInfo = GetPaymentInfo(); if ( paymentInfo == null ) { errorMessage = "There was a problem creating the payment information"; return false; } else { paymentInfo.FirstName = person.FirstName; paymentInfo.LastName = person.LastName; } if ( paymentInfo.CreditCardTypeValue != null ) { CreditCardTypeValueId = paymentInfo.CreditCardTypeValue.Id; } PaymentSchedule schedule = GetSchedule(); if ( schedule != null ) { schedule.PersonId = person.Id; var scheduledTransaction = gateway.AddScheduledPayment( schedule, paymentInfo, out errorMessage ); if ( scheduledTransaction != null ) { scheduledTransaction.TransactionFrequencyValueId = schedule.TransactionFrequencyValue.Id; scheduledTransaction.AuthorizedPersonId = person.Id; scheduledTransaction.GatewayEntityTypeId = EntityTypeCache.Read( gateway.TypeGuid ).Id; foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) ) { var transactionDetail = new FinancialScheduledTransactionDetail(); transactionDetail.Amount = account.Amount; transactionDetail.AccountId = account.Id; scheduledTransaction.ScheduledTransactionDetails.Add( transactionDetail ); } var transactionService = new FinancialScheduledTransactionService(); transactionService.Add( scheduledTransaction, CurrentPersonId ); transactionService.Save( scheduledTransaction, CurrentPersonId ); ScheduleId = scheduledTransaction.GatewayScheduleId; TransactionCode = scheduledTransaction.TransactionCode; } else { return false; } } else { var transaction = gateway.Charge( paymentInfo, out errorMessage ); if ( transaction != null ) { transaction.TransactionDateTime = DateTime.Now; transaction.AuthorizedPersonId = person.Id; transaction.GatewayEntityTypeId = gateway.TypeId; transaction.Amount = paymentInfo.Amount; transaction.TransactionTypeValueId = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION)).Id; transaction.CurrencyTypeValueId = paymentInfo.CurrencyTypeValue.Id; transaction.CreditCardTypeValueId = CreditCardTypeValueId; Guid sourceGuid = Guid.Empty; if (Guid.TryParse(GetAttributeValue("Source"), out sourceGuid)) { transaction.SourceTypeValueId = DefinedValueCache.Read(sourceGuid).Id; } foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) ) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = account.Amount; transactionDetail.AccountId = account.Id; transaction.TransactionDetails.Add( transactionDetail ); } // Get the batch name string ccSuffix = string.Empty; if ( paymentInfo.CreditCardTypeValue != null ) { ccSuffix = paymentInfo.CreditCardTypeValue.GetAttributeValue( "BatchNameSuffix" ); } if ( string.IsNullOrWhiteSpace( ccSuffix ) ) { ccSuffix = paymentInfo.CurrencyTypeValue.Name; } string batchName = GetAttributeValue( "BatchNamePrefix" ).Trim() + " " + ccSuffix; using ( new UnitOfWorkScope() ) { var batchService = new FinancialBatchService(); var batch = batchService.Queryable() .Where( b => b.Status == BatchStatus.Open && b.BatchStartDateTime <= transaction.TransactionDateTime && b.BatchEndDateTime > transaction.TransactionDateTime && b.Name == batchName ) .FirstOrDefault(); if ( batch == null ) { batch = new FinancialBatch(); batch.Name = batchName; batch.Status = BatchStatus.Open; batch.BatchStartDateTime = transaction.TransactionDateTime.Value.Date.Add( gateway.BatchTimeOffset ); if ( batch.BatchStartDateTime > transaction.TransactionDateTime ) { batch.BatchStartDateTime.Value.AddDays( -1 ); } batch.BatchEndDateTime = batch.BatchStartDateTime.Value.AddDays( 1 ).AddMilliseconds( -1 ); batch.CreatedByPersonId = person.Id; batchService.Add( batch, CurrentPersonId ); batchService.Save( batch, CurrentPersonId ); batch = batchService.Get( batch.Id ); } batch.ControlAmount += transaction.Amount; batchService.Save( batch, CurrentPersonId ); var transactionService = new FinancialTransactionService(); transaction.BatchId = batch.Id; transactionService.Add( transaction, CurrentPersonId ); transactionService.Save( transaction, CurrentPersonId ); } TransactionCode = transaction.TransactionCode; } else { return false; } } tdTransactionCode.Description = TransactionCode; tdTransactionCode.Visible = !string.IsNullOrWhiteSpace( TransactionCode ); tdScheduleId.Description = ScheduleId; tdScheduleId.Visible = !string.IsNullOrWhiteSpace( ScheduleId ); // 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 ) ) { 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().GetByPersonId( person.Id ).Any(); } else { pnlSaveAccount.Visible = false; } return true; } else { pnlDupWarning.Visible = true; errorMessage = string.Empty; return false; } }
/// <summary> /// Processes the payments and returns a summary in HTML format /// </summary> /// <param name="gateway">The gateway.</param> /// <param name="batchNamePrefix">The batch name prefix.</param> /// <param name="payments">The payments.</param> /// <param name="batchUrlFormat">The batch URL format.</param> /// <param name="receiptEmail">The receipt email.</param> /// <param name="failedPaymentEmail">The failed payment email.</param> /// <param name="failedPaymentWorkflowType">Type of the failed payment workflow.</param> /// <returns></returns> public static string ProcessPayments(FinancialGateway gateway, string batchNamePrefix, List <Payment> payments, string batchUrlFormat, Guid?receiptEmail, Guid?failedPaymentEmail, Guid?failedPaymentWorkflowType) { int totalPayments = 0; int totalAlreadyDownloaded = 0; List <Payment> paymentsWithoutTransaction = new List <Payment>(); int totalAdded = 0; int totalReversals = 0; int totalFailures = 0; int totalStatusChanges = 0; var batchSummary = new Dictionary <Guid, List <Decimal> >(); var newTransactionsForReceiptEmails = new List <FinancialTransaction>(); var failedPayments = new List <FinancialTransaction>(); var contributionTxnType = DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid()); int?defaultAccountId = null; using (var rockContext2 = new RockContext()) { defaultAccountId = new FinancialAccountService(rockContext2).Queryable() .Where(a => a.IsActive && !a.ParentAccountId.HasValue && (!a.StartDate.HasValue || a.StartDate.Value <= RockDateTime.Now) && (!a.EndDate.HasValue || a.EndDate.Value >= RockDateTime.Now) ) .OrderBy(a => a.Order) .Select(a => a.Id) .FirstOrDefault(); } var batchTxnChanges = new Dictionary <Guid, List <string> >(); var batchBatchChanges = new Dictionary <Guid, List <string> >(); var scheduledTransactionIds = new List <int>(); List <FinancialTransaction> transactionsWithAttributes = new List <FinancialTransaction>(); foreach (var payment in payments.Where(p => p.Amount > 0.0M)) { using (var rockContext = new RockContext()) { totalPayments++; var financialTransactionService = new FinancialTransactionService(rockContext); FinancialTransaction originalTxn = null; List <FinancialTransaction> txns = null; // Find existing payments with same transaction code as long as it is not blank. if (payment.TransactionCode.IsNotNullOrWhiteSpace()) { txns = financialTransactionService .Queryable("TransactionDetails") .Where(t => t.FinancialGatewayId.HasValue && t.FinancialGatewayId.Value == gateway.Id && t.TransactionCode == payment.TransactionCode) .ToList(); originalTxn = txns.Any() ? txns.OrderBy(t => t.Id).First() : null; } FinancialScheduledTransaction scheduledTransaction = null; // We don't want to match a blank schedule ID, so if we don't have one then scheduledTransaction will stay NULL if (payment.GatewayScheduleId.IsNotNullOrWhiteSpace()) { scheduledTransaction = new FinancialScheduledTransactionService(rockContext).GetByScheduleId(payment.GatewayScheduleId, gateway.Id); } // Calculate whether a transaction needs to be added var txnAmount = CalculateTransactionAmount(payment, txns); if (txnAmount != 0.0M || (payment.IsFailure && originalTxn == null && scheduledTransaction != null)) { // Verify that the payment is for an existing scheduled transaction, or has the same transaction code as an existing payment if (scheduledTransaction != null || originalTxn != null) { var transaction = new FinancialTransaction(); transaction.Guid = Guid.NewGuid(); transaction.TransactionCode = payment.TransactionCode; transaction.TransactionDateTime = payment.TransactionDateTime; transaction.Status = payment.Status; transaction.IsSettled = payment.IsSettled; transaction.SettledGroupId = payment.SettledGroupId; transaction.SettledDate = payment.SettledDate; transaction.StatusMessage = payment.StatusMessage; transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); if (payment.ForeignKey.IsNotNullOrWhiteSpace()) { transaction.ForeignKey = payment.ForeignKey; } FinancialPaymentDetail financialPaymentDetail = null; List <ITransactionDetail> originalTxnDetails = new List <ITransactionDetail>(); if (scheduledTransaction != null) { scheduledTransactionIds.Add(scheduledTransaction.Id); if (payment.ScheduleActive.HasValue) { scheduledTransaction.IsActive = payment.ScheduleActive.Value; } transaction.ScheduledTransactionId = scheduledTransaction.Id; transaction.AuthorizedPersonAliasId = scheduledTransaction.AuthorizedPersonAliasId; transaction.SourceTypeValueId = scheduledTransaction.SourceTypeValueId; financialPaymentDetail = scheduledTransaction.FinancialPaymentDetail; scheduledTransaction.ScheduledTransactionDetails.ToList().ForEach(d => originalTxnDetails.Add(d)); } else { transaction.AuthorizedPersonAliasId = originalTxn.AuthorizedPersonAliasId; transaction.SourceTypeValueId = originalTxn.SourceTypeValueId; financialPaymentDetail = originalTxn.FinancialPaymentDetail; originalTxn.TransactionDetails.ToList().ForEach(d => originalTxnDetails.Add(d)); } transaction.FinancialGatewayId = gateway.Id; transaction.TransactionTypeValueId = contributionTxnType.Id; if (txnAmount < 0.0M) { transaction.Summary = "Reversal created for previous transaction(s) to correct the total transaction amount." + Environment.NewLine; } // Set the attributes of the transaction if (payment.Attributes != null && payment.Attributes.Count > 0) { transaction.LoadAttributes(); foreach (var attribute in payment.Attributes) { transaction.SetAttributeValue(attribute.Key, attribute.Value); } transactionsWithAttributes.Add(transaction); } var currencyTypeValue = payment.CurrencyTypeValue; var creditCardTypevalue = payment.CreditCardTypeValue; if (financialPaymentDetail != null) { if (currencyTypeValue == null && financialPaymentDetail.CurrencyTypeValueId.HasValue) { currencyTypeValue = DefinedValueCache.Get(financialPaymentDetail.CurrencyTypeValueId.Value); } if (creditCardTypevalue == null && financialPaymentDetail.CreditCardTypeValueId.HasValue) { creditCardTypevalue = DefinedValueCache.Get(financialPaymentDetail.CreditCardTypeValueId.Value); } transaction.FinancialPaymentDetail.AccountNumberMasked = financialPaymentDetail.AccountNumberMasked; transaction.FinancialPaymentDetail.NameOnCardEncrypted = financialPaymentDetail.NameOnCardEncrypted; transaction.FinancialPaymentDetail.ExpirationMonthEncrypted = financialPaymentDetail.ExpirationMonthEncrypted; transaction.FinancialPaymentDetail.ExpirationYearEncrypted = financialPaymentDetail.ExpirationYearEncrypted; transaction.FinancialPaymentDetail.BillingLocationId = financialPaymentDetail.BillingLocationId; if (financialPaymentDetail.GatewayPersonIdentifier.IsNullOrWhiteSpace()) { // if Rock doesn't have the GatewayPersonIdentifier, get it from the downloaded payment (if it has a value) transaction.FinancialPaymentDetail.GatewayPersonIdentifier = payment.GatewayPersonIdentifier; } else { transaction.FinancialPaymentDetail.GatewayPersonIdentifier = financialPaymentDetail.GatewayPersonIdentifier; } transaction.FinancialPaymentDetail.FinancialPersonSavedAccountId = financialPaymentDetail.FinancialPersonSavedAccountId; } if (currencyTypeValue != null) { transaction.FinancialPaymentDetail.CurrencyTypeValueId = currencyTypeValue.Id; } if (creditCardTypevalue != null) { transaction.FinancialPaymentDetail.CreditCardTypeValueId = creditCardTypevalue.Id; } // Try to allocate the amount of the transaction based on the current scheduled transaction accounts decimal remainingAmount = Math.Abs(txnAmount); foreach (var detail in originalTxnDetails.Where(d => d.Amount != 0.0M)) { if (remainingAmount <= 0.0M) { // If there's no amount left, break out of details break; } var transactionDetail = new FinancialTransactionDetail(); transactionDetail.AccountId = detail.AccountId; transactionDetail.EntityTypeId = detail.EntityTypeId; transactionDetail.EntityId = detail.EntityId; if (detail.Amount <= remainingAmount) { // If the configured amount for this account is less than or equal to the remaining // amount, allocate the configured amount transactionDetail.Amount = detail.Amount; remainingAmount -= detail.Amount; } else { // If the configured amount is greater than the remaining amount, only allocate // the remaining amount transaction.Summary += "Note: Downloaded transaction amount was less than the configured allocation amounts for the Scheduled Transaction."; transactionDetail.Amount = remainingAmount; transactionDetail.Summary = "Note: The downloaded amount was not enough to apply the configured amount to this account."; remainingAmount = 0.0M; } transaction.TransactionDetails.Add(transactionDetail); } // If there's still amount left after allocating based on current config, add the remainder // to the account that was configured for the most amount if (remainingAmount > 0.0M) { transaction.Summary += "Note: Downloaded transaction amount was greater than the configured allocation amounts for the Scheduled Transaction."; var transactionDetail = transaction.TransactionDetails .OrderByDescending(d => d.Amount) .FirstOrDefault(); if (transactionDetail == null && defaultAccountId.HasValue) { transactionDetail = new FinancialTransactionDetail(); transactionDetail.AccountId = defaultAccountId.Value; transaction.TransactionDetails.Add(transactionDetail); } if (transactionDetail != null) { transactionDetail.Amount += remainingAmount; transactionDetail.Summary = "Note: Extra amount was applied to this account."; } } // If the amount to apply was negative, update all details to be negative (absolute value was used when allocating to accounts) if (txnAmount < 0.0M) { foreach (var txnDetail in transaction.TransactionDetails) { txnDetail.Amount = 0 - txnDetail.Amount; } } // Get the batch var batchService = new FinancialBatchService(rockContext); var batch = batchService.Get( batchNamePrefix, string.Empty, currencyTypeValue, creditCardTypevalue, transaction.TransactionDateTime.Value, gateway.GetBatchTimeOffset(), gateway.BatchDayOfWeek); if (batch.Id == 0) { // get a batch Id rockContext.SaveChanges(); } transaction.BatchId = batch.Id; financialTransactionService.Add(transaction); batchService.IncrementControlAmount(batch.Id, transaction.TotalAmount, null); if (receiptEmail.HasValue && txnAmount > 0.0M) { newTransactionsForReceiptEmails.Add(transaction); } if ( payment.IsFailure && ( (txnAmount == 0.0M && scheduledTransaction != null && originalTxn == null) || (txnAmount < 0.0M && originalTxn != null) )) { failedPayments.Add(transaction); } // Add summary if (!batchSummary.ContainsKey(batch.Guid)) { batchSummary.Add(batch.Guid, new List <Decimal>()); } batchSummary[batch.Guid].Add(txnAmount); totalAdded++; if (txnAmount < 0.0M) { totalReversals++; } else if (txnAmount == 0.0M) { totalFailures++; } } else { paymentsWithoutTransaction.Add(payment); } } else { totalAlreadyDownloaded++; } if (txns != null) { foreach (var txn in txns .Where(t => t.Status != payment.Status || t.StatusMessage != payment.StatusMessage || t.IsSettled != payment.IsSettled || t.SettledGroupId != payment.SettledGroupId || t.SettledDate != payment.SettledDate)) { txn.IsSettled = payment.IsSettled; txn.SettledGroupId = payment.SettledGroupId; txn.SettledDate = payment.SettledDate; txn.Status = payment.Status; txn.StatusMessage = payment.StatusMessage; totalStatusChanges++; } } rockContext.SaveChanges(); } } if (transactionsWithAttributes.Count > 0) { foreach (var transaction in transactionsWithAttributes) { using (var rockContext3 = new RockContext()) { transaction.SaveAttributeValues(rockContext3); rockContext3.SaveChanges(); } } } // Queue a transaction to update the status of all affected scheduled transactions var updatePaymentStatusTxn = new Rock.Transactions.UpdatePaymentStatusTransaction(gateway.Id, scheduledTransactionIds); Rock.Transactions.RockQueue.TransactionQueue.Enqueue(updatePaymentStatusTxn); if (receiptEmail.HasValue && newTransactionsForReceiptEmails.Any()) { // Queue a transaction to send receipts var newTransactionIds = newTransactionsForReceiptEmails.Select(t => t.Id).ToList(); var sendPaymentReceiptsTxn = new Rock.Transactions.SendPaymentReceipts(receiptEmail.Value, newTransactionIds); Rock.Transactions.RockQueue.TransactionQueue.Enqueue(sendPaymentReceiptsTxn); } // Queue transactions to launch failed payment workflow if (failedPayments.Any()) { if (failedPaymentEmail.HasValue) { // Queue a transaction to send payment failure var newTransactionIds = failedPayments.Select(t => t.Id).ToList(); var sendPaymentFailureTxn = new Rock.Transactions.SendPaymentReceipts(failedPaymentEmail.Value, newTransactionIds); Rock.Transactions.RockQueue.TransactionQueue.Enqueue(sendPaymentFailureTxn); } if (failedPaymentWorkflowType.HasValue) { // Queue a transaction to launch workflow var workflowDetails = failedPayments.Select(p => new LaunchWorkflowDetails(p)).ToList(); var launchWorkflowsTxn = new Rock.Transactions.LaunchWorkflowsTransaction(failedPaymentWorkflowType.Value, workflowDetails); Rock.Transactions.RockQueue.TransactionQueue.Enqueue(launchWorkflowsTxn); } } StringBuilder sb = new StringBuilder(); sb.AppendFormat("<li>{0} {1} downloaded.</li>", totalPayments.ToString("N0"), (totalPayments == 1 ? "payment" : "payments")); if (totalAlreadyDownloaded > 0) { sb.AppendFormat("<li>{0} {1} previously downloaded and {2} already been added.</li>", totalAlreadyDownloaded.ToString("N0"), (totalAlreadyDownloaded == 1 ? "payment was" : "payments were"), (totalAlreadyDownloaded == 1 ? "has" : "have")); } if (totalStatusChanges > 0) { sb.AppendFormat("<li>{0} {1} previously downloaded but had a change of status.</li>", totalStatusChanges.ToString("N0"), (totalStatusChanges == 1 ? "payment was" : "payments were")); } if (paymentsWithoutTransaction.Any()) { var scheduledPaymentList = paymentsWithoutTransaction.Where(a => a.GatewayScheduleId.IsNotNullOrWhiteSpace()).Select(a => a.GatewayScheduleId).ToList(); if (scheduledPaymentList.Any()) { sb.Append($@"<li>The following {scheduledPaymentList.Count.ToString( "N0" )} gateway payments could not be matched to an existing scheduled payment profile: <pre>{scheduledPaymentList.AsDelimited( "\n" )}</pre> </li>"); } var previousTransactionList = paymentsWithoutTransaction.Where(a => a.GatewayScheduleId.IsNullOrWhiteSpace()).Select(a => a.TransactionCode).ToList(); if (previousTransactionList.Any()) { sb.Append($@"<li>The following {previousTransactionList.Count.ToString( "N0" )} gateway payments could not be matched to a previous transaction: <pre>{previousTransactionList.AsDelimited( "\n" )}</pre> </li>"); } } sb.AppendFormat("<li>{0} {1} added.</li>", totalAdded.ToString("N0"), (totalAdded == 1 ? "new payment was" : "new payments were")); if (totalReversals > 0) { sb.AppendFormat("<li>{0} {1} added as a reversal to a previous transaction.</li>", totalReversals.ToString("N0"), (totalReversals == 1 ? "payment was" : "payments were")); } if (totalFailures > 0) { sb.AppendFormat("<li>{0} {1} recorded as a failed transaction.</li>", totalFailures.ToString("N0"), (totalFailures == 1 ? "payment was" : "payments were")); } using (var rockContext = new RockContext()) { var batches = new FinancialBatchService(rockContext) .Queryable().AsNoTracking() .Where(b => batchSummary.Keys.Contains(b.Guid)) .ToList(); foreach (var batchItem in batchSummary) { int items = batchItem.Value.Count; if (items > 0) { var batch = batches .Where(b => b.Guid.Equals(batchItem.Key)) .FirstOrDefault(); string batchName = string.Format("'{0} ({1})'", batch.Name, batch.BatchStartDateTime.Value.ToString("d")); if (!string.IsNullOrWhiteSpace(batchUrlFormat)) { batchName = string.Format("<a href='{0}'>{1}</a>", string.Format(batchUrlFormat, batch.Id), batchName); } decimal sum = batchItem.Value.Sum(); string summaryformat = items == 1 ? "<li>{0} transaction of {1} was added to the {2} batch.</li>" : "<li>{0} transactions totaling {1} were added to the {2} batch</li>"; sb.AppendFormat(summaryformat, items.ToString("N0"), sum.FormatAsCurrency(), batchName); } } } return(sb.ToString()); }
/// <summary> /// Handles the Click event of the lbCancel 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 lbCancel_Click( object sender, EventArgs e ) { int? txnId = PageParameter( "ScheduledTransactionId" ).AsIntegerOrNull(); if ( txnId.HasValue ) { var rockContext = new RockContext(); var txnService = new FinancialScheduledTransactionService( rockContext ); var txn = txnService.Get( txnId.Value ); if ( txn != null ) { string errorMessage = string.Empty; if ( txnService.Cancel( txn, out errorMessage ) ) { txnService.GetStatus( txn, out errorMessage ); rockContext.SaveChanges(); } else { ShowErrorMessage( errorMessage ); } ShowView( txn ); } } }
/// <summary> /// Processes the confirmation. /// </summary> /// <param name="errorMessage">The error message.</param> /// <returns></returns> private bool ProcessConfirmation( out string errorMessage ) { var rockContext = new RockContext(); if ( string.IsNullOrWhiteSpace( TransactionCode ) ) { GatewayComponent gateway = null; var financialGateway = hfPaymentTab.Value == "ACH" ? _achGateway : _ccGateway; if ( financialGateway != null ) { gateway = financialGateway.GetGatewayComponent(); } if ( gateway == null ) { errorMessage = "There was a problem creating the payment gateway information"; return false; } Person person = GetPerson( true ); if ( person == null ) { errorMessage = "There was a problem creating the person information"; return false; } if ( !person.PrimaryAliasId.HasValue ) { errorMessage = "There was a problem creating the person's primary alias"; return false; } PaymentInfo paymentInfo = GetPaymentInfo(); if ( paymentInfo == null ) { errorMessage = "There was a problem creating the payment information"; return false; } else { paymentInfo.FirstName = person.FirstName; paymentInfo.LastName = person.LastName; } if ( paymentInfo.CreditCardTypeValue != null ) { CreditCardTypeValueId = paymentInfo.CreditCardTypeValue.Id; } if ( _showCommmentEntry ) { paymentInfo.Comment1 = !string.IsNullOrWhiteSpace(GetAttributeValue( "PaymentComment" )) ? string.Format("{0}: {1}", GetAttributeValue( "PaymentComment" ), txtCommentEntry.Text ) : txtCommentEntry.Text; } else { paymentInfo.Comment1 = GetAttributeValue( "PaymentComment" ); } PaymentSchedule schedule = GetSchedule(); if ( schedule != null ) { schedule.PersonId = person.Id; var scheduledTransaction = gateway.AddScheduledPayment( financialGateway, schedule, paymentInfo, out errorMessage ); if ( scheduledTransaction != null ) { scheduledTransaction.TransactionFrequencyValueId = schedule.TransactionFrequencyValue.Id; scheduledTransaction.AuthorizedPersonAliasId = person.PrimaryAliasId.Value; scheduledTransaction.FinancialGatewayId = financialGateway.Id; if ( scheduledTransaction.FinancialPaymentDetail == null ) { scheduledTransaction.FinancialPaymentDetail = new FinancialPaymentDetail(); } scheduledTransaction.FinancialPaymentDetail.SetFromPaymentInfo( paymentInfo, gateway, rockContext ); var changeSummary = new StringBuilder(); changeSummary.AppendFormat( "{0} starting {1}", schedule.TransactionFrequencyValue.Value, schedule.StartDate.ToShortDateString() ); changeSummary.AppendLine(); changeSummary.Append( paymentInfo.CurrencyTypeValue.Value ); if ( paymentInfo.CreditCardTypeValue != null ) { changeSummary.AppendFormat( " - {0}", paymentInfo.CreditCardTypeValue.Value ); } changeSummary.AppendFormat( " {0}", paymentInfo.MaskedNumber ); changeSummary.AppendLine(); foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) ) { var transactionDetail = new FinancialScheduledTransactionDetail(); transactionDetail.Amount = account.Amount; transactionDetail.AccountId = account.Id; scheduledTransaction.ScheduledTransactionDetails.Add( transactionDetail ); changeSummary.AppendFormat( "{0}: {1}", account.Name, account.Amount.FormatAsCurrency() ); changeSummary.AppendLine(); } var transactionService = new FinancialScheduledTransactionService( rockContext ); transactionService.Add( scheduledTransaction ); rockContext.SaveChanges(); // Add a note about the change var noteType = NoteTypeCache.Read( Rock.SystemGuid.NoteType.SCHEDULED_TRANSACTION_NOTE.AsGuid() ); if ( noteType != null ) { var noteService = new NoteService( rockContext ); var note = new Note(); note.NoteTypeId = noteType.Id; note.EntityId = scheduledTransaction.Id; note.Caption = "Created Transaction"; note.Text = changeSummary.ToString(); noteService.Add( note ); } rockContext.SaveChanges(); ScheduleId = scheduledTransaction.GatewayScheduleId; TransactionCode = scheduledTransaction.TransactionCode; } else { return false; } } else { var transaction = gateway.Charge( financialGateway, paymentInfo, out errorMessage ); if ( transaction != null ) { var txnChanges = new List<string>(); txnChanges.Add( "Created Transaction" ); History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode ); transaction.AuthorizedPersonAliasId = person.PrimaryAliasId; History.EvaluateChange( txnChanges, "Person", string.Empty, person.FullName ); transaction.TransactionDateTime = RockDateTime.Now; History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime ); transaction.FinancialGatewayId = financialGateway.Id; History.EvaluateChange( txnChanges, "Gateway", string.Empty, financialGateway.Name ); var txnType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ) ); transaction.TransactionTypeValueId = txnType.Id; History.EvaluateChange( txnChanges, "Type", string.Empty, txnType.Value ); if ( transaction.FinancialPaymentDetail == null ) { transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); } transaction.FinancialPaymentDetail.SetFromPaymentInfo( paymentInfo, gateway, rockContext, txnChanges ); Guid sourceGuid = Guid.Empty; if ( Guid.TryParse( GetAttributeValue( "Source" ), out sourceGuid ) ) { var source = DefinedValueCache.Read( sourceGuid ); if ( source != null ) { transaction.SourceTypeValueId = source.Id; History.EvaluateChange( txnChanges, "Source", string.Empty, source.Value ); } } foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) ) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = account.Amount; transactionDetail.AccountId = account.Id; transaction.TransactionDetails.Add( transactionDetail ); History.EvaluateChange( txnChanges, account.Name, 0.0M.FormatAsCurrency(), transactionDetail.Amount.FormatAsCurrency() ); } var batchService = new FinancialBatchService( rockContext ); // Get the batch var batch = batchService.Get( GetAttributeValue( "BatchNamePrefix" ), paymentInfo.CurrencyTypeValue, paymentInfo.CreditCardTypeValue, transaction.TransactionDateTime.Value, financialGateway.GetBatchTimeOffset() ); var batchChanges = new List<string>(); if ( batch.Id == 0 ) { batchChanges.Add( "Generated the batch" ); History.EvaluateChange( batchChanges, "Batch Name", string.Empty, batch.Name ); History.EvaluateChange( batchChanges, "Status", null, batch.Status ); History.EvaluateChange( batchChanges, "Start Date/Time", null, batch.BatchStartDateTime ); History.EvaluateChange( batchChanges, "End Date/Time", null, batch.BatchEndDateTime ); } decimal newControlAmount = batch.ControlAmount + transaction.TotalAmount; History.EvaluateChange( batchChanges, "Control Amount", batch.ControlAmount.FormatAsCurrency(), newControlAmount.FormatAsCurrency() ); batch.ControlAmount = newControlAmount; transaction.BatchId = batch.Id; batch.Transactions.Add( transaction ); rockContext.SaveChanges(); HistoryService.SaveChanges( rockContext, typeof( FinancialBatch ), Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), batch.Id, batchChanges ); HistoryService.SaveChanges( rockContext, typeof( FinancialBatch ), Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(), batch.Id, txnChanges, person.FullName, typeof( FinancialTransaction ), transaction.Id ); SendReceipt( transaction.Id ); TransactionCode = transaction.TransactionCode; } else { return false; } } 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; tdAccountNumberReceipt.Description = paymentInfo.MaskedNumber; 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 ) && gateway.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; } return true; } else { pnlDupWarning.Visible = true; divActions.Visible = false; errorMessage = string.Empty; return false; } }
// helper functional methods (like BindGrid(), etc.) private void ShowContent() { // get scheduled contributions for current user if ( CurrentPerson != null ) { var rockContext = new RockContext(); var transactionService = new FinancialScheduledTransactionService( rockContext ); var personService = new PersonService( rockContext ); // get business giving id var givingIds = personService.GetBusinesses( CurrentPerson.Id ).Select( g => g.GivingId ).ToList(); // add the person's regular giving id givingIds.Add( CurrentPerson.GivingId ); var schedules = transactionService.Queryable( "ScheduledTransactionDetails.Account" ) .Where( s => givingIds.Contains( s.AuthorizedPersonAlias.Person.GivingId ) && s.IsActive == true ); // filter the list if necesssary var gatewayFilterGuid = GetAttributeValue( "GatewayFilter" ).AsGuidOrNull(); if ( gatewayFilterGuid != null ) { schedules = schedules.Where( s => s.FinancialGateway.Guid == gatewayFilterGuid ); } rptScheduledTransactions.DataSource = schedules.ToList(); rptScheduledTransactions.DataBind(); if ( schedules.Count() == 0 ) { pnlNoScheduledTransactions.Visible = true; lNoScheduledTransactionsMessage.Text = string.Format("No {0} currently exist.", GetAttributeValue("TransactionLabel").Pluralize().ToLower()); } } }
/// <summary> /// Processes the payments. /// </summary> /// <param name="gateway">The gateway.</param> /// <param name="batchNamePrefix">The batch name prefix.</param> /// <param name="payments">The payments.</param> /// <param name="batchUrlFormat">The batch URL format.</param> /// <param name="receiptEmail">The receipt email.</param> /// <returns></returns> public static string ProcessPayments(FinancialGateway gateway, string batchNamePrefix, List <Payment> payments, string batchUrlFormat = "", Guid?receiptEmail = null) { int totalPayments = 0; int totalAlreadyDownloaded = 0; int totalNoScheduledTransaction = 0; int totalAdded = 0; int totalReversals = 0; int totalStatusChanges = 0; var batches = new List <FinancialBatch>(); var batchSummary = new Dictionary <Guid, List <Decimal> >(); var initialControlAmounts = new Dictionary <Guid, decimal>(); var txnPersonNames = new Dictionary <Guid, string>(); var gatewayComponent = gateway.GetGatewayComponent(); var newTransactions = new List <FinancialTransaction>(); using (var rockContext = new RockContext()) { var accountService = new FinancialAccountService(rockContext); var txnService = new FinancialTransactionService(rockContext); var batchService = new FinancialBatchService(rockContext); var scheduledTxnService = new FinancialScheduledTransactionService(rockContext); var contributionTxnType = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid()); var defaultAccount = accountService.Queryable() .Where(a => a.IsActive && !a.ParentAccountId.HasValue && (!a.StartDate.HasValue || a.StartDate.Value <= RockDateTime.Now) && (!a.EndDate.HasValue || a.EndDate.Value >= RockDateTime.Now) ) .OrderBy(a => a.Order) .FirstOrDefault(); var batchTxnChanges = new Dictionary <Guid, List <string> >(); var batchBatchChanges = new Dictionary <Guid, List <string> >(); var scheduledTransactionIds = new List <int>(); foreach (var payment in payments.Where(p => p.Amount > 0.0M)) { totalPayments++; var scheduledTransaction = scheduledTxnService.GetByScheduleId(payment.GatewayScheduleId); if (scheduledTransaction != null) { // Find existing payments with same transaction code var txns = txnService .Queryable("TransactionDetails") .Where(t => t.TransactionCode == payment.TransactionCode) .ToList(); // Calculate whether a transaction needs to be added var txnAmount = CalculateTransactionAmount(payment, txns); if (txnAmount != 0.0M) { scheduledTransactionIds.Add(scheduledTransaction.Id); if (payment.ScheduleActive.HasValue) { scheduledTransaction.IsActive = payment.ScheduleActive.Value; } var transaction = new FinancialTransaction(); transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); transaction.Guid = Guid.NewGuid(); transaction.TransactionCode = payment.TransactionCode; transaction.TransactionDateTime = payment.TransactionDateTime; transaction.Status = payment.Status; transaction.StatusMessage = payment.StatusMessage; transaction.ScheduledTransactionId = scheduledTransaction.Id; transaction.AuthorizedPersonAliasId = scheduledTransaction.AuthorizedPersonAliasId; transaction.SourceTypeValueId = scheduledTransaction.SourceTypeValueId; txnPersonNames.Add(transaction.Guid, scheduledTransaction.AuthorizedPersonAlias.Person.FullName); transaction.FinancialGatewayId = gateway.Id; transaction.TransactionTypeValueId = contributionTxnType.Id; if (txnAmount < 0.0M) { transaction.Summary = "Reversal for previous transaction that failed during processing." + Environment.NewLine; } var currencyTypeValue = payment.CurrencyTypeValue; var creditCardTypevalue = payment.CreditCardTypeValue; if (scheduledTransaction.FinancialPaymentDetail != null) { if (currencyTypeValue == null && scheduledTransaction.FinancialPaymentDetail.CurrencyTypeValueId.HasValue) { currencyTypeValue = DefinedValueCache.Read(scheduledTransaction.FinancialPaymentDetail.CurrencyTypeValueId.Value); } if (creditCardTypevalue == null && scheduledTransaction.FinancialPaymentDetail.CreditCardTypeValueId.HasValue) { creditCardTypevalue = DefinedValueCache.Read(scheduledTransaction.FinancialPaymentDetail.CreditCardTypeValueId.Value); } transaction.FinancialPaymentDetail.AccountNumberMasked = scheduledTransaction.FinancialPaymentDetail.AccountNumberMasked; transaction.FinancialPaymentDetail.NameOnCardEncrypted = scheduledTransaction.FinancialPaymentDetail.NameOnCardEncrypted; transaction.FinancialPaymentDetail.ExpirationMonthEncrypted = scheduledTransaction.FinancialPaymentDetail.ExpirationMonthEncrypted; transaction.FinancialPaymentDetail.ExpirationYearEncrypted = scheduledTransaction.FinancialPaymentDetail.ExpirationYearEncrypted; transaction.FinancialPaymentDetail.BillingLocationId = scheduledTransaction.FinancialPaymentDetail.BillingLocationId; } if (currencyTypeValue != null) { transaction.FinancialPaymentDetail.CurrencyTypeValueId = currencyTypeValue.Id; } if (creditCardTypevalue != null) { transaction.FinancialPaymentDetail.CreditCardTypeValueId = creditCardTypevalue.Id; } // Try to allocate the amount of the transaction based on the current scheduled transaction accounts decimal remainingAmount = Math.Abs(txnAmount); foreach (var detail in scheduledTransaction.ScheduledTransactionDetails.Where(d => d.Amount != 0.0M)) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.AccountId = detail.AccountId; if (detail.Amount <= remainingAmount) { // If the configured amount for this account is less than or equal to the remaining // amount, allocate the configured amount transactionDetail.Amount = detail.Amount; remainingAmount -= detail.Amount; } else { // If the configured amount is greater than the remaining amount, only allocate // the remaining amount transaction.Summary += "Note: Downloaded transaction amount was less than the configured allocation amounts for the Scheduled Transaction."; transactionDetail.Amount = remainingAmount; transactionDetail.Summary = "Note: The downloaded amount was not enough to apply the configured amount to this account."; remainingAmount = 0.0M; } transaction.TransactionDetails.Add(transactionDetail); if (remainingAmount <= 0.0M) { // If there's no amount left, break out of details break; } } // If there's still amount left after allocating based on current config, add the remainder // to the account that was configured for the most amount if (remainingAmount > 0.0M) { transaction.Summary += "Note: Downloaded transaction amount was greater than the configured allocation amounts for the Scheduled Transaction."; var transactionDetail = transaction.TransactionDetails .OrderByDescending(d => d.Amount) .FirstOrDefault(); if (transactionDetail == null && defaultAccount != null) { transactionDetail = new FinancialTransactionDetail(); transactionDetail.AccountId = defaultAccount.Id; transaction.TransactionDetails.Add(transactionDetail); } if (transactionDetail != null) { transactionDetail.Amount += remainingAmount; transactionDetail.Summary = "Note: Extra amount was applied to this account."; } } // If the amount to apply was negative, update all details to be negative (absolute value was used when allocating to accounts) if (txnAmount < 0.0M) { foreach (var txnDetail in transaction.TransactionDetails) { txnDetail.Amount = 0 - txnDetail.Amount; } } // Get the batch var batch = batchService.Get( batchNamePrefix, currencyTypeValue, creditCardTypevalue, transaction.TransactionDateTime.Value, gateway.GetBatchTimeOffset(), batches); var batchChanges = new List <string>(); if (batch.Id != 0) { initialControlAmounts.AddOrIgnore(batch.Guid, batch.ControlAmount); } batch.ControlAmount += transaction.TotalAmount; batch.Transactions.Add(transaction); if (txnAmount > 0.0M && receiptEmail.HasValue) { newTransactions.Add(transaction); } // Add summary if (!batchSummary.ContainsKey(batch.Guid)) { batchSummary.Add(batch.Guid, new List <Decimal>()); } batchSummary[batch.Guid].Add(txnAmount); if (txnAmount > 0.0M) { totalAdded++; } else { totalReversals++; } } else { totalAlreadyDownloaded++; foreach (var txn in txns.Where(t => t.Status != payment.Status || t.StatusMessage != payment.StatusMessage)) { txn.Status = payment.Status; txn.StatusMessage = payment.StatusMessage; totalStatusChanges++; } } } else { totalNoScheduledTransaction++; } } rockContext.SaveChanges(); // Queue a transaction to update the status of all affected scheduled transactions var updatePaymentStatusTxn = new Rock.Transactions.UpdatePaymentStatusTransaction(gateway.Id, scheduledTransactionIds); Rock.Transactions.RockQueue.TransactionQueue.Enqueue(updatePaymentStatusTxn); if (receiptEmail.HasValue) { // Queue a transaction to send receipts var newTransactionIds = newTransactions.Select(t => t.Id).ToList(); var sendPaymentReceiptsTxn = new Rock.Transactions.SendPaymentReceipts(receiptEmail.Value, newTransactionIds); Rock.Transactions.RockQueue.TransactionQueue.Enqueue(sendPaymentReceiptsTxn); } } StringBuilder sb = new StringBuilder(); sb.AppendFormat("<li>{0} {1} downloaded.</li>", totalPayments.ToString("N0"), (totalPayments == 1 ? "payment" : "payments")); if (totalAlreadyDownloaded > 0) { sb.AppendFormat("<li>{0} {1} previously downloaded and {2} already been added.</li>", totalAlreadyDownloaded.ToString("N0"), (totalAlreadyDownloaded == 1 ? "payment was" : "payments were"), (totalAlreadyDownloaded == 1 ? "has" : "have")); } if (totalStatusChanges > 0) { sb.AppendFormat("<li>{0} {1} previously downloaded but had a change of status.</li>", totalStatusChanges.ToString("N0"), (totalStatusChanges == 1 ? "payment was" : "payments were")); } if (totalNoScheduledTransaction > 0) { sb.AppendFormat("<li>{0} {1} could not be matched to an existing scheduled payment profile.</li>", totalNoScheduledTransaction.ToString("N0"), (totalNoScheduledTransaction == 1 ? "payment" : "payments")); } sb.AppendFormat("<li>{0} {1} successfully added.</li>", totalAdded.ToString("N0"), (totalAdded == 1 ? "payment was" : "payments were")); if (totalReversals > 0) { sb.AppendFormat("<li>{0} {1} added as a reversal to a previous transaction.</li>", totalReversals.ToString("N0"), (totalReversals == 1 ? "payment was" : "payments were")); } foreach (var batchItem in batchSummary) { int items = batchItem.Value.Count; if (items > 0) { var batch = batches .Where(b => b.Guid.Equals(batchItem.Key)) .FirstOrDefault(); string batchName = string.Format("'{0} ({1})'", batch.Name, batch.BatchStartDateTime.Value.ToString("d")); if (!string.IsNullOrWhiteSpace(batchUrlFormat)) { batchName = string.Format("<a href='{0}'>{1}</a>", string.Format(batchUrlFormat, batch.Id), batchName); } decimal sum = batchItem.Value.Sum(); string summaryformat = items == 1 ? "<li>{0} transaction of {1} was added to the {2} batch.</li>" : "<li>{0} transactions totaling {1} were added to the {2} batch</li>"; sb.AppendFormat(summaryformat, items.ToString("N0"), sum.FormatAsCurrency(), batchName); } } return(sb.ToString()); }
// helper functional methods (like BindGrid(), etc.) private void ShowContent() { // get pledges for current user if ( CurrentPerson != null ) { var rockContext = new RockContext(); FinancialScheduledTransactionService transactionService = new FinancialScheduledTransactionService( rockContext ); var schedules = transactionService.Queryable( "ScheduledTransactionDetails.Account" ) .Where( s => s.AuthorizedPersonId == CurrentPerson.Id && s.IsActive == true ); List<Dictionary<string, object>> scheduleSummaries = new List<Dictionary<string, object>>(); foreach ( FinancialScheduledTransaction schedule in schedules ) { decimal totalAmount = 0; Dictionary<string, object> scheduleSummary = new Dictionary<string, object>(); scheduleSummary.Add("Id", schedule.Id); scheduleSummary.Add("Guid", schedule.Guid); scheduleSummary.Add("StartDate", schedule.StartDate); scheduleSummary.Add("EndDate", schedule.EndDate); scheduleSummary.Add("NextPaymentDate", schedule.NextPaymentDate); if ( schedule.NextPaymentDate.HasValue ) { scheduleSummary.Add( "DaysTillNextPayment", (schedule.NextPaymentDate.Value - DateTime.Now).Days ); } else { scheduleSummary.Add( "DaysTillNextPayment", null ); } DateTime? lastPaymentDate = schedule.Transactions.Max(t => t.TransactionDateTime); scheduleSummary.Add("LastPaymentDate", lastPaymentDate); if ( lastPaymentDate.HasValue ) { scheduleSummary.Add("DaysSinceLastPayment", (DateTime.Now - lastPaymentDate.Value).Days); } else { scheduleSummary.Add( "DaysSinceLastPayment", null ); } scheduleSummary.Add("CurrencyType", schedule.CurrencyTypeValue.Value); scheduleSummary.Add("CreditCardType", schedule.CreditCardTypeValue.Value); scheduleSummary.Add("UrlEncryptedKey", schedule.UrlEncodedKey); scheduleSummary.Add("Frequency", schedule.TransactionFrequencyValue.Value); scheduleSummary.Add("FrequencyDescription", schedule.TransactionFrequencyValue.Description); List<Dictionary<string, object>> summaryDetails = new List<Dictionary<string,object>>(); foreach ( FinancialScheduledTransactionDetail detail in schedule.ScheduledTransactionDetails ) { Dictionary<string, object> detailSummary = new Dictionary<string,object>(); detailSummary.Add("AccountId", detail.Id); detailSummary.Add("AccountName", detail.Account.Name); detailSummary.Add("Amount", detail.Amount); detailSummary.Add("Summary", detail.Summary); summaryDetails.Add( detailSummary ); totalAmount += detail.Amount; } scheduleSummary.Add("ScheduledAmount", totalAmount); scheduleSummary.Add( "TransactionDetails", summaryDetails ); scheduleSummaries.Add( scheduleSummary ); } // added linked pages to mergefields Dictionary<string, object> linkedPages = new Dictionary<string, object>(); linkedPages.Add( "ManageScheduledTransactionsPage", LinkedPageUrl( "ManageScheduledTransactionsPage", null )); linkedPages.Add( "TransactionHistoryPage", LinkedPageUrl( "TransactionHistoryPage", null ) ); linkedPages.Add( "TransactionEntryPage", LinkedPageUrl( "TransactionEntryPage", null ) ); var scheduleValues = new Dictionary<string, object>(); scheduleValues.Add( "ScheduledTransactions", scheduleSummaries.ToList() ); scheduleValues.Add( "LinkedPages", linkedPages ); scheduleValues.Add( "Person", CurrentPerson ); string content = GetAttributeValue( "Template" ).ResolveMergeFields( scheduleValues ); // show merge fields if needed if ( GetAttributeValue( "EnableDebug" ).AsBoolean() ) { string debugInfo = string.Format( @" <pre> {0} </pre> ", scheduleValues.LiquidHelpText() ); content += debugInfo; } lContent.Text = content; } }
// helper functional methods (like BindGrid(), etc.) private void ShowContent() { // get scheduled contributions for current user if ( CurrentPerson != null ) { var rockContext = new RockContext(); FinancialScheduledTransactionService transactionService = new FinancialScheduledTransactionService( rockContext ); var schedules = transactionService.Queryable( "ScheduledTransactionDetails.Account" ) .Where( s => s.AuthorizedPersonAlias.Person.GivingId == CurrentPerson.GivingId && s.IsActive == true ); rptScheduledTransactions.DataSource = schedules.ToList(); rptScheduledTransactions.DataBind(); if ( schedules.Count() == 0 ) { pnlNoScheduledTransactions.Visible = true; lNoScheduledTransactionsMessage.Text = string.Format("No {0} currently exist.", GetAttributeValue("TransactionLabel").Pluralize().ToLower()); } } }
/// <summary> /// Executes the specified context. /// </summary> /// <param name="context">The context.</param> public void Execute( IJobExecutionContext context ) { var rockContext = new RockContext(); JobDataMap dataMap = context.JobDetail.JobDataMap; // Get the details for the email that we'll be sending out. Guid? systemEmailGuid = dataMap.GetString( "ExpiringCreditCardEmail" ).AsGuidOrNull(); SystemEmailService emailService = new SystemEmailService( rockContext ); SystemEmail systemEmail = null; if ( systemEmailGuid.HasValue ) { systemEmail = emailService.Get( systemEmailGuid.Value ); } // Fetch the configured Workflow once if one was set, we'll use it later. Guid? workflowGuid = dataMap.GetString( "Workflow" ).AsGuidOrNull(); WorkflowType workflowType = null; var workflowTypeService = new WorkflowTypeService( rockContext ); var workflowService = new WorkflowService( rockContext ); if ( workflowGuid != null ) { workflowType = workflowTypeService.Get( workflowGuid.Value ); } var qry = new FinancialScheduledTransactionService( rockContext ) .Queryable( "ScheduledTransactionDetails,FinancialPaymentDetail.CurrencyTypeValue,FinancialPaymentDetail.CreditCardTypeValue" ) .Where( t => t.IsActive && t.FinancialPaymentDetail.ExpirationMonthEncrypted != null && ( t.EndDate == null || t.EndDate > DateTime.Now ) ) .AsNoTracking(); var appRoot = Rock.Web.Cache.GlobalAttributesCache.Read( rockContext ).GetValue( "PublicApplicationRoot" ); // Get the current month and year DateTime now = DateTime.Now; int month = now.Month; int year = now.Year; int counter = 0; foreach ( var transaction in qry ) { int expirationMonthDecrypted = Int32.Parse( Encryption.DecryptString( transaction.FinancialPaymentDetail.ExpirationMonthEncrypted ) ); int expirationYearDecrypted = Int32.Parse( Encryption.DecryptString( transaction.FinancialPaymentDetail.ExpirationYearEncrypted ) ); string acctNum = transaction.FinancialPaymentDetail.AccountNumberMasked.Substring( transaction.FinancialPaymentDetail.AccountNumberMasked.Length - 4 ); int warningYear = expirationYearDecrypted; int warningMonth = expirationMonthDecrypted - 1; if ( warningMonth == 0 ) { warningYear -= 1; warningMonth = 12; } string warningDate = warningMonth.ToString() + warningYear.ToString(); string currentMonthString = month.ToString() + year.ToString(); if ( warningDate == currentMonthString ) { // as per ISO7813 https://en.wikipedia.org/wiki/ISO/IEC_7813 var expirationDate = string.Format( "{0:D2}/{1:D2}", expirationMonthDecrypted, expirationYearDecrypted ); var recipients = new List<RecipientData>(); var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields( null ); var person = transaction.AuthorizedPersonAlias.Person; mergeFields.Add( "Person", person ); mergeFields.Add( "Card", acctNum ); mergeFields.Add( "Expiring", expirationDate ); recipients.Add( new RecipientData( person.Email, mergeFields ) ); Email.Send( systemEmail.Guid, recipients, appRoot ); // Start workflow for this person if ( workflowType != null ) { Dictionary<string, string> attributes = new Dictionary<string, string>(); attributes.Add( "Person", transaction.AuthorizedPersonAlias.Guid.ToString() ); attributes.Add( "Card", acctNum ); attributes.Add( "Expiring", expirationDate ); StartWorkflow( workflowService, workflowType, attributes, string.Format( "{0} (scheduled transaction Id: {1})", person.FullName, transaction.Id ) ); } counter++; } } context.Result = string.Format( "{0} scheduled credit card transactions were examined with {1} notice(s) sent.", qry.Count(), counter ); }
// helper functional methods (like BindGrid(), etc.) private void ShowContent() { List<Dictionary<string, object>> scheduleSummaries = new List<Dictionary<string, object>>(); // get scheduled transactions for current user if ( CurrentPerson != null ) { var rockContext = new RockContext(); FinancialScheduledTransactionService transactionService = new FinancialScheduledTransactionService( rockContext ); var schedules = transactionService.Queryable( "ScheduledTransactionDetails.Account" ) .Where( s => s.AuthorizedPersonAlias.Person.GivingId == CurrentPerson.GivingId && s.IsActive == true ); foreach ( FinancialScheduledTransaction schedule in schedules ) { string errorMsgs = string.Empty; transactionService.GetStatus( schedule, out errorMsgs ); decimal totalAmount = 0; Dictionary<string, object> scheduleSummary = new Dictionary<string, object>(); scheduleSummary.Add("Id", schedule.Id); scheduleSummary.Add("Guid", schedule.Guid); scheduleSummary.Add("StartDate", schedule.StartDate); scheduleSummary.Add("EndDate", schedule.EndDate); scheduleSummary.Add("NextPaymentDate", schedule.NextPaymentDate); if ( schedule.NextPaymentDate.HasValue ) { scheduleSummary.Add( "DaysTillNextPayment", (schedule.NextPaymentDate.Value - DateTime.Now).Days ); } else { scheduleSummary.Add( "DaysTillNextPayment", null ); } DateTime? lastPaymentDate = schedule.Transactions.Max(t => t.TransactionDateTime); scheduleSummary.Add("LastPaymentDate", lastPaymentDate); if ( lastPaymentDate.HasValue ) { scheduleSummary.Add("DaysSinceLastPayment", (DateTime.Now - lastPaymentDate.Value).Days); } else { scheduleSummary.Add( "DaysSinceLastPayment", null ); } scheduleSummary.Add("CurrencyType", ( schedule.FinancialPaymentDetail != null && schedule.FinancialPaymentDetail.CurrencyTypeValue != null ) ? schedule.FinancialPaymentDetail.CurrencyTypeValue.Value : "" ); scheduleSummary.Add( "CreditCardType", ( schedule.FinancialPaymentDetail != null && schedule.FinancialPaymentDetail.CreditCardTypeValue != null) ? schedule.FinancialPaymentDetail.CreditCardTypeValue.Value : "" ); scheduleSummary.Add("UrlEncryptedKey", schedule.UrlEncodedKey); scheduleSummary.Add("Frequency", schedule.TransactionFrequencyValue.Value); scheduleSummary.Add("FrequencyDescription", schedule.TransactionFrequencyValue.Description); List<Dictionary<string, object>> summaryDetails = new List<Dictionary<string,object>>(); foreach ( FinancialScheduledTransactionDetail detail in schedule.ScheduledTransactionDetails ) { Dictionary<string, object> detailSummary = new Dictionary<string,object>(); detailSummary.Add("AccountId", detail.Id); detailSummary.Add("AccountName", detail.Account.Name); detailSummary.Add("Amount", detail.Amount); detailSummary.Add("Summary", detail.Summary); summaryDetails.Add( detailSummary ); totalAmount += detail.Amount; } scheduleSummary.Add("ScheduledAmount", totalAmount); scheduleSummary.Add( "TransactionDetails", summaryDetails ); scheduleSummaries.Add( scheduleSummary ); } rockContext.SaveChanges(); } // added linked pages to mergefields Dictionary<string, object> linkedPages = new Dictionary<string, object>(); linkedPages.Add( "ManageScheduledTransactionsPage", LinkedPageRoute( "ManageScheduledTransactionsPage" ) ); linkedPages.Add( "TransactionHistoryPage", LinkedPageRoute( "TransactionHistoryPage" ) ); linkedPages.Add( "TransactionEntryPage", LinkedPageRoute( "TransactionEntryPage" ) ); var scheduleValues = new Dictionary<string, object>(); scheduleValues.Add( "ScheduledTransactions", scheduleSummaries.ToList() ); scheduleValues.Add( "LinkedPages", linkedPages ); // TODO: When support for "Person" is not supported anymore (should use "CurrentPerson" instead), remove this line scheduleValues.Add( "Person", CurrentPerson ); scheduleValues.Add( "CurrentPerson", CurrentPerson ); string content = GetAttributeValue( "Template" ).ResolveMergeFields( scheduleValues ); // show merge fields if needed if ( GetAttributeValue( "EnableDebug" ).AsBoolean() && IsUserAuthorized( Authorization.EDIT ) ) { // TODO: When support for "Person" is not supported anymore (should use "CurrentPerson" instead), remove this line scheduleValues.Remove( "Person" ); content += scheduleValues.lavaDebugInfo(); } lContent.Text = content; }
/// <summary> /// Gets the scheduled transaction. /// </summary> /// <param name="refresh">if set to <c>true</c> [refresh].</param> /// <returns></returns> private FinancialScheduledTransaction GetScheduledTransaction( bool refresh = false ) { Person targetPerson = null; using ( var rockContext = new RockContext() ) { // If impersonation is allowed, and a valid person key was used, set the target to that person bool allowImpersonation = GetAttributeValue( "Impersonation" ).AsBoolean(); if ( allowImpersonation ) { string personKey = PageParameter( "Person" ); if ( !string.IsNullOrWhiteSpace( personKey ) ) { targetPerson = new PersonService( rockContext ).GetByUrlEncodedKey( personKey ); } } if ( targetPerson == null ) { targetPerson = CurrentPerson; } // Verify that transaction id is valid for selected person if ( targetPerson != null ) { int txnId = int.MinValue; if ( int.TryParse( PageParameter( "ScheduledTransactionId" ), out txnId ) ) { var personService = new PersonService( rockContext ); var validGivingIds = new List<string> { targetPerson.GivingId }; validGivingIds.AddRange( personService.GetBusinesses( targetPerson.Id ).Select( b => b.GivingId ) ); var service = new FinancialScheduledTransactionService( rockContext ); var scheduledTransaction = service .Queryable( "AuthorizedPersonAlias.Person,ScheduledTransactionDetails,FinancialGateway,FinancialPaymentDetail.CurrencyTypeValue,FinancialPaymentDetail.CreditCardTypeValue" ) .Where( t => t.Id == txnId && t.AuthorizedPersonAlias != null && t.AuthorizedPersonAlias.Person != null && validGivingIds.Contains( t.AuthorizedPersonAlias.Person.GivingId ) ) .FirstOrDefault(); if ( scheduledTransaction != null ) { if ( scheduledTransaction.AuthorizedPersonAlias != null ) { TargetPersonId = scheduledTransaction.AuthorizedPersonAlias.PersonId; } ScheduledTransactionId = scheduledTransaction.Id; if ( scheduledTransaction.FinancialGateway != null ) { scheduledTransaction.FinancialGateway.LoadAttributes( rockContext ); } if ( refresh ) { string errorMessages = string.Empty; service.GetStatus( scheduledTransaction, out errorMessages ); rockContext.SaveChanges(); } return scheduledTransaction; } } } } return null; }
/// <summary> /// Handles the Click event of the lbSaveAccount 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 lbSaveAccount_Click( object sender, EventArgs e ) { var rockContext = new RockContext(); if ( string.IsNullOrWhiteSpace( TransactionCode ) ) { nbSaveAccount.Text = "Sorry, the account information cannot be saved as there's not a valid transaction code to reference"; nbSaveAccount.Visible = true; return; } if ( phCreateLogin.Visible ) { if ( string.IsNullOrWhiteSpace( txtUserName.Text ) || string.IsNullOrWhiteSpace( txtPassword.Text ) ) { nbSaveAccount.Title = "Missing Informaton"; nbSaveAccount.Text = "A username and password are required when saving an account"; nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; return; } if ( new UserLoginService( rockContext ).GetByUserName( txtUserName.Text ) != null ) { nbSaveAccount.Title = "Invalid Username"; nbSaveAccount.Text = "The selected Username is already being used. Please select a different Username"; nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; return; } if ( txtPasswordConfirm.Text != txtPassword.Text ) { nbSaveAccount.Title = "Invalid Password"; nbSaveAccount.Text = "The password and password confirmation do not match"; nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; return; } } if ( !string.IsNullOrWhiteSpace( txtSaveAccount.Text ) ) { GatewayComponent gateway = hfPaymentTab.Value == "ACH" ? _achGateway : _ccGateway; var ccCurrencyType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ) ); var achCurrencyType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ) ); string errorMessage = string.Empty; PersonAlias authorizedPersonAlias = null; string referenceNumber = string.Empty; int? currencyTypeValueId = hfPaymentTab.Value == "ACH" ? achCurrencyType.Id : ccCurrencyType.Id; if ( string.IsNullOrWhiteSpace( ScheduleId ) ) { var transaction = new FinancialTransactionService( rockContext ).GetByTransactionCode( TransactionCode ); if ( transaction != null && transaction.AuthorizedPersonAlias != null ) { authorizedPersonAlias = transaction.AuthorizedPersonAlias; referenceNumber = gateway.GetReferenceNumber( transaction, out errorMessage ); } } else { var scheduledTransaction = new FinancialScheduledTransactionService( rockContext ).GetByScheduleId( ScheduleId ); if ( scheduledTransaction != null ) { authorizedPersonAlias = scheduledTransaction.AuthorizedPersonAlias; referenceNumber = gateway.GetReferenceNumber( scheduledTransaction, out errorMessage ); } } if ( authorizedPersonAlias != null && authorizedPersonAlias.Person != null ) { if ( phCreateLogin.Visible ) { var user = UserLoginService.Create( rockContext, authorizedPersonAlias.Person, Rock.Model.AuthenticationServiceType.Internal, EntityTypeCache.Read( Rock.SystemGuid.EntityType.AUTHENTICATION_DATABASE.AsGuid() ).Id, txtUserName.Text, txtPassword.Text, false ); var mergeObjects = GlobalAttributesCache.GetMergeFields( null ); mergeObjects.Add( "ConfirmAccountUrl", RootPath + "ConfirmAccount" ); var personDictionary = authorizedPersonAlias.Person.ToLiquid() as Dictionary<string, object>; mergeObjects.Add( "Person", personDictionary ); mergeObjects.Add( "User", user ); var recipients = new List<Rock.Communication.RecipientData>(); recipients.Add( new Rock.Communication.RecipientData( authorizedPersonAlias.Person.Email, mergeObjects ) ); Rock.Communication.Email.Send( GetAttributeValue( "ConfirmAccountTemplate" ).AsGuid(), recipients, ResolveRockUrl( "~/" ), ResolveRockUrl( "~~/" ) ); } var paymentInfo = GetPaymentInfo(); if ( errorMessage.Any() ) { nbSaveAccount.Title = "Invalid Transaction"; nbSaveAccount.Text = "Sorry, the account information cannot be saved. " + errorMessage; nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; } else { if ( authorizedPersonAlias != null ) { var savedAccount = new FinancialPersonSavedAccount(); savedAccount.PersonAliasId = authorizedPersonAlias.Id; savedAccount.ReferenceNumber = referenceNumber; savedAccount.Name = txtSaveAccount.Text; savedAccount.MaskedAccountNumber = paymentInfo.MaskedNumber; savedAccount.TransactionCode = TransactionCode; savedAccount.GatewayEntityTypeId = gateway.TypeId; savedAccount.CurrencyTypeValueId = currencyTypeValueId; savedAccount.CreditCardTypeValueId = CreditCardTypeValueId; var savedAccountService = new FinancialPersonSavedAccountService( rockContext ); savedAccountService.Add( savedAccount ); rockContext.SaveChanges(); cbSaveAccount.Visible = false; txtSaveAccount.Visible = false; phCreateLogin.Visible = false; divSaveActions.Visible = false; nbSaveAccount.Title = "Success"; nbSaveAccount.Text = "The account has been saved for future use"; nbSaveAccount.NotificationBoxType = NotificationBoxType.Success; nbSaveAccount.Visible = true; } } } else { nbSaveAccount.Title = "Invalid Transaction"; nbSaveAccount.Text = "Sorry, the account information cannot be saved as there's not a valid transaction code to reference"; nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; } } else { nbSaveAccount.Title = "Missing Account Name"; nbSaveAccount.Text = "Please enter a name to use for this account"; nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; } }
/// <summary> /// Processes the confirmation. /// </summary> /// <param name="errorMessage">The error message.</param> /// <returns></returns> private bool ProcessConfirmation( out string errorMessage ) { var rockContext = new RockContext(); errorMessage = string.Empty; if ( string.IsNullOrWhiteSpace( TransactionCode ) ) { if ( Gateway == null ) { errorMessage = "There was a problem creating the payment gateway information"; return false; } var personService = new PersonService( rockContext ); var transactionService = new FinancialScheduledTransactionService( rockContext ); var transactionDetailService = new FinancialScheduledTransactionDetailService( rockContext ); FinancialScheduledTransaction scheduledTransaction = null; if ( ScheduledTransactionId.HasValue ) { scheduledTransaction = transactionService.Get( ScheduledTransactionId.Value ); } if ( scheduledTransaction == null ) { errorMessage = "There was a problem getting the transaction information"; return false; } if ( scheduledTransaction.AuthorizedPerson == null ) { errorMessage = "There was a problem determining the person associated with the transaction"; return false; } var changeSummary = new StringBuilder(); // Get the payment schedule scheduledTransaction.TransactionFrequencyValueId = btnFrequency.SelectedValueAsId().Value; changeSummary.Append( DefinedValueCache.Read( scheduledTransaction.TransactionFrequencyValueId, rockContext ) ); if ( dtpStartDate.SelectedDate.HasValue && dtpStartDate.SelectedDate > RockDateTime.Today ) { scheduledTransaction.StartDate = dtpStartDate.SelectedDate.Value; changeSummary.AppendFormat( " starting {0}", scheduledTransaction.StartDate.ToShortDateString() ); } else { scheduledTransaction.StartDate = DateTime.MinValue; } changeSummary.AppendLine(); PaymentInfo paymentInfo = GetPaymentInfo( personService, scheduledTransaction ); if ( paymentInfo == null ) { errorMessage = "There was a problem creating the payment information"; return false; } else { } // If transaction is not active, attempt to re-activate it first if ( !scheduledTransaction.IsActive ) { if ( !transactionService.Reactivate( scheduledTransaction, out errorMessage ) ) { return false; } } if ( Gateway.UpdateScheduledPayment( scheduledTransaction, paymentInfo, out errorMessage ) ) { if ( paymentInfo.CurrencyTypeValue != null ) { changeSummary.Append( paymentInfo.CurrencyTypeValue.Value ); scheduledTransaction.CurrencyTypeValueId = paymentInfo.CurrencyTypeValue.Id; DefinedValueCache creditCardTypeValue = paymentInfo.CreditCardTypeValue; if ( creditCardTypeValue != null ) { changeSummary.AppendFormat( " - {0}", creditCardTypeValue.Value ); scheduledTransaction.CreditCardTypeValueId = creditCardTypeValue.Id; } else { scheduledTransaction.CreditCardTypeValueId = null; } changeSummary.AppendFormat( " {0}", paymentInfo.MaskedNumber ); changeSummary.AppendLine(); } var selectedAccountIds = SelectedAccounts .Where( a => a.Amount > 0 ) .Select( a => a.Id ).ToList(); var deletedAccounts = scheduledTransaction.ScheduledTransactionDetails .Where( a => !selectedAccountIds.Contains( a.AccountId ) ).ToList(); foreach ( var deletedAccount in deletedAccounts ) { scheduledTransaction.ScheduledTransactionDetails.Remove( deletedAccount ); transactionDetailService.Delete( deletedAccount ); } foreach ( var account in SelectedAccounts ) { var detail = scheduledTransaction.ScheduledTransactionDetails .Where( d => d.AccountId == account.Id ).FirstOrDefault(); if ( detail == null ) { detail = new FinancialScheduledTransactionDetail(); detail.AccountId = account.Id; scheduledTransaction.ScheduledTransactionDetails.Add( detail ); } detail.Amount = account.Amount; changeSummary.AppendFormat( "{0}: {1:C2}", account.Name, account.Amount ); changeSummary.AppendLine(); } rockContext.SaveChanges(); // Add a note about the change var noteTypeService = new NoteTypeService( rockContext ); var noteType = noteTypeService.Get( scheduledTransaction.TypeId, "Note" ); var noteService = new NoteService( rockContext ); var note = new Note(); note.NoteTypeId = noteType.Id; note.EntityId = scheduledTransaction.Id; note.Caption = "Updated Transaction"; note.Text = changeSummary.ToString(); noteService.Add( note ); rockContext.SaveChanges(); ScheduleId = scheduledTransaction.GatewayScheduleId; TransactionCode = scheduledTransaction.TransactionCode; if (transactionService.GetStatus( scheduledTransaction, out errorMessage )) { rockContext.SaveChanges(); } } else { return false; } tdTransactionCode.Description = TransactionCode; tdTransactionCode.Visible = !string.IsNullOrWhiteSpace( TransactionCode ); tdScheduleId.Description = ScheduleId; tdScheduleId.Visible = !string.IsNullOrWhiteSpace( ScheduleId ); return true; } else { pnlDupWarning.Visible = true; return false; } }
private FinancialScheduledTransaction GetScheduledTransaction(bool refresh = false) { Person targetPerson = null; // If impersonation is allowed, and a valid person key was used, set the target to that person bool allowImpersonation = false; if ( bool.TryParse( GetAttributeValue( "Impersonation" ), out allowImpersonation ) && allowImpersonation ) { string personKey = PageParameter( "Person" ); if ( !string.IsNullOrWhiteSpace( personKey ) ) { targetPerson = new PersonService().GetByUrlEncodedKey( personKey ); } } if ( targetPerson == null ) { targetPerson = CurrentPerson; } // Verify that transaction id is valid for selected person if ( targetPerson != null ) { int txnId = int.MinValue; if ( int.TryParse( PageParameter( "Txn" ), out txnId ) ) { var service = new FinancialScheduledTransactionService(); var scheduledTransaction = service.Queryable( "ScheduledTransactionDetails,GatewayEntityType" ) .Where( t => t.Id == txnId && ( t.AuthorizedPersonId == targetPerson.Id || t.AuthorizedPerson.GivingGroupId == targetPerson.GivingGroupId ) ) .FirstOrDefault(); if (scheduledTransaction != null) { TargetPersonId = scheduledTransaction.AuthorizedPersonId; ScheduledTransactionId = scheduledTransaction.Id; if ( refresh ) { string errorMessages = string.Empty; service.UpdateStatus( scheduledTransaction, CurrentPersonId, out errorMessages ); } return scheduledTransaction; } } } return null; }
/// <summary> /// Executes this instance. /// </summary> public void Execute() { using ( var rockContext = new RockContext() ) { var gateway = new FinancialGatewayService( rockContext ).Get( GatewayId ); if ( gateway != null ) { var gatewayComponent = gateway.GetGatewayComponent(); if ( gatewayComponent != null ) { var scheduledTxnService = new FinancialScheduledTransactionService( rockContext ); foreach( var txnId in ScheduledTransactionIds ) { var scheduledTxn = scheduledTxnService.Get( txnId ); if ( scheduledTxn != null ) { string statusMsgs = string.Empty; gatewayComponent.GetScheduledPaymentStatus( scheduledTxn, out statusMsgs ); rockContext.SaveChanges(); } } } } } }
/// <summary> /// Processes the confirmation. /// </summary> /// <param name="errorMessage">The error message.</param> /// <returns></returns> private bool ProcessConfirmation( out string errorMessage ) { errorMessage = string.Empty; if ( string.IsNullOrWhiteSpace( TransactionCode ) ) { if ( Gateway == null ) { errorMessage = "There was a problem creating the payment gateway information"; return false; } using ( new UnitOfWorkScope() ) { var personService = new PersonService(); var transactionService = new FinancialScheduledTransactionService(); var transactionDetailService = new FinancialScheduledTransactionDetailService(); FinancialScheduledTransaction scheduledTransaction = null; if ( ScheduledTransactionId.HasValue ) { scheduledTransaction = transactionService.Get( ScheduledTransactionId.Value ); } if ( scheduledTransaction == null ) { errorMessage = "There was a problem getting the transaction information"; return false; } if ( scheduledTransaction.AuthorizedPerson == null ) { errorMessage = "There was a problem determining the person associated with the transaction"; return false; } // Get the payment schedule scheduledTransaction.TransactionFrequencyValueId = btnFrequency.SelectedValueAsId().Value; if ( dtpStartDate.SelectedDate.HasValue && dtpStartDate.SelectedDate > DateTime.Today ) { scheduledTransaction.StartDate = dtpStartDate.SelectedDate.Value; } else { scheduledTransaction.StartDate = DateTime.MinValue; } PaymentInfo paymentInfo = GetPaymentInfo( personService, scheduledTransaction ); if ( paymentInfo == null ) { errorMessage = "There was a problem creating the payment information"; return false; } else { } if ( Gateway.UpdateScheduledPayment( scheduledTransaction, paymentInfo, out errorMessage ) ) { var selectedAccountIds = SelectedAccounts .Where( a => a.Amount > 0 ) .Select( a => a.Id ).ToList(); var deletedAccounts = scheduledTransaction.ScheduledTransactionDetails .Where( a => !selectedAccountIds.Contains( a.AccountId ) ).ToList(); foreach ( var deletedAccount in deletedAccounts ) { scheduledTransaction.ScheduledTransactionDetails.Remove( deletedAccount ); transactionDetailService.Delete( deletedAccount, CurrentPersonId ); } foreach ( var account in SelectedAccounts ) { var detail = scheduledTransaction.ScheduledTransactionDetails .Where( d => d.AccountId == account.Id ).FirstOrDefault(); if ( detail == null ) { detail = new FinancialScheduledTransactionDetail(); detail.AccountId = account.Id; scheduledTransaction.ScheduledTransactionDetails.Add( detail ); } detail.Amount = account.Amount; } transactionService.Save( scheduledTransaction, CurrentPersonId ); ScheduleId = scheduledTransaction.GatewayScheduleId; TransactionCode = scheduledTransaction.TransactionCode; } else { return false; } tdTransactionCode.Description = TransactionCode; tdTransactionCode.Visible = !string.IsNullOrWhiteSpace( TransactionCode ); tdScheduleId.Description = ScheduleId; tdScheduleId.Visible = !string.IsNullOrWhiteSpace( ScheduleId ); return true; } } else { pnlDupWarning.Visible = true; return false; } }
/// <summary> /// Processes the payments. /// </summary> /// <param name="gateway">The gateway.</param> /// <param name="batchNamePrefix">The batch name prefix.</param> /// <param name="payments">The payments.</param> /// <param name="batchUrlFormat">The batch URL format.</param> /// <returns></returns> public static string ProcessPayments(GatewayComponent gateway, string batchNamePrefix, List <Payment> payments, string batchUrlFormat = "") { int totalPayments = 0; int totalAlreadyDownloaded = 0; int totalNoScheduledTransaction = 0; int totalAdded = 0; var batches = new List <FinancialBatch>(); var batchSummary = new Dictionary <Guid, List <Payment> >(); var rockContext = new RockContext(); var accountService = new FinancialAccountService(rockContext); var txnService = new FinancialTransactionService(rockContext); var batchService = new FinancialBatchService(rockContext); var scheduledTxnService = new FinancialScheduledTransactionService(rockContext); var contributionTxnTypeId = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid()).Id; var defaultAccount = accountService.Queryable() .Where(a => a.IsActive && !a.ParentAccountId.HasValue && (!a.StartDate.HasValue || a.StartDate.Value <= RockDateTime.Now) && (!a.EndDate.HasValue || a.EndDate.Value >= RockDateTime.Now) ) .OrderBy(a => a.Order) .FirstOrDefault(); foreach (var payment in payments.Where(p => p.Amount > 0.0M)) { totalPayments++; // Only consider transactions that have not already been added if (txnService.GetByTransactionCode(payment.TransactionCode) == null) { var scheduledTransaction = scheduledTxnService.GetByScheduleId(payment.GatewayScheduleId); if (scheduledTransaction != null) { scheduledTransaction.IsActive = payment.ScheduleActive; var transaction = new FinancialTransaction(); transaction.TransactionCode = payment.TransactionCode; transaction.TransactionDateTime = payment.TransactionDateTime; transaction.ScheduledTransactionId = scheduledTransaction.Id; transaction.AuthorizedPersonAliasId = scheduledTransaction.AuthorizedPersonAliasId; transaction.GatewayEntityTypeId = gateway.TypeId; transaction.TransactionTypeValueId = contributionTxnTypeId; var currencyTypeValue = payment.CurrencyTypeValue; if (currencyTypeValue == null && scheduledTransaction.CurrencyTypeValueId.HasValue) { currencyTypeValue = DefinedValueCache.Read(scheduledTransaction.CurrencyTypeValueId.Value); } if (currencyTypeValue != null) { transaction.CurrencyTypeValueId = currencyTypeValue.Id; } var creditCardTypevalue = payment.CreditCardTypeValue; if (creditCardTypevalue == null && scheduledTransaction.CreditCardTypeValueId.HasValue) { creditCardTypevalue = DefinedValueCache.Read(scheduledTransaction.CreditCardTypeValueId.Value); } if (creditCardTypevalue != null) { transaction.CreditCardTypeValueId = creditCardTypevalue.Id; } //transaction.SourceTypeValueId = DefinedValueCache.Read( sourceGuid ).Id; // Try to allocate the amount of the transaction based on the current scheduled transaction accounts decimal remainingAmount = payment.Amount; foreach (var detail in scheduledTransaction.ScheduledTransactionDetails.Where(d => d.Amount != 0.0M)) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.AccountId = detail.AccountId; if (detail.Amount <= remainingAmount) { // If the configured amount for this account is less than or equal to the remaining // amount, allocate the configured amount transactionDetail.Amount = detail.Amount; remainingAmount -= detail.Amount; } else { // If the configured amount is greater than the remaining amount, only allocate // the remaining amount transaction.Summary = "Note: Downloaded transaction amount was less than the configured allocation amounts for the Scheduled Transaction."; detail.Amount = remainingAmount; detail.Summary = "Note: The downloaded amount was not enough to apply the configured amount to this account."; remainingAmount = 0.0M; } transaction.TransactionDetails.Add(transactionDetail); if (remainingAmount <= 0.0M) { // If there's no amount left, break out of details break; } } // If there's still amount left after allocating based on current config, add the remainder // to the account that was configured for the most amount if (remainingAmount > 0.0M) { transaction.Summary = "Note: Downloaded transaction amount was greater than the configured allocation amounts for the Scheduled Transaction."; var transactionDetail = transaction.TransactionDetails .OrderByDescending(d => d.Amount) .First(); if (transactionDetail == null && defaultAccount != null) { transactionDetail = new FinancialTransactionDetail(); transactionDetail.AccountId = defaultAccount.Id; } if (transactionDetail != null) { transactionDetail.Amount += remainingAmount; transactionDetail.Summary = "Note: Extra amount was applied to this account."; } } // Get the batch var batch = batchService.Get( batchNamePrefix, currencyTypeValue, creditCardTypevalue, transaction.TransactionDateTime.Value, gateway.BatchTimeOffset, batches); batch.ControlAmount += transaction.TotalAmount; batch.Transactions.Add(transaction); // Add summary if (!batchSummary.ContainsKey(batch.Guid)) { batchSummary.Add(batch.Guid, new List <Payment>()); } batchSummary[batch.Guid].Add(payment); totalAdded++; } else { totalNoScheduledTransaction++; } } else { totalAlreadyDownloaded++; } } rockContext.SaveChanges(); StringBuilder sb = new StringBuilder(); sb.AppendFormat("<li>{0} {1} downloaded.</li>", totalPayments.ToString("N0"), (totalPayments == 1 ? "payment" : "payments")); if (totalAlreadyDownloaded > 0) { sb.AppendFormat("<li>{0} {1} previously downloaded and {2} already been added.</li>", totalAlreadyDownloaded.ToString("N0"), (totalAlreadyDownloaded == 1 ? "payment was" : "payments were"), (totalAlreadyDownloaded == 1 ? "has" : "have")); } if (totalNoScheduledTransaction > 0) { sb.AppendFormat("<li>{0} {1} could not be matched to an existing scheduled payment profile.</li>", totalNoScheduledTransaction.ToString("N0"), (totalNoScheduledTransaction == 1 ? "payment" : "payments")); } sb.AppendFormat("<li>{0} {1} successfully added.</li>", totalAdded.ToString("N0"), (totalAdded == 1 ? "payment was" : "payments were")); foreach (var batchItem in batchSummary) { int items = batchItem.Value.Count; if (items > 0) { var batch = batches .Where(b => b.Guid.Equals(batchItem.Key)) .FirstOrDefault(); string batchName = string.Format("'{0} ({1})'", batch.Name, batch.BatchStartDateTime.Value.ToString("d")); if (!string.IsNullOrWhiteSpace(batchUrlFormat)) { batchName = string.Format("<a href='{0}'>{1}</a>", string.Format(batchUrlFormat, batch.Id), batchName); } decimal sum = batchItem.Value.Select(p => p.Amount).Sum(); string summaryformat = items == 1 ? "<li>{0} transaction of {1} was added to the {2} batch.</li>" : "<li>{0} transactions totaling {1} were added to the {2} batch</li>"; sb.AppendFormat(summaryformat, items.ToString("N0"), sum.ToString("C2"), batchName); } } return(sb.ToString()); }
/// <summary> /// Processes the confirmation. /// </summary> /// <param name="errorMessage">The error message.</param> /// <returns></returns> private bool ProcessConfirmation( out string errorMessage ) { var rockContext = new RockContext(); if ( string.IsNullOrWhiteSpace( TransactionCode ) ) { var transactionGuid = hfTransactionGuid.Value.AsGuid(); bool isACHTxn = hfPaymentTab.Value == "ACH"; var financialGateway = isACHTxn ? _achGateway : _ccGateway; var gateway = isACHTxn ? _achGatewayComponent : _ccGatewayComponent; if ( gateway == null ) { errorMessage = "There was a problem creating the payment gateway information"; return false; } // only create/update the person if they are giving as a person. If they are giving as a Business, the person record already exists Person person = GetPerson( !phGiveAsOption.Visible || tglGiveAsOption.Checked ); if ( person == null ) { errorMessage = "There was a problem creating the person information"; return false; } if ( !person.PrimaryAliasId.HasValue ) { errorMessage = "There was a problem creating the person's primary alias"; return false; } Person BusinessOrPerson = GetPersonOrBusiness( person ); PaymentInfo paymentInfo = GetTxnPaymentInfo( BusinessOrPerson, out errorMessage ); if ( paymentInfo == null ) { return false; } PaymentSchedule schedule = GetSchedule(); FinancialPaymentDetail paymentDetail = null; if ( schedule != null ) { schedule.PersonId = person.Id; var scheduledTransactionAlreadyExists = new FinancialScheduledTransactionService( rockContext ).Queryable().FirstOrDefault( a => a.Guid == transactionGuid ); if ( scheduledTransactionAlreadyExists != null ) { // hopefully shouldn't happen, but just in case the scheduledtransaction already went thru, show the success screen ShowSuccess( gateway, person, paymentInfo, schedule, scheduledTransactionAlreadyExists.FinancialPaymentDetail, rockContext ); return true; } var scheduledTransaction = gateway.AddScheduledPayment( financialGateway, schedule, paymentInfo, out errorMessage ); if ( scheduledTransaction == null ) { return false; } // manually assign the Guid that we generated at the beginning of the transaction UI entry to help make duplicate scheduled transactions impossible scheduledTransaction.Guid = transactionGuid; SaveScheduledTransaction( financialGateway, gateway, BusinessOrPerson, paymentInfo, schedule, scheduledTransaction, rockContext ); paymentDetail = scheduledTransaction.FinancialPaymentDetail.Clone( false ); } else { var transactionAlreadyExists = new FinancialTransactionService( rockContext ).Queryable().FirstOrDefault( a => a.Guid == transactionGuid ); if ( transactionAlreadyExists != null ) { // hopefully shouldn't happen, but just in case the transaction already went thru, show the success screen ShowSuccess( gateway, person, paymentInfo, null, transactionAlreadyExists.FinancialPaymentDetail, rockContext ); return true; } var transaction = gateway.Charge( financialGateway, paymentInfo, out errorMessage ); if ( transaction == null ) { return false; } // manually assign the Guid that we generated at the beginning of the transaction UI entry to help make duplicate transactions impossible transaction.Guid = transactionGuid; SaveTransaction( financialGateway, gateway, BusinessOrPerson, paymentInfo, transaction, rockContext ); paymentDetail = transaction.FinancialPaymentDetail.Clone( false ); } ShowSuccess( gateway, person, paymentInfo, schedule, paymentDetail, rockContext ); return true; } else { pnlDupWarning.Visible = true; errorMessage = string.Empty; return false; } }
/// <summary> /// Gets the scheduled transaction. /// </summary> /// <returns></returns> private FinancialScheduledTransaction GetScheduledTransaction() { int? txnId = PageParameter( "ScheduledTransactionId" ).AsIntegerOrNull(); if (txnId.HasValue) { var rockContext = new RockContext(); var service = new FinancialScheduledTransactionService( rockContext ); return service .Queryable( "ScheduledTransactionDetails,FinancialGateway,FinancialPaymentDetail.CurrencyTypeValue,FinancialPaymentDetail.CreditCardTypeValue" ) .Where( t => t.Id == txnId.Value ) .FirstOrDefault(); } return null; }
/// <summary> /// Handles the Click event of the lbSaveAccount 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 lbSaveAccount_Click( object sender, EventArgs e ) { if ( string.IsNullOrWhiteSpace( TransactionCode ) ) { nbSaveAccount.Text = "Sorry, the account information cannot be saved as there's not a valid transaction code to reference"; nbSaveAccount.Visible = true; return; } using ( var rockContext = new RockContext() ) { if ( phCreateLogin.Visible ) { if ( string.IsNullOrWhiteSpace( txtUserName.Text ) || string.IsNullOrWhiteSpace( txtPassword.Text ) ) { nbSaveAccount.Title = "Missing Informaton"; nbSaveAccount.Text = "A username and password are required when saving an account"; nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; return; } if ( new UserLoginService( rockContext ).GetByUserName( txtUserName.Text ) != null ) { nbSaveAccount.Title = "Invalid Username"; nbSaveAccount.Text = "The selected Username is already being used. Please select a different Username"; nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; return; } if ( !UserLoginService.IsPasswordValid( txtPassword.Text ) ) { nbSaveAccount.Title = string.Empty; nbSaveAccount.Text = UserLoginService.FriendlyPasswordRules(); nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; return; } if ( txtPasswordConfirm.Text != txtPassword.Text ) { nbSaveAccount.Title = "Invalid Password"; nbSaveAccount.Text = "The password and password confirmation do not match"; nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; return; } } if ( !string.IsNullOrWhiteSpace( txtSaveAccount.Text ) ) { bool isACHTxn = hfPaymentTab.Value == "ACH"; var financialGateway = isACHTxn ? _achGateway : _ccGateway; var gateway = isACHTxn ? _achGatewayComponent : _ccGatewayComponent; if ( gateway != null ) { var ccCurrencyType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ) ); var achCurrencyType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ) ); string errorMessage = string.Empty; var person = GetPerson( false ); string referenceNumber = string.Empty; FinancialPaymentDetail paymentDetail = null; int? currencyTypeValueId = isACHTxn ? achCurrencyType.Id : ccCurrencyType.Id; if ( string.IsNullOrWhiteSpace( ScheduleId ) ) { var transaction = new FinancialTransactionService( rockContext ).GetByTransactionCode( TransactionCode ); if ( transaction != null && transaction.AuthorizedPersonAlias != null ) { if ( transaction.FinancialGateway != null ) { transaction.FinancialGateway.LoadAttributes( rockContext ); } referenceNumber = gateway.GetReferenceNumber( transaction, out errorMessage ); paymentDetail = transaction.FinancialPaymentDetail; } } else { var scheduledTransaction = new FinancialScheduledTransactionService( rockContext ).GetByScheduleId( ScheduleId ); if ( scheduledTransaction != null ) { if ( scheduledTransaction.FinancialGateway != null ) { scheduledTransaction.FinancialGateway.LoadAttributes( rockContext ); } referenceNumber = gateway.GetReferenceNumber( scheduledTransaction, out errorMessage ); paymentDetail = scheduledTransaction.FinancialPaymentDetail; } } if ( person != null && paymentDetail != null ) { if ( phCreateLogin.Visible ) { var user = UserLoginService.Create( rockContext, person, Rock.Model.AuthenticationServiceType.Internal, EntityTypeCache.Read( Rock.SystemGuid.EntityType.AUTHENTICATION_DATABASE.AsGuid() ).Id, txtUserName.Text, txtPassword.Text, false ); var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields( this.RockPage, this.CurrentPerson ); mergeFields.Add( "ConfirmAccountUrl", RootPath + "ConfirmAccount" ); var personDictionary = person.ToLiquid() as Dictionary<string, object>; mergeFields.Add( "Person", personDictionary ); mergeFields.Add( "User", user ); var recipients = new List<Rock.Communication.RecipientData>(); recipients.Add( new Rock.Communication.RecipientData( person.Email, mergeFields ) ); Rock.Communication.Email.Send( GetAttributeValue( "ConfirmAccountTemplate" ).AsGuid(), recipients, ResolveRockUrl( "~/" ), ResolveRockUrl( "~~/" ), false ); } if ( errorMessage.Any() ) { nbSaveAccount.Title = "Invalid Transaction"; nbSaveAccount.Text = "Sorry, the account information cannot be saved. " + errorMessage; nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; } else { var savedAccount = new FinancialPersonSavedAccount(); savedAccount.PersonAliasId = person.PrimaryAliasId; savedAccount.ReferenceNumber = referenceNumber; savedAccount.Name = txtSaveAccount.Text; savedAccount.TransactionCode = TransactionCode; savedAccount.FinancialGatewayId = financialGateway.Id; savedAccount.FinancialPaymentDetail = new FinancialPaymentDetail(); savedAccount.FinancialPaymentDetail.AccountNumberMasked = paymentDetail.AccountNumberMasked; savedAccount.FinancialPaymentDetail.CurrencyTypeValueId = paymentDetail.CurrencyTypeValueId; savedAccount.FinancialPaymentDetail.CreditCardTypeValueId = paymentDetail.CreditCardTypeValueId; savedAccount.FinancialPaymentDetail.NameOnCardEncrypted = paymentDetail.NameOnCardEncrypted; savedAccount.FinancialPaymentDetail.ExpirationMonthEncrypted = paymentDetail.ExpirationMonthEncrypted; savedAccount.FinancialPaymentDetail.ExpirationYearEncrypted = paymentDetail.ExpirationYearEncrypted; savedAccount.FinancialPaymentDetail.BillingLocationId = paymentDetail.BillingLocationId; var savedAccountService = new FinancialPersonSavedAccountService( rockContext ); savedAccountService.Add( savedAccount ); rockContext.SaveChanges(); cbSaveAccount.Visible = false; txtSaveAccount.Visible = false; phCreateLogin.Visible = false; divSaveActions.Visible = false; nbSaveAccount.Title = "Success"; nbSaveAccount.Text = "The account has been saved for future use"; nbSaveAccount.NotificationBoxType = NotificationBoxType.Success; nbSaveAccount.Visible = true; } } else { nbSaveAccount.Title = "Invalid Transaction"; nbSaveAccount.Text = "Sorry, the account information cannot be saved as there's not a valid transaction code to reference."; nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; } } else { nbSaveAccount.Title = "Invalid Gateway"; nbSaveAccount.Text = "Sorry, the financial gateway information for this type of transaction is not valid."; nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; } } else { nbSaveAccount.Title = "Missing Account Name"; nbSaveAccount.Text = "Please enter a name to use for this account."; nbSaveAccount.NotificationBoxType = NotificationBoxType.Danger; nbSaveAccount.Visible = true; } } }
/// <summary> /// Handles the Click event of the lbCancelSchedule 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 lbCancelSchedule_Click( object sender, EventArgs e ) { int? txnId = PageParameter( "ScheduledTransactionId" ).AsIntegerOrNull(); if ( txnId.HasValue ) { using ( var rockContext = new RockContext() ) { var txnService = new FinancialScheduledTransactionService( rockContext ); var txn = txnService .Queryable( "AuthorizedPersonAlias.Person,FinancialGateway" ) .FirstOrDefault( t => t.Id == txnId.Value ); if ( txn != null ) { if ( txn.FinancialGateway != null ) { txn.FinancialGateway.LoadAttributes( rockContext ); } string errorMessage = string.Empty; if ( txnService.Cancel( txn, out errorMessage ) ) { txnService.GetStatus( txn, out errorMessage ); rockContext.SaveChanges(); } else { ShowErrorMessage( errorMessage ); } ShowView( txn ); } } } }
/// <summary> /// Processes the payments. /// </summary> /// <param name="gateway">The gateway.</param> /// <param name="batchNamePrefix">The batch name prefix.</param> /// <param name="payments">The payments.</param> /// <param name="batchUrlFormat">The batch URL format.</param> /// <param name="receiptEmail">The receipt email.</param> /// <returns></returns> public static string ProcessPayments( FinancialGateway gateway, string batchNamePrefix, List<Payment> payments, string batchUrlFormat = "", Guid? receiptEmail = null ) { int totalPayments = 0; int totalAlreadyDownloaded = 0; int totalNoScheduledTransaction = 0; int totalAdded = 0; int totalReversals = 0; int totalStatusChanges = 0; var batches = new List<FinancialBatch>(); var batchSummary = new Dictionary<Guid, List<Decimal>>(); var initialControlAmounts = new Dictionary<Guid, decimal>(); var txnPersonNames = new Dictionary<Guid, string>(); var gatewayComponent = gateway.GetGatewayComponent(); var newTransactions = new List<FinancialTransaction>(); using ( var rockContext = new RockContext() ) { var accountService = new FinancialAccountService( rockContext ); var txnService = new FinancialTransactionService( rockContext ); var batchService = new FinancialBatchService( rockContext ); var scheduledTxnService = new FinancialScheduledTransactionService( rockContext ); var contributionTxnType = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid() ); var defaultAccount = accountService.Queryable() .Where( a => a.IsActive && !a.ParentAccountId.HasValue && ( !a.StartDate.HasValue || a.StartDate.Value <= RockDateTime.Now ) && ( !a.EndDate.HasValue || a.EndDate.Value >= RockDateTime.Now ) ) .OrderBy( a => a.Order ) .FirstOrDefault(); var batchTxnChanges = new Dictionary<Guid, List<string>>(); var batchBatchChanges = new Dictionary<Guid, List<string>>(); var scheduledTransactionIds = new List<int>(); foreach ( var payment in payments.Where( p => p.Amount > 0.0M ) ) { totalPayments++; var scheduledTransaction = scheduledTxnService.GetByScheduleId( payment.GatewayScheduleId ); if ( scheduledTransaction != null ) { // Find existing payments with same transaction code var txns = txnService .Queryable( "TransactionDetails" ) .Where( t => t.TransactionCode == payment.TransactionCode ) .ToList(); // Calculate whether a transaction needs to be added var txnAmount = CalculateTransactionAmount( payment, txns ); if ( txnAmount != 0.0M ) { scheduledTransactionIds.Add( scheduledTransaction.Id ); if ( payment.ScheduleActive.HasValue ) { scheduledTransaction.IsActive = payment.ScheduleActive.Value; } var transaction = new FinancialTransaction(); transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); transaction.Guid = Guid.NewGuid(); transaction.TransactionCode = payment.TransactionCode; transaction.TransactionDateTime = payment.TransactionDateTime; transaction.Status = payment.Status; transaction.StatusMessage = payment.StatusMessage; transaction.ScheduledTransactionId = scheduledTransaction.Id; transaction.AuthorizedPersonAliasId = scheduledTransaction.AuthorizedPersonAliasId; transaction.SourceTypeValueId = scheduledTransaction.SourceTypeValueId; txnPersonNames.Add( transaction.Guid, scheduledTransaction.AuthorizedPersonAlias.Person.FullName ); transaction.FinancialGatewayId = gateway.Id; transaction.TransactionTypeValueId = contributionTxnType.Id; if ( txnAmount < 0.0M ) { transaction.Summary = "Reversal for previous transaction that failed during processing." + Environment.NewLine; } var currencyTypeValue = payment.CurrencyTypeValue; var creditCardTypevalue = payment.CreditCardTypeValue; if ( scheduledTransaction.FinancialPaymentDetail != null ) { if ( currencyTypeValue == null && scheduledTransaction.FinancialPaymentDetail.CurrencyTypeValueId.HasValue ) { currencyTypeValue = DefinedValueCache.Read( scheduledTransaction.FinancialPaymentDetail.CurrencyTypeValueId.Value ); } if ( creditCardTypevalue == null && scheduledTransaction.FinancialPaymentDetail.CreditCardTypeValueId.HasValue ) { creditCardTypevalue = DefinedValueCache.Read( scheduledTransaction.FinancialPaymentDetail.CreditCardTypeValueId.Value ); } transaction.FinancialPaymentDetail.AccountNumberMasked = scheduledTransaction.FinancialPaymentDetail.AccountNumberMasked; transaction.FinancialPaymentDetail.NameOnCardEncrypted = scheduledTransaction.FinancialPaymentDetail.NameOnCardEncrypted; transaction.FinancialPaymentDetail.ExpirationMonthEncrypted = scheduledTransaction.FinancialPaymentDetail.ExpirationMonthEncrypted; transaction.FinancialPaymentDetail.ExpirationYearEncrypted = scheduledTransaction.FinancialPaymentDetail.ExpirationYearEncrypted; transaction.FinancialPaymentDetail.BillingLocationId = scheduledTransaction.FinancialPaymentDetail.BillingLocationId; } if ( currencyTypeValue != null ) { transaction.FinancialPaymentDetail.CurrencyTypeValueId = currencyTypeValue.Id; } if ( creditCardTypevalue != null ) { transaction.FinancialPaymentDetail.CreditCardTypeValueId = creditCardTypevalue.Id; } // Try to allocate the amount of the transaction based on the current scheduled transaction accounts decimal remainingAmount = Math.Abs( txnAmount ); foreach ( var detail in scheduledTransaction.ScheduledTransactionDetails.Where( d => d.Amount != 0.0M ) ) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.AccountId = detail.AccountId; if ( detail.Amount <= remainingAmount ) { // If the configured amount for this account is less than or equal to the remaining // amount, allocate the configured amount transactionDetail.Amount = detail.Amount; remainingAmount -= detail.Amount; } else { // If the configured amount is greater than the remaining amount, only allocate // the remaining amount transaction.Summary += "Note: Downloaded transaction amount was less than the configured allocation amounts for the Scheduled Transaction."; transactionDetail.Amount = remainingAmount; transactionDetail.Summary = "Note: The downloaded amount was not enough to apply the configured amount to this account."; remainingAmount = 0.0M; } transaction.TransactionDetails.Add( transactionDetail ); if ( remainingAmount <= 0.0M ) { // If there's no amount left, break out of details break; } } // If there's still amount left after allocating based on current config, add the remainder // to the account that was configured for the most amount if ( remainingAmount > 0.0M ) { transaction.Summary += "Note: Downloaded transaction amount was greater than the configured allocation amounts for the Scheduled Transaction."; var transactionDetail = transaction.TransactionDetails .OrderByDescending( d => d.Amount ) .FirstOrDefault(); if ( transactionDetail == null && defaultAccount != null ) { transactionDetail = new FinancialTransactionDetail(); transactionDetail.AccountId = defaultAccount.Id; transaction.TransactionDetails.Add( transactionDetail ); } if ( transactionDetail != null ) { transactionDetail.Amount += remainingAmount; transactionDetail.Summary = "Note: Extra amount was applied to this account."; } } // If the amount to apply was negative, update all details to be negative (absolute value was used when allocating to accounts) if ( txnAmount < 0.0M ) { foreach ( var txnDetail in transaction.TransactionDetails ) { txnDetail.Amount = 0 - txnDetail.Amount; } } // Get the batch var batch = batchService.Get( batchNamePrefix, currencyTypeValue, creditCardTypevalue, transaction.TransactionDateTime.Value, gateway.GetBatchTimeOffset(), batches ); var batchChanges = new List<string>(); if ( batch.Id != 0 ) { initialControlAmounts.AddOrIgnore( batch.Guid, batch.ControlAmount ); } batch.ControlAmount += transaction.TotalAmount; batch.Transactions.Add( transaction ); if ( txnAmount > 0.0M && receiptEmail.HasValue ) { newTransactions.Add( transaction ); } // Add summary if ( !batchSummary.ContainsKey( batch.Guid ) ) { batchSummary.Add( batch.Guid, new List<Decimal>() ); } batchSummary[batch.Guid].Add( txnAmount ); if ( txnAmount > 0.0M ) { totalAdded++; } else { totalReversals++; } } else { totalAlreadyDownloaded++; foreach ( var txn in txns.Where( t => t.Status != payment.Status || t.StatusMessage != payment.StatusMessage ) ) { txn.Status = payment.Status; txn.StatusMessage = payment.StatusMessage; totalStatusChanges++; } } } else { totalNoScheduledTransaction++; } } rockContext.SaveChanges(); // Queue a transaction to update the status of all affected scheduled transactions var updatePaymentStatusTxn = new Rock.Transactions.UpdatePaymentStatusTransaction( gateway.Id, scheduledTransactionIds ); Rock.Transactions.RockQueue.TransactionQueue.Enqueue( updatePaymentStatusTxn ); if ( receiptEmail.HasValue ) { // Queue a transaction to send receipts var newTransactionIds = newTransactions.Select( t => t.Id ).ToList(); var sendPaymentReceiptsTxn = new Rock.Transactions.SendPaymentReceipts( receiptEmail.Value, newTransactionIds ); Rock.Transactions.RockQueue.TransactionQueue.Enqueue( sendPaymentReceiptsTxn ); } } StringBuilder sb = new StringBuilder(); sb.AppendFormat( "<li>{0} {1} downloaded.</li>", totalPayments.ToString( "N0" ), ( totalPayments == 1 ? "payment" : "payments" ) ); if ( totalAlreadyDownloaded > 0 ) { sb.AppendFormat( "<li>{0} {1} previously downloaded and {2} already been added.</li>", totalAlreadyDownloaded.ToString( "N0" ), ( totalAlreadyDownloaded == 1 ? "payment was" : "payments were" ), ( totalAlreadyDownloaded == 1 ? "has" : "have" ) ); } if ( totalStatusChanges > 0 ) { sb.AppendFormat( "<li>{0} {1} previously downloaded but had a change of status.</li>", totalStatusChanges.ToString( "N0" ), ( totalStatusChanges == 1 ? "payment was" : "payments were" ) ); } if ( totalNoScheduledTransaction > 0 ) { sb.AppendFormat( "<li>{0} {1} could not be matched to an existing scheduled payment profile.</li>", totalNoScheduledTransaction.ToString( "N0" ), ( totalNoScheduledTransaction == 1 ? "payment" : "payments" ) ); } sb.AppendFormat( "<li>{0} {1} successfully added.</li>", totalAdded.ToString( "N0" ), ( totalAdded == 1 ? "payment was" : "payments were" ) ); if ( totalReversals > 0 ) { sb.AppendFormat( "<li>{0} {1} added as a reversal to a previous transaction.</li>", totalReversals.ToString( "N0" ), ( totalReversals == 1 ? "payment was" : "payments were" ) ); } if ( totalStatusChanges > 0 ) { sb.AppendFormat( "<li>{0} {1} previously downloaded but had a change of status.</li>", totalStatusChanges.ToString( "N0" ), ( totalStatusChanges == 1 ? "payment was" : "payments were" ) ); } foreach ( var batchItem in batchSummary ) { int items = batchItem.Value.Count; if ( items > 0 ) { var batch = batches .Where( b => b.Guid.Equals( batchItem.Key ) ) .FirstOrDefault(); string batchName = string.Format( "'{0} ({1})'", batch.Name, batch.BatchStartDateTime.Value.ToString( "d" ) ); if ( !string.IsNullOrWhiteSpace( batchUrlFormat ) ) { batchName = string.Format( "<a href='{0}'>{1}</a>", string.Format( batchUrlFormat, batch.Id ), batchName ); } decimal sum = batchItem.Value.Sum(); string summaryformat = items == 1 ? "<li>{0} transaction of {1} was added to the {2} batch.</li>" : "<li>{0} transactions totaling {1} were added to the {2} batch</li>"; sb.AppendFormat( summaryformat, items.ToString( "N0" ), sum.FormatAsCurrency(), batchName ); } } return sb.ToString(); }
/// <summary> /// Binds the grid. /// </summary> private void BindGrid() { int? personId = null; int? givingGroupId = null; bool validRequest = false; if ( TargetPerson != null ) { personId = TargetPerson.Id; givingGroupId = TargetPerson.GivingGroupId; validRequest = true; } else { int personEntityTypeId = EntityTypeCache.Read( "Rock.Model.Person" ).Id; if ( !ContextTypesRequired.Any( e => e.Id == personEntityTypeId ) ) { validRequest = true; } } if ( validRequest ) { var rockContext = new RockContext(); var qry = new FinancialScheduledTransactionService( rockContext ) .Queryable( "ScheduledTransactionDetails,FinancialPaymentDetail.CurrencyTypeValue,FinancialPaymentDetail.CreditCardTypeValue" ) .AsNoTracking(); // Amount Range var nre = new NumberRangeEditor(); nre.DelimitedValues = gfSettings.GetUserPreference( "Amount" ); if ( nre.LowerValue.HasValue ) { qry = qry.Where( t => t.ScheduledTransactionDetails.Sum( d => d.Amount ) >= nre.LowerValue.Value ); } if ( nre.UpperValue.HasValue ) { qry = qry.Where( t => t.ScheduledTransactionDetails.Sum( d => d.Amount ) <= nre.UpperValue.Value ); } // Frequency int? frequencyTypeId = gfSettings.GetUserPreference( "Frequency" ).AsIntegerOrNull(); if ( frequencyTypeId.HasValue ) { qry = qry.Where( t => t.TransactionFrequencyValueId == frequencyTypeId.Value ); } // Date Range var drp = new DateRangePicker(); drp.DelimitedValues = gfSettings.GetUserPreference( "Created" ); if ( drp.LowerValue.HasValue ) { qry = qry.Where( t => t.CreatedDateTime >= drp.LowerValue.Value ); } if ( drp.UpperValue.HasValue ) { DateTime upperDate = drp.UpperValue.Value.Date.AddDays( 1 ); qry = qry.Where( t => t.CreatedDateTime < upperDate ); } // Account Id int accountId = int.MinValue; if ( int.TryParse( gfSettings.GetUserPreference( "Account" ), out accountId ) ) { qry = qry.Where( t => t.ScheduledTransactionDetails.Any( d => d.AccountId == accountId ) ); } // Active only (no filter) if ( string.IsNullOrWhiteSpace( gfSettings.GetUserPreference( "Include Inactive" ) ) ) { qry = qry.Where( t => t.IsActive ); } if ( givingGroupId.HasValue ) { // Person contributes with family qry = qry.Where( t => t.AuthorizedPersonAlias.Person.GivingGroupId == givingGroupId ); } else if ( personId.HasValue ) { // Person contributes individually qry = qry.Where( t => t.AuthorizedPersonAlias.PersonId == personId ); } SortProperty sortProperty = gList.SortProperty; if ( sortProperty != null ) { if ( sortProperty.Property == "Amount" ) { if ( sortProperty.Direction == SortDirection.Ascending ) { qry = qry.OrderBy( t => t.ScheduledTransactionDetails.Sum( d => (decimal?)d.Amount ) ?? 0.00M ); } else { qry = qry.OrderByDescending( t => t.ScheduledTransactionDetails.Sum( d => (decimal?)d.Amount ) ?? 0.0M ); } } else { qry = qry.Sort( sortProperty ); } } else { qry = qry .OrderBy( t => t.AuthorizedPersonAlias.Person.LastName ) .ThenBy( t => t.AuthorizedPersonAlias.Person.NickName ) .ThenByDescending( t => t.IsActive ) .ThenByDescending( t => t.StartDate ); } gList.SetLinqDataSource<FinancialScheduledTransaction>( qry ); gList.DataBind(); } }