/// <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> /// Maps the account data. /// </summary> /// <param name="tableData">The table data.</param> /// <returns></returns> private void MapBankAccount(IQueryable <Row> tableData) { var lookupContext = new RockContext(); var importedBankAccounts = new FinancialPersonBankAccountService(lookupContext).Queryable().ToList(); var newBankAccounts = new List <FinancialPersonBankAccount>(); var householdAVList = new AttributeValueService(lookupContext).Queryable().Where(av => av.AttributeId == HouseholdAttributeId).ToList(); int completed = 0; int totalRows = tableData.Count(); int percentage = (totalRows - 1) / 100 + 1; ReportProgress(0, string.Format("Verifying check number import ({0:N0} found, {1:N0} already exist).", totalRows, importedBankAccounts.Count())); foreach (var row in tableData) { int?individualId = row["Individual_ID"] as int?; int?householdId = row["Household_ID"] as int?; //int? personId = GetPersonAliasId( individualId, householdId ); int?personId; if (individualId != null) { personId = GetPersonAliasId(individualId, householdId); } //will get the exact person if Individual Id is not null. else { personId = GetPersonId(householdAVList, householdId); } //Will attempt to get the Head first, then Spouse, then Child. Will exclude Other and Visitor if (personId != null) { int? routingNumber = row["Routing_Number"] as int?; string accountNumber = row["Account"] as string; if (routingNumber != null && !string.IsNullOrWhiteSpace(accountNumber)) { accountNumber = accountNumber.Replace(" ", string.Empty); string encodedNumber = FinancialPersonBankAccount.EncodeAccountNumber(routingNumber.ToString(), accountNumber); if (!importedBankAccounts.Any(a => a.PersonAliasId == personId && a.AccountNumberSecured == encodedNumber)) { var bankAccount = new FinancialPersonBankAccount(); bankAccount.CreatedByPersonAliasId = ImportPersonAlias.Id; bankAccount.AccountNumberSecured = encodedNumber; bankAccount.AccountNumberMasked = accountNumber.ToString().Masked(); bankAccount.PersonAliasId = (int)personId; // Other Attributes (not used): // Account_Type_Name newBankAccounts.Add(bankAccount); completed++; if (completed % percentage < 1) { int percentComplete = completed / percentage; ReportProgress(percentComplete, string.Format("{0:N0} numbers imported ({1}% complete).", completed, percentComplete)); } else if (completed % ReportingNumber < 1) { SaveBankAccounts(newBankAccounts); newBankAccounts.Clear(); ReportPartialProgress(); } } } } } if (newBankAccounts.Any()) { SaveBankAccounts(newBankAccounts); } ReportProgress(100, string.Format("Finished check number import: {0:N0} numbers imported.", completed)); }