/// <summary> /// This method stores the transaction in the database along with the appropriate details and batch information. /// </summary> private FinancialTransaction SaveTransaction(Guid transactionGuid) { // if this is a future transaction, the payment hasn't been charged yet if (_payment == null && _automatedPaymentArgs.FutureProcessingDateTime.HasValue) { _payment = new Payment { Status = "PreProcessing", StatusMessage = "This transaction is scheduled to be processed in the future", TransactionCode = _financialPersonSavedAccount.Id.ToStringSafe() }; } // Create a new transaction or update the future transaction now that it has been charged var financialTransaction = _futureTransaction ?? new FinancialTransaction(); financialTransaction.TransactionCode = _payment.TransactionCode; financialTransaction.Guid = transactionGuid; financialTransaction.CreatedByPersonAliasId = _currentPersonAliasId; financialTransaction.ScheduledTransactionId = _automatedPaymentArgs.ScheduledTransactionId; financialTransaction.AuthorizedPersonAliasId = _automatedPaymentArgs.AuthorizedPersonAliasId; financialTransaction.ShowAsAnonymous = _automatedPaymentArgs.ShowAsAnonymous; financialTransaction.TransactionDateTime = _automatedPaymentArgs.FutureProcessingDateTime.HasValue ? ( DateTime? )null : RockDateTime.Now; financialTransaction.FinancialGatewayId = _financialGateway.Id; financialTransaction.TransactionTypeValueId = _transactionType.Id; financialTransaction.Summary = string.Format("{0} {1}", financialTransaction.Summary, _referencePaymentInfo.Comment1).Trim(); financialTransaction.SourceTypeValueId = _financialSource.Id; financialTransaction.IsSettled = _payment.IsSettled; financialTransaction.Status = _payment.Status; financialTransaction.StatusMessage = _payment.StatusMessage; financialTransaction.SettledDate = _payment.SettledDate; financialTransaction.ForeignKey = _payment.ForeignKey; financialTransaction.FutureProcessingDateTime = _automatedPaymentArgs.FutureProcessingDateTime; financialTransaction.ForeignCurrencyCodeValueId = GetCurrencyCodeDefinedValueCache(_automatedPaymentArgs.AmountCurrencyCode)?.Id; // Create a new payment detail or update the future transaction's payment detail now that it has been charged var financialPaymentDetail = financialTransaction.FinancialPaymentDetail ?? new FinancialPaymentDetail(); financialPaymentDetail.AccountNumberMasked = _payment.AccountNumberMasked; financialPaymentDetail.NameOnCard = _payment.NameOnCard; financialPaymentDetail.ExpirationMonth = _payment.ExpirationMonth; financialPaymentDetail.ExpirationYear = _payment.ExpirationYear; financialPaymentDetail.CreatedByPersonAliasId = _currentPersonAliasId; financialPaymentDetail.ForeignKey = _payment.ForeignKey; financialPaymentDetail.GatewayPersonIdentifier = _financialPersonSavedAccount?.GatewayPersonIdentifier; financialPaymentDetail.FinancialPersonSavedAccountId = _financialPersonSavedAccount?.Id; if (_payment.CurrencyTypeValue != null) { financialPaymentDetail.CurrencyTypeValueId = _payment.CurrencyTypeValue.Id; } if (_payment.CreditCardTypeValue != null) { financialPaymentDetail.CreditCardTypeValueId = _payment.CreditCardTypeValue.Id; } financialPaymentDetail.SetFromPaymentInfo(_referencePaymentInfo, _automatedGatewayComponent, _rockContext); financialTransaction.FinancialPaymentDetail = financialPaymentDetail; financialTransaction.FinancialPaymentDetailId = financialPaymentDetail.Id == 0 ? ( int? )null : financialPaymentDetail.Id; // Future transactions already have the appropriate FinancialTransactionDetail models if (_futureTransaction == null) { var doesHaveForeignCurrency = financialTransaction.ForeignCurrencyCodeValueId != null; foreach (var detailArgs in _automatedPaymentArgs.AutomatedPaymentDetails) { var transactionDetail = new FinancialTransactionDetail { Amount = detailArgs.Amount, AccountId = detailArgs.AccountId }; if (doesHaveForeignCurrency) { transactionDetail.ForeignCurrencyAmount = detailArgs.Amount; } financialTransaction.TransactionDetails.Add(transactionDetail); } if (doesHaveForeignCurrency) { /* * The amount coming from the gateway is always in the Organization's currency. * As such the Amount value could be different than the original amount passed in if the * specified currency code is different then the Organization's currency code. */ financialTransaction.SetApportionedDetailAmounts(_payment.Amount); } } // New transactions and future transactions need fee info financialTransaction.SetApportionedFeesOnDetails(_payment.FeeAmount); // Get an existing or new batch according to the name prefix and payment type FinancialBatch batch; if (!financialTransaction.BatchId.HasValue) { batch = _financialBatchService.Get( _automatedPaymentArgs.BatchNamePrefix ?? "Online Giving", string.Empty, _referencePaymentInfo.CurrencyTypeValue, _referencePaymentInfo.CreditCardTypeValue, financialTransaction.TransactionDateTime ?? financialTransaction.FutureProcessingDateTime.Value, _financialGateway.GetBatchTimeOffset(), _financialGateway.BatchDayOfWeek); } else { batch = _financialBatchService.Get(financialTransaction.BatchId.Value); } var batchChanges = new History.HistoryChangeList(); var isNewBatch = batch.Id == 0; // If this is a new Batch, SaveChanges so that we can get the Batch.Id and also // add history entries about the batch creation if (isNewBatch) { batchChanges.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "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); _rockContext.SaveChanges(); } if (_futureTransaction == null) { // Use the financialTransactionService to add the transaction instead of batch.Transactions // to avoid lazy-loading the transactions already associated with the batch financialTransaction.BatchId = batch.Id; _financialTransactionService.Add(financialTransaction); } _rockContext.SaveChanges(); if (_futureTransaction == null) { // Update the batch control amount _financialBatchService.IncrementControlAmount(batch.Id, financialTransaction.TotalAmount, batchChanges); _rockContext.SaveChanges(); } // Save the changes history for the batch HistoryService.SaveChanges( _rockContext, typeof(FinancialBatch), SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), batch.Id, batchChanges ); return(financialTransaction); }