Ejemplo n.º 1
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().AsNoTracking().ToList();
            var newBankAccounts      = new List <FinancialPersonBankAccount>();

            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.Where(r => r != null))
            {
                int?individualId = row["Individual_ID"] as int?;
                int?householdId  = row["Household_ID"] as int?;
                var personKeys   = GetPersonKeys(individualId, householdId, false);
                if (personKeys != null && personKeys.PersonAliasId > 0)
                {
                    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().PadLeft(9, '0'), accountNumber);
                        if (!importedBankAccounts.Any(a => a.PersonAliasId == personKeys.PersonAliasId && a.AccountNumberSecured == encodedNumber))
                        {
                            var bankAccount = new FinancialPersonBankAccount();
                            bankAccount.CreatedByPersonAliasId = ImportPersonAliasId;
                            bankAccount.CreatedDateTime        = ImportDateTime;
                            bankAccount.ModifiedDateTime       = ImportDateTime;
                            bankAccount.AccountNumberSecured   = encodedNumber;
                            bankAccount.AccountNumberMasked    = accountNumber.ToString().Masked();
                            bankAccount.PersonAliasId          = (int)personKeys.PersonAliasId;

                            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));
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Creates the saved account.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <param name="paymentDetail">The payment detail.</param>
        /// <param name="financialGateway">The financial gateway.</param>
        /// <param name="person">The person.</param>
        /// <param name="rockContext">The rock context.</param>
        /// <returns></returns>
        private FinancialPersonSavedAccount CreateSavedAccount(PaymentParameters parameters, FinancialPaymentDetail paymentDetail, FinancialGateway financialGateway, Person person, RockContext rockContext)
        {
            var lastFour = paymentDetail.AccountNumberMasked.Substring(paymentDetail.AccountNumberMasked.Length - 4);
            var name     = string.Empty;

            if (parameters.AccountType.ToLower() != "credit")
            {
                if (string.IsNullOrWhiteSpace(parameters.RoutingNumber))
                {
                    GenerateResponse(HttpStatusCode.BadRequest, "RoutingNumber is required for ACH transactions");
                    return(null);
                }

                if (string.IsNullOrWhiteSpace(parameters.AccountNumber))
                {
                    GenerateResponse(HttpStatusCode.BadRequest, "AccountNumber is required");
                    return(null);
                }

                name = "Bank card ***" + lastFour;
                var bankAccountService   = new FinancialPersonBankAccountService(rockContext);
                var accountNumberSecured = FinancialPersonBankAccount.EncodeAccountNumber(parameters.RoutingNumber, parameters.AccountNumber);
                var bankAccount          = bankAccountService.Queryable().Where(a =>
                                                                                a.AccountNumberSecured == accountNumberSecured &&
                                                                                a.PersonAliasId == person.PrimaryAliasId.Value).FirstOrDefault();

                if (bankAccount == null)
                {
                    bankAccount = new FinancialPersonBankAccount();
                    bankAccount.PersonAliasId        = person.PrimaryAliasId.Value;
                    bankAccount.AccountNumberMasked  = paymentDetail.AccountNumberMasked;
                    bankAccount.AccountNumberSecured = accountNumberSecured;
                    bankAccountService.Add(bankAccount);
                }
            }
            else
            {
                name = "Credit card ***" + lastFour;
            }

            var savedAccount = new FinancialPersonSavedAccount {
                PersonAliasId      = person.PrimaryAliasId,
                FinancialGatewayId = financialGateway.Id,
                Name = name,
                FinancialPaymentDetailId = paymentDetail.Id
            };

            new FinancialPersonSavedAccountService(rockContext).Add(savedAccount);
            rockContext.SaveChanges();
            return(savedAccount);
        }
