/// <summary> /// Gets the transaction details. /// </summary> /// <param name="rockContext">The rock context.</param> /// <returns></returns> protected List <FinancialTransactionDetail> GetTransactionDetails(RockContext rockContext) { var details = new List <FinancialTransactionDetail>(); var financialAccountService = new FinancialAccountService(rockContext); int defaultAccountId = financialAccountService.Get(GetAttributeValue("DefaultAccount").AsGuid()).Id; foreach (var item in Cart.Items) { int financialAccountId = item.AccountId ?? defaultAccountId; var transactionDetail = details.FirstOrDefault(d => d.AccountId == financialAccountId); if (transactionDetail == null) { transactionDetail = new FinancialTransactionDetail { Amount = 0, AccountId = financialAccountId }; details.Add(transactionDetail); } transactionDetail.Amount += item.ExtendedPrice; } return(details); }
public static FinancialTransactionDetail Translate(XElement inputTransactionDetail) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Id = inputTransactionDetail.Attribute("id").Value.AsInteger(); // Checking if there is a subfund if (string.IsNullOrEmpty(inputTransactionDetail.Element("subFund")?.Attribute("id").Value)) { transactionDetail.AccountId = inputTransactionDetail.Element("fund")?.Attribute("id")?.Value.AsInteger(); } else { transactionDetail.AccountId = inputTransactionDetail.Element("subFund")?.Attribute("id")?.Value.AsInteger(); } transactionDetail.Amount = inputTransactionDetail.Element("amount").Value.AsDecimal(); transactionDetail.TransactionId = inputTransactionDetail.Attribute("id").Value.AsInteger(); transactionDetail.CreatedDateTime = inputTransactionDetail.Element("createdDate")?.Value.AsDateTime(); transactionDetail.CreatedByPersonId = inputTransactionDetail.Element("createdByPerson").Attribute("id")?.Value.AsIntegerOrNull(); transactionDetail.ModifiedDateTime = inputTransactionDetail.Element("lastUpdateDate")?.Value.AsDateTime(); transactionDetail.ModifiedByPersonId = inputTransactionDetail.Element("lastUpdatedByPerson").Attribute("id")?.Value.AsIntegerOrNull(); return(transactionDetail); }
public static FinancialTransactionDetail Translate(DataRow row) { var financialTransactionDetail = new FinancialTransactionDetail(); financialTransactionDetail.AccountId = row.Field <Int16>("FundNumber"); financialTransactionDetail.Amount = row.Field <decimal>("Amount"); financialTransactionDetail.TransactionId = row.Field <int>("TransactionID"); financialTransactionDetail.Summary = row.Field <string>("GiftDescription"); financialTransactionDetail.CreatedDateTime = row.Field <DateTime?>("GiftDate"); return(financialTransactionDetail); }
public static FinancialTransactionDetail Translate(DataRow row) { var financialTransactionDetail = new FinancialTransactionDetail(); financialTransactionDetail.TransactionId = row.Field <int>("Id"); financialTransactionDetail.AccountId = row.Field <int>("AccountId"); financialTransactionDetail.Amount = row.Field <decimal>("Amount"); financialTransactionDetail.CreatedDateTime = row.Field <DateTime?>("CreatedDateTime"); financialTransactionDetail.ModifiedDateTime = row.Field <DateTime?>("ModifiedDateTime"); return(financialTransactionDetail); }
public static FinancialTransactionDetail Translate(DataRow row) { FinancialTransactionDetail detail = new FinancialTransactionDetail(); // Identifiers detail.Id = row.Field <int>("DETAIL_ID"); detail.TransactionId = row.Field <int>("CONTRIBUTION_ID"); detail.AccountId = row.Field <int>("ACCOUNT_ID"); // Other Fields detail.Amount = (decimal)row.Field <double>("AMT"); detail.Summary = row.Field <string>("NOTE"); detail.CreatedDateTime = row.Field <DateTime?>("CREATE_TS"); detail.ModifiedDateTime = row.Field <DateTime?>("UPDATE_TS"); return(detail); }
public static FinancialTransactionDetail Translate(XElement inputTransactionDetail, int transactionId) { var financialTransactionDetail = new FinancialTransactionDetail(); financialTransactionDetail.Id = inputTransactionDetail.Attribute("id").Value.AsInteger(); financialTransactionDetail.AccountId = inputTransactionDetail.Element("coa")?.Attribute("id")?.Value.AsInteger(); financialTransactionDetail.Amount = inputTransactionDetail.Element("amount").Value.AsDecimal(); financialTransactionDetail.Summary = $"Contribution to: {inputTransactionDetail.Element( "coa" )?.Value} {inputTransactionDetail.Element( "note" )?.Value}"; financialTransactionDetail.TransactionId = transactionId; financialTransactionDetail.CreatedDateTime = inputTransactionDetail.Element("created")?.Value.AsDateTime(); financialTransactionDetail.ModifiedDateTime = inputTransactionDetail.Element("modified")?.Value.AsDateTime(); financialTransactionDetail.CreatedByPersonId = inputTransactionDetail.Element("creator")?.Attribute("id")?.Value.AsIntegerOrNull(); financialTransactionDetail.ModifiedByPersonId = inputTransactionDetail.Element("modifier")?.Attribute("id")?.Value.AsIntegerOrNull(); return(financialTransactionDetail); }
public static FinancialTransactionDetail Translate(DataRow row) { FinancialTransactionDetail detail = new FinancialTransactionDetail(); // Identifiers Random rnd = new Random(); detail.Id = row.Field <int>("Id") + 10000000; detail.TransactionId = row.Field <int>("Id"); detail.AccountId = Math.Abs(row.Field <String>("Category").GetHashCode()); // Other Fields detail.Amount = decimal.Parse(Convert.ToString(row["Amount"]), System.Globalization.NumberStyles.Currency); detail.Summary = row.Field <string>("Note"); detail.CreatedDateTime = row.Field <DateTime?>("Date"); detail.ModifiedDateTime = row.Field <DateTime?>("Date"); return(detail); }
/// <summary> /// Handles the SaveClick event of the mdAccount 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 mdAccount_SaveClick(object sender, EventArgs e) { Guid?guid = hfAccountGuid.Value.AsGuidOrNull(); if (guid.HasValue) { var txnDetail = TransactionDetailsState.Where(t => t.Guid.Equals(guid.Value)).FirstOrDefault(); if (txnDetail == null) { txnDetail = new FinancialTransactionDetail(); TransactionDetailsState.Add(txnDetail); } txnDetail.AccountId = ddlAccount.SelectedValue.AsInteger(); txnDetail.Amount = tbAccountAmount.Text.AsDecimal(); txnDetail.Summary = tbAccountSummary.Text; BindAccounts(); } HideDialog(); }
public static List <FinancialTransactionDetail> Translate(DonationDTO inputDonation) { var transactionDetails = new List <FinancialTransactionDetail>(); foreach (var inputTransactionDetail in inputDonation.Designations) { var transactionDetail = new FinancialTransactionDetail { Id = inputTransactionDetail.Id, AccountId = inputTransactionDetail.FundId, Amount = Convert.ToDecimal(inputTransactionDetail.AmountCents.Value / 100.00), TransactionId = inputDonation.Id, CreatedDateTime = inputDonation.CreatedAt, ModifiedDateTime = inputDonation.UpdatedAt }; transactionDetails.Add(transactionDetail); } return(transactionDetails); }
/// <summary> /// Handles the SaveClick event of the mdDetails control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> private void mdDetails_SaveClick(object sender, EventArgs e) { var rockContext = new RockContext(); if (!string.IsNullOrWhiteSpace(tbTransactionAmount.Text)) { var ftdService = new FinancialTransactionDetailService(rockContext); FinancialTransactionDetail ftd = null; var transactionDetailId = int.Parse(hfIdValue.Value); if (transactionDetailId > 0) { ftd = ftdService.Get(transactionDetailId); } else { ftd = new FinancialTransactionDetail { Id = 0 }; } ftd.TransactionId = hfIdTransValue.ValueAsInt(); ftd.AccountId = int.Parse(ddlTransactionAccount.SelectedValue); ftd.Amount = decimal.Parse(tbTransactionAmount.Text); ftd.Summary = tbTransactionSummary.Text; if (transactionDetailId == 0) { ftdService.Add(ftd); } rockContext.SaveChanges(); } mdDetails.Hide(); FinancialTransaction transaction = new FinancialTransaction(); transaction = new FinancialTransactionService(rockContext).Get(hfIdTransValue.ValueAsInt()); BindTransactionDetailGrid(transaction); LoadRelatedImages(transaction.Id); }
private void LoadFinancialTransactionDetails(FinancialTransaction financialTransaction) { decimal sum = 0; List <DisplayFinancialTransactionDetailModel> displayFinancialTransactionDetailList = new List <DisplayFinancialTransactionDetailModel>(); // first, make sure all the accounts that are part of the existing transaction are included, even if they aren't included in the configured selected accounts if (financialTransaction.TransactionDetails != null) { foreach (var detail in financialTransaction.TransactionDetails) { sum += detail.Amount; detail.Account = ScanningPageUtility.Accounts.FirstOrDefault(a => a.Id == detail.AccountId); displayFinancialTransactionDetailList.Add(new DisplayFinancialTransactionDetailModel(detail)); } } RockConfig rockConfig = RockConfig.Load(); List <DisplayAccountValueModel> sortedDisplayedAccountList = ScanningPageUtility.GetVisibleAccountsSortedAndFlattened(); // now, add accounts that aren't part of the Transaction in case they want to split to different accounts foreach (var displayAccount in sortedDisplayedAccountList) { if (!displayFinancialTransactionDetailList.Any(a => a.AccountId == displayAccount.AccountId)) { FinancialTransactionDetail financialTransactionDetail = new FinancialTransactionDetail(); financialTransactionDetail.Guid = Guid.NewGuid(); financialTransactionDetail.AccountId = displayAccount.AccountId; financialTransactionDetail.Account = displayAccount.Account; displayFinancialTransactionDetailList.Add(new DisplayFinancialTransactionDetailModel(financialTransactionDetail)); } } // show displayed accounts sorted by its position in sortedDisplayedAccountList displayFinancialTransactionDetailList = displayFinancialTransactionDetailList.OrderBy(a => sortedDisplayedAccountList.FirstOrDefault(s => s.AccountId == a.AccountId)?.DisplayIndex).ToList(); this.lvAccountDetails.ItemsSource = displayFinancialTransactionDetailList; this.lblTotals.Content = sum.ToString("C"); }
public static FinancialTransactionDetail Translate(ContributionDetail contributionDetail) { FinancialTransactionDetail detail = new FinancialTransactionDetail(); detail.Id = Math.Abs(unchecked (( int )contributionDetail.Id)); // Increment the id until we find one that is unqiue. while (!UsedDetailIds.Add(detail.Id)) { detail.Id++; } detail.TransactionId = IdMap[contributionDetail.ContributionId]; detail.CreatedDateTime = contributionDetail.CreatedDate; detail.ModifiedDateTime = contributionDetail.UpdatedDate; detail.AccountId = Math.Abs(unchecked (( int )contributionDetail.AccountId)); if (contributionDetail.Amount == 0) { string amount = contributionDetail.EncodedAmount; foreach (var trans in AmountTranslation) { amount = amount.Replace(trans.Value, trans.Key); } try { detail.Amount = Decimal.Parse(amount); } catch (Exception e) { throw e; } } else { detail.Amount = contributionDetail.Amount; } return(detail); }
private static FinancialTransactionDetail CreateFinancialTransactionDetail( int accountId, int transactionId, int number, DateTime transactionDateTime) { var transactionDetail = new FinancialTransactionDetail { TransactionId = transactionId, AccountId = accountId, Amount = TRANSACTION_AMOUNT, Summary = $"Giving Test {number}", EntityTypeId = null, Guid = Guid.NewGuid(), CreatedDateTime = transactionDateTime, ModifiedDateTime = RockDateTime.Now }; _transactionDetailService.Add(transactionDetail); _rockContext.SaveChanges(true); return(transactionDetail); }
public static List <FinancialTransactionDetail> Translate(PCODonation inputDonation) { var transactionDetails = new List <FinancialTransactionDetail>(); foreach (var inputTransactionDetail in inputDonation.designations) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Id = inputTransactionDetail.id; transactionDetail.AccountId = inputTransactionDetail.fundId; transactionDetail.Amount = Convert.ToDecimal(inputTransactionDetail.amount_cents.Value / 100.00); transactionDetail.TransactionId = inputDonation.id; transactionDetail.CreatedDateTime = inputDonation.created_at; transactionDetail.ModifiedDateTime = inputDonation.updated_at; transactionDetails.Add(transactionDetail); } return(transactionDetails); }
/// <summary> /// Process the data read from the card reader and generate the transaction. /// </summary> /// <param name="swipeData">The data read from the card.</param> private void ProcessSwipe(string swipeData) { try { using (var rockContext = new RockContext()) { // create swipe object SwipePaymentInfo swipeInfo = new SwipePaymentInfo(swipeData); swipeInfo.Amount = tbAmount.Text.AsDecimal(); // add comment to the transation swipeInfo.Comment1 = PageParameter("Memo"); // get gateway FinancialGateway financialGateway = null; GatewayComponent gateway = null; Guid? gatewayGuid = GetAttributeValue("CreditCardGateway").AsGuidOrNull(); if (gatewayGuid.HasValue) { financialGateway = new FinancialGatewayService(rockContext).Get(gatewayGuid.Value); if (financialGateway != null) { financialGateway.LoadAttributes(rockContext); } gateway = financialGateway.GetGatewayComponent(); } if (gateway == null) { lSwipeErrors.Text = "<div class='alert alert-danger'>Invalid gateway provided. Please provide a gateway. Transaction not processed.</div>"; return; } // // Process the transaction. // string errorMessage = string.Empty; var transaction = gateway.Charge(financialGateway, swipeInfo, out errorMessage); if (transaction == null) { lSwipeErrors.Text = String.Format("<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", errorMessage); return; } _transactionCode = transaction.TransactionCode; // // Set some common information about the transaction. // transaction.AuthorizedPersonAliasId = new PersonService(rockContext).Get(SelectedPersonGuid).PrimaryAliasId; transaction.TransactionDateTime = RockDateTime.Now; transaction.FinancialGatewayId = financialGateway.Id; transaction.TransactionTypeValueId = DefinedValueCache.Read(GetAttributeValue("TransactionType")).Id; transaction.SourceTypeValueId = DefinedValueCache.Read(GetAttributeValue("Source")).Id; transaction.Summary = swipeInfo.Comment1; // // Ensure we have payment details. // if (transaction.FinancialPaymentDetail == null) { transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); } transaction.FinancialPaymentDetail.SetFromPaymentInfo(swipeInfo, gateway, rockContext); var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = swipeInfo.Amount; transactionDetail.AccountId = new FinancialAccountService(rockContext).Get(GetAttributeValue("Account").AsGuid()).Id; transaction.TransactionDetails.Add(transactionDetail); var batchService = new FinancialBatchService(rockContext); // Get the batch var batch = batchService.Get( GetAttributeValue("BatchNamePrefix"), swipeInfo.CurrencyTypeValue, swipeInfo.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.WrapTransaction(() => { rockContext.SaveChanges(); HistoryService.SaveChanges( rockContext, typeof(FinancialBatch), Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), batch.Id, batchChanges ); }); ShowReceiptPanel(); } } catch (Exception ex) { lSwipeErrors.Text = String.Format("<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", ex.Message); } }
/// <summary> /// Processes a transaction. /// </summary> /// <param name="giftElement">The gift element.</param> /// <param name="batch">The batch.</param> /// <param name="rockContext">The rock context.</param> /// <param name="envelopeAttributeId">The envelope attribute identifier.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> private ProcessStatus ProcessTransaction(XElement giftElement, int?batchId, int?envelopeAttributeId, int?binaryFileTypeId, out List <string> errorMessages) { errorMessages = new List <string>(); // Get batch/sequence number first as they are used in any error messages string batchNo = GetChildElementValue(giftElement, "BatchNo"); string seqNo = GetChildElementValue(giftElement, "SequenceNo"); try { using (var rockContext = new RockContext()) { // Check to see if accout/routing/check information is specified string encryptedAccountNum = GetChildElementValue(giftElement, "DFIAcct"); string encryptedRoutingNum = GetChildElementValue(giftElement, "DFID"); string checkNum = GetChildElementValue(giftElement, "CheckNum"); // Start to create the transaction var txn = new FinancialTransaction(); txn.BatchId = batchId; txn.TransactionTypeValueId = _transactionTypeContributionId; txn.TransactionDateTime = GetChildElementValue(giftElement, "GiftDate").AsDateTime(); txn.Summary = string.Format("{0}:{1}", batchNo, seqNo); txn.FinancialPaymentDetail = new FinancialPaymentDetail(); // Try to find an person to associate with this account int?personAliasId = null; if (!string.IsNullOrWhiteSpace(encryptedAccountNum) && !string.IsNullOrWhiteSpace(encryptedRoutingNum)) { // If account/routing information was included, use it to find matching person from Bank Account table // A person will be selected if there is only ONE match found with same information. var accountNum = DecryptAccountInformation(encryptedAccountNum); var routingNum = DecryptAccountInformation(encryptedRoutingNum); string checkMicrHashed = FinancialPersonBankAccount.EncodeAccountNumber(routingNum, accountNum); if (!string.IsNullOrWhiteSpace(checkMicrHashed)) { var matchedPersonIds = new FinancialPersonBankAccountService(rockContext) .Queryable() .Where(a => a.AccountNumberSecured == checkMicrHashed) .Select(a => a.PersonAlias.PersonId) .Distinct() .ToList(); if (matchedPersonIds.Count() == 1) { personAliasId = new PersonAliasService(rockContext) .GetPrimaryAliasId(matchedPersonIds.First()); } } txn.MICRStatus = MICRStatus.Success; txn.CheckMicrParts = Encryption.EncryptString(string.Format("{0}_{1}_{2}", routingNum, accountNum, checkNum)); txn.FinancialPaymentDetail.CurrencyTypeValueId = _currencyTypeCheck; txn.TransactionCode = checkNum; } else { // If account/routing number was NOT included, check for an envelope number, and if provided find first // person with same envelope number (unlike account/routing number, this will automatically select first // person when there are multiple people with same envelope number. string envelopeNum = GetChildElementValue(giftElement, "EnvNum"); if (!string.IsNullOrWhiteSpace(envelopeNum)) { int?personId = new AttributeValueService(rockContext) .Queryable().AsNoTracking() .Where(v => v.AttributeId == envelopeAttributeId && v.Value == envelopeNum) .OrderBy(v => v.EntityId) .Select(v => v.EntityId) .FirstOrDefault(); if (personId.HasValue) { personAliasId = new PersonAliasService(rockContext) .GetPrimaryAliasId(personId.Value); } txn.TransactionCode = envelopeNum; } txn.FinancialPaymentDetail.CurrencyTypeValueId = _currencyTypeCash; } txn.AuthorizedPersonAliasId = personAliasId; // Save any images if (binaryFileTypeId.HasValue) { SaveImage(txn, GetChildElementValue(giftElement, "CheckImgFront"), binaryFileTypeId.Value, string.Format("CheckImageFront_{0}:{1}", batchNo, seqNo)); SaveImage(txn, GetChildElementValue(giftElement, "CheckImgBack"), binaryFileTypeId.Value, string.Format("CheckImageFront_{0}:{1}", batchNo, seqNo)); SaveImage(txn, GetChildElementValue(giftElement, "EnvImgFront"), binaryFileTypeId.Value, string.Format("CheckImageFront_{0}:{1}", batchNo, seqNo)); SaveImage(txn, GetChildElementValue(giftElement, "EnvImgBack"), binaryFileTypeId.Value, string.Format("CheckImageFront_{0}:{1}", batchNo, seqNo)); } // Loop through the purposes and create the transaction detail (account) records var purposes = giftElement.Element("Purposes"); if (purposes != null) { foreach (var purpose in purposes.Descendants().Where(p => p.Name == "Purpose")) { FinancialTransactionDetail txnDetail = null; int? accountId = GetChildElementValue(purpose, "PurposeID").AsIntegerOrNull(); decimal?amount = GetChildElementValue(purpose, "Amount").AsDecimalOrNull(); if (accountId.HasValue && amount.HasValue) { var account = new FinancialAccountService(rockContext).Get(accountId.Value); if (account != null) { txnDetail = new FinancialTransactionDetail(); txnDetail.AccountId = accountId.Value; txnDetail.Amount = amount.Value; txn.TransactionDetails.Add(txnDetail); _totalAmount += amount.Value; } } if (txnDetail == null) { errorMessages.Add(string.Format("Batch: {0}; Sequence: {1}; Error: Invalid Account (PurposeId:{2})", batchNo, seqNo, accountId)); } } } if (errorMessages.Any()) { return(ProcessStatus.Error); } // Save the transaction and update the batch control amount new FinancialTransactionService(rockContext).Add(txn); rockContext.SaveChanges(); return(personAliasId.HasValue ? ProcessStatus.Matched : ProcessStatus.Unmatched); } } catch (Exception ex) { errorMessages.Add(string.Format("Batch: {0}; Sequence: {1}; Error: {2}", batchNo, seqNo, ex.Message)); return(ProcessStatus.Error); } }
/// <summary> /// Handles the Click event of the btnNext 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 btnNext_Click( object sender, EventArgs e ) { var rockContext = new RockContext(); var financialTransactionService = new FinancialTransactionService( rockContext ); var financialTransactionDetailService = new FinancialTransactionDetailService( rockContext ); var financialPersonBankAccountService = new FinancialPersonBankAccountService( rockContext ); int txnId = hfTransactionId.Value.AsInteger(); var financialTransaction = financialTransactionService .Queryable( "AuthorizedPersonAlias.Person,ProcessedByPersonAlias.Person" ) .FirstOrDefault( t => t.Id == txnId ); // set the AuthorizedPersonId (the person who wrote the check, for example) to the if the SelectNew person (if selected) or person selected in the drop down (if there is somebody selected) int? authorizedPersonId = ppSelectNew.PersonId ?? ddlIndividual.SelectedValue.AsIntegerOrNull(); var accountNumberSecured = hfCheckMicrHashed.Value; if ( cbTotalAmount.Text.AsDecimalOrNull().HasValue && !authorizedPersonId.HasValue ) { nbSaveError.Text = "Transaction must be matched to a person when the amount is specified."; nbSaveError.Visible = true; return; } // if the transaction was previously matched, but user unmatched it, save it as an unmatched transaction and clear out the detail records (we don't want an unmatched transaction to have detail records) if ( financialTransaction != null && financialTransaction.AuthorizedPersonAliasId.HasValue && !authorizedPersonId.HasValue ) { financialTransaction.AuthorizedPersonAliasId = null; foreach ( var detail in financialTransaction.TransactionDetails ) { financialTransactionDetailService.Delete( detail ); } rockContext.SaveChanges(); // if the transaction was unmatched, clear out the ProcessedBy fields since we didn't match the transaction and are moving on to process another transaction MarkTransactionAsNotProcessedByCurrentUser( hfTransactionId.Value.AsInteger() ); } // if the transaction is matched to somebody, attempt to save it. Otherwise, if the transaction was previously matched, but user unmatched it, save it as an unmatched transaction if ( financialTransaction != null && authorizedPersonId.HasValue ) { bool requiresMicr = financialTransaction.CurrencyTypeValue.Guid == Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK.AsGuid(); if ( requiresMicr && string.IsNullOrWhiteSpace( accountNumberSecured ) ) { // should be showing already, but just in case nbNoMicrWarning.Visible = true; return; } if ( cbTotalAmount.Text.AsDecimalOrNull() == null ) { nbSaveError.Text = "Total amount must be allocated to accounts."; nbSaveError.Visible = true; return; } int? personAliasId = new PersonAliasService( rockContext ).GetPrimaryAliasId( authorizedPersonId.Value ); // if this transaction has an accountnumber associated with it (in other words, it's a scanned check), ensure there is a financialPersonBankAccount record if ( !string.IsNullOrWhiteSpace( accountNumberSecured ) ) { var financialPersonBankAccount = financialPersonBankAccountService.Queryable().Where( a => a.AccountNumberSecured == accountNumberSecured && a.PersonAlias.PersonId == authorizedPersonId.Value ).FirstOrDefault(); if ( financialPersonBankAccount == null ) { if ( personAliasId.HasValue ) { financialPersonBankAccount = new FinancialPersonBankAccount(); financialPersonBankAccount.PersonAliasId = personAliasId.Value; financialPersonBankAccount.AccountNumberSecured = accountNumberSecured; var checkMicrClearText = Encryption.DecryptString( financialTransaction.CheckMicrEncrypted ); var parts = checkMicrClearText.Split( '_' ); if ( parts.Length >= 2 ) { financialPersonBankAccount.AccountNumberMasked = parts[1].Masked(); } financialPersonBankAccountService.Add( financialPersonBankAccount ); } } } if ( personAliasId.HasValue ) { financialTransaction.AuthorizedPersonAliasId = personAliasId; } // just in case this transaction is getting re-edited either by the same user, or somebody else, clean out any existing TransactionDetail records foreach ( var detail in financialTransaction.TransactionDetails.ToList() ) { financialTransactionDetailService.Delete( detail ); } foreach ( var accountBox in rptAccounts.ControlsOfTypeRecursive<CurrencyBox>() ) { var amount = accountBox.Text.AsDecimalOrNull(); if ( amount.HasValue && amount.Value >= 0 ) { var financialTransactionDetail = new FinancialTransactionDetail(); financialTransactionDetail.TransactionId = financialTransaction.Id; financialTransactionDetail.AccountId = accountBox.Attributes["data-account-id"].AsInteger(); financialTransactionDetail.Amount = amount.Value; financialTransactionDetailService.Add( financialTransactionDetail ); } } financialTransaction.ProcessedByPersonAliasId = this.CurrentPersonAlias.Id; financialTransaction.ProcessedDateTime = RockDateTime.Now; rockContext.SaveChanges(); } else { // if the transaction was not matched, clear out the ProcessedBy fields since we didn't match the transaction and are moving on to process another transaction MarkTransactionAsNotProcessedByCurrentUser( hfTransactionId.Value.AsInteger() ); } NavigateToTransaction( Direction.Next ); }
/// <summary> /// Shows the detail. /// </summary> /// <param name="transactionId">The transaction identifier.</param> public void ShowDetail( int transactionId, int? batchId ) { FinancialTransaction txn = null; bool editAllowed = UserCanEdit; var rockContext = new RockContext(); FinancialBatch batch = null; if ( batchId.HasValue ) { batch = new FinancialBatchService( rockContext ).Get( batchId.Value ); } BindDropdowns( rockContext ); if ( !transactionId.Equals( 0 ) ) { txn = GetTransaction( transactionId, rockContext ); if ( !editAllowed && txn != null ) { editAllowed = txn.IsAuthorized( Authorization.EDIT, CurrentPerson ); } } bool batchEditAllowed = true; if ( txn == null ) { txn = new FinancialTransaction { Id = 0 }; txn.FinancialPaymentDetail = new FinancialPaymentDetail(); txn.BatchId = batchId; // Hide processor fields when adding a new transaction gpPaymentGateway.Visible = false; // Set values based on previously saved txn values int prevBatchId = Session["NewTxnDefault_BatchId"] as int? ?? 0; if ( prevBatchId == batchId ) { txn.TransactionDateTime = Session["NewTxnDefault_TransactionDateTime"] as DateTime?; txn.TransactionTypeValueId = Session["NewTxnDefault_TransactionType"] as int? ?? 0; txn.SourceTypeValueId = Session["NewTxnDefault_SourceType"] as int?; txn.FinancialPaymentDetail.CurrencyTypeValueId = Session["NewTxnDefault_CurrencyType"] as int?; txn.FinancialPaymentDetail.CreditCardTypeValueId = Session["NewTxnDefault_CreditCardType"] as int?; int? accountId = Session["NewTxnDefault_Account"] as int?; if ( accountId.HasValue ) { var txnDetail = new FinancialTransactionDetail(); txnDetail.AccountId = accountId.Value; txn.TransactionDetails.Add( txnDetail ); } } } else { gpPaymentGateway.Visible = true; if ( txn.Batch != null && txn.Batch.Status == BatchStatus.Closed ) { batchEditAllowed = false; } } hfTransactionId.Value = txn.Id.ToString(); hfBatchId.Value = batchId.HasValue ? batchId.Value.ToString() : string.Empty; ShowNextButton( transactionId, batchId ); bool readOnly = false; nbEditModeMessage.Text = string.Empty; lbEdit.Visible = editAllowed && batchEditAllowed; lbRefund.Visible = editAllowed && batchEditAllowed && txn.RefundDetails == null; lbAddTransaction.Visible = editAllowed && batch != null && batch.Status != BatchStatus.Closed; if ( !editAllowed ) { readOnly = true; nbEditModeMessage.Text = EditModeMessage.ReadOnlyEditActionNotAllowed( FinancialTransaction.FriendlyTypeName ); } else { if ( !batchEditAllowed ) { readOnly = true; nbEditModeMessage.Text = string.Format( "<strong>Note</strong> Because this {0} belongs to a batch that is closed, editing is not enabled.", FinancialTransaction.FriendlyTypeName ); } } txn.LoadAttributes( rockContext ); txn.FinancialPaymentDetail.LoadAttributes(rockContext); if ( readOnly ) { ShowReadOnlyDetails( txn ); } else { if ( txn.Id > 0 ) { ShowReadOnlyDetails( txn ); } else { ShowEditDetails( txn, rockContext ); } } lbSave.Visible = !readOnly; }
/// <summary> /// Shows the account dialog. /// </summary> /// <param name="guid">The unique identifier.</param> private void ShowAccountDialog( Guid guid ) { hfAccountGuid.Value = guid.ToString(); var txnDetail = TransactionDetailsState.Where( d => d.Guid.Equals( guid ) ).FirstOrDefault(); if ( txnDetail != null ) { apAccount.SetValue( txnDetail.AccountId ); tbAccountAmount.Text = txnDetail.Amount.ToString( "N2" ); tbAccountSummary.Text = txnDetail.Summary; if ( txnDetail.Attributes == null ) { txnDetail.LoadAttributes(); } } else { apAccount.SetValue( null ); tbAccountAmount.Text = string.Empty; tbAccountSummary.Text = string.Empty; txnDetail = new FinancialTransactionDetail(); txnDetail.LoadAttributes(); } phAccountAttributeEdits.Controls.Clear(); Helper.AddEditControls( txnDetail, phAccountAttributeEdits, true, mdAccount.ValidationGroup ); ShowDialog( "ACCOUNT" ); _focusControl = tbAccountAmount; }
/// <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; } }
private bool SaveTransaction( GatewayComponent gateway, Registration registration, FinancialTransaction transaction, PaymentInfo paymentInfo, RockContext rockContext ) { if ( transaction != null ) { var txnChanges = new List<string>(); txnChanges.Add( "Created Transaction" ); History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode ); transaction.AuthorizedPersonAliasId = registration.PersonAliasId; transaction.TransactionDateTime = RockDateTime.Now; History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime ); transaction.FinancialGatewayId = RegistrationTemplate.FinancialGatewayId; History.EvaluateChange( txnChanges, "Gateway", string.Empty, RegistrationTemplate.FinancialGateway.Name ); var txnType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_EVENT_REGISTRATION ) ); transaction.TransactionTypeValueId = txnType.Id; History.EvaluateChange( txnChanges, "Type", string.Empty, txnType.Value ); if ( transaction.FinancialPaymentDetail == null ) { transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); } DefinedValueCache currencyType = null; DefinedValueCache creditCardType = null; if ( paymentInfo != null ) { transaction.FinancialPaymentDetail.SetFromPaymentInfo( paymentInfo, gateway, rockContext, txnChanges ); currencyType = paymentInfo.CurrencyTypeValue; creditCardType = paymentInfo.CreditCardTypeValue; } 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 ); } } transaction.Summary = registration.GetSummary( RegistrationInstanceState ); var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = RegistrationState.PaymentAmount ?? 0.0m; transactionDetail.AccountId = RegistrationInstanceState.AccountId.Value; transactionDetail.EntityTypeId = EntityTypeCache.Read( typeof( Rock.Model.Registration ) ).Id; transactionDetail.EntityId = registration.Id; transaction.TransactionDetails.Add( transactionDetail ); History.EvaluateChange( txnChanges, RegistrationInstanceState.Account.Name, 0.0M.FormatAsCurrency(), transactionDetail.Amount.FormatAsCurrency() ); var batchChanges = new List<string>(); rockContext.WrapTransaction( () => { var batchService = new FinancialBatchService( rockContext ); // determine batch prefix string batchPrefix = string.Empty; if ( !string.IsNullOrWhiteSpace( RegistrationTemplate.BatchNamePrefix ) ) { batchPrefix = RegistrationTemplate.BatchNamePrefix; } else { batchPrefix = GetAttributeValue( "BatchNamePrefix" ); } // Get the batch var batch = batchService.Get( batchPrefix, currencyType, creditCardType, transaction.TransactionDateTime.Value, RegistrationTemplate.FinancialGateway.GetBatchTimeOffset() ); 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(); } ); if ( transaction.BatchId.HasValue ) { Task.Run( () => HistoryService.SaveChanges( new RockContext(), typeof( FinancialBatch ), Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), transaction.BatchId.Value, batchChanges, true, CurrentPersonAliasId ) ); Task.Run( () => HistoryService.SaveChanges( new RockContext(), typeof( FinancialBatch ), Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(), transaction.BatchId.Value, txnChanges, CurrentPerson != null ? CurrentPerson.FullName : string.Empty, typeof( FinancialTransaction ), transaction.Id, true, CurrentPersonAliasId ) ); } List<string> registrationChanges = new List<string>(); registrationChanges.Add( string.Format( "Made {0} payment", transaction.TotalAmount.FormatAsCurrency() ) ); Task.Run( () => HistoryService.SaveChanges( new RockContext(), typeof( Registration ), Rock.SystemGuid.Category.HISTORY_EVENT_REGISTRATION.AsGuid(), registration.Id, registrationChanges, true, CurrentPersonAliasId ) ); TransactionCode = transaction.TransactionCode; return true; } else { 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> /// 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); }
/// <summary> /// Exports any contributions. /// </summary> public static void ExportContributions() { try { // Retrieve & Output the Fund Accounts using (var dtFunds = GetTableData(SQL_FINANCIAL_ACCOUNTS)) { foreach (DataRow row in dtFunds.Rows) { FinancialAccount account = SkFinancialAccount.Translate(row); if (account is null) { continue; } ImportPackage.WriteToPackage(account); } } // Retrieve & Output the Batches using (var dtBatches = GetTableData(SQL_FINANCIAL_BATCHES)) { foreach (DataRow row in dtBatches.Rows) { FinancialBatch batch = SkFinancialBatch.Translate(row); if (batch is null) { continue; } ImportPackage.WriteToPackage(batch); } } // Retrieve & Output the Contributions using (var dtContributions = GetTableData(SQL_FINANCIAL_CONTRIBUTIONS)) { foreach (DataRow row in dtContributions.Rows) { FinancialTransaction transaction = SkFinancialContribution.Translate(row); if (transaction is null) { continue; } ImportPackage.WriteToPackage(transaction); } } // Retrieve & Output the Contribution Details using (var dtContributionDetails = GetTableData(SQL_FINANCIAL_CONTRIBUTIONDETAILS)) { foreach (DataRow row in dtContributionDetails.Rows) { FinancialTransactionDetail details = SkFinancialContributionDetail.Translate(row); if (details is null) { continue; } ImportPackage.WriteToPackage(details); } } } catch (Exception ex) { ErrorMessage = ex.Message; } }
/// <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> /// Handles the SaveClick event of the mdRefund 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 mdRefund_SaveClick( object sender, EventArgs e ) { decimal refundAmount = tbRefundAmount.Text.AsDecimal(); if ( refundAmount > 0.0m ) { int? txnId = hfTransactionId.Value.AsIntegerOrNull(); if ( txnId.HasValue ) { using ( var rockContext = new RockContext() ) { var txnService = new FinancialTransactionService( rockContext ); var txn = txnService.Get( txnId.Value ); if ( txn != null && txn.Batch != null ) { FinancialTransaction refundTxn = null; if ( !string.IsNullOrWhiteSpace( txn.TransactionCode ) && txn.FinancialGateway != null && cbProcess.Visible && cbProcess.Checked ) { var gateway = txn.FinancialGateway.GetGatewayComponent(); if ( gateway != null ) { string errorMessage = string.Empty; refundTxn = gateway.Credit( txn, refundAmount, tbRefundSummary.Text, out errorMessage ); if ( refundTxn == null ) { nbRefundError.Title = "Refund Error"; nbRefundError.Text = string.Format( "<p>{0}</p>", errorMessage ); nbRefundError.Visible = true; return; } } else { nbRefundError.Title = "Gateway Error"; nbRefundError.Text = "<p>Transaction has a valid gateway, but we could not use it.</p>"; nbRefundError.Visible = true; return; } } else { refundTxn = new FinancialTransaction(); } refundTxn.AuthorizedPersonAliasId = txn.AuthorizedPersonAliasId; refundTxn.TransactionDateTime = RockDateTime.Now; refundTxn.FinancialGatewayId = txn.FinancialGatewayId; refundTxn.TransactionTypeValueId = txn.TransactionTypeValueId; if ( txn.FinancialPaymentDetail != null ) { refundTxn.FinancialPaymentDetail = new FinancialPaymentDetail(); refundTxn.FinancialPaymentDetail.AccountNumberMasked = txn.FinancialPaymentDetail.AccountNumberMasked; refundTxn.FinancialPaymentDetail.BillingLocationId = txn.FinancialPaymentDetail.BillingLocationId; refundTxn.FinancialPaymentDetail.CreditCardTypeValueId = txn.FinancialPaymentDetail.CreditCardTypeValueId; refundTxn.FinancialPaymentDetail.CurrencyTypeValueId = txn.FinancialPaymentDetail.CurrencyTypeValueId; refundTxn.FinancialPaymentDetail.ExpirationMonthEncrypted = txn.FinancialPaymentDetail.ExpirationMonthEncrypted; refundTxn.FinancialPaymentDetail.ExpirationYearEncrypted = txn.FinancialPaymentDetail.ExpirationYearEncrypted; refundTxn.FinancialPaymentDetail.NameOnCardEncrypted = txn.FinancialPaymentDetail.NameOnCardEncrypted; } decimal remBalance = refundAmount; foreach ( var account in txn.TransactionDetails.Where( a => a.Amount > 0 ) ) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.AccountId = account.AccountId; transactionDetail.EntityId = account.EntityId; transactionDetail.EntityTypeId = account.EntityTypeId; refundTxn.TransactionDetails.Add( transactionDetail ); if ( remBalance >= account.Amount ) { transactionDetail.Amount = 0 - account.Amount; remBalance -= account.Amount; } else { transactionDetail.Amount = 0 - remBalance; remBalance = 0.0m; } if ( remBalance <= 0.0m ) { break; } } if ( remBalance > 0 && refundTxn.TransactionDetails.Any() ) { refundTxn.TransactionDetails.Last().Amount += remBalance; } var registrationEntityType = EntityTypeCache.Read( typeof( Rock.Model.Registration ) ); if ( registrationEntityType != null ) { foreach ( var transactionDetail in refundTxn.TransactionDetails .Where( d => d.EntityTypeId.HasValue && d.EntityTypeId.Value == registrationEntityType.Id && d.EntityId.HasValue ) ) { var registrationChanges = new List<string>(); registrationChanges.Add( string.Format( "Processed refund for {0}.", transactionDetail.Amount.FormatAsCurrency() ) ); HistoryService.SaveChanges( rockContext, typeof( Registration ), Rock.SystemGuid.Category.HISTORY_EVENT_REGISTRATION.AsGuid(), transactionDetail.EntityId.Value, registrationChanges ); } } refundTxn.RefundDetails = new FinancialTransactionRefund(); refundTxn.RefundDetails.RefundReasonValueId = ddlRefundReason.SelectedValueAsId(); refundTxn.RefundDetails.RefundReasonSummary = tbRefundSummary.Text; refundTxn.RefundDetails.OriginalTransactionId = txn.Id; string batchName = txn.Batch.Name; string suffix = GetAttributeValue( "RefundBatchNameSuffix" ); if ( !string.IsNullOrWhiteSpace( suffix ) && !batchName.EndsWith( suffix ) ) { batchName += suffix; } // Get the batch var batchService = new FinancialBatchService( rockContext ); TimeSpan timespan = new TimeSpan(); if ( txn.FinancialGateway != null ) { timespan = txn.FinancialGateway.GetBatchTimeOffset(); } var batch = batchService.GetByNameAndDate( batchName, refundTxn.TransactionDateTime.Value, timespan ); decimal controlAmount = batch.ControlAmount + refundTxn.TotalAmount; batch.ControlAmount = controlAmount; refundTxn.BatchId = batch.Id; batch.Transactions.Add( refundTxn ); rockContext.SaveChanges(); var updatedTxn = GetTransaction( txn.Id ); if ( updatedTxn != null ) { updatedTxn.LoadAttributes( rockContext ); updatedTxn.FinancialPaymentDetail.LoadAttributes(rockContext); ShowReadOnlyDetails( updatedTxn ); } } else { nbRefundError.Title = "Transaction Error"; nbRefundError.Text = "<p>Existing transaction does not hava a valid batch.</p>"; nbRefundError.Visible = true; return; } } } } HideDialog(); }
/// <summary> /// Handles the SaveClick event of the mdAccount 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 mdAccount_SaveClick( object sender, EventArgs e ) { Guid? guid = hfAccountGuid.Value.AsGuidOrNull(); if ( guid.HasValue ) { var txnDetail = TransactionDetailsState.Where( t => t.Guid.Equals( guid.Value ) ).FirstOrDefault(); if ( txnDetail == null ) { txnDetail = new FinancialTransactionDetail(); TransactionDetailsState.Add( txnDetail ); } txnDetail.AccountId = apAccount.SelectedValue.AsInteger(); txnDetail.Amount = tbAccountAmount.Text.AsDecimal(); txnDetail.Summary = tbAccountSummary.Text; txnDetail.LoadAttributes(); Rock.Attribute.Helper.GetEditValues( phAccountAttributeEdits, txnDetail ); foreach ( var attributeValue in txnDetail.AttributeValues ) { txnDetail.SetAttributeValue( attributeValue.Key, attributeValue.Value.Value ); } BindAccounts(); } HideDialog(); }
/// <summary> /// Handles the Click event of the lbSave 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 lbSave_Click( object sender, EventArgs e ) { var rockContext = new RockContext(); var txnService = new FinancialTransactionService( rockContext ); var txnDetailService = new FinancialTransactionDetailService( rockContext ); var txnImageService = new FinancialTransactionImageService( rockContext ); var binaryFileService = new BinaryFileService( rockContext ); FinancialTransaction txn = null; int? txnId = hfTransactionId.Value.AsIntegerOrNull(); int? batchId = hfBatchId.Value.AsIntegerOrNull(); var changes = new List<string>(); if ( txnId.HasValue ) { txn = txnService.Get( txnId.Value ); } if ( txn == null ) { txn = new FinancialTransaction(); txnService.Add( txn ); txn.BatchId = batchId; changes.Add( "Created transaction" ); } if ( txn != null ) { if ( txn.FinancialPaymentDetail == null ) { txn.FinancialPaymentDetail = new FinancialPaymentDetail(); } string newPerson = ppAuthorizedPerson.PersonName; if ( batchId.HasValue ) { if ( !txn.AuthorizedPersonAliasId.Equals( ppAuthorizedPerson.PersonAliasId ) ) { string prevPerson = ( txn.AuthorizedPersonAlias != null && txn.AuthorizedPersonAlias.Person != null ) ? txn.AuthorizedPersonAlias.Person.FullName : string.Empty; History.EvaluateChange( changes, "Person", prevPerson, newPerson ); } History.EvaluateChange( changes, "Date/Time", txn.TransactionDateTime, dtTransactionDateTime.SelectedDateTime ); History.EvaluateChange( changes, "Type", GetDefinedValue( txn.TransactionTypeValueId ), GetDefinedValue( ddlTransactionType.SelectedValue.AsInteger() ) ); History.EvaluateChange( changes, "Source", GetDefinedValue( txn.SourceTypeValueId ), GetDefinedValue( ddlSourceType.SelectedValueAsInt() ) ); if ( !txn.FinancialGatewayId.Equals( gpPaymentGateway.SelectedValueAsInt() ) ) { History.EvaluateChange( changes, "Gateway", GetFinancialGatewayName( txn.FinancialGatewayId, rockContext ), GetFinancialGatewayName( gpPaymentGateway.SelectedValueAsInt(), rockContext ) ); } History.EvaluateChange( changes, "Transaction Code", txn.TransactionCode, tbTransactionCode.Text ); History.EvaluateChange( changes, "Currency Type", GetDefinedValue( txn.FinancialPaymentDetail.CurrencyTypeValueId ), GetDefinedValue( ddlCurrencyType.SelectedValueAsInt() ) ); History.EvaluateChange( changes, "Credit Card Type", GetDefinedValue( txn.FinancialPaymentDetail.CreditCardTypeValueId ), GetDefinedValue( ddlCreditCardType.SelectedValueAsInt() ) ); History.EvaluateChange( changes, "Summary", txn.Summary, tbSummary.Text ); History.EvaluateChange( changes, "Is Refund", ( txn.RefundDetails != null ), cbIsRefund.Checked ); } txn.AuthorizedPersonAliasId = ppAuthorizedPerson.PersonAliasId; txn.TransactionDateTime = dtTransactionDateTime.SelectedDateTime; txn.TransactionTypeValueId = ddlTransactionType.SelectedValue.AsInteger(); txn.SourceTypeValueId = ddlSourceType.SelectedValueAsInt(); txn.FinancialGatewayId = gpPaymentGateway.SelectedValueAsInt(); txn.TransactionCode = tbTransactionCode.Text; txn.FinancialPaymentDetail.CurrencyTypeValueId = ddlCurrencyType.SelectedValueAsInt(); txn.FinancialPaymentDetail.CreditCardTypeValueId = ddlCreditCardType.SelectedValueAsInt(); txn.Summary = tbSummary.Text; decimal totalAmount = TransactionDetailsState.Select( d => d.Amount ).ToList().Sum(); if ( cbIsRefund.Checked && totalAmount > 0 ) { nbErrorMessage.Title = "Incorrect Refund Amount"; nbErrorMessage.Text = "<p>A refund should have a negative amount. Please unselect the refund option, or change amounts to be negative values.</p>"; nbErrorMessage.Visible = true; return; } if ( cbIsRefund.Checked ) { if ( txn.RefundDetails != null ) { txn.RefundDetails = new FinancialTransactionRefund(); } txn.RefundDetails.RefundReasonValueId = ddlRefundReasonEdit.SelectedValueAsId(); txn.RefundDetails.RefundReasonSummary = tbRefundSummaryEdit.Text; } if ( !Page.IsValid || !txn.IsValid ) { return; } foreach ( var txnDetail in TransactionDetailsState ) { if ( !txnDetail.IsValid ) { return; } } rockContext.WrapTransaction( () => { // Save the transaction rockContext.SaveChanges(); // Delete any transaction details that were removed var txnDetailsInDB = txnDetailService.Queryable().Where( a => a.TransactionId.Equals( txn.Id ) ).ToList(); var deletedDetails = from txnDetail in txnDetailsInDB where !TransactionDetailsState.Select( d => d.Guid ).Contains( txnDetail.Guid ) select txnDetail; deletedDetails.ToList().ForEach( txnDetail => { if ( batchId.HasValue ) { History.EvaluateChange( changes, txnDetail.Account != null ? txnDetail.Account.Name : "Unknown", txnDetail.Amount.FormatAsCurrency(), string.Empty ); } txnDetailService.Delete( txnDetail ); } ); // Save Transaction Details foreach ( var editorTxnDetail in TransactionDetailsState ) { string oldAccountName = string.Empty; string newAccountName = string.Empty; decimal oldAmount = 0.0M; decimal newAmount = 0.0M; // Add or Update the activity type var txnDetail = txn.TransactionDetails.FirstOrDefault( d => d.Guid.Equals( editorTxnDetail.Guid ) ); if ( txnDetail != null ) { oldAccountName = AccountName( txnDetail.AccountId ); oldAmount = txnDetail.Amount; } else { txnDetail = new FinancialTransactionDetail(); txnDetail.Guid = editorTxnDetail.Guid; txn.TransactionDetails.Add( txnDetail ); } newAccountName = AccountName( editorTxnDetail.AccountId ); newAmount = UseSimpleAccountMode ? tbSingleAccountAmount.Text.AsDecimal() : editorTxnDetail.Amount; if ( batchId.HasValue ) { if ( string.IsNullOrWhiteSpace(oldAccountName) ) { History.EvaluateChange( changes, newAccountName, string.Empty, newAmount.FormatAsCurrency() ); } else { if ( oldAccountName == newAccountName ) { if ( oldAmount != newAmount ) { History.EvaluateChange( changes, oldAccountName, oldAmount.FormatAsCurrency(), newAmount.FormatAsCurrency() ); } } else { History.EvaluateChange( changes, oldAccountName, oldAmount.FormatAsCurrency(), string.Empty ); History.EvaluateChange( changes, newAccountName, string.Empty, newAmount.FormatAsCurrency() ); } } } txnDetail.AccountId = editorTxnDetail.AccountId; txnDetail.Amount = newAmount; txnDetail.Summary = editorTxnDetail.Summary; if ( editorTxnDetail.AttributeValues != null ) { txnDetail.LoadAttributes(); txnDetail.AttributeValues = editorTxnDetail.AttributeValues; rockContext.SaveChanges(); txnDetail.SaveAttributeValues( rockContext ); } } // Delete any transaction images that were removed var orphanedBinaryFileIds = new List<int>(); var txnImagesInDB = txnImageService.Queryable().Where( a => a.TransactionId.Equals( txn.Id ) ).ToList(); foreach ( var txnImage in txnImagesInDB.Where( i => !TransactionImagesState.Contains( i.BinaryFileId ) ) ) { changes.Add( "Removed Image" ); orphanedBinaryFileIds.Add( txnImage.BinaryFileId ); txnImageService.Delete( txnImage ); } // Save Transaction Images int imageOrder = 0; foreach ( var binaryFileId in TransactionImagesState ) { // Add or Update the activity type var txnImage = txnImagesInDB.FirstOrDefault( i => i.BinaryFileId == binaryFileId ); if ( txnImage == null ) { changes.Add( "Added Image" ); txnImage = new FinancialTransactionImage(); txnImage.TransactionId = txn.Id; txn.Images.Add( txnImage ); } else { if ( txnImage.BinaryFileId != binaryFileId ) { changes.Add( "Updated Image" ); } } txnImage.BinaryFileId = binaryFileId; txnImage.Order = imageOrder; imageOrder++; } rockContext.SaveChanges(); // Make sure updated binary files are not temporary foreach ( var binaryFile in binaryFileService.Queryable().Where( f => TransactionImagesState.Contains( f.Id ) ) ) { binaryFile.IsTemporary = false; } // Delete any orphaned images foreach ( var binaryFile in binaryFileService.Queryable().Where( f => orphanedBinaryFileIds.Contains( f.Id ) ) ) { binaryFileService.Delete( binaryFile ); } // Update any attributes txn.LoadAttributes(rockContext); txn.FinancialPaymentDetail.LoadAttributes(rockContext); Helper.GetEditValues(phAttributeEdits, txn); Helper.GetEditValues(phPaymentAttributeEdits, txn.FinancialPaymentDetail); // If the transaction is associated with a batch, update that batch's history if ( batchId.HasValue ) { HistoryService.SaveChanges( rockContext, typeof( FinancialBatch ), Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(), batchId.Value, changes, !string.IsNullOrWhiteSpace( newPerson ) ? newPerson : string.Format( "Transaction Id:{0}", txn.Id ), typeof( FinancialTransaction ), txn.Id ); } rockContext.SaveChanges(); txn.SaveAttributeValues(rockContext); txn.FinancialPaymentDetail.SaveAttributeValues(rockContext); } ); // Save selected options to session state in order to prefill values for next added txn Session["NewTxnDefault_BatchId"] = txn.BatchId; Session["NewTxnDefault_TransactionDateTime"] = txn.TransactionDateTime; Session["NewTxnDefault_TransactionType"] = txn.TransactionTypeValueId; Session["NewTxnDefault_SourceType"] = txn.SourceTypeValueId; Session["NewTxnDefault_CurrencyType"] = txn.FinancialPaymentDetail.CurrencyTypeValueId; Session["NewTxnDefault_CreditCardType"] = txn.FinancialPaymentDetail.CreditCardTypeValueId; if ( TransactionDetailsState.Count() == 1 ) { Session["NewTxnDefault_Account"] = TransactionDetailsState.First().AccountId; } else { Session.Remove("NewTxnDefault_Account"); } // Requery the batch to support EF navigation properties var savedTxn = GetTransaction( txn.Id ); if ( savedTxn != null ) { savedTxn.LoadAttributes(); savedTxn.FinancialPaymentDetail.LoadAttributes(); ShowReadOnlyDetails( savedTxn ); } } }
/// <summary> /// Processes the payment. /// </summary> /// <param name="submitToGateway">if set to <c>true</c> [submit to gateway].</param> /// <param name="rockContext">The rock context.</param> /// <param name="registration">The registration.</param> /// <param name="personAliasId">The person alias identifier.</param> /// <param name="amount">The amount.</param> /// <param name="errorMessage">The error message.</param> /// <returns></returns> private bool ProcessPayment( bool submitToGateway, RockContext rockContext, Registration registration, int? personAliasId, decimal amount, out string errorMessage ) { FinancialTransaction transaction = null; var txnChanges = new List<string>(); txnChanges.Add( "Created Transaction" ); var registrationChanges = new List<string>(); DefinedValueCache dvCurrencyType = null; DefinedValueCache dvCredCardType = null; if ( submitToGateway ) { GatewayComponent gateway = null; if ( RegistrationTemplateState != null && RegistrationTemplateState.FinancialGateway != null ) { gateway = RegistrationTemplateState.FinancialGateway.GetGatewayComponent(); } if ( gateway == null ) { errorMessage = "There was a problem creating the payment gateway information"; return false; } if ( registration == null || registration.RegistrationInstance == null || !registration.RegistrationInstance.AccountId.HasValue || registration.RegistrationInstance.Account == null ) { errorMessage = "There was a problem with the account configuration for this registration."; return false; } var paymentInfo = new CreditCardPaymentInfo( txtCreditCard.Text, txtCVV.Text, mypExpiration.SelectedDate.Value ); paymentInfo.NameOnCard = gateway != null && gateway.SplitNameOnCard ? txtCardFirstName.Text : txtCardName.Text; paymentInfo.LastNameOnCard = txtCardLastName.Text; paymentInfo.BillingStreet1 = acBillingAddress.Street1; paymentInfo.BillingStreet2 = acBillingAddress.Street2; paymentInfo.BillingCity = acBillingAddress.City; paymentInfo.BillingState = acBillingAddress.State; paymentInfo.BillingPostalCode = acBillingAddress.PostalCode; paymentInfo.BillingCountry = acBillingAddress.Country; paymentInfo.Amount = amount; paymentInfo.Email = registration.ConfirmationEmail; paymentInfo.FirstName = registration.FirstName; paymentInfo.LastName = registration.LastName; paymentInfo.Comment1 = string.Format( "{0} ({1})", registration.RegistrationInstance.Name, registration.RegistrationInstance.Account.GlCode ); transaction = gateway.Charge( RegistrationTemplateState.FinancialGateway, paymentInfo, out errorMessage ); if ( transaction != null ) { transaction.FinancialGatewayId = RegistrationTemplateState.FinancialGatewayId; if ( transaction.FinancialPaymentDetail == null ) { transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); } transaction.FinancialPaymentDetail.SetFromPaymentInfo( paymentInfo, gateway, rockContext, txnChanges ); dvCurrencyType = paymentInfo.CurrencyTypeValue; dvCredCardType = paymentInfo.CreditCardTypeValue; registrationChanges.Add( string.Format( "Processed payment of {0}.", amount.FormatAsCurrency() ) ); } } else { errorMessage = string.Empty; transaction = new FinancialTransaction(); transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); transaction.FinancialPaymentDetail.CurrencyTypeValueId = ddlCurrencyType.SelectedValueAsInt(); transaction.FinancialPaymentDetail.CreditCardTypeValueId = ddlCreditCardType.SelectedValueAsInt(); transaction.TransactionCode = tbTransactionCode.Text; registrationChanges.Add( string.Format( "Manually added payment of {0}.", amount.FormatAsCurrency() ) ); } if ( transaction != null ) { transaction.Summary = tbSummary.Text; History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode ); transaction.AuthorizedPersonAliasId = personAliasId; transaction.TransactionDateTime = RockDateTime.Now; History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime ); if ( transaction.FinancialGatewayId.HasValue ) { History.EvaluateChange( txnChanges, "Gateway", string.Empty, RegistrationTemplateState.FinancialGateway.Name ); } var txnType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_EVENT_REGISTRATION ) ); transaction.TransactionTypeValueId = txnType.Id; History.EvaluateChange( txnChanges, "Type", string.Empty, txnType.Value ); 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 ); } } var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = amount; transactionDetail.AccountId = registration.RegistrationInstance.AccountId.Value; transactionDetail.EntityTypeId = EntityTypeCache.Read( typeof( Rock.Model.Registration ) ).Id; transactionDetail.EntityId = registration.Id; transaction.TransactionDetails.Add( transactionDetail ); History.EvaluateChange( txnChanges, registration.RegistrationInstance.Account.Name, 0.0M.FormatAsCurrency(), transactionDetail.Amount.FormatAsCurrency() ); var batchService = new FinancialBatchService( rockContext ); // Get the batch var batch = batchService.Get( GetAttributeValue( "BatchNamePrefix" ), dvCurrencyType, dvCredCardType, transaction.TransactionDateTime.Value, RegistrationTemplateState.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, CurrentPerson != null ? CurrentPerson.FullName : string.Empty, typeof( FinancialTransaction ), transaction.Id ); HistoryService.SaveChanges( rockContext, typeof( Registration ), Rock.SystemGuid.Category.HISTORY_EVENT_REGISTRATION.AsGuid(), registration.Id, registrationChanges ); return true; } else { return false; } }
/// <summary> /// Handles the Click event of the lbSave 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 lbSave_Click( object sender, EventArgs e ) { var rockContext = new RockContext(); var txnService = new FinancialTransactionService( rockContext ); var txnDetailService = new FinancialTransactionDetailService( rockContext ); var txnImageService = new FinancialTransactionImageService( rockContext ); var binaryFileService = new BinaryFileService( rockContext ); FinancialTransaction txn = null; int? txnId = hfTransactionId.Value.AsIntegerOrNull(); int? batchId = hfBatchId.Value.AsIntegerOrNull(); if ( txnId.HasValue ) { txn = txnService.Get( txnId.Value ); } if ( txn == null && batchId.HasValue ) { txn = new FinancialTransaction(); txnService.Add( txn ); txn.BatchId = batchId.Value; } if ( txn != null ) { txn.AuthorizedPersonId = ppAuthorizedPerson.PersonId; txn.TransactionDateTime = dtTransactionDateTime.SelectedDateTime; txn.TransactionTypeValueId = ddlTransactionType.SelectedValue.AsInteger(); txn.SourceTypeValueId = ddlSourceType.SelectedValueAsInt(); Guid? gatewayGuid = cpPaymentGateway.SelectedValueAsGuid(); if ( gatewayGuid.HasValue ) { var gatewayEntity = EntityTypeCache.Read( gatewayGuid.Value ); if ( gatewayEntity != null ) { txn.GatewayEntityTypeId = gatewayEntity.Id; } else { txn.GatewayEntityTypeId = null; } } else { txn.GatewayEntityTypeId = null; } txn.TransactionCode = tbTransactionCode.Text; txn.CurrencyTypeValueId = ddlCurrencyType.SelectedValueAsInt(); txn.CreditCardTypeValueId = ddlCreditCardType.SelectedValueAsInt(); txn.Summary = tbSummary.Text; if ( !Page.IsValid || !txn.IsValid ) { return; } foreach ( var txnDetail in TransactionDetailsState ) { if ( !txnDetail.IsValid ) { return; } } foreach ( var txnImage in TransactionImagesState ) { if ( !txnImage.IsValid ) { return; } } rockContext.WrapTransaction( () => { // Save the transaction rockContext.SaveChanges(); // Delete any transaction details that were removed var txnDetailsInDB = txnDetailService.Queryable().Where( a => a.TransactionId.Equals( txn.Id ) ).ToList(); var deletedDetails = from txnDetail in txnDetailsInDB where !TransactionDetailsState.Select( d => d.Guid ).Contains( txnDetail.Guid ) select txnDetail; deletedDetails.ToList().ForEach( txnDetail => { txnDetailService.Delete( txnDetail ); } ); rockContext.SaveChanges(); // Save Transaction Details foreach ( var editorTxnDetail in TransactionDetailsState ) { // Add or Update the activity type var txnDetail = txn.TransactionDetails.FirstOrDefault( d => d.Guid.Equals( editorTxnDetail.Guid ) ); if ( txnDetail == null ) { txnDetail = new FinancialTransactionDetail(); txnDetail.Guid = editorTxnDetail.Guid; txn.TransactionDetails.Add( txnDetail ); } txnDetail.AccountId = editorTxnDetail.AccountId; txnDetail.Amount = editorTxnDetail.Amount; txnDetail.Summary = editorTxnDetail.Summary; } rockContext.SaveChanges(); // Remove any images that do not have a binary file foreach ( var txnImage in TransactionImagesState.Where( i => i.BinaryFileId == 0 ).ToList() ) { TransactionImagesState.Remove( txnImage ); } // Delete any transaction images that were removed var txnImagesInDB = txnImageService.Queryable().Where( a => a.TransactionId.Equals( txn.Id ) ).ToList(); var deletedImages = from txnImage in txnImagesInDB where !TransactionImagesState.Select( d => d.Guid ).Contains( txnImage.Guid ) select txnImage; deletedImages.ToList().ForEach( txnImage => { txnImageService.Delete( txnImage ); } ); rockContext.SaveChanges(); // Save Transaction Images foreach ( var editorTxnImage in TransactionImagesState ) { // Add or Update the activity type var txnImage = txn.Images.FirstOrDefault( d => d.Guid.Equals( editorTxnImage.Guid ) ); if ( txnImage == null ) { txnImage = new FinancialTransactionImage(); txnImage.Guid = editorTxnImage.Guid; txn.Images.Add( txnImage ); } txnImage.BinaryFileId = editorTxnImage.BinaryFileId; txnImage.TransactionImageTypeValueId = editorTxnImage.TransactionImageTypeValueId; } rockContext.SaveChanges(); // Make sure updated binary files are not temporary var savedBinaryFileIds = txn.Images.Select( i => i.BinaryFileId ).ToList(); foreach ( var binaryFile in binaryFileService.Queryable().Where( f => savedBinaryFileIds.Contains( f.Id ) ) ) { binaryFile.IsTemporary = false; } // Delete any orphaned images var orphanedBinaryFileIds = BinaryFileIds.Where( f => !savedBinaryFileIds.Contains( f ) ); foreach ( var binaryFile in binaryFileService.Queryable().Where( f => orphanedBinaryFileIds.Contains( f.Id ) ) ) { binaryFileService.Delete( binaryFile ); } rockContext.SaveChanges(); } ); // Requery the batch to support EF navigation properties var savedTxn = GetTransaction( txn.Id ); ShowReadOnlyDetails( savedTxn ); } }
/// <summary> /// Maps the contribution. /// </summary> /// <param name="tableData">The table data.</param> /// <param name="totalRows">The total rows.</param> private void MapContribution(IQueryable <Row> tableData, long totalRows = 0) { var lookupContext = new RockContext(); var transactionTypeContributionId = DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid(), lookupContext).Id; var currencyTypes = DefinedTypeCache.Get(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE)); var currencyTypeACH = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH))).Id; var currencyTypeCash = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH))).Id; var currencyTypeCheck = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK))).Id; var currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD))).Id; var currencyTypeNonCash = currencyTypes.DefinedValues.Where(dv => dv.Value.Equals("Non-Cash")).Select(dv => ( int? )dv.Id).FirstOrDefault(); if (currencyTypeNonCash == null) { var newTenderNonCash = new DefinedValue { Value = "Non-Cash", Description = "Non-Cash", DefinedTypeId = currencyTypes.Id }; lookupContext.DefinedValues.Add(newTenderNonCash); lookupContext.SaveChanges(); currencyTypeNonCash = newTenderNonCash.Id; } var creditCardTypes = DefinedTypeCache.Get(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE)).DefinedValues; var refundReasons = DefinedTypeCache.Get(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON), lookupContext).DefinedValues; var accountList = new FinancialAccountService(lookupContext).Queryable().AsNoTracking().ToList(); int?defaultBatchId = null; if (ImportedBatches.ContainsKey(0)) { defaultBatchId = ImportedBatches[0]; } // Get all imported contributions var importedContributions = new FinancialTransactionService(lookupContext).Queryable().AsNoTracking() .Where(c => c.ForeignId != null) .ToDictionary(t => ( int )t.ForeignId, t => ( int? )t.Id); // List for batching new contributions var newTransactions = new List <FinancialTransaction>(); if (totalRows == 0) { totalRows = tableData.Count(); } var completedItems = 0; var percentage = (totalRows - 1) / 100 + 1; ReportProgress(0, $"Verifying contribution import ({totalRows:N0} found, {importedContributions.Count:N0} already exist)."); foreach (var row in tableData.Where(r => r != null)) { var individualId = row["Individual_ID"] as int?; var householdId = row["Household_ID"] as int?; var contributionId = row["ContributionID"] as int?; if (contributionId.HasValue && !importedContributions.ContainsKey(( int )contributionId)) { var transaction = new FinancialTransaction { CreatedByPersonAliasId = ImportPersonAliasId, ModifiedByPersonAliasId = ImportPersonAliasId, TransactionTypeValueId = transactionTypeContributionId, ForeignKey = contributionId.ToString(), ForeignId = contributionId }; int?giverAliasId = null; var personKeys = GetPersonKeys(individualId, householdId); if (personKeys != null && personKeys.PersonAliasId > 0) { giverAliasId = personKeys.PersonAliasId; transaction.CreatedByPersonAliasId = giverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } var summary = row["Memo"] as string; if (!string.IsNullOrWhiteSpace(summary)) { transaction.Summary = summary; } var batchId = row["BatchID"] as int?; if (batchId.HasValue && ImportedBatches.Any(b => b.Key.Equals(batchId))) { transaction.BatchId = ImportedBatches.FirstOrDefault(b => b.Key.Equals(batchId)).Value; } else { // use the default batch for any non-matching transactions transaction.BatchId = defaultBatchId; } var receivedDate = row["Received_Date"] as DateTime?; if (receivedDate.HasValue) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; transaction.ModifiedDateTime = ImportDateTime; } var contributionFields = row.Columns.Select(c => c.Name).ToList(); var cardType = contributionFields.Contains("Card_Type") ? row["Card_Type"] as string : string.Empty; var cardLastFour = contributionFields.Contains("Last_Four") ? row["Last_Four"] as string : string.Empty; var contributionType = contributionFields.Contains("Contribution_Type_Name") ? row["Contribution_Type_Name"] as string : string.Empty; if (!string.IsNullOrWhiteSpace(contributionType)) { // set default source to onsite, exceptions listed below transaction.SourceTypeValueId = TransactionSourceTypeOnsiteId; int?paymentCurrencyTypeId = null, creditCardTypeId = null; switch (contributionType.ToLower()) { case "cash": paymentCurrencyTypeId = currencyTypeCash; break; case "check": paymentCurrencyTypeId = currencyTypeCheck; break; case "ach": paymentCurrencyTypeId = currencyTypeACH; transaction.SourceTypeValueId = TransactionSourceTypeWebsiteId; break; case "credit card": paymentCurrencyTypeId = currencyTypeCreditCard; transaction.SourceTypeValueId = TransactionSourceTypeWebsiteId; if (!string.IsNullOrWhiteSpace(cardType)) { creditCardTypeId = creditCardTypes.Where(t => t.Value.Equals(cardType, StringComparison.OrdinalIgnoreCase)) .Select(t => ( int? )t.Id).FirstOrDefault(); } break; default: paymentCurrencyTypeId = currencyTypeNonCash; break; } var paymentDetail = new FinancialPaymentDetail { CreatedDateTime = receivedDate, CreatedByPersonAliasId = giverAliasId, ModifiedDateTime = ImportDateTime, ModifiedByPersonAliasId = giverAliasId, CurrencyTypeValueId = paymentCurrencyTypeId, CreditCardTypeValueId = creditCardTypeId, AccountNumberMasked = cardLastFour, ForeignKey = contributionId.ToString(), ForeignId = contributionId }; transaction.FinancialPaymentDetail = paymentDetail; } var checkNumber = row["Check_Number"] as string; // if the check number is valid, put it in the transaction code if (checkNumber.AsType <int?>().HasValue) { transaction.TransactionCode = checkNumber; } // check for SecureGive kiosk transactions else if (!string.IsNullOrWhiteSpace(checkNumber) && checkNumber.StartsWith("SG")) { transaction.SourceTypeValueId = TransactionSourceTypeKioskId; } var fundName = contributionFields.Contains("Fund_Name") ? row["Fund_Name"] as string : string.Empty; var fundType = contributionFields.Contains("Fund_type") ? row["Fund_type"] as string : string.Empty; var subFund = contributionFields.Contains("Sub_Fund_Name") ? row["Sub_Fund_Name"] as string : string.Empty; var fundGLAccount = contributionFields.Contains("Fund_GL_Account") ? row["Fund_GL_Account"] as string : string.Empty; var subFundGLAccount = contributionFields.Contains("Sub_Fund_GL_Account") ? row["Sub_Fund_GL_Account"] as string : string.Empty; var isFundActive = contributionFields.Contains("Fund_Is_active") ? row["Fund_Is_active"] as string : null; var statedValue = row["Stated_Value"] as decimal?; var amount = row["Amount"] as decimal?; if (!string.IsNullOrWhiteSpace(fundName) && amount.HasValue) { int transactionAccountId; var parentAccount = accountList.FirstOrDefault(a => !a.CampusId.HasValue && a.Name.Equals(fundName.Truncate(50), StringComparison.OrdinalIgnoreCase)); if (parentAccount == null) { int?accountTypeDefinedTypeId = null; if (!string.IsNullOrWhiteSpace(fundType)) { accountTypeDefinedTypeId = LoadAccountTypeDefinedValue(lookupContext, fundType); } parentAccount = AddFinancialAccount(lookupContext, fundName, $"{fundName} imported {ImportDateTime}", fundGLAccount, null, null, isFundActive.AsBooleanOrNull(), receivedDate, fundName.RemoveSpecialCharacters(), accountTypeValueId: accountTypeDefinedTypeId); accountList.Add(parentAccount); } if (!string.IsNullOrWhiteSpace(subFund)) { int?campusFundId = null; // assign a campus if the subfund is a campus fund var campusFund = CampusList.FirstOrDefault(c => subFund.StartsWith(c.Name, StringComparison.OrdinalIgnoreCase) || subFund.StartsWith(c.ShortCode, StringComparison.OrdinalIgnoreCase)); if (campusFund != null) { // use full campus name as the subfund subFund = campusFund.Name; campusFundId = campusFund.Id; } // add info to easily find/assign this fund in the view subFund = $"{subFund} {fundName}"; var childAccount = accountList.FirstOrDefault(c => c.ParentAccountId == parentAccount.Id && c.Name.Equals(subFund.Truncate(50), StringComparison.OrdinalIgnoreCase)); if (childAccount == null) { // create a child account with a campusId if it was set childAccount = AddFinancialAccount(lookupContext, subFund, $"{subFund} imported {ImportDateTime}", subFundGLAccount, campusFundId, parentAccount.Id, isFundActive.AsBooleanOrNull(), receivedDate, subFund.RemoveSpecialCharacters(), accountTypeValueId: parentAccount.AccountTypeValueId); accountList.Add(childAccount); } transactionAccountId = childAccount.Id; } else { transactionAccountId = parentAccount.Id; } if (amount == 0 && statedValue.HasValue && statedValue != 0) { amount = statedValue; } var transactionDetail = new FinancialTransactionDetail { Amount = ( decimal )amount, CreatedDateTime = receivedDate, AccountId = transactionAccountId }; transaction.TransactionDetails.Add(transactionDetail); if (amount < 0) { transaction.RefundDetails = new FinancialTransactionRefund(); transaction.RefundDetails.CreatedDateTime = receivedDate; transaction.RefundDetails.RefundReasonValueId = refundReasons.Where(dv => summary != null && dv.Value.Contains(summary)) .Select(dv => ( int? )dv.Id).FirstOrDefault(); transaction.RefundDetails.RefundReasonSummary = summary; } } newTransactions.Add(transaction); completedItems++; if (completedItems % percentage < 1) { var percentComplete = completedItems / percentage; ReportProgress(percentComplete, $"{completedItems:N0} contributions imported ({percentComplete}% complete)."); } if (completedItems % ReportingNumber < 1) { SaveContributions(newTransactions); newTransactions.Clear(); ReportPartialProgress(); } } } if (newTransactions.Any()) { SaveContributions(newTransactions); } ReportProgress(100, $"Finished contribution import: {completedItems:N0} contributions imported."); }
/// <summary> /// Maps the contribution. /// </summary> /// <param name="tableData">The table data.</param> /// <param name="selectedColumns">The selected columns.</param> private void MapContribution( IQueryable<Row> tableData, List<string> selectedColumns = null ) { var lookupContext = new RockContext(); int transactionEntityTypeId = EntityTypeCache.Read( "Rock.Model.FinancialTransaction" ).Id; var transactionTypeContributionId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ), lookupContext ).Id; var currencyTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE ) ); int currencyTypeACH = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ) ) ).Id; int currencyTypeCash = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH ) ) ).Id; int currencyTypeCheck = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK ) ) ).Id; int currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ) ) ).Id; int? currencyTypeNonCash = currencyTypes.DefinedValues.Where( dv => dv.Value.Equals( "Non-Cash" ) ).Select( dv => (int?)dv.Id ).FirstOrDefault(); if ( currencyTypeNonCash == null ) { var newTenderNonCash = new DefinedValue(); newTenderNonCash.Value = "Non-Cash"; newTenderNonCash.Description = "Non-Cash"; newTenderNonCash.DefinedTypeId = currencyTypes.Id; lookupContext.DefinedValues.Add( newTenderNonCash ); lookupContext.SaveChanges(); currencyTypeNonCash = newTenderNonCash.Id; } var creditCardTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE ) ).DefinedValues; int sourceTypeOnsite = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_ONSITE_COLLECTION ), lookupContext ).Id; int sourceTypeWebsite = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE ), lookupContext ).Id; int sourceTypeKiosk = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_KIOSK ), lookupContext ).Id; var refundReasons = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON ), lookupContext ).DefinedValues; var accountList = new FinancialAccountService( lookupContext ).Queryable().AsNoTracking().ToList(); int? defaultBatchId = null; if ( ImportedBatches.ContainsKey( 0 ) ) { defaultBatchId = ImportedBatches[0]; } // Get all imported contributions var importedContributions = new FinancialTransactionService( lookupContext ).Queryable().AsNoTracking() .Where( c => c.ForeignId != null ) .ToDictionary( t => (int)t.ForeignId, t => (int?)t.Id ); // List for batching new contributions var newTransactions = new List<FinancialTransaction>(); int completed = 0; int totalRows = tableData.Count(); int percentage = ( totalRows - 1 ) / 100 + 1; ReportProgress( 0, string.Format( "Verifying contribution import ({0:N0} found, {1:N0} already exist).", totalRows, importedContributions.Count ) ); foreach ( var row in tableData.Where( r => r != null ) ) { int? individualId = row["Individual_ID"] as int?; int? householdId = row["Household_ID"] as int?; int? contributionId = row["ContributionID"] as int?; if ( contributionId != null && !importedContributions.ContainsKey( (int)contributionId ) ) { var transaction = new FinancialTransaction(); transaction.CreatedByPersonAliasId = ImportPersonAliasId; transaction.ModifiedByPersonAliasId = ImportPersonAliasId; transaction.TransactionTypeValueId = transactionTypeContributionId; transaction.ForeignKey = contributionId.ToString(); transaction.ForeignId = contributionId; int? giverAliasId = null; var personKeys = GetPersonKeys( individualId, householdId ); if ( personKeys != null && personKeys.PersonAliasId > 0 ) { giverAliasId = personKeys.PersonAliasId; transaction.CreatedByPersonAliasId = giverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } string summary = row["Memo"] as string; if ( summary != null ) { transaction.Summary = summary; } int? batchId = row["BatchID"] as int?; if ( batchId != null && ImportedBatches.Any( b => b.Key.Equals( batchId ) ) ) { transaction.BatchId = ImportedBatches.FirstOrDefault( b => b.Key.Equals( batchId ) ).Value; } else { // use the default batch for any non-matching transactions transaction.BatchId = defaultBatchId; } DateTime? receivedDate = row["Received_Date"] as DateTime?; if ( receivedDate != null ) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; transaction.ModifiedDateTime = ImportDateTime; } string cardType = row["Card_Type"] as string; string cardLastFour = row["Last_Four"] as string; string contributionType = row["Contribution_Type_Name"].ToStringSafe().ToLower(); if ( contributionType != null ) { // set default source to onsite, exceptions listed below transaction.SourceTypeValueId = sourceTypeOnsite; int? paymentCurrencyTypeId = null, creditCardTypeId = null; if ( contributionType == "cash" ) { paymentCurrencyTypeId = currencyTypeCash; } else if ( contributionType == "check" ) { paymentCurrencyTypeId = currencyTypeCheck; } else if ( contributionType == "ach" ) { paymentCurrencyTypeId = currencyTypeACH; transaction.SourceTypeValueId = sourceTypeWebsite; } else if ( contributionType == "credit card" ) { paymentCurrencyTypeId = currencyTypeCreditCard; transaction.SourceTypeValueId = sourceTypeWebsite; if ( cardType != null ) { creditCardTypeId = creditCardTypes.Where( t => t.Value.Equals( cardType ) ).Select( t => (int?)t.Id ).FirstOrDefault(); } } else { paymentCurrencyTypeId = currencyTypeNonCash; } var paymentDetail = new FinancialPaymentDetail(); paymentDetail.CreatedDateTime = receivedDate; paymentDetail.CreatedByPersonAliasId = giverAliasId; paymentDetail.ModifiedDateTime = ImportDateTime; paymentDetail.ModifiedByPersonAliasId = giverAliasId; paymentDetail.CurrencyTypeValueId = paymentCurrencyTypeId; paymentDetail.CreditCardTypeValueId = creditCardTypeId; paymentDetail.AccountNumberMasked = cardLastFour; paymentDetail.ForeignKey = contributionId.ToString(); paymentDetail.ForeignId = contributionId; transaction.FinancialPaymentDetail = paymentDetail; } string checkNumber = row["Check_Number"] as string; // if the check number is valid, put it in the transaction code if ( checkNumber.AsType<int?>() != null ) { transaction.TransactionCode = checkNumber; } // check for SecureGive kiosk transactions else if ( !string.IsNullOrEmpty( checkNumber ) && checkNumber.StartsWith( "SG" ) ) { transaction.SourceTypeValueId = sourceTypeKiosk; } string fundName = row["Fund_Name"] as string; string subFund = row["Sub_Fund_Name"] as string; string fundGLAccount = row["Fund_GL_Account"] as string; string subFundGLAccount = row["Sub_Fund_GL_Account"] as string; Boolean? isFundActive = row["Fund_Is_active"] as Boolean?; decimal? statedValue = row["Stated_Value"] as decimal?; decimal? amount = row["Amount"] as decimal?; if ( fundName != null & amount != null ) { int transactionAccountId; var parentAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName ) && a.CampusId == null ); if ( parentAccount == null ) { parentAccount = AddAccount( lookupContext, fundName, fundGLAccount, null, null, isFundActive ); accountList.Add( parentAccount ); } if ( subFund != null ) { int? campusFundId = null; // assign a campus if the subfund is a campus fund var campusFund = CampusList.FirstOrDefault( c => subFund.StartsWith( c.Name ) || subFund.StartsWith( c.ShortCode ) ); if ( campusFund != null ) { // use full campus name as the subfund subFund = campusFund.Name; campusFundId = campusFund.Id; } // add info to easily find/assign this fund in the view subFund = string.Format( "{0} {1}", subFund, fundName ); var childAccount = accountList.FirstOrDefault( c => c.Name.Equals( subFund ) && c.ParentAccountId == parentAccount.Id ); if ( childAccount == null ) { // create a child account with a campusId if it was set childAccount = AddAccount( lookupContext, subFund, subFundGLAccount, campusFundId, parentAccount.Id, isFundActive ); accountList.Add( childAccount ); } transactionAccountId = childAccount.Id; } else { transactionAccountId = parentAccount.Id; } if ( amount == 0 && statedValue != null && statedValue != 0 ) { amount = statedValue; } var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = (decimal)amount; transactionDetail.CreatedDateTime = receivedDate; transactionDetail.AccountId = transactionAccountId; transaction.TransactionDetails.Add( transactionDetail ); if ( amount < 0 ) { transaction.RefundDetails = new FinancialTransactionRefund(); transaction.RefundDetails.CreatedDateTime = receivedDate; transaction.RefundDetails.RefundReasonValueId = refundReasons.Where( dv => summary != null && dv.Value.Contains( summary ) ) .Select( dv => (int?)dv.Id ).FirstOrDefault(); transaction.RefundDetails.RefundReasonSummary = summary; } } newTransactions.Add( transaction ); completed++; if ( completed % percentage < 1 ) { int percentComplete = completed / percentage; ReportProgress( percentComplete, string.Format( "{0:N0} contributions imported ({1}% complete).", completed, percentComplete ) ); } else if ( completed % ReportingNumber < 1 ) { SaveContributions( newTransactions ); newTransactions.Clear(); ReportPartialProgress(); } } } if ( newTransactions.Any() ) { SaveContributions( newTransactions ); } ReportProgress( 100, string.Format( "Finished contribution import: {0:N0} contributions imported.", completed ) ); }
/// <summary> /// Handles the Click event of the lbSave 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 lbSave_Click( object sender, EventArgs e ) { var rockContext = new RockContext(); var txnService = new FinancialTransactionService( rockContext ); var txnDetailService = new FinancialTransactionDetailService( rockContext ); var txnImageService = new FinancialTransactionImageService( rockContext ); var binaryFileService = new BinaryFileService( rockContext ); FinancialTransaction txn = null; int? txnId = hfTransactionId.Value.AsIntegerOrNull(); int? batchId = hfBatchId.Value.AsIntegerOrNull(); if ( txnId.HasValue ) { txn = txnService.Get( txnId.Value ); } if ( txn == null ) { txn = new FinancialTransaction(); txnService.Add( txn ); txn.BatchId = batchId; } if ( txn != null ) { if ( ppAuthorizedPerson.PersonId.HasValue ) { txn.AuthorizedPersonAliasId = ppAuthorizedPerson.PersonAliasId; } txn.TransactionDateTime = dtTransactionDateTime.SelectedDateTime; txn.TransactionTypeValueId = ddlTransactionType.SelectedValue.AsInteger(); txn.SourceTypeValueId = ddlSourceType.SelectedValueAsInt(); Guid? gatewayGuid = cpPaymentGateway.SelectedValueAsGuid(); if ( gatewayGuid.HasValue ) { var gatewayEntity = EntityTypeCache.Read( gatewayGuid.Value ); if ( gatewayEntity != null ) { txn.GatewayEntityTypeId = gatewayEntity.Id; } else { txn.GatewayEntityTypeId = null; } } else { txn.GatewayEntityTypeId = null; } txn.TransactionCode = tbTransactionCode.Text; txn.CurrencyTypeValueId = ddlCurrencyType.SelectedValueAsInt(); txn.CreditCardTypeValueId = ddlCreditCardType.SelectedValueAsInt(); txn.Summary = tbSummary.Text; if ( !Page.IsValid || !txn.IsValid ) { return; } foreach ( var txnDetail in TransactionDetailsState ) { if ( !txnDetail.IsValid ) { return; } } rockContext.WrapTransaction( () => { // Save the transaction rockContext.SaveChanges(); // Delete any transaction details that were removed var txnDetailsInDB = txnDetailService.Queryable().Where( a => a.TransactionId.Equals( txn.Id ) ).ToList(); var deletedDetails = from txnDetail in txnDetailsInDB where !TransactionDetailsState.Select( d => d.Guid ).Contains( txnDetail.Guid ) select txnDetail; deletedDetails.ToList().ForEach( txnDetail => { txnDetailService.Delete( txnDetail ); } ); rockContext.SaveChanges(); // Save Transaction Details foreach ( var editorTxnDetail in TransactionDetailsState ) { // Add or Update the activity type var txnDetail = txn.TransactionDetails.FirstOrDefault( d => d.Guid.Equals( editorTxnDetail.Guid ) ); if ( txnDetail == null ) { txnDetail = new FinancialTransactionDetail(); txnDetail.Guid = editorTxnDetail.Guid; txn.TransactionDetails.Add( txnDetail ); } txnDetail.AccountId = editorTxnDetail.AccountId; txnDetail.Amount = UseSimpleAccountMode ? tbSingleAccountAmount.Text.AsDecimal() : editorTxnDetail.Amount; txnDetail.Summary = editorTxnDetail.Summary; } rockContext.SaveChanges(); // Delete any transaction images that were removed var orphanedBinaryFileIds = new List<int>(); var txnImagesInDB = txnImageService.Queryable().Where( a => a.TransactionId.Equals( txn.Id ) ).ToList(); foreach ( var txnImage in txnImagesInDB.Where( i => !TransactionImagesState.Contains( i.BinaryFileId ) ) ) { orphanedBinaryFileIds.Add( txnImage.BinaryFileId ); txnImageService.Delete( txnImage ); } // Save Transaction Images int imageOrder = 0; foreach ( var binaryFileId in TransactionImagesState ) { // Add or Update the activity type var txnImage = txnImagesInDB.FirstOrDefault( i => i.BinaryFileId == binaryFileId ); if ( txnImage == null ) { txnImage = new FinancialTransactionImage(); txnImage.TransactionId = txn.Id; txn.Images.Add( txnImage ); } txnImage.BinaryFileId = binaryFileId; txnImage.Order = imageOrder; imageOrder++; } rockContext.SaveChanges(); // Make sure updated binary files are not temporary foreach ( var binaryFile in binaryFileService.Queryable().Where( f => TransactionImagesState.Contains( f.Id ) ) ) { binaryFile.IsTemporary = false; } // Delete any orphaned images foreach ( var binaryFile in binaryFileService.Queryable().Where( f => orphanedBinaryFileIds.Contains( f.Id ) ) ) { binaryFileService.Delete( binaryFile ); } rockContext.SaveChanges(); } ); // Save selected options to session state in order to prefill values for next added txn Session["NewTxnDefault_BatchId"] = txn.BatchId; Session["NewTxnDefault_TransactionDateTime"] = txn.TransactionDateTime; Session["NewTxnDefault_TransactionType"] = txn.TransactionTypeValueId; Session["NewTxnDefault_SourceType"] = txn.SourceTypeValueId; Session["NewTxnDefault_CurrencyType"] = txn.CurrencyTypeValueId; Session["NewTxnDefault_CreditCardType"] = txn.CreditCardTypeValueId; if ( TransactionDetailsState.Count() == 1 ) { Session["NewTxnDefault_Account"] = TransactionDetailsState.First().AccountId; } else { Session.Remove("NewTxnDefault_Account"); } // Requery the batch to support EF navigation properties var savedTxn = GetTransaction( txn.Id ); ShowReadOnlyDetails( savedTxn ); } }
/// <summary> /// Writes to package. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="model">The model.</param> public static void WriteToPackage <T>(T model) { var typeName = model.GetType().Name; if (model is IImportModel) { var importModel = (IImportModel)model; // check if a textwriter is needed for this model type if (!textWriters.ContainsKey(typeName)) { if (!Directory.Exists(_packageDirectory)) { InitalizePackageFolder(); } textWriters.Add(typeName, (TextWriter)File.CreateText($@"{_packageDirectory}\{importModel.GetFileName()}")); // if model is for person create related writers if (importModel is Person) { // person attributes var personAttributeValue = new PersonAttributeValue(); textWriters.Add(personAttributeValue.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{personAttributeValue.GetFileName()}")); // person phones var personPhone = new PersonPhone(); textWriters.Add(personPhone.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{personPhone.GetFileName()}")); // person addresses var personAddress = new PersonAddress(); textWriters.Add(personAddress.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{personAddress.GetFileName()}")); } // if model is for financial batch create related writers if (importModel is FinancialBatch) { // financial transactions var financialTransaction = new FinancialTransaction(); textWriters.Add(financialTransaction.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{financialTransaction.GetFileName()}")); // financial transation details var financialTransactionDetail = new FinancialTransactionDetail(); textWriters.Add(financialTransactionDetail.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{financialTransactionDetail.GetFileName()}")); } // if model is for financial transaction create related writers if (importModel is FinancialTransaction) { // financial transation details var financialTransactionDetail = new FinancialTransactionDetail(); textWriters.Add(financialTransactionDetail.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{financialTransactionDetail.GetFileName()}")); } // if model is for group create related writers if (importModel is Group) { // group member var groupMember = new GroupMember(); textWriters.Add(groupMember.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{groupMember.GetFileName()}")); // group attributes var groupAttributeValue = new GroupAttributeValue(); textWriters.Add(groupAttributeValue.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{groupAttributeValue.GetFileName()}")); // group addresses var groupAddress = new GroupAddress(); textWriters.Add(groupAddress.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{groupAddress.GetFileName()}")); } } var txtWriter = textWriters[typeName]; // check if a csvwriter is needed for this model type if (!csvWriters.ContainsKey(typeName)) { var newCsvWriter = new CsvWriter(txtWriter); csvWriters.Add(typeName, newCsvWriter); newCsvWriter.WriteHeader <T>(); //newCsvWriter.Configuration.QuoteAllFields = true; // if model is for person create related writers if (importModel is Person) { // person attributes var personAttributeValue = new PersonAttributeValue(); var newPersonAttributeValueCsvWriter = new CsvWriter(textWriters[personAttributeValue.GetType().Name]); csvWriters.Add(personAttributeValue.GetType().Name, newPersonAttributeValueCsvWriter); newPersonAttributeValueCsvWriter.WriteHeader <PersonAttributeValue>(); // person phones var personPhone = new PersonPhone(); var newPersonPhoneCsvWriter = new CsvWriter(textWriters[personPhone.GetType().Name]); csvWriters.Add(personPhone.GetType().Name, newPersonPhoneCsvWriter); newPersonPhoneCsvWriter.WriteHeader <PersonPhone>(); // person addresses var personAddress = new PersonAddress(); var newPersonAddressCsvWriter = new CsvWriter(textWriters[personAddress.GetType().Name]); csvWriters.Add(personAddress.GetType().Name, newPersonAddressCsvWriter); newPersonAddressCsvWriter.WriteHeader <PersonAddress>(); } // if model is for financial batch create related writers if (importModel is FinancialBatch) { // financial transaction var financialTransaction = new FinancialTransaction(); var newFinancialTransactionCsvWriter = new CsvWriter(textWriters[financialTransaction.GetType().Name]); csvWriters.Add(financialTransaction.GetType().Name, newFinancialTransactionCsvWriter); newFinancialTransactionCsvWriter.WriteHeader <FinancialTransaction>(); // financial transaction detail var financialTransactionDetail = new FinancialTransactionDetail(); var newFinancialTransactionDetailCsvWriter = new CsvWriter(textWriters[financialTransactionDetail.GetType().Name]); csvWriters.Add(financialTransactionDetail.GetType().Name, newFinancialTransactionDetailCsvWriter); newFinancialTransactionDetailCsvWriter.WriteHeader <FinancialTransactionDetail>(); } //if model is for financial transaction, create related writers if (importModel is FinancialTransaction) { // financial transaction detail var financialTransactionDetail = new FinancialTransactionDetail(); var newFinancialTransactionDetailCsvWriter = new CsvWriter(textWriters[financialTransactionDetail.GetType().Name]); csvWriters.Add(financialTransactionDetail.GetType().Name, newFinancialTransactionDetailCsvWriter); newFinancialTransactionDetailCsvWriter.WriteHeader <FinancialTransactionDetail>(); } // if model is for group create related writers if (importModel is Group) { // group member var groupMember = new GroupMember(); var newGroupMemberCsvWriter = new CsvWriter(textWriters[groupMember.GetType().Name]); csvWriters.Add(groupMember.GetType().Name, newGroupMemberCsvWriter); newGroupMemberCsvWriter.WriteHeader <GroupMember>(); // group attributes var groupAttributeValue = new GroupAttributeValue(); var newGroupAttributeValueCsvWriter = new CsvWriter(textWriters[groupAttributeValue.GetType().Name]); csvWriters.Add(groupAttributeValue.GetType().Name, newGroupAttributeValueCsvWriter); newGroupAttributeValueCsvWriter.WriteHeader <GroupAttributeValue>(); // group addresses var groupAddress = new GroupAddress(); var newGroupAddressCsvWriter = new CsvWriter(textWriters[groupAddress.GetType().Name]); csvWriters.Add(groupAddress.GetType().Name, newGroupAddressCsvWriter); newGroupAddressCsvWriter.WriteHeader <GroupAddress>(); } } var csvWriter = csvWriters[typeName]; csvWriter.WriteRecord <T>(model); // if person model write out any related models if (importModel is Person) { // person attributes var personAttributeValue = new PersonAttributeValue(); var csvPersonAttributeValueWriter = csvWriters[personAttributeValue.GetType().Name]; if (csvPersonAttributeValueWriter != null) { foreach (var attribute in ((Person)importModel).Attributes) { csvPersonAttributeValueWriter.WriteRecord(attribute); } } // person phones var personPhone = new PersonPhone(); var csvPersonPhoneWriter = csvWriters[personPhone.GetType().Name]; if (csvPersonPhoneWriter != null) { foreach (var phone in ((Person)importModel).PhoneNumbers) { csvPersonPhoneWriter.WriteRecord(phone); } } // person addresses var personAddress = new PersonAddress(); var csvPersonAddressWriter = csvWriters[personAddress.GetType().Name]; if (csvPersonAddressWriter != null) { foreach (var address in ((Person)importModel).Addresses) { csvPersonAddressWriter.WriteRecord(address); } } } // if financial model write out any related models if (importModel is FinancialBatch) { // write out financial transactions and transaction details var financialTransaction = new FinancialTransaction(); var csvFinancialTransactionWriter = csvWriters[financialTransaction.GetType().Name]; var financialTransactionDetail = new FinancialTransactionDetail(); var csvFinancialTransactionDetailWriter = csvWriters[financialTransactionDetail.GetType().Name]; if (csvFinancialTransactionWriter != null && csvFinancialTransactionDetailWriter != null) { foreach (var transaction in ((FinancialBatch)importModel).FinancialTransactions) { csvFinancialTransactionWriter.WriteRecord(transaction); foreach (var transactionDetail in transaction.FinancialTransactionDetails) { csvFinancialTransactionDetailWriter.WriteRecord(transactionDetail); } } } } // if financial Transaction model write out any related models if (importModel is FinancialTransaction) { var financialTransactionDetail = new FinancialTransactionDetail(); var csvFinancialTransactionDetailWriter = csvWriters[financialTransactionDetail.GetType().Name]; if (csvFinancialTransactionDetailWriter != null) { foreach (var transactionDetail in ((FinancialTransaction)importModel).FinancialTransactionDetails) { csvFinancialTransactionDetailWriter.WriteRecord(transactionDetail); } } } // if group model write out any related models if (importModel is Group) { // group members var groupMember = new GroupMember(); var csvGroupMemberWriter = csvWriters[groupMember.GetType().Name]; if (csvGroupMemberWriter != null) { foreach (var groupMemberItem in ((Group)importModel).GroupMembers) { csvGroupMemberWriter.WriteRecord(groupMemberItem); } } // group attributes var groupAttributeValue = new GroupAttributeValue(); var csvPersonAttributeValueWriter = csvWriters[groupAttributeValue.GetType().Name]; if (csvPersonAttributeValueWriter != null) { foreach (var attribute in ((Group)importModel).Attributes) { csvPersonAttributeValueWriter.WriteRecord(attribute); } } // group addresses var groupAddress = new GroupAddress(); var csvGroupAddressWriter = csvWriters[groupAddress.GetType().Name]; if (csvGroupAddressWriter != null) { foreach (var address in ((Group)importModel).Addresses) { csvGroupAddressWriter.WriteRecord(address); } } } } }
private void SaveTransaction(FinancialGateway financialGateway, GatewayComponent gateway, Person person, PaymentInfo paymentInfo, FinancialTransaction transaction, RockContext rockContext) { transaction.AuthorizedPersonAliasId = person.PrimaryAliasId; if (RockTransactionEntry != null) { RockCheckBox cbGiveAnonymouslyControl = (( RockCheckBox )(RockTransactionEntry.FindControl("cbGiveAnonymously"))); if (cbGiveAnonymouslyControl != null) { transaction.ShowAsAnonymous = cbGiveAnonymouslyControl.Checked; } } transaction.TransactionDateTime = RockDateTime.Now; transaction.FinancialGatewayId = financialGateway.Id; var txnType = DefinedValueCache.Get(this.GetAttributeValue("TransactionType").AsGuidOrNull() ?? Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid()); transaction.TransactionTypeValueId = txnType.Id; transaction.Summary = paymentInfo.Comment1; if (transaction.FinancialPaymentDetail == null) { transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); } transaction.FinancialPaymentDetail.SetFromPaymentInfo(paymentInfo, gateway, rockContext); Guid sourceGuid = Guid.Empty; if (Guid.TryParse(GetAttributeValue("Source"), out sourceGuid)) { var source = DefinedValueCache.Get(sourceGuid); if (source != null) { transaction.SourceTypeValueId = source.Id; } } var transactionEntity = this.GetTransactionEntity(); foreach (var account in GetSelectedAccounts().Where(a => a.Amount > 0)) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = account.Amount; transactionDetail.AccountId = account.Id; if (transactionEntity != null) { transactionDetail.EntityTypeId = transactionEntity.TypeId; transactionDetail.EntityId = transactionEntity.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, financialGateway.GetBatchTimeOffset()); var batchChanges = new History.HistoryChangeList(); if (batch.Id == 0) { batchChanges.AddCustom("Add", "Record", "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; transaction.LoadAttributes(rockContext); var allowedTransactionAttributes = GetAttributeValue("AllowedTransactionAttributesFromURL").Split(',').AsGuidList().Select(x => AttributeCache.Get(x).Key); foreach (KeyValuePair <string, AttributeValueCache> attr in transaction.AttributeValues) { if (PageParameters().ContainsKey("Attribute_" + attr.Key) && allowedTransactionAttributes.Contains(attr.Key)) { attr.Value.Value = Server.UrlDecode(PageParameter("Attribute_" + attr.Key)); } } batch.Transactions.Add(transaction); rockContext.SaveChanges(); transaction.SaveAttributeValues(); HistoryService.SaveChanges( rockContext, typeof(FinancialBatch), Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), batch.Id, batchChanges ); SendReceipt(transaction.Id); TransactionCode = transaction.TransactionCode; }
/// <summary> /// Raises the <see cref="E:System.Web.UI.Control.Load" /> event. /// </summary> /// <param name="e">The <see cref="T:System.EventArgs" /> object that contains the event data.</param> protected override void OnLoad( EventArgs e ) { if ( !Page.IsPostBack ) { ShowDetail( PageParameter( "transactionId" ).AsInteger(), PageParameter( "batchId" ).AsIntegerOrNull() ); } else { nbErrorMessage.Visible = false; nbRefundError.Visible = false; ShowDialog(); if ( pnlEditDetails.Visible ) { // Add Transaction and Payment Detail attribute controls FinancialTransaction txn; var txnId = hfTransactionId.Value.AsIntegerOrNull(); if (txnId == 0) txnId = null; // Get the current transaction if there is one if (txnId.HasValue) { using (var rockContext = new RockContext()) { txn = GetTransaction(hfTransactionId.Value.AsInteger(), rockContext); } } else { txn = new FinancialTransaction(); txn.FinancialPaymentDetail = new FinancialPaymentDetail(); } // Update the transaction's properties to match what is currently selected on the screen // This allows the shown attributes to change during AutoPostBack events, based on any Qualifiers specified in the attributes txn.FinancialPaymentDetail.CurrencyTypeValueId = ddlCurrencyType.SelectedValueAsInt(); txn.LoadAttributes(); txn.FinancialPaymentDetail.LoadAttributes(); phAttributeEdits.Controls.Clear(); Helper.AddEditControls(txn, phAttributeEdits, false); phPaymentAttributeEdits.Controls.Clear(); Helper.AddEditControls(txn.FinancialPaymentDetail, phPaymentAttributeEdits, false); } } var txnDetail = new FinancialTransactionDetail(); txnDetail.LoadAttributes(); phAccountAttributeEdits.Controls.Clear(); Helper.AddEditControls( txnDetail, phAccountAttributeEdits, true, mdAccount.ValidationGroup ); }
/// <summary> /// Handles the SaveClick event of the mdAccount 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 mdAccount_SaveClick( object sender, EventArgs e ) { Guid? guid = hfAccountGuid.Value.AsGuidOrNull(); if ( guid.HasValue ) { var txnDetail = TransactionDetailsState.Where( t => t.Guid.Equals( guid.Value ) ).FirstOrDefault(); if ( txnDetail == null ) { txnDetail = new FinancialTransactionDetail(); TransactionDetailsState.Add( txnDetail ); } txnDetail.AccountId = ddlAccount.SelectedValue.AsInteger(); txnDetail.Amount = tbAccountAmount.Text.AsDecimal(); txnDetail.Summary = tbAccountSummary.Text; BindAccountsEditGrid(); } HideDialog(); }
/// <summary> /// Initializes a new instance of the <see cref="FinancialTransactionDetailExport"/> class. /// </summary> /// <param name="financialTransactionDetail">The financial transaction detail.</param> public FinancialTransactionDetailExport(FinancialTransactionDetail financialTransactionDetail) { _financialTransactionDetail = financialTransactionDetail; }
/// <summary> /// Handles the Click event of the btnNext 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 btnNext_Click(object sender, EventArgs e) { var changes = new List <string>(); var rockContext = new RockContext(); var financialTransactionService = new FinancialTransactionService(rockContext); var financialTransactionDetailService = new FinancialTransactionDetailService(rockContext); var financialPersonBankAccountService = new FinancialPersonBankAccountService(rockContext); int txnId = hfTransactionId.Value.AsInteger(); var financialTransaction = financialTransactionService .Queryable("AuthorizedPersonAlias.Person,ProcessedByPersonAlias.Person") .FirstOrDefault(t => t.Id == txnId); // set the AuthorizedPersonId (the person who wrote the check, for example) to the if the SelectNew person (if selected) or person selected in the drop down (if there is somebody selected) int?authorizedPersonId = ppSelectNew.PersonId ?? ddlIndividual.SelectedValue.AsIntegerOrNull(); var accountNumberSecured = hfCheckMicrHashed.Value; if (cbTotalAmount.Text.AsDecimalOrNull().HasValue&& !authorizedPersonId.HasValue) { nbSaveError.Text = "Transaction must be matched to a person when the amount is specified."; nbSaveError.Visible = true; return; } // if the transaction was previously matched, but user unmatched it, save it as an unmatched transaction and clear out the detail records (we don't want an unmatched transaction to have detail records) if (financialTransaction != null && financialTransaction.AuthorizedPersonAliasId.HasValue && !authorizedPersonId.HasValue) { financialTransaction.AuthorizedPersonAliasId = null; foreach (var detail in financialTransaction.TransactionDetails) { History.EvaluateChange(changes, detail.Account != null ? detail.Account.Name : "Unknown", detail.Amount.FormatAsCurrency(), string.Empty); financialTransactionDetailService.Delete(detail); } changes.Add("Unmatched transaction"); HistoryService.SaveChanges( rockContext, typeof(FinancialBatch), Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(), financialTransaction.BatchId.Value, changes, string.Format("Transaction Id: {0}", financialTransaction.Id), typeof(FinancialTransaction), financialTransaction.Id, false); rockContext.SaveChanges(); // if the transaction was unmatched, clear out the ProcessedBy fields since we didn't match the transaction and are moving on to process another transaction MarkTransactionAsNotProcessedByCurrentUser(hfTransactionId.Value.AsInteger()); } // if the transaction is matched to somebody, attempt to save it. Otherwise, if the transaction was previously matched, but user unmatched it, save it as an unmatched transaction if (financialTransaction != null && authorizedPersonId.HasValue) { if (cbTotalAmount.Text.AsDecimalOrNull() == null) { nbSaveError.Text = "Total amount must be allocated to accounts."; nbSaveError.Visible = true; return; } var personAlias = new PersonAliasService(rockContext).GetPrimaryAlias(authorizedPersonId.Value); int?personAliasId = personAlias != null ? personAlias.Id : (int?)null; // if this transaction has an accountnumber associated with it (in other words, it's a valid scanned check), ensure there is a financialPersonBankAccount record if (financialTransaction.MICRStatus == MICRStatus.Success && !string.IsNullOrWhiteSpace(accountNumberSecured)) { var financialPersonBankAccount = financialPersonBankAccountService.Queryable().Where(a => a.AccountNumberSecured == accountNumberSecured && a.PersonAlias.PersonId == authorizedPersonId.Value).FirstOrDefault(); if (financialPersonBankAccount == null) { if (personAliasId.HasValue) { financialPersonBankAccount = new FinancialPersonBankAccount(); financialPersonBankAccount.PersonAliasId = personAliasId.Value; financialPersonBankAccount.AccountNumberSecured = accountNumberSecured; var checkMicrClearText = Encryption.DecryptString(financialTransaction.CheckMicrParts); var parts = checkMicrClearText.Split('_'); if (parts.Length >= 2) { financialPersonBankAccount.AccountNumberMasked = parts[1].Masked(); } if (string.IsNullOrWhiteSpace(financialPersonBankAccount.AccountNumberMasked)) { financialPersonBankAccount.AccountNumberMasked = "************????"; } financialPersonBankAccountService.Add(financialPersonBankAccount); } } } string prevPerson = (financialTransaction.AuthorizedPersonAlias != null && financialTransaction.AuthorizedPersonAlias.Person != null) ? financialTransaction.AuthorizedPersonAlias.Person.FullName : string.Empty; string newPerson = string.Empty; if (personAliasId.HasValue) { newPerson = personAlias.Person.FullName; financialTransaction.AuthorizedPersonAliasId = personAliasId; } History.EvaluateChange(changes, "Person", prevPerson, newPerson); // just in case this transaction is getting re-edited either by the same user, or somebody else, clean out any existing TransactionDetail records foreach (var detail in financialTransaction.TransactionDetails.ToList()) { financialTransactionDetailService.Delete(detail); History.EvaluateChange(changes, detail.Account != null ? detail.Account.Name : "Unknown", detail.Amount.FormatAsCurrency(), string.Empty); } foreach (var accountBox in rptAccounts.ControlsOfTypeRecursive <CurrencyBox>()) { var amount = accountBox.Text.AsDecimalOrNull(); if (amount.HasValue && amount.Value >= 0) { var financialTransactionDetail = new FinancialTransactionDetail(); financialTransactionDetail.TransactionId = financialTransaction.Id; financialTransactionDetail.AccountId = accountBox.Attributes["data-account-id"].AsInteger(); financialTransactionDetail.Amount = amount.Value; financialTransactionDetailService.Add(financialTransactionDetail); History.EvaluateChange(changes, accountBox.Label, 0.0M.FormatAsCurrency(), amount.Value.FormatAsCurrency()); } } financialTransaction.Summary = tbSummary.Text; financialTransaction.ProcessedByPersonAliasId = this.CurrentPersonAlias.Id; financialTransaction.ProcessedDateTime = RockDateTime.Now; changes.Add("Matched transaction"); HistoryService.SaveChanges( rockContext, typeof(FinancialBatch), Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(), financialTransaction.BatchId.Value, changes, personAlias != null && personAlias.Person != null ? personAlias.Person.FullName : string.Format("Transaction Id: {0}", financialTransaction.Id), typeof(FinancialTransaction), financialTransaction.Id, false); rockContext.SaveChanges(); } else { // if the transaction was not matched, clear out the ProcessedBy fields since we didn't match the transaction and are moving on to process another transaction MarkTransactionAsNotProcessedByCurrentUser(hfTransactionId.Value.AsInteger()); } NavigateToTransaction(Direction.Next); }
/// <summary> /// Maps the contribution. /// </summary> /// <param name="csvData">The table data.</param> private int MapContribution(CSVInstance csvData) { var lookupContext = new RockContext(); int transactionEntityTypeId = EntityTypeCache.Read("Rock.Model.FinancialTransaction").Id; var transactionTypeContributionId = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION), lookupContext).Id; var currencyTypes = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE)); int currencyTypeACH = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH))).Id; int currencyTypeCash = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH))).Id; int currencyTypeCheck = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK))).Id; int currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD))).Id; int?currencyTypeNonCash = currencyTypes.DefinedValues.Where(dv => dv.Value.Equals("Non-Cash")).Select(dv => (int?)dv.Id).FirstOrDefault(); if (currencyTypeNonCash == null) { var newTenderNonCash = new DefinedValue(); newTenderNonCash.Value = "Non-Cash"; newTenderNonCash.Description = "Non-Cash"; newTenderNonCash.DefinedTypeId = currencyTypes.Id; lookupContext.DefinedValues.Add(newTenderNonCash); lookupContext.SaveChanges(); currencyTypeNonCash = newTenderNonCash.Id; } var creditCardTypes = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE)).DefinedValues; int sourceTypeOnsite = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_ONSITE_COLLECTION), lookupContext).Id; int sourceTypeWebsite = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE), lookupContext).Id; int sourceTypeKiosk = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_KIOSK), lookupContext).Id; var refundReasons = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON), lookupContext).DefinedValues; var accountList = new FinancialAccountService(lookupContext).Queryable().AsNoTracking().ToList(); int?defaultBatchId = null; if (ImportedBatches.ContainsKey(0)) { defaultBatchId = ImportedBatches[0]; } // Get all imported contributions var importedContributions = new FinancialTransactionService(lookupContext).Queryable().AsNoTracking() .Where(c => c.ForeignId != null) .ToDictionary(t => (int)t.ForeignId, t => (int?)t.Id); // List for batching new contributions var newTransactions = new List <FinancialTransaction>(); int completed = 0; ReportProgress(0, string.Format("Verifying contribution import ({0:N0} already exist).", importedContributions.Count)); string[] row; // Uses a look-ahead enumerator: this call will move to the next record immediately while ((row = csvData.Database.FirstOrDefault()) != null) { string individualIdKey = row[IndividualID]; int? individualId = individualIdKey.AsType <int?>(); string contributionIdKey = row[ContributionID]; int? contributionId = contributionIdKey.AsType <int?>(); if (contributionId != null && !importedContributions.ContainsKey((int)contributionId)) { var transaction = new FinancialTransaction(); transaction.CreatedByPersonAliasId = ImportPersonAliasId; transaction.ModifiedByPersonAliasId = ImportPersonAliasId; transaction.TransactionTypeValueId = transactionTypeContributionId; transaction.ForeignKey = contributionId.ToString(); transaction.ForeignId = contributionId; int?giverAliasId = null; var personKeys = GetPersonKeys(individualId); if (personKeys != null && personKeys.PersonAliasId > 0) { giverAliasId = personKeys.PersonAliasId; transaction.CreatedByPersonAliasId = giverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } string summary = row[Memo] as string; if (summary != null) { transaction.Summary = summary; } string batchIdKey = row[ContributionBatchID]; int? batchId = batchIdKey.AsType <int?>(); if (batchId != null && ImportedBatches.Any(b => b.Key.Equals(batchId))) { transaction.BatchId = ImportedBatches.FirstOrDefault(b => b.Key.Equals(batchId)).Value; } else { // use the default batch for any non-matching transactions transaction.BatchId = defaultBatchId; } string receivedDateKey = row[ReceivedDate]; DateTime?receivedDate = receivedDateKey.AsType <DateTime?>(); if (receivedDate != null) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; transaction.ModifiedDateTime = ImportDateTime; } string contributionType = row[ContributionTypeName].ToStringSafe().ToLower(); if (contributionType != null) { // set default source to onsite, exceptions listed below transaction.SourceTypeValueId = sourceTypeOnsite; int?paymentCurrencyTypeId = null, creditCardTypeId = null; if (contributionType == "cash") { paymentCurrencyTypeId = currencyTypeCash; } else if (contributionType == "check") { paymentCurrencyTypeId = currencyTypeCheck; } else if (contributionType == "ach") { paymentCurrencyTypeId = currencyTypeACH; transaction.SourceTypeValueId = sourceTypeWebsite; } else if (contributionType == "credit card") { paymentCurrencyTypeId = currencyTypeCreditCard; transaction.SourceTypeValueId = sourceTypeWebsite; } else { paymentCurrencyTypeId = currencyTypeNonCash; } var paymentDetail = new FinancialPaymentDetail(); paymentDetail.CreatedDateTime = receivedDate; paymentDetail.CreatedByPersonAliasId = giverAliasId; paymentDetail.ModifiedDateTime = ImportDateTime; paymentDetail.ModifiedByPersonAliasId = giverAliasId; paymentDetail.CurrencyTypeValueId = paymentCurrencyTypeId; paymentDetail.CreditCardTypeValueId = creditCardTypeId; paymentDetail.ForeignKey = contributionId.ToString(); paymentDetail.ForeignId = contributionId; transaction.FinancialPaymentDetail = paymentDetail; } string checkNumber = row[CheckNumber] as string; // if the check number is valid, put it in the transaction code if (checkNumber.AsType <int?>() != null) { transaction.TransactionCode = checkNumber; } // check for SecureGive kiosk transactions else if (!string.IsNullOrEmpty(checkNumber) && checkNumber.StartsWith("SG")) { transaction.SourceTypeValueId = sourceTypeKiosk; } string fundName = row[FundName] as string; string subFund = row[SubFundName] as string; string fundGLAccount = row[FundGLAccount] as string; string subFundGLAccount = row[SubFundGLAccount] as string; string isFundActiveKey = row[FundIsActive]; Boolean?isFundActive = isFundActiveKey.AsType <Boolean?>(); string statedValueKey = row[StatedValue]; decimal?statedValue = statedValueKey.AsType <decimal?>(); string amountKey = row[Amount]; decimal?amount = amountKey.AsType <decimal?>(); if (fundName != null & amount != null) { int transactionAccountId; var parentAccount = accountList.FirstOrDefault(a => a.Name.Equals(fundName) && a.CampusId == null); if (parentAccount == null) { parentAccount = AddAccount(lookupContext, fundName, fundGLAccount, null, null, isFundActive); accountList.Add(parentAccount); } if (!String.IsNullOrWhiteSpace(subFund)) { int?campusFundId = null; // assign a campus if the subfund is a campus fund var campusFund = CampusList.FirstOrDefault(c => subFund.StartsWith(c.Name) || subFund.StartsWith(c.ShortCode)); if (campusFund != null) { // use full campus name as the subfund subFund = campusFund.Name; campusFundId = campusFund.Id; } // add info to easily find/assign this fund in the view subFund = string.Format("{0} {1}", subFund, fundName); var childAccount = accountList.FirstOrDefault(c => c.Name.Equals(subFund) && c.ParentAccountId == parentAccount.Id); if (childAccount == null) { // create a child account with a campusId if it was set childAccount = AddAccount(lookupContext, subFund, subFundGLAccount, campusFundId, parentAccount.Id, isFundActive); accountList.Add(childAccount); } transactionAccountId = childAccount.Id; } else { transactionAccountId = parentAccount.Id; } if (amount == 0 && statedValue != null && statedValue != 0) { amount = statedValue; } var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = (decimal)amount; transactionDetail.CreatedDateTime = receivedDate; transactionDetail.AccountId = transactionAccountId; transaction.TransactionDetails.Add(transactionDetail); if (amount < 0) { transaction.RefundDetails = new FinancialTransactionRefund(); transaction.RefundDetails.CreatedDateTime = receivedDate; transaction.RefundDetails.RefundReasonValueId = refundReasons.Where(dv => summary != null && dv.Value.Contains(summary)) .Select(dv => (int?)dv.Id).FirstOrDefault(); transaction.RefundDetails.RefundReasonSummary = summary; } } newTransactions.Add(transaction); completed++; if (completed % (ReportingNumber * 10) < 1) { ReportProgress(0, string.Format("{0:N0} contributions imported.", completed)); } else if (completed % ReportingNumber < 1) { SaveContributions(newTransactions); newTransactions.Clear(); ReportPartialProgress(); } } } if (newTransactions.Any()) { SaveContributions(newTransactions); } ReportProgress(100, string.Format("Finished contribution import: {0:N0} contributions imported.", completed)); return(completed); }
/// <summary> /// Creates the giving records for the given parameters. /// </summary> /// <param name="personGuid">The person unique identifier.</param> /// <param name="startingDate">The starting date.</param> /// <param name="endDate">The end date.</param> /// <param name="frequency">The frequency (onetime, weekly, monthly).</param> /// <param name="percentGive">The percent give.</param> /// <param name="growRatePercent">The grow rate percent.</param> /// <param name="growFrequencyWeeks">The grow frequency weeks.</param> /// <param name="specialGiftPercent">The special gift percent.</param> /// <param name="accountAmountDict">The account amount dictionary.</param> /// <param name="circularImageList">A circular linked list of imageUrls to use for the fake contribution checks.</param> /// <param name="rockContexe">A rock context.</param> private void CreateGiving( Guid personGuid, DateTime startingDate, DateTime endDate, Frequency frequency, int percentGive, int growRatePercent, int growFrequencyWeeks, int specialGiftPercent, Dictionary<int, decimal> accountAmountDict, LinkedList<string> circularImageList, RockContext rockContext ) { int weekNumber = 0; DateTime monthly = startingDate; var currencyTypeCheck = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK.AsGuid() ); var imageUrlNode = circularImageList.First ?? null; // foreach weekend or monthly between the starting and ending date... for ( DateTime date = startingDate; date <= endDate; date = frequency == Frequency.weekly ? date.AddDays( 7 ) : frequency == Frequency.monthly ? date.AddMonths( 1 ) : endDate.AddDays(1) ) { weekNumber = (int)(date - startingDate).TotalDays / 7; // increase by growRatePercent every growFrequencyWeeks if ( growFrequencyWeeks != 0 && growRatePercent != 0 && weekNumber !=0 && weekNumber % growFrequencyWeeks == 0 ) { var copy = accountAmountDict.ToDictionary( entry => entry.Key, entry => entry.Value ); foreach ( var item in accountAmountDict ) { decimal amount = Math.Round( ( item.Value * 0.01M ) + item.Value, 0 ); copy[item.Key] = amount; } accountAmountDict = copy; } // randomized skip/missed weeks int summerFactor = ( 7 <= date.Month && date.Month <= 9 ) ? summerPercentFactor : 0; if ( _random.Next( 0, 100 ) > percentGive - summerFactor ) { continue; // skip this week } FinancialBatch batch; if ( _contributionBatches.ContainsKey( date ) ) { batch = _contributionBatches[date]; } else { batch = new FinancialBatch { Id = 0, Guid = Guid.NewGuid(), BatchStartDateTime = date, BatchEndDateTime = date, Status = BatchStatus.Closed, ControlAmount = 0, Name = string.Format( "SampleData{0}", date.ToJavascriptMilliseconds() ), CreatedByPersonAliasId = CurrentPerson.PrimaryAliasId }; _contributionBatches.Add( date, batch ); } // Set up the new transaction FinancialTransaction financialTransaction = new FinancialTransaction { TransactionTypeValueId = _transactionTypeContributionId, Guid = Guid.NewGuid(), TransactionDateTime = date, AuthorizedPersonAliasId = _peopleAliasDictionary[personGuid] }; financialTransaction.FinancialPaymentDetail = new FinancialPaymentDetail(); financialTransaction.FinancialPaymentDetail.CurrencyTypeValueId = currencyTypeCheck.Id; financialTransaction.FinancialPaymentDetail.Guid = Guid.NewGuid(); // Add a transaction detail record for each account they're donating to foreach ( var item in accountAmountDict ) { FinancialTransactionDetail transactionDetail = new FinancialTransactionDetail { AccountId = item.Key, Amount = item.Value, Guid = Guid.NewGuid() }; financialTransaction.TransactionDetails.Add( transactionDetail ); } // Add the image to the transaction (if any) if ( imageUrlNode != null ) { FinancialTransactionImage transactionImage = new FinancialTransactionImage { BinaryFile = SaveImage( imageUrlNode.Value, _checkImageBinaryFileType, _checkImageBinaryFileTypeSettings, rockContext ), Guid = Guid.NewGuid(), }; financialTransaction.Images.Add( transactionImage ); imageUrlNode = imageUrlNode.Next ?? imageUrlNode.List.First; } // Update the batch with the new control amount batch.ControlAmount += financialTransaction.TotalAmount; batch.Transactions.Add( financialTransaction ); } }
/// <summary> /// Processes the payment. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="registration">The registration.</param> /// <param name="errorMessage">The error message.</param> /// <returns></returns> private bool ProcessPayment( RockContext rockContext, Registration registration, out string errorMessage ) { GatewayComponent gateway = null; if ( RegistrationTemplate != null && RegistrationTemplate.FinancialGateway != null ) { gateway = RegistrationTemplate.FinancialGateway.GetGatewayComponent(); } if ( gateway == null ) { errorMessage = "There was a problem creating the payment gateway information"; return false; } if ( !RegistrationInstanceState.AccountId.HasValue || RegistrationInstanceState.Account == null ) { errorMessage = "There was a problem with the account configuration for this " + RegistrationTerm.ToLower(); return false; } PaymentInfo paymentInfo = null; if ( rblSavedCC.Items.Count > 0 && ( rblSavedCC.SelectedValueAsId() ?? 0 ) > 0 ) { var savedAccount = new FinancialPersonSavedAccountService( new RockContext() ).Get( rblSavedCC.SelectedValueAsId().Value ); if ( savedAccount != null ) { paymentInfo = savedAccount.GetReferencePayment(); paymentInfo.Amount = RegistrationState.PaymentAmount ?? 0.0m; } else { errorMessage = "There was a problem retrieving the saved account"; return false; } } else { paymentInfo = GetCCPaymentInfo( gateway ); } paymentInfo.Comment1 = string.Format( "{0} ({1})", RegistrationInstanceState.Name, RegistrationInstanceState.Account.GlCode ); var transaction = gateway.Charge( RegistrationTemplate.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 = registration.PersonAliasId; transaction.TransactionDateTime = RockDateTime.Now; History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime ); transaction.FinancialGatewayId = RegistrationTemplate.FinancialGatewayId; History.EvaluateChange( txnChanges, "Gateway", string.Empty, RegistrationTemplate.FinancialGateway.Name ); var txnType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_EVENT_REGISTRATION ) ); 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 ); } } transaction.Summary = registration.GetSummary( RegistrationInstanceState ); var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = RegistrationState.PaymentAmount ?? 0.0m; transactionDetail.AccountId = RegistrationInstanceState.AccountId.Value; transactionDetail.EntityTypeId = EntityTypeCache.Read( typeof( Rock.Model.Registration ) ).Id; transactionDetail.EntityId = registration.Id; transaction.TransactionDetails.Add( transactionDetail ); History.EvaluateChange( txnChanges, RegistrationInstanceState.Account.Name, 0.0M.FormatAsCurrency(), transactionDetail.Amount.FormatAsCurrency() ); var batchChanges = new List<string>(); rockContext.WrapTransaction( () => { var batchService = new FinancialBatchService( rockContext ); // Get the batch var batch = batchService.Get( GetAttributeValue( "BatchNamePrefix" ), paymentInfo.CurrencyTypeValue, paymentInfo.CreditCardTypeValue, transaction.TransactionDateTime.Value, RegistrationTemplate.FinancialGateway.GetBatchTimeOffset() ); 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(); } ); if ( transaction.BatchId.HasValue ) { Task.Run( () => HistoryService.SaveChanges( new RockContext(), typeof( FinancialBatch ), Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), transaction.BatchId.Value, batchChanges, true, CurrentPersonAliasId ) ); Task.Run( () => HistoryService.SaveChanges( new RockContext(), typeof( FinancialBatch ), Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(), transaction.BatchId.Value, txnChanges, CurrentPerson != null ? CurrentPerson.FullName : string.Empty, typeof( FinancialTransaction ), transaction.Id, true, CurrentPersonAliasId ) ); } List<string> registrationChanges = new List<string>(); registrationChanges.Add( string.Format( "Made {0} payment", transaction.TotalAmount.FormatAsCurrency() ) ); Task.Run( () => HistoryService.SaveChanges( new RockContext(), typeof( Registration ), Rock.SystemGuid.Category.HISTORY_EVENT_REGISTRATION.AsGuid(), registration.Id, registrationChanges, true, CurrentPersonAliasId ) ); TransactionCode = transaction.TransactionCode; return true; } else { return false; } }
/// <summary> /// Handles the Click event of the btnGive 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 btnGive_Click(object sender, EventArgs e) { Person person = FindPerson(); using (new UnitOfWorkScope()) { RockTransactionScope.WrapTransaction(() => { var groupLocationService = new GroupLocationService(); var groupMemberService = new GroupMemberService(); var phoneService = new PhoneNumberService(); var locationService = new LocationService(); var groupService = new GroupService(); GroupLocation groupLocation; Location homeAddress; Group familyGroup; var homeLocationType = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.LOCATION_TYPE_HOME); var addressList = locationService.Queryable().Where(l => l.Street1 == txtStreet.Text && l.City == txtCity.Text && l.State == ddlState.SelectedValue && l.Zip == txtZip.Text && l.LocationTypeValueId == homeLocationType.Id).ToList(); if (!addressList.Any()) { homeAddress = new Location(); locationService.Add(homeAddress, person.Id); } else { homeAddress = addressList.FirstOrDefault(); } homeAddress.Street1 = txtStreet.Text ?? homeAddress.Street1; homeAddress.City = txtCity.Text ?? homeAddress.City; homeAddress.State = ddlState.SelectedValue ?? homeAddress.State; homeAddress.Zip = txtZip.Text ?? homeAddress.Zip; homeAddress.IsActive = true; homeAddress.IsLocation = true; homeAddress.Country = "US"; homeAddress.LocationTypeValueId = homeLocationType.Id; locationService.Save(homeAddress, person.Id); GroupType familyGroupType = new GroupTypeService().Get(new Guid(Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY)); var familyGroupList = groupMemberService.Queryable().Where(g => g.PersonId == person.Id && g.Group.GroupType.Guid == familyGroupType.Guid).Select(g => g.Group).ToList(); if (!familyGroupList.Any()) { familyGroup = new Group(); familyGroup.IsActive = true; familyGroup.IsSystem = false; familyGroup.IsSecurityRole = false; familyGroup.Name = "The " + txtLastName.Text + " Family"; familyGroup.GroupTypeId = familyGroupType.Id; groupService.Add(familyGroup, person.Id); groupService.Save(familyGroup, person.Id); var familyMember = new GroupMember(); familyMember.IsSystem = false; familyMember.GroupId = familyGroup.Id; familyMember.PersonId = person.Id; familyMember.GroupRoleId = new GroupRoleService().Get(new Guid(Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT)).Id; groupMemberService.Add(familyMember, person.Id); groupMemberService.Save(familyMember, person.Id); } else { familyGroup = familyGroupList.FirstOrDefault(); } var groupLocationList = groupLocationService.Queryable().Where(g => g.GroupLocationTypeValueId == familyGroupType.Id && g.GroupId == familyGroup.Id).ToList(); if (!groupLocationList.Any()) { groupLocation = new GroupLocation(); groupLocation.GroupId = familyGroup.Id; groupLocation.LocationId = homeAddress.Id; groupLocation.IsMailing = true; groupLocation.IsLocation = true; groupLocation.GroupLocationTypeValueId = homeLocationType.Id; groupLocationService.Add(groupLocation, person.Id); groupLocationService.Save(groupLocation, person.Id); } else { groupLocation = groupLocationList.FirstOrDefault(); } groupLocation.LocationId = homeAddress.Id; groupLocationService.Save(groupLocation, person.Id); var homePhoneType = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_HOME); string phoneNumeric = txtPhone.Text.AsNumeric(); if (!phoneService.Queryable().Where(n => n.PersonId == person.Id && n.NumberTypeValueId == homePhoneType.Id && n.Number == phoneNumeric).Any()) { var homePhone = new PhoneNumber(); homePhone.Number = phoneNumeric; homePhone.PersonId = person.Id; homePhone.IsSystem = false; homePhone.IsMessagingEnabled = false; homePhone.IsUnlisted = false; homePhone.NumberTypeValueId = homePhoneType.Id; phoneService.Add(homePhone, person.Id); phoneService.Save(homePhone, person.Id); } }); } var amountList = (Dictionary <FinancialAccount, Decimal>)Session["CachedAmounts"]; var profileId = (int)Session["CachedProfileId"]; Location giftLocation = new Location(); var configValues = (Dictionary <string, object>)Session["CachedMergeFields"]; configValues.Add("Date", DateTimeOffset.Now.ToString("MM/dd/yyyy hh:mm tt")); var receiptTemplate = GetAttributeValue("ReceiptMessage"); lReceipt.Text = receiptTemplate.ResolveMergeFields(configValues); var summaryTemplate = GetAttributeValue("SummaryMessage"); string summaryMessage = summaryTemplate.ResolveMergeFields(configValues); var creditProcessorId = GetAttributeValue("CreditCardProvider"); var achProcessorId = GetAttributeValue("Checking/ACHProvider"); var gatewayService = new FinancialGatewayService(); FinancialGateway gateway; if (!string.IsNullOrEmpty(txtCreditCard.Text) && !string.IsNullOrWhiteSpace(creditProcessorId)) { int creditId = Convert.ToInt32(creditProcessorId); gateway = new FinancialGatewayService().Get(creditId); } else if (!string.IsNullOrEmpty(txtAccountNumber.Text) && !string.IsNullOrWhiteSpace(achProcessorId)) { int achId = Convert.ToInt32(achProcessorId); gateway = new FinancialGatewayService().Get(achId); } else { gateway = gatewayService.Queryable().FirstOrDefault(); } // #TODO test card through gateway if (btnFrequency.SelectedIndex > -1 && btnFrequency.SelectedValueAsInt() != DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.TRANSACTION_FREQUENCY_TYPE_ONE_TIME).Id) { using (new UnitOfWorkScope()) { RockTransactionScope.WrapTransaction(() => { var scheduledTransactionDetailService = new FinancialScheduledTransactionDetailService(); var scheduledTransactionService = new FinancialScheduledTransactionService(); FinancialScheduledTransaction scheduledTransaction; var detailList = amountList.ToList(); if (profileId > 0) { scheduledTransaction = scheduledTransactionService.Get(profileId); } else { scheduledTransaction = new FinancialScheduledTransaction(); scheduledTransactionService.Add(scheduledTransaction, person.Id); } DateTime startDate = (DateTime)dtpStartDate.SelectedDate; if (startDate != null) { scheduledTransaction.StartDate = startDate; } scheduledTransaction.TransactionFrequencyValueId = (int)btnFrequency.SelectedValueAsInt(); scheduledTransaction.AuthorizedPersonId = person.Id; scheduledTransaction.IsActive = true; if (!string.IsNullOrEmpty(txtCreditCard.Text)) { scheduledTransaction.CardReminderDate = mypExpiration.SelectedDate; } if (chkLimitGifts.Checked && !string.IsNullOrWhiteSpace(txtLimitNumber.Text)) { scheduledTransaction.NumberOfPayments = Convert.ToInt32(txtLimitNumber.Text); } foreach (var detail in amountList.ToList()) { var scheduledTransactionDetail = new FinancialScheduledTransactionDetail(); scheduledTransactionDetail.AccountId = detail.Key.Id; scheduledTransactionDetail.Amount = detail.Value; scheduledTransactionDetail.ScheduledTransactionId = scheduledTransaction.Id; scheduledTransactionDetailService.Add(scheduledTransactionDetail, person.Id); scheduledTransactionDetailService.Save(scheduledTransactionDetail, person.Id); } // implement gateway charge() scheduledTransactionService.Save(scheduledTransaction, person.Id); }); } } else { using (new UnitOfWorkScope()) { RockTransactionScope.WrapTransaction(() => { var transactionService = new FinancialTransactionService(); var tdService = new FinancialTransactionDetailService(); var transaction = new FinancialTransaction(); var detailList = amountList.ToList(); transaction.Summary = summaryMessage; transaction.Amount = detailList.Sum(d => d.Value); transaction.TransactionTypeValueId = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION).Id; transaction.TransactionDateTime = DateTimeOffset.Now.DateTime; transaction.AuthorizedPersonId = person.Id; transactionService.Add(transaction, person.Id); foreach (var detail in detailList) { var td = new FinancialTransactionDetail(); td.TransactionId = transaction.Id; td.AccountId = detail.Key.Id; td.Amount = detail.Value; td.TransactionId = transaction.Id; tdService.Add(td, person.Id); tdService.Save(td, person.Id); } // #TODO implement gateway.charge() transactionService.Save(transaction, person.Id); }); } } Session["CachedMergeFields"] = configValues; pnlConfirm.Visible = false; pnlComplete.Visible = true; pnlContribution.Update(); }
/// <summary> /// Handles the SaveClick event of the mdDetails control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> private void mdDetails_SaveClick( object sender, EventArgs e ) { var rockContext = new RockContext(); if ( !string.IsNullOrWhiteSpace( tbTransactionAmount.Text ) ) { var ftdService = new FinancialTransactionDetailService( rockContext ); FinancialTransactionDetail ftd = null; var transactionDetailId = int.Parse( hfIdValue.Value ); if ( transactionDetailId > 0 ) { ftd = ftdService.Get( transactionDetailId ); } else { ftd = new FinancialTransactionDetail { Id = 0 }; } ftd.TransactionId = hfIdTransValue.ValueAsInt(); ftd.AccountId = int.Parse( ddlTransactionAccount.SelectedValue ); ftd.Amount = decimal.Parse( tbTransactionAmount.Text ); ftd.Summary = tbTransactionSummary.Text; if ( transactionDetailId == 0 ) { ftdService.Add( ftd ); } rockContext.SaveChanges(); } mdDetails.Hide(); FinancialTransaction transaction = new FinancialTransaction(); transaction = new FinancialTransactionService( rockContext ).Get( hfIdTransValue.ValueAsInt() ); BindTransactionDetailGrid( transaction ); LoadRelatedImages( transaction.Id ); }
/// <summary> /// Maps the contribution. /// </summary> /// <param name="tableData">The table data.</param> /// <param name="selectedColumns">The selected columns.</param> private void MapContribution(IQueryable <Row> tableData, List <string> selectedColumns = null) { var lookupContext = new RockContext(); int transactionEntityTypeId = EntityTypeCache.Read("Rock.Model.FinancialTransaction").Id; var transactionTypeContributionId = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION), lookupContext).Id; var currencyTypes = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE)); int currencyTypeACH = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH))).Id; int currencyTypeCash = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH))).Id; int currencyTypeCheck = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK))).Id; int currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD))).Id; int?currencyTypeNonCash = currencyTypes.DefinedValues.Where(dv => dv.Value.Equals("Non-Cash")).Select(dv => (int?)dv.Id).FirstOrDefault(); if (currencyTypeNonCash == null) { var newTenderNonCash = new DefinedValue(); newTenderNonCash.Value = "Non-Cash"; newTenderNonCash.Description = "Non-Cash"; newTenderNonCash.DefinedTypeId = currencyTypes.Id; lookupContext.DefinedValues.Add(newTenderNonCash); lookupContext.SaveChanges(); currencyTypeNonCash = newTenderNonCash.Id; } var creditCardTypes = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE)).DefinedValues; int sourceTypeOnsite = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_ONSITE_COLLECTION), lookupContext).Id; int sourceTypeWebsite = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE), lookupContext).Id; int sourceTypeKiosk = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_KIOSK), lookupContext).Id; var refundReasons = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON), lookupContext).DefinedValues; var accountList = new FinancialAccountService(lookupContext).Queryable().AsNoTracking().ToList(); int?defaultBatchId = null; if (ImportedBatches.ContainsKey(0)) { defaultBatchId = ImportedBatches[0]; } // Get all imported contributions var importedContributions = new FinancialTransactionService(lookupContext).Queryable().AsNoTracking() .Where(c => c.ForeignId != null) .ToDictionary(t => (int)t.ForeignId, t => (int?)t.Id); // List for batching new contributions var newTransactions = new List <FinancialTransaction>(); int completed = 0; int totalRows = tableData.Count(); int percentage = (totalRows - 1) / 100 + 1; ReportProgress(0, string.Format("Verifying contribution import ({0:N0} found, {1:N0} already exist).", totalRows, importedContributions.Count)); foreach (var row in tableData.Where(r => r != null)) { int?individualId = row["Individual_ID"] as int?; int?householdId = row["Household_ID"] as int?; int?contributionId = row["ContributionID"] as int?; if (contributionId != null && !importedContributions.ContainsKey((int)contributionId)) { var transaction = new FinancialTransaction(); transaction.CreatedByPersonAliasId = ImportPersonAliasId; transaction.ModifiedByPersonAliasId = ImportPersonAliasId; transaction.TransactionTypeValueId = transactionTypeContributionId; transaction.ForeignKey = contributionId.ToString(); transaction.ForeignId = contributionId; int?giverAliasId = null; var personKeys = GetPersonKeys(individualId, householdId); if (personKeys != null && personKeys.PersonAliasId > 0) { giverAliasId = personKeys.PersonAliasId; transaction.CreatedByPersonAliasId = giverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } string summary = row["Memo"] as string; if (summary != null) { transaction.Summary = summary; } int?batchId = row["BatchID"] as int?; if (batchId != null && ImportedBatches.Any(b => b.Key.Equals(batchId))) { transaction.BatchId = ImportedBatches.FirstOrDefault(b => b.Key.Equals(batchId)).Value; } else { // use the default batch for any non-matching transactions transaction.BatchId = defaultBatchId; } DateTime?receivedDate = row["Received_Date"] as DateTime?; if (receivedDate != null) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; transaction.ModifiedDateTime = ImportDateTime; } string cardType = row["Card_Type"] as string; string cardLastFour = row["Last_Four"] as string; string contributionType = row["Contribution_Type_Name"].ToStringSafe().ToLower(); if (contributionType != null) { // set default source to onsite, exceptions listed below transaction.SourceTypeValueId = sourceTypeOnsite; int?paymentCurrencyTypeId = null, creditCardTypeId = null; if (contributionType == "cash") { paymentCurrencyTypeId = currencyTypeCash; } else if (contributionType == "check") { paymentCurrencyTypeId = currencyTypeCheck; } else if (contributionType == "ach") { paymentCurrencyTypeId = currencyTypeACH; transaction.SourceTypeValueId = sourceTypeWebsite; } else if (contributionType == "credit card") { paymentCurrencyTypeId = currencyTypeCreditCard; transaction.SourceTypeValueId = sourceTypeWebsite; if (cardType != null) { creditCardTypeId = creditCardTypes.Where(t => t.Value.Equals(cardType)).Select(t => (int?)t.Id).FirstOrDefault(); } } else { paymentCurrencyTypeId = currencyTypeNonCash; } var paymentDetail = new FinancialPaymentDetail(); paymentDetail.CreatedDateTime = receivedDate; paymentDetail.CreatedByPersonAliasId = giverAliasId; paymentDetail.ModifiedDateTime = ImportDateTime; paymentDetail.ModifiedByPersonAliasId = giverAliasId; paymentDetail.CurrencyTypeValueId = paymentCurrencyTypeId; paymentDetail.CreditCardTypeValueId = creditCardTypeId; paymentDetail.AccountNumberMasked = cardLastFour; paymentDetail.ForeignKey = contributionId.ToString(); paymentDetail.ForeignId = contributionId; transaction.FinancialPaymentDetail = paymentDetail; } string checkNumber = row["Check_Number"] as string; // if the check number is valid, put it in the transaction code if (checkNumber.AsType <int?>() != null) { transaction.TransactionCode = checkNumber; } // check for SecureGive kiosk transactions else if (!string.IsNullOrEmpty(checkNumber) && checkNumber.StartsWith("SG")) { transaction.SourceTypeValueId = sourceTypeKiosk; } string fundName = row["Fund_Name"] as string; string subFund = row["Sub_Fund_Name"] as string; string fundGLAccount = row["Fund_GL_Account"] as string; string subFundGLAccount = row["Sub_Fund_GL_Account"] as string; Boolean?isFundActive = row["Fund_Is_active"] as Boolean?; decimal?statedValue = row["Stated_Value"] as decimal?; decimal?amount = row["Amount"] as decimal?; if (fundName != null & amount != null) { int transactionAccountId; var parentAccount = accountList.FirstOrDefault(a => a.Name.Equals(fundName) && a.CampusId == null); if (parentAccount == null) { parentAccount = AddAccount(lookupContext, fundName, fundGLAccount, null, null, isFundActive); accountList.Add(parentAccount); } if (subFund != null) { int?campusFundId = null; // assign a campus if the subfund is a campus fund var campusFund = CampusList.FirstOrDefault(c => subFund.StartsWith(c.Name) || subFund.StartsWith(c.ShortCode)); if (campusFund != null) { // use full campus name as the subfund subFund = campusFund.Name; campusFundId = campusFund.Id; } // add info to easily find/assign this fund in the view subFund = string.Format("{0} {1}", subFund, fundName); var childAccount = accountList.FirstOrDefault(c => c.Name.Equals(subFund) && c.ParentAccountId == parentAccount.Id); if (childAccount == null) { // create a child account with a campusId if it was set childAccount = AddAccount(lookupContext, subFund, subFundGLAccount, campusFundId, parentAccount.Id, isFundActive); accountList.Add(childAccount); } transactionAccountId = childAccount.Id; } else { transactionAccountId = parentAccount.Id; } if (amount == 0 && statedValue != null && statedValue != 0) { amount = statedValue; } var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = (decimal)amount; transactionDetail.CreatedDateTime = receivedDate; transactionDetail.AccountId = transactionAccountId; transaction.TransactionDetails.Add(transactionDetail); if (amount < 0) { transaction.RefundDetails = new FinancialTransactionRefund(); transaction.RefundDetails.CreatedDateTime = receivedDate; transaction.RefundDetails.RefundReasonValueId = refundReasons.Where(dv => summary != null && dv.Value.Contains(summary)) .Select(dv => (int?)dv.Id).FirstOrDefault(); transaction.RefundDetails.RefundReasonSummary = summary; } } newTransactions.Add(transaction); completed++; if (completed % percentage < 1) { int percentComplete = completed / percentage; ReportProgress(percentComplete, string.Format("{0:N0} contributions imported ({1}% complete).", completed, percentComplete)); } else if (completed % ReportingNumber < 1) { SaveContributions(newTransactions); newTransactions.Clear(); ReportPartialProgress(); } } } if (newTransactions.Any()) { SaveContributions(newTransactions); } ReportProgress(100, string.Format("Finished contribution import: {0:N0} contributions imported.", completed)); }
/// <summary> /// Handles the Click event of the btnNext 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 btnNext_Click(object sender, EventArgs e) { var rockContext = new RockContext(); var financialTransactionService = new FinancialTransactionService(rockContext); var financialTransactionDetailService = new FinancialTransactionDetailService(rockContext); var financialPersonBankAccountService = new FinancialPersonBankAccountService(rockContext); int txnId = hfTransactionId.Value.AsInteger(); var financialTransaction = financialTransactionService .Queryable("AuthorizedPersonAlias.Person,ProcessedByPersonAlias.Person") .FirstOrDefault(t => t.Id == txnId); // set the AuthorizedPersonId (the person who wrote the check, for example) to the if the SelectNew person (if selected) or person selected in the drop down (if there is somebody selected) int?authorizedPersonId = ppSelectNew.PersonId ?? ddlIndividual.SelectedValue.AsIntegerOrNull(); var accountNumberSecured = hfCheckMicrHashed.Value; if (cbTotalAmount.Text.AsDecimalOrNull().HasValue&& !authorizedPersonId.HasValue) { nbSaveError.Text = "Transaction must be matched to a person when the amount is specified."; nbSaveError.Visible = true; return; } // if the transaction was previously matched, but user unmatched it, save it as an unmatched transaction and clear out the detail records (we don't want an unmatched transaction to have detail records) if (financialTransaction != null && financialTransaction.AuthorizedPersonAliasId.HasValue && !authorizedPersonId.HasValue) { financialTransaction.AuthorizedPersonAliasId = null; foreach (var detail in financialTransaction.TransactionDetails) { financialTransactionDetailService.Delete(detail); } rockContext.SaveChanges(); // if the transaction was unmatched, clear out the ProcessedBy fields since we didn't match the transaction and are moving on to process another transaction MarkTransactionAsNotProcessedByCurrentUser(hfTransactionId.Value.AsInteger()); } // if the transaction is matched to somebody, attempt to save it. Otherwise, if the transaction was previously matched, but user unmatched it, save it as an unmatched transaction if (financialTransaction != null && authorizedPersonId.HasValue) { bool requiresMicr = financialTransaction.CurrencyTypeValue.Guid == Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK.AsGuid(); if (requiresMicr && string.IsNullOrWhiteSpace(accountNumberSecured)) { // should be showing already, but just in case nbNoMicrWarning.Visible = true; return; } if (cbTotalAmount.Text.AsDecimalOrNull() == null) { nbSaveError.Text = "Total amount must be allocated to accounts."; nbSaveError.Visible = true; return; } int?personAliasId = new PersonAliasService(rockContext).GetPrimaryAliasId(authorizedPersonId.Value); // if this transaction has an accountnumber associated with it (in other words, it's a scanned check), ensure there is a financialPersonBankAccount record if (!string.IsNullOrWhiteSpace(accountNumberSecured)) { var financialPersonBankAccount = financialPersonBankAccountService.Queryable().Where(a => a.AccountNumberSecured == accountNumberSecured && a.PersonAlias.PersonId == authorizedPersonId.Value).FirstOrDefault(); if (financialPersonBankAccount == null) { if (personAliasId.HasValue) { financialPersonBankAccount = new FinancialPersonBankAccount(); financialPersonBankAccount.PersonAliasId = personAliasId.Value; financialPersonBankAccount.AccountNumberSecured = accountNumberSecured; var checkMicrClearText = Encryption.DecryptString(financialTransaction.CheckMicrEncrypted); var parts = checkMicrClearText.Split('_'); if (parts.Length >= 2) { financialPersonBankAccount.AccountNumberMasked = parts[1].Masked(); } financialPersonBankAccountService.Add(financialPersonBankAccount); } } } if (personAliasId.HasValue) { financialTransaction.AuthorizedPersonAliasId = personAliasId; } // just in case this transaction is getting re-edited either by the same user, or somebody else, clean out any existing TransactionDetail records foreach (var detail in financialTransaction.TransactionDetails.ToList()) { financialTransactionDetailService.Delete(detail); } foreach (var accountBox in rptAccounts.ControlsOfTypeRecursive <CurrencyBox>()) { var amount = accountBox.Text.AsDecimalOrNull(); if (amount.HasValue && amount.Value >= 0) { var financialTransactionDetail = new FinancialTransactionDetail(); financialTransactionDetail.TransactionId = financialTransaction.Id; financialTransactionDetail.AccountId = accountBox.Attributes["data-account-id"].AsInteger(); financialTransactionDetail.Amount = amount.Value; financialTransactionDetailService.Add(financialTransactionDetail); } } financialTransaction.ProcessedByPersonAliasId = this.CurrentPersonAlias.Id; financialTransaction.ProcessedDateTime = RockDateTime.Now; rockContext.SaveChanges(); } else { // if the transaction was not matched, clear out the ProcessedBy fields since we didn't match the transaction and are moving on to process another transaction MarkTransactionAsNotProcessedByCurrentUser(hfTransactionId.Value.AsInteger()); } NavigateToTransaction(Direction.Next); }
// // Swipe Panel Events // private void ProcessSwipe( string swipeData ) { try { using ( var rockContext = new RockContext() ) { // create swipe object SwipePaymentInfo swipeInfo = new SwipePaymentInfo( swipeData ); swipeInfo.Amount = this.Amounts.Sum( a => a.Value ); // if not anonymous then add contact info to the gateway transaction if ( this.AnonymousGiverPersonAliasId != this.SelectedGivingUnit.PersonAliasId ) { var giver = new PersonAliasService( rockContext ).Queryable( "Person, Person.PhoneNumbers" ).Where( p => p.Id == this.SelectedGivingUnit.PersonAliasId ).FirstOrDefault(); swipeInfo.FirstName = giver.Person.NickName; swipeInfo.LastName = giver.Person.LastName; if ( giver.Person.PhoneNumbers != null ) { Guid homePhoneValueGuid = new Guid( Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_HOME ); var homephone = giver.Person.PhoneNumbers.Where( p => p.NumberTypeValue.Guid == homePhoneValueGuid ).FirstOrDefault(); if ( homephone != null ) { swipeInfo.Phone = homephone.NumberFormatted; } } var homeLocation = giver.Person.GetHomeLocation(); if ( homeLocation != null ) { swipeInfo.Street1 = homeLocation.Street1; if ( !string.IsNullOrWhiteSpace( homeLocation.Street2 ) ) { swipeInfo.Street2 = homeLocation.Street2; } swipeInfo.City = homeLocation.City; swipeInfo.State = homeLocation.State; swipeInfo.PostalCode = homeLocation.PostalCode; } } // add comment to the transation swipeInfo.Comment1 = GetAttributeValue( "PaymentComment" ); // get gateway FinancialGateway financialGateway = null; GatewayComponent gateway = null; Guid? gatewayGuid = GetAttributeValue( "CreditCardGateway" ).AsGuidOrNull(); if ( gatewayGuid.HasValue ) { financialGateway = new FinancialGatewayService( rockContext ).Get( gatewayGuid.Value ); if ( financialGateway != null ) { financialGateway.LoadAttributes( rockContext ); } gateway = financialGateway.GetGatewayComponent(); } if ( gateway != null ) { string errorMessage = string.Empty; var transaction = gateway.Charge( financialGateway, swipeInfo, out errorMessage ); if ( transaction != null ) { var txnChanges = new List<string>(); txnChanges.Add( "Created Transaction (from kiosk)" ); _transactionCode = transaction.TransactionCode; History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode ); var personName = new PersonAliasService( rockContext ) .Queryable().AsNoTracking() .Where( a => a.Id == this.SelectedGivingUnit.PersonAliasId ) .Select( a => a.Person.NickName + " " + a.Person.LastName ) .FirstOrDefault(); transaction.AuthorizedPersonAliasId = this.SelectedGivingUnit.PersonAliasId; History.EvaluateChange( txnChanges, "Person", string.Empty, personName ); 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 ); transaction.Summary = swipeInfo.Comment1; History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.Summary ); if ( transaction.FinancialPaymentDetail == null ) { transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); } transaction.FinancialPaymentDetail.SetFromPaymentInfo( swipeInfo, 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 accountAmount in this.Amounts.Where( a => a.Value > 0 ) ) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = accountAmount.Value; transactionDetail.AccountId = accountAmount.Key; transaction.TransactionDetails.Add( transactionDetail ); var account = new FinancialAccountService( rockContext ).Get( accountAmount.Key ); if ( account != null ) { 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" ), swipeInfo.CurrencyTypeValue, swipeInfo.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.WrapTransaction( () => { 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, personName, typeof( FinancialTransaction ), transaction.Id ); } ); // send receipt in one is configured and not giving anonymously if ( !string.IsNullOrWhiteSpace( GetAttributeValue( "ReceiptEmail" ) ) && ( this.AnonymousGiverPersonAliasId != this.SelectedGivingUnit.PersonAliasId ) ) { _receiptSent = true; SendReceipt(); } HidePanels(); ShowReceiptPanel(); } else { lSwipeErrors.Text = String.Format( "<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", errorMessage ); } } else { lSwipeErrors.Text = "<div class='alert alert-danger'>Invalid gateway provided. Please provide a gateway. Transaction not processed.</div>"; } } } catch ( Exception ex ) { lSwipeErrors.Text = String.Format( "<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", ex.Message ); } }
/// <summary> /// Maps the contribution. /// </summary> /// <param name="tableData">The table data.</param> /// <param name="selectedColumns">The selected columns.</param> private void MapContribution( IQueryable<Row> tableData, List<string> selectedColumns = null ) { var lookupContext = new RockContext(); int transactionEntityTypeId = EntityTypeCache.Read( "Rock.Model.FinancialTransaction" ).Id; var transactionTypeContributionId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ), lookupContext ).Id; var transactionTypeEventRegistrationId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_EVENT_REGISTRATION ), lookupContext ).Id; int currencyTypeACH = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ), lookupContext ).Id; int currencyTypeCash = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH ), lookupContext ).Id; int currencyTypeCheck = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK ), lookupContext ).Id; int currencyTypeCreditCard = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ), lookupContext ).Id; var refundReasons = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON ), lookupContext ).DefinedValues; List<FinancialPledge> pledgeList = new FinancialPledgeService( lookupContext ).Queryable().ToList(); List<FinancialAccount> accountList = new FinancialAccountService( lookupContext ).Queryable().ToList(); // Get all imported contributions var importedContributions = new FinancialTransactionService( lookupContext ).Queryable() .Select( t => new { ContributionId = t.ForeignId, TransactionId = t.Id } ) .ToDictionary( t => t.ContributionId.AsType<int?>(), t => (int?)t.TransactionId ); var householdAVList = new AttributeValueService( lookupContext ).Queryable().Where( av => av.AttributeId == HouseholdAttributeId ).ToList(); // List for batching new contributions var newTransactions = new List<FinancialTransaction>(); int completed = 0; int totalRows = tableData.Count(); int percentage = ( totalRows - 1 ) / 100 + 1; ReportProgress( 0, string.Format( "Verifying contribution import ({0:N0} found, {1:N0} already exist).", totalRows, importedContributions.Count() ) ); foreach ( var row in tableData ) { int? individualId = row["Individual_ID"] as int?; int? householdId = row["Household_ID"] as int?; int? contributionId = row["ContributionID"] as int?; if ( contributionId != null && !importedContributions.ContainsKey( contributionId ) ) { var transaction = new FinancialTransaction(); string fundName = row["Fund_Name"] as string; //Crossroads - Anything under a fund name that starts with Receipt - is an Event Registration. if ( fundName.StartsWith( "Receipt -" ) ) { transaction.TransactionTypeValueId = transactionTypeEventRegistrationId; } else { transaction.TransactionTypeValueId = transactionTypeContributionId; } int? associatedPersonId; if ( individualId != null ) { associatedPersonId = GetPersonAliasId( individualId, householdId ); } //will get the exact person if Individual Id is not null. else { associatedPersonId = GetPersonId( householdAVList, householdId ); } //Will attempt to get the Head first, then Spouse, then Child. Will exclude Other and Visitor if ( associatedPersonId != null ) { transaction.AuthorizedPersonAliasId = associatedPersonId; transaction.CreatedByPersonAliasId = ImportPersonAlias.Id; transaction.ProcessedByPersonAliasId = associatedPersonId; transaction.ForeignId = contributionId.ToString(); string summary = row["Memo"] as string; if ( summary != null ) { transaction.Summary = summary; } int? batchId = row["BatchID"] as int?; if ( batchId != null && ImportedBatches.Any( b => b.Key == batchId ) ) { transaction.BatchId = ImportedBatches.FirstOrDefault( b => b.Key == batchId ).Value; } DateTime? receivedDate = row["Received_Date"] as DateTime?; if ( receivedDate != null ) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; } bool isTypeNonCash = false; string contributionType = row["Contribution_Type_Name"].ToString().ToLower(); if ( contributionType != null ) { if ( contributionType == "ach" ) { transaction.CurrencyTypeValueId = currencyTypeACH; } else if ( contributionType == "cash" ) { transaction.CurrencyTypeValueId = currencyTypeCash; } else if ( contributionType == "check" ) { transaction.CurrencyTypeValueId = currencyTypeCheck; } else if ( contributionType == "credit card" ) { transaction.CurrencyTypeValueId = currencyTypeCreditCard; } else { isTypeNonCash = true; } } string checkNumber = row["Check_Number"] as string; if ( checkNumber != null && checkNumber.AsType<int?>() != null ) { // routing & account set to zero transaction.CheckMicrEncrypted = Encryption.EncryptString( string.Format( "{0}_{1}_{2}", 0, 0, checkNumber ) ); } decimal? amount = row["Amount"] as decimal?; if ( fundName != null & amount != null ) { FinancialAccount matchingAccount = null; int? parentAccountId = null; string parentAccountName = String.Empty; int? fundCampusId = null; fundName = fundName.Trim(); string subFund = row["Sub_Fund_Name"] as string; if ( subFund != null ) { subFund = subFund.Trim(); // Check if subfund was used to mark a multi-site campus fundCampusId = CampusList.Where( c => subFund.StartsWith( c.Name ) || subFund.StartsWith( c.ShortCode ) ) .Select( c => (int?)c.Id ).FirstOrDefault(); // Matched a campus, check to see if an account exists for that campus already if ( fundCampusId != null ) { matchingAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName ) && a.CampusId != null && a.CampusId.Equals( fundCampusId ) ); } else { // No campus match, look for an account that matches parent name and subfund name matchingAccount = accountList.FirstOrDefault( a => a.ParentAccountId != null && a.ParentAccount.Name.Equals( fundName ) && a.Name.Equals( subFund ) ); if ( matchingAccount == null ) { // Check if a parent account exists already FinancialAccount parentAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName ) ); if ( parentAccount == null ) { parentAccount = AddAccount( lookupContext, fundName, fundCampusId ); accountList.Add( parentAccount ); } // set data for subfund to be created parentAccountId = parentAccount.Id; fundName = subFund; parentAccountName = parentAccount.Name; } } } else { matchingAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName ) && a.CampusId == null ); } if ( matchingAccount == null ) { // No account matches, create the new account with campus Id and parent Id if they were set matchingAccount = AddAccount( lookupContext, fundName, fundCampusId, parentAccountName, parentAccountId ); accountList.Add( matchingAccount ); } var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = (decimal)amount; transactionDetail.CreatedDateTime = receivedDate; transactionDetail.AccountId = matchingAccount.Id; transactionDetail.IsNonCash = isTypeNonCash; transaction.TransactionDetails.Add( transactionDetail ); if ( amount < 0 ) { var transactionRefund = new FinancialTransactionRefund(); transactionRefund.CreatedDateTime = receivedDate; transactionRefund.RefundReasonSummary = summary; transactionRefund.RefundReasonValueId = refundReasons.Where( dv => summary != null && dv.Value.Contains( summary ) ) .Select( dv => (int?)dv.Id ).FirstOrDefault(); transaction.Refund = transactionRefund; } } newTransactions.Add( transaction ); completed++; if ( completed % percentage < 1 ) { int percentComplete = completed / percentage; ReportProgress( percentComplete, string.Format( "{0:N0} contributions imported ({1}% complete).", completed, percentComplete ) ); } else if ( completed % ReportingNumber < 1 ) { SaveContributions( newTransactions ); newTransactions.Clear(); ReportPartialProgress(); } } } } if ( newTransactions.Any() ) { SaveContributions( newTransactions ); } ReportProgress( 100, string.Format( "Finished contribution import: {0:N0} contributions imported.", completed ) ); }
/// <summary> /// Handles the Click event of the btnNext 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 btnNext_Click( object sender, EventArgs e ) { var changes = new List<string>(); var rockContext = new RockContext(); var financialTransactionService = new FinancialTransactionService( rockContext ); var financialTransactionDetailService = new FinancialTransactionDetailService( rockContext ); var financialPersonBankAccountService = new FinancialPersonBankAccountService( rockContext ); int txnId = hfTransactionId.Value.AsInteger(); var financialTransaction = financialTransactionService .Queryable( "AuthorizedPersonAlias.Person,ProcessedByPersonAlias.Person" ) .FirstOrDefault( t => t.Id == txnId ); // set the AuthorizedPersonId (the person who wrote the check, for example) to the if the SelectNew person (if selected) or person selected in the drop down (if there is somebody selected) int? authorizedPersonId = ppSelectNew.PersonId ?? ddlIndividual.SelectedValue.AsIntegerOrNull(); var accountNumberSecured = hfCheckMicrHashed.Value; if ( cbTotalAmount.Text.AsDecimalOrNull().HasValue && !authorizedPersonId.HasValue ) { nbSaveError.Text = "Transaction must be matched to a person when the amount is specified."; nbSaveError.Visible = true; return; } // if the transaction was previously matched, but user unmatched it, save it as an unmatched transaction and clear out the detail records (we don't want an unmatched transaction to have detail records) if ( financialTransaction != null && financialTransaction.AuthorizedPersonAliasId.HasValue && !authorizedPersonId.HasValue ) { financialTransaction.AuthorizedPersonAliasId = null; foreach ( var detail in financialTransaction.TransactionDetails ) { History.EvaluateChange( changes, detail.Account != null ? detail.Account.Name : "Unknown", detail.Amount.ToString( "C2" ), string.Empty ); financialTransactionDetailService.Delete( detail ); } changes.Add( "Unmatched transaction" ); HistoryService.SaveChanges( rockContext, typeof( FinancialBatch ), Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(), financialTransaction.BatchId.Value, changes, string.Format( "Transaction Id: {0}", financialTransaction.Id ), typeof( FinancialTransaction ), financialTransaction.Id, false ); rockContext.SaveChanges(); // if the transaction was unmatched, clear out the ProcessedBy fields since we didn't match the transaction and are moving on to process another transaction MarkTransactionAsNotProcessedByCurrentUser( hfTransactionId.Value.AsInteger() ); } // if the transaction is matched to somebody, attempt to save it. Otherwise, if the transaction was previously matched, but user unmatched it, save it as an unmatched transaction if ( financialTransaction != null && authorizedPersonId.HasValue ) { bool requiresMicr = financialTransaction.FinancialPaymentDetail != null && financialTransaction.FinancialPaymentDetail.CurrencyTypeValue != null && financialTransaction.FinancialPaymentDetail.CurrencyTypeValue.Guid == Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK.AsGuid(); if ( cbTotalAmount.Text.AsDecimalOrNull() == null ) { nbSaveError.Text = "Total amount must be allocated to accounts."; nbSaveError.Visible = true; return; } var personAlias = new PersonAliasService( rockContext ).GetPrimaryAlias( authorizedPersonId.Value ); int? personAliasId = personAlias != null ? personAlias.Id : (int?)null; // if this transaction has an accountnumber associated with it (in other words, it's a valid scanned check), ensure there is a financialPersonBankAccount record if ( financialTransaction.MICRStatus == MICRStatus.Success && !string.IsNullOrWhiteSpace( accountNumberSecured ) ) { var financialPersonBankAccount = financialPersonBankAccountService.Queryable().Where( a => a.AccountNumberSecured == accountNumberSecured && a.PersonAlias.PersonId == authorizedPersonId.Value ).FirstOrDefault(); if ( financialPersonBankAccount == null ) { if ( personAliasId.HasValue ) { financialPersonBankAccount = new FinancialPersonBankAccount(); financialPersonBankAccount.PersonAliasId = personAliasId.Value; financialPersonBankAccount.AccountNumberSecured = accountNumberSecured; var checkMicrClearText = Encryption.DecryptString( financialTransaction.CheckMicrParts ); var parts = checkMicrClearText.Split( '_' ); if ( parts.Length >= 2 ) { financialPersonBankAccount.AccountNumberMasked = parts[1].Masked(); } financialPersonBankAccountService.Add( financialPersonBankAccount ); } } } string prevPerson = ( financialTransaction.AuthorizedPersonAlias != null && financialTransaction.AuthorizedPersonAlias.Person != null ) ? financialTransaction.AuthorizedPersonAlias.Person.FullName : string.Empty; string newPerson = string.Empty; if ( personAliasId.HasValue ) { newPerson = personAlias.Person.FullName; financialTransaction.AuthorizedPersonAliasId = personAliasId; } History.EvaluateChange( changes, "Person", prevPerson, newPerson ); // just in case this transaction is getting re-edited either by the same user, or somebody else, clean out any existing TransactionDetail records foreach ( var detail in financialTransaction.TransactionDetails.ToList() ) { financialTransactionDetailService.Delete( detail ); History.EvaluateChange( changes, detail.Account != null ? detail.Account.Name : "Unknown", detail.Amount.ToString( "C2" ), string.Empty ); } foreach ( var accountBox in rptAccounts.ControlsOfTypeRecursive<CurrencyBox>() ) { var amount = accountBox.Text.AsDecimalOrNull(); if ( amount.HasValue && amount.Value >= 0 ) { var financialTransactionDetail = new FinancialTransactionDetail(); financialTransactionDetail.TransactionId = financialTransaction.Id; financialTransactionDetail.AccountId = accountBox.Attributes["data-account-id"].AsInteger(); financialTransactionDetail.Amount = amount.Value; financialTransactionDetailService.Add( financialTransactionDetail ); History.EvaluateChange( changes, accountBox.Label, 0.0M.ToString( "C2" ), amount.Value.ToString( "C2" ) ); } } financialTransaction.ProcessedByPersonAliasId = this.CurrentPersonAlias.Id; financialTransaction.ProcessedDateTime = RockDateTime.Now; changes.Add( "Matched transaction" ); HistoryService.SaveChanges( rockContext, typeof( FinancialBatch ), Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(), financialTransaction.BatchId.Value, changes, personAlias != null && personAlias.Person != null ? personAlias.Person.FullName : string.Format( "Transaction Id: {0}", financialTransaction.Id ), typeof( FinancialTransaction ), financialTransaction.Id, false ); rockContext.SaveChanges(); } else { // if the transaction was not matched, clear out the ProcessedBy fields since we didn't match the transaction and are moving on to process another transaction MarkTransactionAsNotProcessedByCurrentUser( hfTransactionId.Value.AsInteger() ); } NavigateToTransaction( Direction.Next ); }
/// <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> /// 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> /// Maps the contribution. /// </summary> /// <param name="csvData">The table data.</param> private int MapContribution( CSVInstance csvData ) { var lookupContext = new RockContext(); int transactionEntityTypeId = EntityTypeCache.Read( "Rock.Model.FinancialTransaction" ).Id; var transactionTypeContributionId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ), lookupContext ).Id; var currencyTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE ) ); int currencyTypeACH = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ) ) ).Id; int currencyTypeCash = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH ) ) ).Id; int currencyTypeCheck = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK ) ) ).Id; int currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ) ) ).Id; int? currencyTypeNonCash = currencyTypes.DefinedValues.Where( dv => dv.Value.Equals( "Non-Cash" ) ).Select( dv => ( int? )dv.Id ).FirstOrDefault(); if ( currencyTypeNonCash == null ) { var newTenderNonCash = new DefinedValue(); newTenderNonCash.Value = "Non-Cash"; newTenderNonCash.Description = "Non-Cash"; newTenderNonCash.DefinedTypeId = currencyTypes.Id; lookupContext.DefinedValues.Add( newTenderNonCash ); lookupContext.SaveChanges(); currencyTypeNonCash = newTenderNonCash.Id; } var creditCardTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE ) ).DefinedValues; int sourceTypeOnsite = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_ONSITE_COLLECTION ), lookupContext ).Id; int sourceTypeWebsite = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE ), lookupContext ).Id; int sourceTypeKiosk = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_KIOSK ), lookupContext ).Id; var refundReasons = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON ), lookupContext ).DefinedValues; var accountList = new FinancialAccountService( lookupContext ).Queryable().AsNoTracking().ToList(); int? defaultBatchId = null; if ( ImportedBatches.ContainsKey( 0 ) ) { defaultBatchId = ImportedBatches[0]; } // Get all imported contributions var importedContributions = new FinancialTransactionService( lookupContext ).Queryable().AsNoTracking() .Where( c => c.ForeignId != null ) .ToDictionary( t => ( int )t.ForeignId, t => ( int? )t.Id ); // List for batching new contributions var newTransactions = new List<FinancialTransaction>(); int completed = 0; ReportProgress( 0, string.Format( "Verifying contribution import ({0:N0} already exist).", importedContributions.Count ) ); string[] row; // Uses a look-ahead enumerator: this call will move to the next record immediately while ( (row = csvData.Database.FirstOrDefault()) != null ) { string individualIdKey = row[IndividualID]; int? individualId = individualIdKey.AsType<int?>(); string contributionIdKey = row[ContributionID]; int? contributionId = contributionIdKey.AsType<int?>(); if ( contributionId != null && !importedContributions.ContainsKey( ( int )contributionId ) ) { var transaction = new FinancialTransaction(); transaction.CreatedByPersonAliasId = ImportPersonAliasId; transaction.ModifiedByPersonAliasId = ImportPersonAliasId; transaction.TransactionTypeValueId = transactionTypeContributionId; transaction.ForeignKey = contributionId.ToString(); transaction.ForeignId = contributionId; int? giverAliasId = null; var personKeys = GetPersonKeys( individualId ); if ( personKeys != null && personKeys.PersonAliasId > 0 ) { giverAliasId = personKeys.PersonAliasId; transaction.CreatedByPersonAliasId = giverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } else if ( AnonymousGiverAliasId != null && AnonymousGiverAliasId > 0 ) { giverAliasId = AnonymousGiverAliasId; transaction.AuthorizedPersonAliasId = giverAliasId; transaction.ProcessedByPersonAliasId = giverAliasId; } string summary = row[Memo] as string; if ( !String.IsNullOrWhiteSpace( summary ) ) { transaction.Summary = summary; } string batchIdKey = row[ContributionBatchID]; int? batchId = batchIdKey.AsType<int?>(); if ( batchId != null && ImportedBatches.Any( b => b.Key.Equals( batchId ) ) ) { transaction.BatchId = ImportedBatches.FirstOrDefault( b => b.Key.Equals( batchId ) ).Value; } else { // use the default batch for any non-matching transactions transaction.BatchId = defaultBatchId; } string receivedDateKey = row[ReceivedDate]; DateTime? receivedDate = receivedDateKey.AsType<DateTime?>(); if ( receivedDate != null ) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; transaction.ModifiedDateTime = ImportDateTime; } string contributionType = row[ContributionTypeName].ToStringSafe().ToLower(); if ( !String.IsNullOrWhiteSpace( contributionType ) ) { // set default source to onsite, exceptions listed below transaction.SourceTypeValueId = sourceTypeOnsite; int? paymentCurrencyTypeId = null, creditCardTypeId = null; if ( contributionType == "cash" ) { paymentCurrencyTypeId = currencyTypeCash; } else if ( contributionType == "check" ) { paymentCurrencyTypeId = currencyTypeCheck; } else if ( contributionType == "ach" ) { paymentCurrencyTypeId = currencyTypeACH; transaction.SourceTypeValueId = sourceTypeWebsite; } else if ( contributionType == "credit card" ) { paymentCurrencyTypeId = currencyTypeCreditCard; transaction.SourceTypeValueId = sourceTypeWebsite; } else { paymentCurrencyTypeId = currencyTypeNonCash; } var paymentDetail = new FinancialPaymentDetail(); paymentDetail.CreatedDateTime = receivedDate; paymentDetail.CreatedByPersonAliasId = giverAliasId; paymentDetail.ModifiedDateTime = ImportDateTime; paymentDetail.ModifiedByPersonAliasId = giverAliasId; paymentDetail.CurrencyTypeValueId = paymentCurrencyTypeId; paymentDetail.CreditCardTypeValueId = creditCardTypeId; paymentDetail.ForeignKey = contributionId.ToString(); paymentDetail.ForeignId = contributionId; transaction.FinancialPaymentDetail = paymentDetail; } string checkNumber = row[CheckNumber] as string; // if the check number is valid, put it in the transaction code if ( checkNumber.AsType<int?>() != null ) { transaction.TransactionCode = checkNumber; } // check for SecureGive kiosk transactions else if ( !string.IsNullOrEmpty( checkNumber ) && checkNumber.StartsWith( "SG" ) ) { transaction.SourceTypeValueId = sourceTypeKiosk; } string fundName = row[FundName] as string; string subFund = row[SubFundName] as string; string fundGLAccount = row[FundGLAccount] as string; string subFundGLAccount = row[SubFundGLAccount] as string; string isFundActiveKey = row[FundIsActive]; Boolean? isFundActive = isFundActiveKey.AsType<Boolean?>(); string isSubFundActiveKey = row[SubFundIsActive]; Boolean? isSubFundActive = isSubFundActiveKey.AsType<Boolean?>(); string statedValueKey = row[StatedValue]; decimal? statedValue = statedValueKey.AsType<decimal?>(); string amountKey = row[Amount]; decimal? amount = amountKey.AsType<decimal?>(); if ( !String.IsNullOrWhiteSpace( fundName ) & amount != null ) { int transactionAccountId; var parentAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName.Truncate( 50 ) ) && a.CampusId == null ); if ( parentAccount == null ) { parentAccount = AddAccount( lookupContext, fundName, fundGLAccount, null, null, isFundActive ); accountList.Add( parentAccount ); } if ( !String.IsNullOrWhiteSpace( subFund ) ) { int? campusFundId = null; // assign a campus if the subfund is a campus fund var campusFund = CampusList.FirstOrDefault( c => subFund.StartsWith( c.Name ) || subFund.StartsWith( c.ShortCode ) ); if ( campusFund != null ) { // use full campus name as the subfund subFund = campusFund.Name; campusFundId = campusFund.Id; } // add info to easily find/assign this fund in the view subFund = string.Format( "{0} {1}", subFund, fundName ); var childAccount = accountList.FirstOrDefault( c => c.Name.Equals( subFund.Truncate( 50 ) ) && c.ParentAccountId == parentAccount.Id ); if ( childAccount == null ) { // create a child account with a campusId if it was set childAccount = AddAccount( lookupContext, subFund, subFundGLAccount, campusFundId, parentAccount.Id, isSubFundActive ); accountList.Add( childAccount ); } transactionAccountId = childAccount.Id; } else { transactionAccountId = parentAccount.Id; } if ( amount == 0 && statedValue != null && statedValue != 0 ) { amount = statedValue; } var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = ( decimal )amount; transactionDetail.CreatedDateTime = receivedDate; transactionDetail.AccountId = transactionAccountId; transaction.TransactionDetails.Add( transactionDetail ); if ( amount < 0 ) { transaction.RefundDetails = new FinancialTransactionRefund(); transaction.RefundDetails.CreatedDateTime = receivedDate; transaction.RefundDetails.RefundReasonValueId = refundReasons.Where( dv => summary != null && dv.Value.Contains( summary ) ) .Select( dv => ( int? )dv.Id ).FirstOrDefault(); transaction.RefundDetails.RefundReasonSummary = summary; } } newTransactions.Add( transaction ); completed++; if ( completed % (ReportingNumber * 10) < 1 ) { ReportProgress( 0, string.Format( "{0:N0} contributions imported.", completed ) ); } else if ( completed % ReportingNumber < 1 ) { SaveContributions( newTransactions ); newTransactions.Clear(); ReportPartialProgress(); } } } if ( newTransactions.Any() ) { SaveContributions( newTransactions ); } ReportProgress( 100, string.Format( "Finished contribution import: {0:N0} contributions imported.", completed ) ); return completed; }
/// <summary> /// Processes the payment. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="registration">The registration.</param> /// <param name="errorMessage">The error message.</param> /// <returns></returns> private bool ProcessPayment( RockContext rockContext, Registration registration, out string errorMessage ) { GatewayComponent gateway = null; if ( RegistrationTemplate != null && RegistrationTemplate.FinancialGateway != null ) { gateway = RegistrationTemplate.FinancialGateway.GetGatewayComponent(); } if ( gateway == null ) { errorMessage = "There was a problem creating the payment gateway information"; return false; } if ( !RegistrationInstanceState.AccountId.HasValue || RegistrationInstanceState.Account == null ) { errorMessage = "There was a problem with the account configuration for this " + RegistrationTerm.ToLower(); return false; } var paymentInfo = new CreditCardPaymentInfo( txtCreditCard.Text, txtCVV.Text, mypExpiration.SelectedDate.Value ); paymentInfo.NameOnCard = gateway != null && gateway.SplitNameOnCard ? txtCardFirstName.Text : txtCardName.Text; paymentInfo.LastNameOnCard = txtCardLastName.Text; paymentInfo.BillingStreet1 = acBillingAddress.Street1; paymentInfo.BillingStreet2 = acBillingAddress.Street2; paymentInfo.BillingCity = acBillingAddress.City; paymentInfo.BillingState = acBillingAddress.State; paymentInfo.BillingPostalCode = acBillingAddress.PostalCode; paymentInfo.BillingCountry = acBillingAddress.Country; paymentInfo.Amount = RegistrationState.PaymentAmount ?? 0.0m; paymentInfo.Email = RegistrationState.ConfirmationEmail; paymentInfo.FirstName = RegistrationState.FirstName; paymentInfo.LastName = RegistrationState.LastName; var transaction = gateway.Charge( RegistrationTemplate.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 = registration.PersonAliasId; transaction.TransactionDateTime = RockDateTime.Now; History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime ); transaction.FinancialGatewayId = RegistrationTemplate.FinancialGatewayId; History.EvaluateChange( txnChanges, "Gateway", string.Empty, RegistrationTemplate.FinancialGateway.Name ); var txnType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_EVENT_REGISTRATION ) ); transaction.TransactionTypeValueId = txnType.Id; History.EvaluateChange( txnChanges, "Type", string.Empty, txnType.Value ); if ( transaction.FinancialPaymentDetail == null ) { transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); } transaction.FinancialPaymentDetail.NameOnCardEncrypted = Rock.Security.Encryption.EncryptString( paymentInfo.NameOnCard ); transaction.FinancialPaymentDetail.AccountNumberMasked = paymentInfo.MaskedNumber; transaction.FinancialPaymentDetail.ExpirationMonthEncrypted = Rock.Security.Encryption.EncryptString( paymentInfo.ExpirationDate.Month.ToString() ); transaction.FinancialPaymentDetail.ExpirationYearEncrypted = Rock.Security.Encryption.EncryptString( paymentInfo.ExpirationDate.Year.ToString() ); transaction.FinancialPaymentDetail.CurrencyTypeValueId = paymentInfo.CurrencyTypeValue.Id; History.EvaluateChange( txnChanges, "Currency Type", string.Empty, paymentInfo.CurrencyTypeValue.Value ); transaction.FinancialPaymentDetail.CreditCardTypeValueId = paymentInfo.CreditCardTypeValue != null ? paymentInfo.CreditCardTypeValue.Id : (int?)null; if ( transaction.FinancialPaymentDetail.CreditCardTypeValueId.HasValue ) { var ccType = DefinedValueCache.Read( transaction.FinancialPaymentDetail.CreditCardTypeValueId.Value ); History.EvaluateChange( txnChanges, "Credit Card Type", string.Empty, ccType.Value ); } 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 ); } } transaction.Summary = registration.GetSummary( RegistrationInstanceState ); var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = RegistrationState.PaymentAmount ?? 0.0m; transactionDetail.AccountId = RegistrationInstanceState.AccountId.Value; transactionDetail.EntityTypeId = EntityTypeCache.Read( typeof( Rock.Model.Registration ) ).Id; transactionDetail.EntityId = registration.Id; transaction.TransactionDetails.Add( transactionDetail ); History.EvaluateChange( txnChanges, RegistrationInstanceState.Account.Name, 0.0M.ToString( "C2" ), transactionDetail.Amount.ToString( "C2" ) ); var batchService = new FinancialBatchService( rockContext ); // Get the batch var batch = batchService.Get( GetAttributeValue( "BatchNamePrefix" ), paymentInfo.CurrencyTypeValue, paymentInfo.CreditCardTypeValue, transaction.TransactionDateTime.Value, RegistrationTemplate.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.ToString( "C2" ), newControlAmount.ToString( "C2" ) ); 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, CurrentPerson != null ? CurrentPerson.FullName : string.Empty, typeof( FinancialTransaction ), transaction.Id ); TransactionCode = transaction.TransactionCode; return true; } else { return false; } }
/// <summary>Process all transactions (payments) from Service Reef.</summary> /// <param name="message">The message that is returned depending on the result.</param> /// <param name="state">The state of the process.</param> /// <returns><see cref="WorkerResultStatus"/></returns> public void Execute(IJobExecutionContext context) { RockContext dbContext = new RockContext(); FinancialBatchService financialBatchService = new FinancialBatchService(dbContext); PersonService personService = new PersonService(dbContext); PersonAliasService personAliasService = new PersonAliasService(dbContext); FinancialAccountService financialAccountService = new FinancialAccountService(dbContext); FinancialAccountService accountService = new FinancialAccountService(dbContext); FinancialTransactionService financialTransactionService = new FinancialTransactionService(dbContext); FinancialGatewayService financialGatewayService = new FinancialGatewayService(dbContext); DefinedValueService definedValueService = new DefinedValueService(dbContext); DefinedTypeService definedTypeService = new DefinedTypeService(dbContext); TransactionService transactionService = new TransactionService(new PayPalReporting.Data.PayPalReportingContext()); // Get the datamap for loading attributes JobDataMap dataMap = context.JobDetail.JobDataMap; String warnings = string.Empty; FinancialBatch batch = null; Double totalAmount = 0; var total = 1; var processed = 0; try { DateRange dateRange = Rock.Web.UI.Controls.SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues(dataMap.GetString("DateRange") ?? "-1||"); String SRApiKey = Encryption.DecryptString(dataMap.GetString("ServiceReefAPIKey")); String SRApiSecret = Encryption.DecryptString(dataMap.GetString("ServiceReefAPISecret")); String SRApiUrl = dataMap.GetString("ServiceReefAPIURL"); DefinedValueCache transactionSource = DefinedValueCache.Read(dataMap.GetString("TransactionSource").AsGuid(), dbContext); DefinedValueCache connectionStatus = DefinedValueCache.Read(dataMap.GetString("ConnectionStatus").AsGuid(), dbContext); DefinedValueCache contribution = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION); // Setup some lookups DefinedTypeCache creditCards = DefinedTypeCache.Read(Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE.AsGuid(), dbContext); DefinedTypeCache tenderType = DefinedTypeCache.Get(Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE.AsGuid(), dbContext); FinancialAccount specialFund = accountService.Get(dataMap.GetString("Account").AsGuid()); FinancialGateway gateway = financialGatewayService.Get(dataMap.GetString("FinancialGateway").AsGuid()); List <FinancialAccount> trips = financialAccountService.Queryable().Where(fa => fa.ParentAccountId == specialFund.Id).OrderBy(fa => fa.Order).ToList(); // Get the trips DefinedValueCache serviceReefAccountType = DefinedValueCache.Get(dataMap.Get("ServiceReefAccountType").ToString().AsGuid()); // Setup the ServiceReef API Client var client = new RestClient(SRApiUrl); client.Authenticator = new HMACAuthenticator(SRApiKey, SRApiSecret); // Get all payments from ServiceReef var request = new RestRequest("v1/payments", Method.GET); request.AddParameter("pageSize", 100); if (dateRange.Start.HasValue) { request.AddParameter("startDate", dateRange.Start.Value.ToString("o")); } if (dateRange.End.HasValue) { request.AddParameter("endDate", dateRange.End.Value.ToString("o")); } request.AddParameter("page", 1); while (total > processed) { var response = client.Execute <Contracts.Payments>(request); if (response.StatusCode != System.Net.HttpStatusCode.OK) { throw new Exception("ServiceReef API Response: " + response.StatusDescription + " Content Length: " + response.ContentLength); } if (response.Data != null && response.Data.PageInfo != null) { total = response.Data.PageInfo.TotalRecords; foreach (Contracts.Payments.Result result in response.Data.Results) { // Process the transaction if (result.PaymentProcessorTransactionId != null) { if (result.FirstName == null || result.LastName == null) { warnings += "Missing Firstname/Lastname for ServiceReef transaction Id: " + result.TransactionId + Environment.NewLine; processed++; continue; } FinancialAccount trip = null; // Make sure we have a sub-account to go with this transaction if (result.EventId > 0) { trip = trips.Where(t => t.GlCode == result.EventCode && t.Url == result.EventUrl).FirstOrDefault(); } if (trip == null) { if (result.EventCode == null) { warnings += "Event Code is missing on the Service Reef Trip for ServiceReef transaction Id: " + result.TransactionId + Environment.NewLine; processed++; continue; } // Create the trip subaccount FinancialAccount tripFA = new FinancialAccount(); tripFA.Name = result.EventName; // Name is limited to 50 if (tripFA.Name.Length > 50) { tripFA.Name = tripFA.Name.Substring(0, 50); } tripFA.Description = "Service Reef Event. Name: " + result.EventName + " ID: " + result.EventId; tripFA.GlCode = result.EventCode; tripFA.Url = result.EventUrl; tripFA.PublicName = result.EventName; // Public Name is limited to 50 if (tripFA.PublicName.Length > 50) { tripFA.PublicName = tripFA.PublicName.Substring(0, 50); } tripFA.IsTaxDeductible = true; tripFA.IsPublic = false; tripFA.ParentAccountId = specialFund.Id; tripFA.Order = specialFund.Order + 1; tripFA.AccountTypeValueId = serviceReefAccountType.Id; // Figure out what order it should be; foreach (FinancialAccount tmpTrip in trips) { if (tmpTrip.Name.CompareTo(tripFA.Name) < 0) { tripFA.Order++; } } financialAccountService.Add(tripFA); // Now save the trip dbContext.SaveChanges(); // Increment all the rest of the Orders financialAccountService.Queryable().Where(fa => fa.Order >= tripFA.Order && fa.Id != tripFA.Id).ToList().ForEach(c => c.Order++); dbContext.SaveChanges(); trips = financialAccountService.Queryable().Where(fa => fa.ParentAccountId == specialFund.Id).OrderBy(fa => fa.Order).ToList(); trip = tripFA; } FinancialTransaction tran = financialTransactionService.Queryable().Where(tx => tx.TransactionCode == result.PaymentProcessorTransactionId).FirstOrDefault(); // We haven't processed this before so get busy! if (tran == null) { tran = new FinancialTransaction(); tran.FinancialPaymentDetail = new FinancialPaymentDetail(); if (result.Type == "CreditCard") { tran.FinancialPaymentDetail.CurrencyTypeValueId = tenderType.DefinedValues.Where(t => t.Value == "Credit Card").FirstOrDefault().Id; } else { tran.TransactionTypeValueId = tenderType.DefinedValues.Where(t => t.Value == "Credit Card").FirstOrDefault().Id; } Person person = null; // Find the person this transaction belongs to // 1. First start by determining whether this was a person // paying their application fee or contributing to themselves // because then we can just use their member info if (result.UserId > 0 && result.DonatedToUserId == result.UserId && result.DonatedToFirstName == result.FirstName && result.DonatedToLastName == result.LastName) { var memberRequest = new RestRequest("v1/members/{userId}", Method.GET); memberRequest.AddUrlSegment("userId", result.UserId.ToString()); var memberResult = client.Execute <Contracts.Member>(memberRequest); if (memberResult.Data != null && memberResult.Data.ArenaId > 0) { try { Person personMatch = personAliasService.Queryable().Where(pa => pa.AliasPersonId == memberResult.Data.ArenaId).Select(pa => pa.Person).FirstOrDefault(); if (personMatch == null) { throw new Exception("Person not found: " + memberResult.Data.ArenaId); } person = personMatch; } catch (Exception e) { warnings += "Loading the person failed transaction id " + result.TransactionId + " for " + result.FirstName + " " + result.LastName + " with the following error: " + e.Message + Environment.NewLine; processed++; continue; } } } // 2. If we didn't get a person match via their Alias Id // then just use the standard person match logic if (person == null) { String street1 = null; String postalCode = null; if (result.Address != null) { street1 = result.Address.Address1; postalCode = result.Address.Zip; } List <Person> matches = personService.GetByMatch(result.FirstName.Trim(), result.LastName.Trim(), null, result.Email, null, street1, postalCode).ToList(); if (matches.Count > 1) { // Find the oldest member record in the list person = matches.Where(p => p.ConnectionStatusValue.Value == "Member").OrderBy(p => p.Id).FirstOrDefault(); if (person == null) { // Find the oldest attendee record in the list person = matches.Where(p => p.ConnectionStatusValue.Value == "Attendee").OrderBy(p => p.Id).FirstOrDefault(); if (person == null) { person = matches.OrderBy(p => p.Id).First(); } } } else if (matches.Count == 1) { person = matches.First(); } else { // Create the person person = new Person(); person.FirstName = result.FirstName.Trim(); person.LastName = result.LastName.Trim(); if (result.Email.IsValidEmail()) { person.Email = result.Email.Trim(); } person.RecordTypeValueId = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_RECORD_TYPE_PERSON.AsGuid()).Id; person.ConnectionStatusValueId = connectionStatus.Id; person.RecordStatusValueId = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_ACTIVE.AsGuid()).Id; Group family = PersonService.SaveNewPerson(person, dbContext); GroupLocation location = new GroupLocation(); location.GroupLocationTypeValueId = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.GROUP_LOCATION_TYPE_HOME).Id; location.Location = new Location() { Street1 = result.Address.Address1, Street2 = result.Address.Address2, City = result.Address.City, State = result.Address.State, PostalCode = result.Address.Zip, Country = result.Address.Country }; family.CampusId = CampusCache.All().FirstOrDefault().Id; family.GroupLocations.Add(location); dbContext.SaveChanges(); } } // Get details about the transaction from our PayPal report table Transaction tx = transactionService.Get(result.PaymentProcessorTransactionId); if (tx != null) { if (tx.TenderType.Contains("ACH")) { result.Type = "ACH"; result.Method = null; } else { result.Type = "Credit Card"; result.Method = tx.TenderType; } } else { // Defaults result.Type = "Credit Card"; result.Method = "Visa"; warnings += "Unable to find transaction in _org_secc_PaypalReporting_Transaction table: " + result.TransactionId + Environment.NewLine; } // If we don't have a batch, create one if (batch == null) { batch = new FinancialBatch(); batch.BatchStartDateTime = result.Date; batch.BatchEndDateTime = DateTime.Now; batch.Name = "Service Reef Payments"; batch.Status = BatchStatus.Open; financialBatchService.Add(batch); dbContext.SaveChanges(); } // Complete the FinancialTransaction tran.AuthorizedPersonAliasId = person.PrimaryAliasId; tran.BatchId = batch.Id; tran.Summary = "F" + specialFund.Id + ":$" + result.Amount.ToString(); tran.TransactionDateTime = result.Date; tran.FinancialGatewayId = gateway.Id; FinancialTransactionDetail financialTransactionDetail = new FinancialTransactionDetail(); financialTransactionDetail.AccountId = trip.Id; financialTransactionDetail.Amount = result.Amount.ToString().AsDecimal(); tran.TransactionDetails.Add(financialTransactionDetail); tran.TransactionTypeValueId = contribution.Id; tran.FinancialPaymentDetail = new FinancialPaymentDetail(); tran.FinancialPaymentDetail.CurrencyTypeValueId = tenderType.DefinedValues.Where(type => type.Value.ToLower() == result.Type.ToLower()).FirstOrDefault().Id; if (result.Method != null) { tran.FinancialPaymentDetail.CreditCardTypeValueId = creditCards.DefinedValues.Where(card => card.Value.ToLower() == result.Method.ToLower()).FirstOrDefault().Id; } tran.TransactionCode = result.PaymentProcessorTransactionId; tran.SourceTypeValueId = transactionSource.Id; financialTransactionService.Add(tran); dbContext.SaveChanges(); totalAmount += result.Amount; } } processed++; } } else { total = 0; } // Update the page number for the next request var pageParam = request.Parameters.Where(p => p.Name == "page").FirstOrDefault(); pageParam.Value = (int)pageParam.Value + 1; } } catch (Exception ex) { throw new Exception("ServiceReef Job Failed", ex); } finally { if (batch != null && totalAmount > 0) { batch.ControlAmount = (Decimal)totalAmount; } dbContext.SaveChanges(); } if (warnings.Length > 0) { throw new Exception(warnings); } context.Result = "Successfully imported " + processed + " transactions."; }
private void SaveTransaction( FinancialGateway financialGateway, GatewayComponent gateway, Person person, PaymentInfo paymentInfo, FinancialTransaction transaction, RockContext rockContext ) { 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 ); transaction.Summary = paymentInfo.Comment1; History.EvaluateChange( txnChanges, "Summary", string.Empty, transaction.Summary ); 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; }
/// <summary> /// Shows the detail. /// </summary> /// <param name="transactionId">The transaction identifier.</param> public void ShowDetail( int transactionId, int? batchId ) { // show or hide the add new transaction button depending if there is a batch id in the querystring lbAddTransaction.Visible = !string.IsNullOrWhiteSpace( PageParameter( "batchId" ) ); FinancialTransaction txn = null; bool editAllowed = UserCanEdit; var rockContext = new RockContext(); if ( !transactionId.Equals( 0 ) ) { txn = GetTransaction( transactionId, rockContext ); if ( !editAllowed && txn != null ) { editAllowed = txn.IsAuthorized( Authorization.EDIT, CurrentPerson ); } } if ( txn == null ) { txn = new FinancialTransaction { Id = 0 }; txn.BatchId = batchId; // Hide processor fields when adding a new transaction cpPaymentGateway.Visible = false; tbTransactionCode.Visible = false; // Set values based on previously saved txn values int prevBatchId = Session["NewTxnDefault_BatchId"] as int? ?? 0; if ( prevBatchId == batchId ) { txn.TransactionDateTime = Session["NewTxnDefault_TransactionDateTime"] as DateTime?; txn.TransactionTypeValueId = Session["NewTxnDefault_TransactionType"] as int? ?? 0; txn.SourceTypeValueId = Session["NewTxnDefault_SourceType"] as int?; txn.CurrencyTypeValueId = Session["NewTxnDefault_CurrencyType"] as int?; txn.CreditCardTypeValueId = Session["NewTxnDefault_CreditCardType"] as int?; int? accountId = Session["NewTxnDefault_Account"] as int?; if ( accountId.HasValue ) { var txnDetail = new FinancialTransactionDetail(); txnDetail.AccountId = accountId.Value; txn.TransactionDetails.Add( txnDetail ); } } } else { cpPaymentGateway.Visible = true; tbTransactionCode.Visible = true; } hfTransactionId.Value = txn.Id.ToString(); hfBatchId.Value = batchId.HasValue ? batchId.Value.ToString() : string.Empty; bool readOnly = false; nbEditModeMessage.Text = string.Empty; if ( !editAllowed ) { readOnly = true; nbEditModeMessage.Text = EditModeMessage.ReadOnlyEditActionNotAllowed( FinancialTransaction.FriendlyTypeName ); lbEdit.Visible = false; lbAddTransaction.Visible = false; } else { lbEdit.Visible = true; lbAddTransaction.Visible = true; } if ( readOnly ) { ShowReadOnlyDetails( txn ); } else { if ( txn.Id > 0 ) { ShowReadOnlyDetails( txn ); } else { ShowEditDetails( txn, rockContext ); } } lbSave.Visible = !readOnly; }
/// <summary> /// Writes to package. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="model">The model.</param> public static void WriteToPackage <T>(T model) { var typeName = model.GetType().Name; if (model is IImportModel) { var importModel = ( IImportModel )model; // check if a textwriter is needed for this model type if (!textWriters.ContainsKey(typeName)) { if (!Directory.Exists(_packageDirectory)) { InitalizePackageFolder(); } textWriters.Add(typeName, ( TextWriter )File.CreateText($@"{_packageDirectory}\{importModel.GetFileName()}")); // if model is for person create related writers if (importModel is Person) { // person attributes var personAttributeValue = new PersonAttributeValue(); textWriters.Add(personAttributeValue.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{personAttributeValue.GetFileName()}")); // person phones var personPhone = new PersonPhone(); textWriters.Add(personPhone.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{personPhone.GetFileName()}")); // person addresses var personAddress = new PersonAddress(); textWriters.Add(personAddress.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{personAddress.GetFileName()}")); // person search key var personSearchKey = new PersonSearchKey(); textWriters.Add(personSearchKey.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{personSearchKey.GetFileName()}")); } if (importModel is PersonAttributeValue) { var personAttributeValue = new PersonAttributeValue(); textWriters.Add(personAttributeValue.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{personAttributeValue.GetFileName()}")); } // if model is for financial batch create related writers if (importModel is FinancialBatch) { // financial transactions var financialTransaction = new FinancialTransaction(); textWriters.Add(financialTransaction.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{financialTransaction.GetFileName()}")); // financial transation details var financialTransactionDetail = new FinancialTransactionDetail(); textWriters.Add(financialTransactionDetail.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{financialTransactionDetail.GetFileName()}")); } // if model is for financial transaction create related writers if (importModel is FinancialTransaction) { // financial transation details var financialTransactionDetail = new FinancialTransactionDetail(); textWriters.Add(financialTransactionDetail.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{financialTransactionDetail.GetFileName()}")); } // if model is for group create related writers if (importModel is Group) { // group member var groupMember = new GroupMember(); textWriters.Add(groupMember.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{groupMember.GetFileName()}")); // group attributes var groupAttributeValue = new GroupAttributeValue(); textWriters.Add(groupAttributeValue.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{groupAttributeValue.GetFileName()}")); // group addresses var groupAddress = new GroupAddress(); textWriters.Add(groupAddress.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{groupAddress.GetFileName()}")); } // if model is for business create related writers if (importModel is Business) { // business attributes var businessAttributeValue = new BusinessAttributeValue(); textWriters.Add(businessAttributeValue.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{businessAttributeValue.GetFileName()}")); // business phones var businessPhone = new BusinessPhone(); textWriters.Add(businessPhone.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{businessPhone.GetFileName()}")); // business addresses var businessAddress = new BusinessAddress(); textWriters.Add(businessAddress.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{businessAddress.GetFileName()}")); // business contacts var businessContact = new BusinessContact(); textWriters.Add(businessContact.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{businessContact.GetFileName()}")); } } var txtWriter = textWriters[typeName]; // check if a csvwriter is needed for this model type if (!csvWriters.ContainsKey(typeName)) { var newCsvWriter = new CsvWriter(txtWriter); csvWriters.Add(typeName, newCsvWriter); newCsvWriter.WriteHeader <T>(); //newCsvWriter.Configuration.QuoteAllFields = true; // if model is for person create related writers if (importModel is Person) { // person attributes var personAttributeValue = new PersonAttributeValue(); var newPersonAttributeValueCsvWriter = new CsvWriter(textWriters[personAttributeValue.GetType().Name]); csvWriters.Add(personAttributeValue.GetType().Name, newPersonAttributeValueCsvWriter); newPersonAttributeValueCsvWriter.WriteHeader <PersonAttributeValue>(); // person phones var personPhone = new PersonPhone(); var newPersonPhoneCsvWriter = new CsvWriter(textWriters[personPhone.GetType().Name]); csvWriters.Add(personPhone.GetType().Name, newPersonPhoneCsvWriter); newPersonPhoneCsvWriter.WriteHeader <PersonPhone>(); // person addresses var personAddress = new PersonAddress(); var newPersonAddressCsvWriter = new CsvWriter(textWriters[personAddress.GetType().Name]); csvWriters.Add(personAddress.GetType().Name, newPersonAddressCsvWriter); newPersonAddressCsvWriter.WriteHeader <PersonAddress>(); // person search keys var personSearchKey = new PersonSearchKey(); var newPersonSearchKeyCsvWriter = new CsvWriter(textWriters[personSearchKey.GetType().Name]); csvWriters.Add(personSearchKey.GetType().Name, newPersonSearchKeyCsvWriter); newPersonSearchKeyCsvWriter.WriteHeader <PersonSearchKey>(); } if (importModel is PersonAttributeValue) { var personAttributeValue = new PersonAttributeValue(); var newPersonAttributeValueCsvWriter = new CsvWriter(textWriters[personAttributeValue.GetType().Name]); csvWriters.Add(personAttributeValue.GetType().Name, newPersonAttributeValueCsvWriter); newPersonAttributeValueCsvWriter.WriteHeader <PersonAttributeValue>(); } // if model is for financial batch create related writers if (importModel is FinancialBatch) { // financial transaction var financialTransaction = new FinancialTransaction(); var newFinancialTransactionCsvWriter = new CsvWriter(textWriters[financialTransaction.GetType().Name]); csvWriters.Add(financialTransaction.GetType().Name, newFinancialTransactionCsvWriter); newFinancialTransactionCsvWriter.WriteHeader <FinancialTransaction>(); // financial transaction detail var financialTransactionDetail = new FinancialTransactionDetail(); var newFinancialTransactionDetailCsvWriter = new CsvWriter(textWriters[financialTransactionDetail.GetType().Name]); csvWriters.Add(financialTransactionDetail.GetType().Name, newFinancialTransactionDetailCsvWriter); newFinancialTransactionDetailCsvWriter.WriteHeader <FinancialTransactionDetail>(); } //if model is for financial transaction, create related writers if (importModel is FinancialTransaction) { // financial transaction detail var financialTransactionDetail = new FinancialTransactionDetail(); var newFinancialTransactionDetailCsvWriter = new CsvWriter(textWriters[financialTransactionDetail.GetType().Name]); csvWriters.Add(financialTransactionDetail.GetType().Name, newFinancialTransactionDetailCsvWriter); newFinancialTransactionDetailCsvWriter.WriteHeader <FinancialTransactionDetail>(); } // if model is for group create related writers if (importModel is Group) { // group member var groupMember = new GroupMember(); var newGroupMemberCsvWriter = new CsvWriter(textWriters[groupMember.GetType().Name]); csvWriters.Add(groupMember.GetType().Name, newGroupMemberCsvWriter); newGroupMemberCsvWriter.WriteHeader <GroupMember>(); // group attributes var groupAttributeValue = new GroupAttributeValue(); var newGroupAttributeValueCsvWriter = new CsvWriter(textWriters[groupAttributeValue.GetType().Name]); csvWriters.Add(groupAttributeValue.GetType().Name, newGroupAttributeValueCsvWriter); newGroupAttributeValueCsvWriter.WriteHeader <GroupAttributeValue>(); // group addresses var groupAddress = new GroupAddress(); var newGroupAddressCsvWriter = new CsvWriter(textWriters[groupAddress.GetType().Name]); csvWriters.Add(groupAddress.GetType().Name, newGroupAddressCsvWriter); newGroupAddressCsvWriter.WriteHeader <GroupAddress>(); } // if model is for business create related writers if (importModel is Business) { // business attributes var businessAttributeValue = new BusinessAttributeValue(); var newBusinessAttributeValueCsvWriter = new CsvWriter(textWriters[businessAttributeValue.GetType().Name]); csvWriters.Add(businessAttributeValue.GetType().Name, newBusinessAttributeValueCsvWriter); newBusinessAttributeValueCsvWriter.WriteHeader <BusinessAttributeValue>(); // business phones var businessPhone = new BusinessPhone(); var newBusinessPhoneCsvWriter = new CsvWriter(textWriters[businessPhone.GetType().Name]); csvWriters.Add(businessPhone.GetType().Name, newBusinessPhoneCsvWriter); newBusinessPhoneCsvWriter.WriteHeader <BusinessPhone>(); // business addresses var businessAddress = new BusinessAddress(); var newBusinessAddressCsvWriter = new CsvWriter(textWriters[businessAddress.GetType().Name]); csvWriters.Add(businessAddress.GetType().Name, newBusinessAddressCsvWriter); newBusinessAddressCsvWriter.WriteHeader <BusinessAddress>(); // business Contacts var businessContacts = new BusinessContact(); var newBusinessContactsCsvWriter = new CsvWriter(textWriters[businessContacts.GetType().Name]); csvWriters.Add(businessContacts.GetType().Name, newBusinessContactsCsvWriter); newBusinessContactsCsvWriter.WriteHeader <BusinessContact>(); } } var csvWriter = csvWriters[typeName]; csvWriter.WriteRecord <T>(model); // if person model write out any related models if (importModel is Person) { // person attributes var personAttributeValue = new PersonAttributeValue(); var csvPersonAttributeValueWriter = csvWriters[personAttributeValue.GetType().Name]; if (csvPersonAttributeValueWriter != null) { foreach (var attribute in (( Person )importModel).Attributes) { csvPersonAttributeValueWriter.WriteRecord(attribute); } } // person phones var personPhone = new PersonPhone(); var csvPersonPhoneWriter = csvWriters[personPhone.GetType().Name]; if (csvPersonPhoneWriter != null) { foreach (var phone in (( Person )importModel).PhoneNumbers) { csvPersonPhoneWriter.WriteRecord(phone); } } // person addresses var personAddress = new PersonAddress(); var csvPersonAddressWriter = csvWriters[personAddress.GetType().Name]; if (csvPersonAddressWriter != null) { foreach (var address in (( Person )importModel).Addresses) { if ((( Person )importModel).FamilyId.HasValue) { var familyAddress = new FamilyAddress { FamilyId = (( Person )importModel).FamilyId.Value, Street1 = address.Street1, PostalCode = address.PostalCode.Left(5) }; var index = _familyAddresses.FindIndex(a => a.FamilyId == (( Person )importModel).FamilyId.Value && a.Street1.Equals(address.Street1, StringComparison.OrdinalIgnoreCase) && a.PostalCode.Equals(address.PostalCode.Left(5))); if (index == -1) { _familyAddresses.Add(familyAddress); csvPersonAddressWriter.WriteRecord(address); } } else { csvPersonAddressWriter.WriteRecord(address); } } } // person search keys var personSearchKey = new PersonSearchKey(); var csvPersonSearchKeyWriter = csvWriters[personSearchKey.GetType().Name]; if (csvPersonSearchKeyWriter != null) { foreach (var searchKey in (( Person )importModel).PersonSearchKeys) { csvPersonSearchKeyWriter.WriteRecord(searchKey); } } } // if financial model write out any related models if (importModel is FinancialBatch) { // write out financial transactions and transaction details var financialTransaction = new FinancialTransaction(); var csvFinancialTransactionWriter = csvWriters[financialTransaction.GetType().Name]; var financialTransactionDetail = new FinancialTransactionDetail(); var csvFinancialTransactionDetailWriter = csvWriters[financialTransactionDetail.GetType().Name]; if (csvFinancialTransactionWriter != null && csvFinancialTransactionDetailWriter != null) { foreach (var transaction in (( FinancialBatch )importModel).FinancialTransactions) { csvFinancialTransactionWriter.WriteRecord(transaction); foreach (var transactionDetail in transaction.FinancialTransactionDetails) { csvFinancialTransactionDetailWriter.WriteRecord(transactionDetail); } } } } // if financial Transaction model write out any related models if (importModel is FinancialTransaction) { var financialTransactionDetail = new FinancialTransactionDetail(); var csvFinancialTransactionDetailWriter = csvWriters[financialTransactionDetail.GetType().Name]; if (csvFinancialTransactionDetailWriter != null) { foreach (var transactionDetail in (( FinancialTransaction )importModel).FinancialTransactionDetails) { csvFinancialTransactionDetailWriter.WriteRecord(transactionDetail); } } } // if group model write out any related models if (importModel is Group) { // group members var groupMember = new GroupMember(); var csvGroupMemberWriter = csvWriters[groupMember.GetType().Name]; if (csvGroupMemberWriter != null) { foreach (var groupMemberItem in (( Group )importModel).GroupMembers) { csvGroupMemberWriter.WriteRecord(groupMemberItem); } } // group attributes var groupAttributeValue = new GroupAttributeValue(); var csvGroupAttributeValueWriter = csvWriters[groupAttributeValue.GetType().Name]; if (csvGroupAttributeValueWriter != null) { foreach (var attribute in (( Group )importModel).Attributes) { csvGroupAttributeValueWriter.WriteRecord(attribute); } } // group addresses var groupAddress = new GroupAddress(); var csvGroupAddressWriter = csvWriters[groupAddress.GetType().Name]; if (csvGroupAddressWriter != null) { foreach (var address in (( Group )importModel).Addresses) { csvGroupAddressWriter.WriteRecord(address); } } } // if business model write out any related models if (importModel is Business) { // business attributes var personBusinessValue = new BusinessAttributeValue(); var csvBusinessAttributeValueWriter = csvWriters[personBusinessValue.GetType().Name]; if (csvBusinessAttributeValueWriter != null) { foreach (var attribute in (( Business )importModel).Attributes) { csvBusinessAttributeValueWriter.WriteRecord(attribute); } } // business phones var businessPhone = new BusinessPhone(); var csvBusinessPhoneWriter = csvWriters[businessPhone.GetType().Name]; if (csvBusinessPhoneWriter != null) { foreach (var phone in (( Business )importModel).PhoneNumbers) { csvBusinessPhoneWriter.WriteRecord(phone); } } // business addresses var businessAddress = new BusinessAddress(); var csvBusinessAddressWriter = csvWriters[businessAddress.GetType().Name]; if (csvBusinessAddressWriter != null) { foreach (var address in (( Business )importModel).Addresses) { csvBusinessAddressWriter.WriteRecord(address); } } // business contacts var businessContact = new BusinessContact(); var csvBusinessContactWriter = csvWriters[businessContact.GetType().Name]; if (csvBusinessContactWriter != null) { foreach (var contact in (( Business )importModel).Contacts) { csvBusinessAddressWriter.WriteRecord(contact); } } } } }
/// <summary> /// Maps the contribution. /// </summary> /// <param name="tableData">The table data.</param> /// <param name="selectedColumns">The selected columns.</param> private void MapContribution( IQueryable<Row> tableData, List<string> selectedColumns = null ) { int transactionEntityTypeId = EntityTypeCache.Read( "Rock.Model.FinancialTransaction" ).Id; var accountService = new FinancialAccountService(); var attributeService = new AttributeService(); var transactionTypeContributionId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ) ).Id; int currencyTypeACH = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ) ).Id; int currencyTypeCash = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH ) ).Id; int currencyTypeCheck = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK ) ).Id; int currencyTypeCreditCard = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ) ).Id; List<DefinedValue> refundReasons = new DefinedValueService().Queryable().Where( dv => dv.DefinedType.Guid == new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON ) ).ToList(); List<FinancialPledge> pledgeList = new FinancialPledgeService().Queryable().ToList(); List<FinancialAccount> accountList = accountService.Queryable().ToList(); // Add an Attribute for the unique F1 Contribution Id int contributionAttributeId = attributeService.Queryable().Where( a => a.EntityTypeId == transactionEntityTypeId && a.Key == "F1ContributionId" ).Select( a => a.Id ).FirstOrDefault(); if ( contributionAttributeId == 0 ) { var newContributionAttribute = new Rock.Model.Attribute(); newContributionAttribute.Key = "F1ContributionId"; newContributionAttribute.Name = "F1 Contribution Id"; newContributionAttribute.FieldTypeId = IntegerFieldTypeId; newContributionAttribute.EntityTypeId = transactionEntityTypeId; newContributionAttribute.EntityTypeQualifierValue = string.Empty; newContributionAttribute.EntityTypeQualifierColumn = string.Empty; newContributionAttribute.Description = "The FellowshipOne identifier for the contribution that was imported"; newContributionAttribute.DefaultValue = string.Empty; newContributionAttribute.IsMultiValue = false; newContributionAttribute.IsRequired = false; newContributionAttribute.Order = 0; attributeService.Add( newContributionAttribute, ImportPersonAlias ); attributeService.Save( newContributionAttribute, ImportPersonAlias ); contributionAttributeId = newContributionAttribute.Id; } var contributionAttribute = AttributeCache.Read( contributionAttributeId ); // Get all imported contributions var importedContributions = new AttributeValueService().GetByAttributeId( contributionAttributeId ) .Select( av => new { ContributionId = av.Value.AsType<int?>(), TransactionId = av.EntityId } ) .ToDictionary( t => t.ContributionId, t => t.TransactionId ); // List for batching new contributions var newTransactions = new List<FinancialTransaction>(); int completed = 0; int totalRows = tableData.Count(); int percentage = ( totalRows - 1 ) / 100 + 1; ReportProgress( 0, string.Format( "Checking contribution import ({0:N0} found, {1:N0} already exist).", totalRows, importedContributions.Count() ) ); foreach ( var row in tableData ) { int? individualId = row["Individual_ID"] as int?; int? householdId = row["Household_ID"] as int?; int? contributionId = row["ContributionID"] as int?; if ( contributionId != null && !importedContributions.ContainsKey( contributionId ) ) { var transaction = new FinancialTransaction(); transaction.TransactionTypeValueId = transactionTypeContributionId; transaction.AuthorizedPersonId = GetPersonId( individualId, householdId ); transaction.CreatedByPersonAliasId = ImportPersonAlias.Id; transaction.AuthorizedPersonId = GetPersonId( individualId, householdId ); string summary = row["Memo"] as string; if ( summary != null ) { transaction.Summary = summary; } int? batchId = row["BatchID"] as int?; if ( batchId != null && ImportedBatches.Any( b => b.Key == batchId ) ) { transaction.BatchId = ImportedBatches.FirstOrDefault( b => b.Key == batchId ).Value; } DateTime? receivedDate = row["Received_Date"] as DateTime?; if ( receivedDate != null ) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; } bool isTypeNonCash = false; string contributionType = row["Contribution_Type_Name"] as string; if ( contributionType != null ) { if ( contributionType == "ACH" ) { transaction.CurrencyTypeValueId = currencyTypeACH; } else if ( contributionType == "Cash" ) { transaction.CurrencyTypeValueId = currencyTypeCash; } else if ( contributionType == "Check" ) { transaction.CurrencyTypeValueId = currencyTypeCheck; } else if ( contributionType == "Credit Card" ) { transaction.CurrencyTypeValueId = currencyTypeCreditCard; } else { isTypeNonCash = true; } } string checkNumber = row["Check_Number"] as string; if ( checkNumber != null && checkNumber.AsType<int?>() != null ) { // routing & account set to zero transaction.CheckMicrEncrypted = Encryption.EncryptString( string.Format( "{0}_{1}_{2}", 0, 0, checkNumber ) ); } string fundName = row["Fund_Name"] as string; string subFund = row["Sub_Fund_Name"] as string; decimal? amount = row["Amount"] as decimal?; if ( fundName != null & amount != null ) { FinancialAccount matchingAccount = null; fundName = fundName.Trim(); int? fundCampusId = null; if ( subFund != null ) { subFund = subFund.Trim(); fundCampusId = CampusList.Where( c => c.Name.StartsWith( subFund ) || c.ShortCode == subFund ) .Select( c => (int?)c.Id ).FirstOrDefault(); if ( fundCampusId != null ) { matchingAccount = accountList.FirstOrDefault( a => a.Name.StartsWith( fundName ) && a.CampusId != null && a.CampusId.Equals( fundCampusId ) ); } else { matchingAccount = accountList.FirstOrDefault( a => a.Name.StartsWith( fundName ) && a.Name.StartsWith( subFund ) ); } } else { matchingAccount = accountList.FirstOrDefault( a => a.Name.StartsWith( fundName ) && a.CampusId == null ); } if ( matchingAccount == null ) { matchingAccount = new FinancialAccount(); matchingAccount.Name = fundName; matchingAccount.PublicName = fundName; matchingAccount.IsTaxDeductible = true; matchingAccount.IsActive = true; matchingAccount.CampusId = fundCampusId; matchingAccount.CreatedByPersonAliasId = ImportPersonAlias.Id; accountService.Add( matchingAccount ); accountService.Save( matchingAccount ); accountList.Add( matchingAccount ); } var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = (decimal)amount; transactionDetail.CreatedDateTime = receivedDate; transactionDetail.AccountId = matchingAccount.Id; transactionDetail.IsNonCash = isTypeNonCash; transaction.TransactionDetails.Add( transactionDetail ); if ( amount < 0 ) { var transactionRefund = new FinancialTransactionRefund(); transactionRefund.CreatedDateTime = receivedDate; transactionRefund.RefundReasonSummary = summary; transactionRefund.RefundReasonValueId = refundReasons.Where( dv => summary != null && dv.Name.Contains( summary ) ) .Select( dv => (int?)dv.Id ).FirstOrDefault(); transaction.Refund = transactionRefund; } } // Other Attributes to create: // Pledge_Drive_Name // Stated_Value // True_Value // Liquidation_cost transaction.Attributes = new Dictionary<string, AttributeCache>(); transaction.AttributeValues = new Dictionary<string, List<AttributeValue>>(); transaction.Attributes.Add( contributionAttribute.Key, contributionAttribute ); transaction.AttributeValues.Add( contributionAttribute.Key, new List<AttributeValue>() ); transaction.AttributeValues[contributionAttribute.Key].Add( new AttributeValue() { AttributeId = contributionAttribute.Id, Value = contributionId.ToString(), Order = 0 } ); newTransactions.Add( transaction ); completed++; if ( completed % percentage < 1 ) { int percentComplete = completed / percentage; ReportProgress( percentComplete, string.Format( "{0:N0} contributions imported ({1}% complete).", completed, percentComplete ) ); } else if ( completed % ReportingNumber < 1 ) { RockTransactionScope.WrapTransaction( () => { var transactionService = new FinancialTransactionService(); transactionService.RockContext.FinancialTransactions.AddRange( newTransactions ); transactionService.RockContext.SaveChanges(); var attributeValueService = new AttributeValueService(); foreach ( var contribution in newTransactions.Where( c => c.Attributes.Any() ) ) { var attributeValue = contribution.AttributeValues[contributionAttribute.Key].FirstOrDefault(); if ( attributeValue != null ) { attributeValue.EntityId = contribution.Id; attributeValueService.RockContext.AttributeValues.Add( attributeValue ); } } attributeValueService.RockContext.SaveChanges(); } ); newTransactions.Clear(); ReportPartialProgress(); } } } if ( newTransactions.Any() ) { RockTransactionScope.WrapTransaction( () => { var transactionService = new FinancialTransactionService(); transactionService.RockContext.FinancialTransactions.AddRange( newTransactions ); transactionService.RockContext.SaveChanges(); var attributeValueService = new AttributeValueService(); foreach ( var contribution in newTransactions.Where( c => c.Attributes.Any() ) ) { var attributeValue = contribution.AttributeValues[contributionAttribute.Key].FirstOrDefault(); if ( attributeValue != null ) { attributeValue.EntityId = contribution.Id; attributeValueService.RockContext.AttributeValues.Add( attributeValue ); } } attributeValueService.RockContext.SaveChanges(); } ); } ReportProgress( 100, string.Format( "Finished contribution import: {0:N0} contributions imported.", completed ) ); }
// // Swipe Panel Events // private void ProcessSwipe(string swipeData) { try { using (var rockContext = new RockContext()) { // create swipe object SwipePaymentInfo swipeInfo = new SwipePaymentInfo(swipeData); swipeInfo.Amount = this.Amounts.Sum(a => a.Value); // if not anonymous then add contact info to the gateway transaction if (this.AnonymousGiverPersonAliasId != this.SelectedGivingUnit.PersonAliasId) { var giver = new PersonAliasService(rockContext).Queryable("Person, Person.PhoneNumbers").Where(p => p.Id == this.SelectedGivingUnit.PersonAliasId).FirstOrDefault(); swipeInfo.FirstName = giver.Person.NickName; swipeInfo.LastName = giver.Person.LastName; if (giver.Person.PhoneNumbers != null) { Guid homePhoneValueGuid = new Guid(Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_HOME); var homephone = giver.Person.PhoneNumbers.Where(p => p.NumberTypeValue.Guid == homePhoneValueGuid).FirstOrDefault(); if (homephone != null) { swipeInfo.Phone = homephone.NumberFormatted; } } var homeLocation = giver.Person.GetHomeLocation(); if (homeLocation != null) { swipeInfo.Street1 = homeLocation.Street1; if (!string.IsNullOrWhiteSpace(homeLocation.Street2)) { swipeInfo.Street2 = homeLocation.Street2; } swipeInfo.City = homeLocation.City; swipeInfo.State = homeLocation.State; swipeInfo.PostalCode = homeLocation.PostalCode; } } // add comment to the transation swipeInfo.Comment1 = GetAttributeValue("PaymentComment"); // get gateway FinancialGateway financialGateway = null; GatewayComponent gateway = null; Guid? gatewayGuid = GetAttributeValue("CreditCardGateway").AsGuidOrNull(); if (gatewayGuid.HasValue) { financialGateway = new FinancialGatewayService(rockContext).Get(gatewayGuid.Value); if (financialGateway != null) { financialGateway.LoadAttributes(rockContext); } gateway = financialGateway.GetGatewayComponent(); } if (gateway != null) { string errorMessage = string.Empty; var transaction = gateway.Charge(financialGateway, swipeInfo, out errorMessage); if (transaction != null) { var txnChanges = new List <string>(); txnChanges.Add("Created Transaction (from kiosk)"); _transactionCode = transaction.TransactionCode; History.EvaluateChange(txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode); var personName = new PersonAliasService(rockContext) .Queryable().AsNoTracking() .Where(a => a.Id == this.SelectedGivingUnit.PersonAliasId) .Select(a => a.Person.NickName + " " + a.Person.LastName) .FirstOrDefault(); transaction.AuthorizedPersonAliasId = this.SelectedGivingUnit.PersonAliasId; History.EvaluateChange(txnChanges, "Person", string.Empty, personName); 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); transaction.Summary = swipeInfo.Comment1; History.EvaluateChange(txnChanges, "Transaction Code", string.Empty, transaction.Summary); if (transaction.FinancialPaymentDetail == null) { transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); } transaction.FinancialPaymentDetail.SetFromPaymentInfo(swipeInfo, 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 accountAmount in this.Amounts.Where(a => a.Value > 0)) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = accountAmount.Value; transactionDetail.AccountId = accountAmount.Key; transaction.TransactionDetails.Add(transactionDetail); var account = new FinancialAccountService(rockContext).Get(accountAmount.Key); if (account != null) { 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"), swipeInfo.CurrencyTypeValue, swipeInfo.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.WrapTransaction(() => { 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, personName, typeof(FinancialTransaction), transaction.Id ); }); // send receipt in one is configured and not giving anonymously if (!string.IsNullOrWhiteSpace(GetAttributeValue("ReceiptEmail")) && (this.AnonymousGiverPersonAliasId != this.SelectedGivingUnit.PersonAliasId)) { _receiptSent = true; SendReceipt(); } HidePanels(); ShowReceiptPanel(); } else { lSwipeErrors.Text = String.Format("<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", errorMessage); } } else { lSwipeErrors.Text = "<div class='alert alert-danger'>Invalid gateway provided. Please provide a gateway. Transaction not processed.</div>"; } } } catch (Exception ex) { lSwipeErrors.Text = String.Format("<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", ex.Message); } }
/// <summary> /// Maps the contribution. /// </summary> /// <param name="tableData">The table data.</param> /// <param name="selectedColumns">The selected columns.</param> private void MapContribution( IQueryable<Row> tableData, List<string> selectedColumns = null ) { var lookupContext = new RockContext(); int transactionEntityTypeId = EntityTypeCache.Read( "Rock.Model.FinancialTransaction" ).Id; var transactionTypeContributionId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ), lookupContext ).Id; int currencyTypeACH = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ), lookupContext ).Id; int currencyTypeCash = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH ), lookupContext ).Id; int currencyTypeCheck = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK ), lookupContext ).Id; int currencyTypeCreditCard = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ), lookupContext ).Id; var refundReasons = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON ), lookupContext ).DefinedValues; var accountList = new FinancialAccountService( lookupContext ).Queryable().ToList(); // Get all imported contributions var importedContributions = new FinancialTransactionService( lookupContext ).Queryable() .Where( c => c.ForeignId != null ) .ToDictionary( t => t.ForeignId.AsType<int>(), t => (int?)t.Id ); // List for batching new contributions var newTransactions = new List<FinancialTransaction>(); int completed = 0; int totalRows = tableData.Count(); int percentage = ( totalRows - 1 ) / 100 + 1; ReportProgress( 0, string.Format( "Verifying contribution import ({0:N0} found, {1:N0} already exist).", totalRows, importedContributions.Count ) ); foreach ( var row in tableData.Where( r => r != null ) ) { int? individualId = row["Individual_ID"] as int?; int? householdId = row["Household_ID"] as int?; int? contributionId = row["ContributionID"] as int?; if ( contributionId != null && !importedContributions.ContainsKey( (int)contributionId ) ) { var transaction = new FinancialTransaction(); transaction.CreatedByPersonAliasId = ImportPersonAlias.Id; transaction.TransactionTypeValueId = transactionTypeContributionId; transaction.ForeignId = contributionId.ToString(); var personKeys = GetPersonKeys( individualId, householdId, includeVisitors: false ); if ( personKeys != null ) { transaction.AuthorizedPersonAliasId = personKeys.PersonAliasId; transaction.ProcessedByPersonAliasId = personKeys.PersonAliasId; } string summary = row["Memo"] as string; if ( summary != null ) { transaction.Summary = summary; } int? batchId = row["BatchID"] as int?; if ( batchId != null && ImportedBatches.Any( b => b.Key.Equals( batchId ) ) ) { transaction.BatchId = ImportedBatches.FirstOrDefault( b => b.Key.Equals( batchId ) ).Value; } DateTime? receivedDate = row["Received_Date"] as DateTime?; if ( receivedDate != null ) { transaction.TransactionDateTime = receivedDate; transaction.CreatedDateTime = receivedDate; } bool isTypeNonCash = false; string contributionType = row["Contribution_Type_Name"].ToString().ToLower(); if ( contributionType != null ) { if ( contributionType == "ach" ) { transaction.CurrencyTypeValueId = currencyTypeACH; } else if ( contributionType == "cash" ) { transaction.CurrencyTypeValueId = currencyTypeCash; } else if ( contributionType == "check" ) { transaction.CurrencyTypeValueId = currencyTypeCheck; } else if ( contributionType == "credit card" ) { transaction.CurrencyTypeValueId = currencyTypeCreditCard; } else { isTypeNonCash = true; } } string checkNumber = row["Check_Number"] as string; if ( checkNumber != null && checkNumber.AsType<int?>() != null ) { // set the transaction code to the check number transaction.TransactionCode = checkNumber; } string fundName = row["Fund_Name"] as string; string subFund = row["Sub_Fund_Name"] as string; decimal? amount = row["Amount"] as decimal?; if ( fundName != null & amount != null ) { int transactionAccountId; var parentAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName ) && a.CampusId == null ); if ( parentAccount == null ) { parentAccount = AddAccount( lookupContext, fundName, null, null ); accountList.Add( parentAccount ); } if ( subFund != null ) { int? campusFundId = null; // assign a campus if the subfund is a campus fund var campusFund = CampusList.FirstOrDefault( c => subFund.StartsWith( c.Name ) || subFund.StartsWith( c.ShortCode ) ); if ( campusFund != null ) { // use full campus name as the subfund subFund = campusFund.Name; campusFundId = campusFund.Id; } // add info to easily find/assign this fund in the view subFund = string.Format( "{0} {1}", subFund, fundName ); var childAccount = accountList.FirstOrDefault( c => c.Name.Equals( subFund ) && c.ParentAccountId == parentAccount.Id ); if ( childAccount == null ) { // create a child account with a campusId if it was set childAccount = AddAccount( lookupContext, subFund, campusFundId, parentAccount.Id ); accountList.Add( childAccount ); } transactionAccountId = childAccount.Id; } else { transactionAccountId = parentAccount.Id; } var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = (decimal)amount; transactionDetail.CreatedDateTime = receivedDate; transactionDetail.AccountId = transactionAccountId; transactionDetail.IsNonCash = isTypeNonCash; transaction.TransactionDetails.Add( transactionDetail ); if ( amount < 0 ) { var transactionRefund = new FinancialTransactionRefund(); transactionRefund.CreatedDateTime = receivedDate; transactionRefund.RefundReasonSummary = summary; transactionRefund.RefundReasonValueId = refundReasons.Where( dv => summary != null && dv.Value.Contains( summary ) ) .Select( dv => (int?)dv.Id ).FirstOrDefault(); transaction.Refund = transactionRefund; } } newTransactions.Add( transaction ); completed++; if ( completed % percentage < 1 ) { int percentComplete = completed / percentage; ReportProgress( percentComplete, string.Format( "{0:N0} contributions imported ({1}% complete).", completed, percentComplete ) ); } else if ( completed % ReportingNumber < 1 ) { SaveContributions( newTransactions ); newTransactions.Clear(); ReportPartialProgress(); } } } if ( newTransactions.Any() ) { SaveContributions( newTransactions ); } ReportProgress( 100, string.Format( "Finished contribution import: {0:N0} contributions imported.", completed ) ); }