/// <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);
            }
        }
Example #2
0
        /// <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));
        }