Ejemplo n.º 3
0
        public void RockCleanup_Execute_ShouldUpdatePeopleWithFinancialPersonBankAccountToAccountProtectionProfileHigh()
        {
            var personGuid = Guid.NewGuid();
            var personWithFinancialPersonBankAccount = new Person
            {
                FirstName = "Test",
                LastName  = personGuid.ToString(),
                Email     = $"{personGuid}@test.com",
                Guid      = personGuid
            };

            using (var rockContext = new RockContext())
            {
                var personService = new PersonService(rockContext);
                personService.Add(personWithFinancialPersonBankAccount);
                rockContext.SaveChanges();

                personWithFinancialPersonBankAccount = personService.Get(personWithFinancialPersonBankAccount.Id);

                var financialPersonBankAccount = new FinancialPersonBankAccount
                {
                    PersonAliasId        = personWithFinancialPersonBankAccount.PrimaryAliasId.Value,
                    AccountNumberMasked  = "1111",
                    AccountNumberSecured = "1111-111-11"
                };

                var service = new FinancialPersonBankAccountService(rockContext);
                service.Add(financialPersonBankAccount);
                rockContext.SaveChanges();
            }

            ExecuteRockCleanupJob();

            using (var rockContext = new RockContext())
            {
                var actualPerson = new PersonService(rockContext).Get(personGuid);
                Assert.That.AreEqual(AccountProtectionProfile.High, actualPerson.AccountProtectionProfile);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Maps the account data.
        /// </summary>
        /// <param name="tableData">The table data.</param>
        /// <param name="totalRows">The total rows.</param>
        private void MapBankAccount(IQueryable <Row> tableData, long totalRows = 0)
        {
            var lookupContext        = new RockContext();
            var importedBankAccounts = new FinancialPersonBankAccountService(lookupContext).Queryable().AsNoTracking().ToList();
            var newBankAccounts      = new List <FinancialPersonBankAccount>();

            if (totalRows == 0)
            {
                totalRows = tableData.Count();
            }

            var completedItems = 0;
            var percentage     = (totalRows - 1) / 100 + 1;

            ReportProgress(0, $"Verifying check number import ({totalRows:N0} found, {importedBankAccounts.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 personKeys   = GetPersonKeys(individualId, householdId);
                if (personKeys != null && personKeys.PersonAliasId > 0)
                {
                    var routingNumber = row["Routing_Number"] as int?;
                    var accountNumber = row["Account"] as string;
                    if (routingNumber.HasValue && !string.IsNullOrWhiteSpace(accountNumber))
                    {
                        accountNumber = accountNumber.Replace(" ", string.Empty);
                        var encodedNumber = FinancialPersonBankAccount.EncodeAccountNumber(routingNumber.ToString(), accountNumber);
                        if (!importedBankAccounts.Any(a => a.PersonAliasId == personKeys.PersonAliasId && a.AccountNumberSecured == encodedNumber))
                        {
                            var bankAccount = new FinancialPersonBankAccount
                            {
                                CreatedByPersonAliasId = ImportPersonAliasId,
                                AccountNumberSecured   = encodedNumber,
                                AccountNumberMasked    = accountNumber.ToString().Masked(),
                                PersonAliasId          = ( int )personKeys.PersonAliasId
                            };

                            newBankAccounts.Add(bankAccount);
                            completedItems++;
                            if (completedItems % percentage < 1)
                            {
                                var percentComplete = completedItems / percentage;
                                ReportProgress(percentComplete, $"{completedItems:N0} numbers imported ({percentComplete}% complete).");
                            }

                            if (completedItems % ReportingNumber < 1)
                            {
                                SaveBankAccounts(newBankAccounts);
                                newBankAccounts.Clear();
                                ReportPartialProgress();
                            }
                        }
                    }
                }
            }

            if (newBankAccounts.Any())
            {
                SaveBankAccounts(newBankAccounts);
            }

            ReportProgress(100, $"Finished check number import: {completedItems:N0} numbers imported.");
        }
Ejemplo n.º 5
0
        /// <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>
        /// 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>
        /// 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);
            }
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Creates the saved account.
        /// </summary>
        /// <param name="parameters">The parameters.</param>
        /// <param name="paymentDetail">The payment detail.</param>
        /// <param name="financialGateway">The financial gateway.</param>
        /// <param name="person">The person.</param>
        /// <param name="rockContext">The rock context.</param>
        /// <returns></returns>
        private FinancialPersonSavedAccount CreateSavedAccount( PaymentParameters parameters, FinancialPaymentDetail paymentDetail, FinancialGateway financialGateway, Person person, RockContext rockContext)
        {
            var lastFour = paymentDetail.AccountNumberMasked.Substring(paymentDetail.AccountNumberMasked.Length - 4);
            var name = string.Empty;

            if ( parameters.AccountType.ToLower() != "credit" )
            {
                if ( string.IsNullOrWhiteSpace( parameters.RoutingNumber ) )
                {
                    GenerateResponse( HttpStatusCode.BadRequest, "RoutingNumber is required for ACH transactions" );
                    return null;
                }

                if ( string.IsNullOrWhiteSpace( parameters.AccountNumber ) )
                {
                    GenerateResponse( HttpStatusCode.BadRequest, "AccountNumber is required" );
                    return null;
                }

                name = "Bank card ***" + lastFour;
                var bankAccountService = new FinancialPersonBankAccountService( rockContext );
                var accountNumberSecured = FinancialPersonBankAccount.EncodeAccountNumber( parameters.RoutingNumber, parameters.AccountNumber );
                var bankAccount = bankAccountService.Queryable().Where( a =>
                    a.AccountNumberSecured == accountNumberSecured &&
                    a.PersonAliasId == person.PrimaryAliasId.Value ).FirstOrDefault();

                if ( bankAccount == null )
                {
                    bankAccount = new FinancialPersonBankAccount();
                    bankAccount.PersonAliasId = person.PrimaryAliasId.Value;
                    bankAccount.AccountNumberMasked = paymentDetail.AccountNumberMasked;
                    bankAccount.AccountNumberSecured = accountNumberSecured;
                    bankAccountService.Add( bankAccount );
                }
            }
            else
            {
                name = "Credit card ***" + lastFour;
            }

            var savedAccount = new FinancialPersonSavedAccount {
                PersonAliasId = person.PrimaryAliasId,
                FinancialGatewayId = financialGateway.Id,
                Name = name,
                FinancialPaymentDetailId = paymentDetail.Id
            };

            new FinancialPersonSavedAccountService(rockContext).Add( savedAccount );
            rockContext.SaveChanges();
            return savedAccount;
        }
Ejemplo n.º 9
0
        /// <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);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Navigates to the next (or previous) transaction to edit
        /// </summary>
        private void NavigateToTransaction(Direction direction)
        {
            // put a lock around the entire NavigateToTransaction logic so that the navigation and "other person editing" logic will work consistently even if multiple people are editing the same batch
            lock ( transactionMatchingLockObject )
            {
                hfDoFadeIn.Value    = "1";
                nbSaveError.Visible = false;
                int?       fromTransactionId = hfTransactionId.Value.AsIntegerOrNull();
                int?       toTransactionId   = null;
                List <int> historyList       = hfBackNextHistory.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).AsIntegerList().Where(a => a > 0).ToList();
                int        position          = hfHistoryPosition.Value.AsIntegerOrNull() ?? -1;

                if (direction == Direction.Prev)
                {
                    position--;
                }
                else
                {
                    position++;
                }

                if (historyList.Count > position)
                {
                    if (position >= 0)
                    {
                        toTransactionId = historyList[position];
                    }
                    else
                    {
                        // if we trying to go previous when we are already at the start of the list, wrap around to the last item in the list
                        toTransactionId = historyList.Last();
                        position        = historyList.Count - 1;
                    }
                }

                hfHistoryPosition.Value = position.ToString();

                int batchId     = hfBatchId.Value.AsInteger();
                var rockContext = new RockContext();
                var financialPersonBankAccountService = new FinancialPersonBankAccountService(rockContext);
                var financialTransactionService       = new FinancialTransactionService(rockContext);
                var qryTransactionsToMatch            = financialTransactionService.Queryable()
                                                        .Where(a => a.AuthorizedPersonAliasId == null && a.ProcessedByPersonAliasId == null);

                if (batchId != 0)
                {
                    qryTransactionsToMatch = qryTransactionsToMatch.Where(a => a.BatchId == batchId);
                }

                // if a specific transactionId was specified (because we are navigating thru history), load that one. Otherwise, if a batch is specified, get the first unmatched transaction in that batch
                if (toTransactionId.HasValue)
                {
                    qryTransactionsToMatch = financialTransactionService
                                             .Queryable("AuthorizedPersonAlias.Person,ProcessedByPersonAlias.Person")
                                             .Where(a => a.Id == toTransactionId);
                }

                if (historyList.Any() && !toTransactionId.HasValue)
                {
                    // since we are looking for a transaction we haven't viewed or matched yet, look for the next one in the database that we haven't seen yet
                    qryTransactionsToMatch = qryTransactionsToMatch.Where(a => !historyList.Contains(a.Id));
                }

                qryTransactionsToMatch = qryTransactionsToMatch.OrderBy(a => a.CreatedDateTime).ThenBy(a => a.Id);

                FinancialTransaction transactionToMatch = qryTransactionsToMatch.FirstOrDefault();
                if (transactionToMatch == null)
                {
                    // we exhausted the transactions that aren't processed and aren't in our history list, so remove those those restrictions and show all transactions that haven't been matched yet
                    var qryRemainingTransactionsToMatch = financialTransactionService
                                                          .Queryable("AuthorizedPersonAlias.Person,ProcessedByPersonAlias.Person")
                                                          .Where(a => a.AuthorizedPersonAliasId == null);

                    if (batchId != 0)
                    {
                        qryRemainingTransactionsToMatch = qryRemainingTransactionsToMatch.Where(a => a.BatchId == batchId);
                    }

                    // get the first transaction that we haven't visited yet, or the next one we have visited after one we are on, or simple the first unmatched one
                    transactionToMatch = qryRemainingTransactionsToMatch.Where(a => a.Id > fromTransactionId && !historyList.Contains(a.Id)).FirstOrDefault()
                                         ?? qryRemainingTransactionsToMatch.Where(a => a.Id > fromTransactionId).FirstOrDefault()
                                         ?? qryRemainingTransactionsToMatch.FirstOrDefault();
                    if (transactionToMatch != null)
                    {
                        historyList.Add(transactionToMatch.Id);
                        position = historyList.LastIndexOf(transactionToMatch.Id);
                        hfHistoryPosition.Value = position.ToString();
                    }
                }
                else
                {
                    if (!toTransactionId.HasValue)
                    {
                        historyList.Add(transactionToMatch.Id);
                    }
                }

                nbNoUnmatchedTransactionsRemaining.Visible = transactionToMatch == null;
                pnlEdit.Visible       = transactionToMatch != null;
                nbIsInProcess.Visible = false;
                if (transactionToMatch != null)
                {
                    if (transactionToMatch.ProcessedByPersonAlias != null)
                    {
                        if (transactionToMatch.AuthorizedPersonAliasId.HasValue)
                        {
                            nbIsInProcess.Text    = string.Format("Warning. This transaction was matched by {0} at {1} ({2})", transactionToMatch.ProcessedByPersonAlias.Person, transactionToMatch.ProcessedDateTime.ToString(), transactionToMatch.ProcessedDateTime.ToRelativeDateString());
                            nbIsInProcess.Visible = true;
                        }
                        else
                        {
                            // display a warning if some other user has this marked as InProcess (and it isn't matched)
                            if (transactionToMatch.ProcessedByPersonAliasId != CurrentPersonAliasId)
                            {
                                nbIsInProcess.Text    = string.Format("Warning. This transaction is getting processed by {0} as of {1} ({2})", transactionToMatch.ProcessedByPersonAlias.Person, transactionToMatch.ProcessedDateTime.ToString(), transactionToMatch.ProcessedDateTime.ToRelativeDateString());
                                nbIsInProcess.Visible = true;
                            }
                        }
                    }

                    // Unless somebody else is processing it, immediately mark the transaction as getting processed by the current person so that other potentional transaction matching sessions will know that it is currently getting looked at
                    if (!transactionToMatch.ProcessedByPersonAliasId.HasValue)
                    {
                        transactionToMatch.ProcessedByPersonAlias   = null;
                        transactionToMatch.ProcessedByPersonAliasId = CurrentPersonAliasId;
                        transactionToMatch.ProcessedDateTime        = RockDateTime.Now;
                        rockContext.SaveChanges();
                    }

                    hfTransactionId.Value = transactionToMatch.Id.ToString();

                    // get the first 2 images (should be no more than 2, but just in case)
                    var transactionImages = transactionToMatch.Images.OrderBy(a => a.Order).Take(2).ToList();

                    ddlIndividual.Items.Clear();
                    ddlIndividual.Items.Add(new ListItem(null, null));

                    // clear any previously shown badges
                    ddlIndividual.Attributes.Remove("disabled");
                    badgeIndividualCount.InnerText = string.Empty;

                    // if this transaction has a CheckMicrParts, try to find matching person(s)
                    string checkMicrHashed = null;

                    if (!string.IsNullOrWhiteSpace(transactionToMatch.CheckMicrParts))
                    {
                        try
                        {
                            var checkMicrClearText = Encryption.DecryptString(transactionToMatch.CheckMicrParts);
                            var parts = checkMicrClearText.Split('_');
                            if (parts.Length >= 2)
                            {
                                checkMicrHashed = FinancialPersonBankAccount.EncodeAccountNumber(parts[0], parts[1]);
                            }
                        }
                        catch
                        {
                            // intentionally ignore exception when decripting CheckMicrParts since we'll be checking for null below
                        }
                    }

                    hfCheckMicrHashed.Value = checkMicrHashed;

                    if (!string.IsNullOrWhiteSpace(checkMicrHashed))
                    {
                        var matchedPersons = financialPersonBankAccountService.Queryable().Where(a => a.AccountNumberSecured == checkMicrHashed).Select(a => a.PersonAlias.Person).Distinct();
                        foreach (var person in matchedPersons.OrderBy(a => a.LastName).ThenBy(a => a.NickName))
                        {
                            ddlIndividual.Items.Add(new ListItem(person.FullNameReversed, person.Id.ToString()));
                        }
                    }

                    if (ddlIndividual.Items.Count == 2)
                    {
                        // only one person (and the None selection) are in the list, so init to the person
                        ddlIndividual.SelectedIndex = 1;
                    }
                    else
                    {
                        // either zero or multiple people are in the list, so default to none so they are forced to choose
                        ddlIndividual.SelectedIndex = 0;
                    }

                    if (transactionToMatch.AuthorizedPersonAlias != null && transactionToMatch.AuthorizedPersonAlias.Person != null)
                    {
                        var person = transactionToMatch.AuthorizedPersonAlias.Person;

                        // if the drop down does not contains the AuthorizedPerson of this transaction, add them to the drop down
                        // note, this can easily happen for non-check transactions
                        if (!ddlIndividual.Items.OfType <ListItem>().Any(a => a.Value == person.Id.ToString()))
                        {
                            ddlIndividual.Items.Add(new ListItem(person.FullNameReversed, person.Id.ToString()));
                        }

                        ddlIndividual.SelectedValue = person.Id.ToString();
                    }

                    if (ddlIndividual.Items.Count != 1)
                    {
                        badgeIndividualCount.InnerText = (ddlIndividual.Items.Count - 1).ToStringSafe();
                    }
                    else
                    {
                        ddlIndividual.Attributes["disabled"] = "disabled";
                        _focusControl = ppSelectNew;
                    }

                    ddlIndividual_SelectedIndexChanged(null, null);

                    ppSelectNew.SetValue(null);
                    if (transactionToMatch.TransactionDetails.Any())
                    {
                        cbTotalAmount.Text = transactionToMatch.TotalAmount.ToString();
                    }
                    else
                    {
                        cbTotalAmount.Text = string.Empty;
                    }

                    // update accountboxes
                    foreach (var accountBox in rptAccounts.ControlsOfTypeRecursive <CurrencyBox>())
                    {
                        accountBox.Text = string.Empty;
                    }

                    foreach (var detail in transactionToMatch.TransactionDetails)
                    {
                        var accountBox = rptAccounts.ControlsOfTypeRecursive <CurrencyBox>().Where(a => a.Attributes["data-account-id"].AsInteger() == detail.AccountId).FirstOrDefault();
                        if (accountBox != null)
                        {
                            accountBox.Text = detail.Amount.ToString();
                        }
                    }

                    tbSummary.Text = transactionToMatch.Summary;

                    if (transactionToMatch.Images.Any())
                    {
                        var primaryImage = transactionToMatch.Images
                                           .OrderBy(i => i.Order)
                                           .FirstOrDefault();
                        imgPrimary.ImageUrl = string.Format("~/GetImage.ashx?id={0}", primaryImage.BinaryFileId);
                        imgPrimary.Visible  = true;
                        nbNoTransactionImageWarning.Visible = false;

                        rptrImages.DataSource = transactionToMatch.Images
                                                .Where(i => !i.Id.Equals(primaryImage.Id))
                                                .OrderBy(i => i.Order)
                                                .ToList();
                        rptrImages.DataBind();
                    }
                    else
                    {
                        imgPrimary.Visible    = false;
                        rptrImages.DataSource = null;
                        rptrImages.DataBind();
                        nbNoTransactionImageWarning.Visible = true;
                    }
                }
                else
                {
                    hfTransactionId.Value = string.Empty;
                }

                // display how many unmatched transactions are remaining
                var qryTransactionCount = financialTransactionService.Queryable();
                if (batchId != 0)
                {
                    qryTransactionCount = qryTransactionCount.Where(a => a.BatchId == batchId);
                }

                // get count of transactions that haven't been matched (not including the one we are currently editing)
                int currentTranId         = hfTransactionId.Value.AsInteger();
                int matchedRemainingCount = qryTransactionCount.Count(a => a.AuthorizedPersonAliasId != null && a.Id != currentTranId);
                int totalBatchItemCount   = qryTransactionCount.Count();

                int percentComplete = (int)Math.Round((double)(100 * matchedRemainingCount) / totalBatchItemCount);

                lProgressBar.Text = string.Format(
                    @"<div class='progress'>
                            <div class='progress-bar progress-bar-info' role='progressbar' aria-valuenow='{0}' aria-valuemin='0' aria-valuemax='100' style='width: {0}%;'>
                                {0}%
                            </div>
                        </div>",
                    percentComplete);

                hfBackNextHistory.Value = historyList.AsDelimited(",");

                if (_focusControl == null)
                {
                    _focusControl = rptAccounts.ControlsOfTypeRecursive <Rock.Web.UI.Controls.CurrencyBox>().FirstOrDefault();
                }
            }
        }
Ejemplo n.º 11
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().AsNoTracking().ToList();
            var newBankAccounts = new List<FinancialPersonBankAccount>();

            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.Where( r => r != null ) )
            {
                int? individualId = row["Individual_ID"] as int?;
                int? householdId = row["Household_ID"] as int?;
                var personKeys = GetPersonKeys( individualId, householdId, false );
                if ( personKeys != null && personKeys.PersonAliasId > 0 )
                {
                    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().PadLeft( 9, '0' ), accountNumber );
                        if ( !importedBankAccounts.Any( a => a.PersonAliasId == personKeys.PersonAliasId && a.AccountNumberSecured == encodedNumber ) )
                        {
                            var bankAccount = new FinancialPersonBankAccount();
                            bankAccount.CreatedByPersonAliasId = ImportPersonAliasId;
                            bankAccount.CreatedDateTime = ImportDateTime;
                            bankAccount.ModifiedDateTime = ImportDateTime;
                            bankAccount.AccountNumberSecured = encodedNumber;
                            bankAccount.AccountNumberMasked = accountNumber.ToString().Masked();
                            bankAccount.PersonAliasId = (int)personKeys.PersonAliasId;

                            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 ) );
        }
        /// <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);
        }
Ejemplo n.º 13
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));
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Maps the account data.
        /// </summary>
        /// <param name="tableData">The table data.</param>
        /// <returns></returns>
        private void MapBankAccount( IQueryable<Row> tableData )
        {
            var importedBankAccounts = new FinancialPersonBankAccountService().Queryable().ToList();
            var newBankAccounts = new List<FinancialPersonBankAccount>();

            int completed = 0;
            int totalRows = tableData.Count();
            int percentage = ( totalRows - 1 ) / 100 + 1;
            ReportProgress( 0, string.Format( "Checking check number import ({0:N0} found).", totalRows ) );

            foreach ( var row in tableData )
            {
                int? individualId = row["Individual_ID"] as int?;
                int? householdId = row["Household_ID"] as int?;
                int? personId = GetPersonId( individualId, householdId );
                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.PersonId == personId && a.AccountNumberSecured == encodedNumber ) )
                        {
                            var bankAccount = new FinancialPersonBankAccount();
                            bankAccount.CreatedByPersonAliasId = ImportPersonAlias.Id;
                            bankAccount.AccountNumberSecured = encodedNumber;
                            bankAccount.PersonId = (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 )
                            {
                                RockTransactionScope.WrapTransaction( () =>
                                {
                                    var bankAccountService = new FinancialPersonBankAccountService();
                                    bankAccountService.RockContext.FinancialPersonBankAccounts.AddRange( newBankAccounts );
                                    bankAccountService.RockContext.SaveChanges();
                                } );

                                newBankAccounts.Clear();
                                ReportPartialProgress();
                            }
                        }
                    }
                }
            }

            if ( newBankAccounts.Any() )
            {
                RockTransactionScope.WrapTransaction( () =>
                {
                    var bankAccountService = new FinancialPersonBankAccountService();
                    bankAccountService.RockContext.FinancialPersonBankAccounts.AddRange( newBankAccounts );
                    bankAccountService.RockContext.SaveChanges();
                } );
            }

            ReportProgress( 100, string.Format( "Finished check number import: {0:N0} numbers imported.", completed ) );
        }
Ejemplo n.º 15
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 ) );
        }