Beispiel #1
0
        /// <summary>
        /// Gets the transaction details.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <returns></returns>
        protected List <FinancialTransactionDetail> GetTransactionDetails(RockContext rockContext)
        {
            var details = new List <FinancialTransactionDetail>();
            var financialAccountService = new FinancialAccountService(rockContext);
            int defaultAccountId        = financialAccountService.Get(GetAttributeValue("DefaultAccount").AsGuid()).Id;

            foreach (var item in Cart.Items)
            {
                int financialAccountId = item.AccountId ?? defaultAccountId;

                var transactionDetail = details.FirstOrDefault(d => d.AccountId == financialAccountId);

                if (transactionDetail == null)
                {
                    transactionDetail = new FinancialTransactionDetail
                    {
                        Amount    = 0,
                        AccountId = financialAccountId
                    };
                    details.Add(transactionDetail);
                }

                transactionDetail.Amount += item.ExtendedPrice;
            }

            return(details);
        }
        public static FinancialTransactionDetail Translate(XElement inputTransactionDetail)
        {
            var transactionDetail = new FinancialTransactionDetail();

            transactionDetail.Id = inputTransactionDetail.Attribute("id").Value.AsInteger();

            // Checking if there is a subfund
            if (string.IsNullOrEmpty(inputTransactionDetail.Element("subFund")?.Attribute("id").Value))
            {
                transactionDetail.AccountId = inputTransactionDetail.Element("fund")?.Attribute("id")?.Value.AsInteger();
            }
            else
            {
                transactionDetail.AccountId = inputTransactionDetail.Element("subFund")?.Attribute("id")?.Value.AsInteger();
            }

            transactionDetail.Amount        = inputTransactionDetail.Element("amount").Value.AsDecimal();
            transactionDetail.TransactionId = inputTransactionDetail.Attribute("id").Value.AsInteger();

            transactionDetail.CreatedDateTime   = inputTransactionDetail.Element("createdDate")?.Value.AsDateTime();
            transactionDetail.CreatedByPersonId = inputTransactionDetail.Element("createdByPerson").Attribute("id")?.Value.AsIntegerOrNull();

            transactionDetail.ModifiedDateTime   = inputTransactionDetail.Element("lastUpdateDate")?.Value.AsDateTime();
            transactionDetail.ModifiedByPersonId = inputTransactionDetail.Element("lastUpdatedByPerson").Attribute("id")?.Value.AsIntegerOrNull();

            return(transactionDetail);
        }
        public static FinancialTransactionDetail Translate(DataRow row)
        {
            var financialTransactionDetail = new FinancialTransactionDetail();

            financialTransactionDetail.AccountId     = row.Field <Int16>("FundNumber");
            financialTransactionDetail.Amount        = row.Field <decimal>("Amount");
            financialTransactionDetail.TransactionId = row.Field <int>("TransactionID");
            financialTransactionDetail.Summary       = row.Field <string>("GiftDescription");

            financialTransactionDetail.CreatedDateTime = row.Field <DateTime?>("GiftDate");

            return(financialTransactionDetail);
        }
        public static FinancialTransactionDetail Translate(DataRow row)
        {
            var financialTransactionDetail = new FinancialTransactionDetail();

            financialTransactionDetail.TransactionId = row.Field <int>("Id");
            financialTransactionDetail.AccountId     = row.Field <int>("AccountId");
            financialTransactionDetail.Amount        = row.Field <decimal>("Amount");

            financialTransactionDetail.CreatedDateTime  = row.Field <DateTime?>("CreatedDateTime");
            financialTransactionDetail.ModifiedDateTime = row.Field <DateTime?>("ModifiedDateTime");

            return(financialTransactionDetail);
        }
        public static FinancialTransactionDetail Translate(DataRow row)
        {
            FinancialTransactionDetail detail = new FinancialTransactionDetail();

            // Identifiers
            detail.Id            = row.Field <int>("DETAIL_ID");
            detail.TransactionId = row.Field <int>("CONTRIBUTION_ID");
            detail.AccountId     = row.Field <int>("ACCOUNT_ID");

            // Other Fields
            detail.Amount           = (decimal)row.Field <double>("AMT");
            detail.Summary          = row.Field <string>("NOTE");
            detail.CreatedDateTime  = row.Field <DateTime?>("CREATE_TS");
            detail.ModifiedDateTime = row.Field <DateTime?>("UPDATE_TS");

            return(detail);
        }
Beispiel #6
0
        public static FinancialTransactionDetail Translate(XElement inputTransactionDetail, int transactionId)
        {
            var financialTransactionDetail = new FinancialTransactionDetail();

            financialTransactionDetail.Id            = inputTransactionDetail.Attribute("id").Value.AsInteger();
            financialTransactionDetail.AccountId     = inputTransactionDetail.Element("coa")?.Attribute("id")?.Value.AsInteger();
            financialTransactionDetail.Amount        = inputTransactionDetail.Element("amount").Value.AsDecimal();
            financialTransactionDetail.Summary       = $"Contribution to: {inputTransactionDetail.Element( "coa" )?.Value} {inputTransactionDetail.Element( "note" )?.Value}";
            financialTransactionDetail.TransactionId = transactionId;

            financialTransactionDetail.CreatedDateTime  = inputTransactionDetail.Element("created")?.Value.AsDateTime();
            financialTransactionDetail.ModifiedDateTime = inputTransactionDetail.Element("modified")?.Value.AsDateTime();

            financialTransactionDetail.CreatedByPersonId  = inputTransactionDetail.Element("creator")?.Attribute("id")?.Value.AsIntegerOrNull();
            financialTransactionDetail.ModifiedByPersonId = inputTransactionDetail.Element("modifier")?.Attribute("id")?.Value.AsIntegerOrNull();

            return(financialTransactionDetail);
        }
        public static FinancialTransactionDetail Translate(DataRow row)
        {
            FinancialTransactionDetail detail = new FinancialTransactionDetail();

            // Identifiers
            Random rnd = new Random();

            detail.Id            = row.Field <int>("Id") + 10000000;
            detail.TransactionId = row.Field <int>("Id");
            detail.AccountId     = Math.Abs(row.Field <String>("Category").GetHashCode());

            // Other Fields
            detail.Amount           = decimal.Parse(Convert.ToString(row["Amount"]), System.Globalization.NumberStyles.Currency);
            detail.Summary          = row.Field <string>("Note");
            detail.CreatedDateTime  = row.Field <DateTime?>("Date");
            detail.ModifiedDateTime = row.Field <DateTime?>("Date");

            return(detail);
        }
Beispiel #8
0
        /// <summary>
        /// Handles the SaveClick event of the mdAccount control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void mdAccount_SaveClick(object sender, EventArgs e)
        {
            Guid?guid = hfAccountGuid.Value.AsGuidOrNull();

            if (guid.HasValue)
            {
                var txnDetail = TransactionDetailsState.Where(t => t.Guid.Equals(guid.Value)).FirstOrDefault();
                if (txnDetail == null)
                {
                    txnDetail = new FinancialTransactionDetail();
                    TransactionDetailsState.Add(txnDetail);
                }
                txnDetail.AccountId = ddlAccount.SelectedValue.AsInteger();
                txnDetail.Amount    = tbAccountAmount.Text.AsDecimal();
                txnDetail.Summary   = tbAccountSummary.Text;

                BindAccounts();
            }

            HideDialog();
        }
Beispiel #9
0
        public static List <FinancialTransactionDetail> Translate(DonationDTO inputDonation)
        {
            var transactionDetails = new List <FinancialTransactionDetail>();

            foreach (var inputTransactionDetail in inputDonation.Designations)
            {
                var transactionDetail = new FinancialTransactionDetail
                {
                    Id               = inputTransactionDetail.Id,
                    AccountId        = inputTransactionDetail.FundId,
                    Amount           = Convert.ToDecimal(inputTransactionDetail.AmountCents.Value / 100.00),
                    TransactionId    = inputDonation.Id,
                    CreatedDateTime  = inputDonation.CreatedAt,
                    ModifiedDateTime = inputDonation.UpdatedAt
                };

                transactionDetails.Add(transactionDetail);
            }

            return(transactionDetails);
        }
Beispiel #10
0
        /// <summary>
        /// Handles the SaveClick event of the mdDetails control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void mdDetails_SaveClick(object sender, EventArgs e)
        {
            var rockContext = new RockContext();

            if (!string.IsNullOrWhiteSpace(tbTransactionAmount.Text))
            {
                var ftdService = new FinancialTransactionDetailService(rockContext);
                FinancialTransactionDetail ftd = null;
                var transactionDetailId        = int.Parse(hfIdValue.Value);
                if (transactionDetailId > 0)
                {
                    ftd = ftdService.Get(transactionDetailId);
                }
                else
                {
                    ftd = new FinancialTransactionDetail {
                        Id = 0
                    };
                }

                ftd.TransactionId = hfIdTransValue.ValueAsInt();
                ftd.AccountId     = int.Parse(ddlTransactionAccount.SelectedValue);
                ftd.Amount        = decimal.Parse(tbTransactionAmount.Text);
                ftd.Summary       = tbTransactionSummary.Text;

                if (transactionDetailId == 0)
                {
                    ftdService.Add(ftd);
                }

                rockContext.SaveChanges();
            }

            mdDetails.Hide();
            FinancialTransaction transaction = new FinancialTransaction();

            transaction = new FinancialTransactionService(rockContext).Get(hfIdTransValue.ValueAsInt());
            BindTransactionDetailGrid(transaction);
            LoadRelatedImages(transaction.Id);
        }
Beispiel #11
0
        private void LoadFinancialTransactionDetails(FinancialTransaction financialTransaction)
        {
            decimal sum = 0;
            List <DisplayFinancialTransactionDetailModel> displayFinancialTransactionDetailList = new List <DisplayFinancialTransactionDetailModel>();

            // first, make sure all the accounts that are part of the existing transaction are included, even if they aren't included in the configured selected accounts
            if (financialTransaction.TransactionDetails != null)
            {
                foreach (var detail in financialTransaction.TransactionDetails)
                {
                    sum           += detail.Amount;
                    detail.Account = ScanningPageUtility.Accounts.FirstOrDefault(a => a.Id == detail.AccountId);
                    displayFinancialTransactionDetailList.Add(new DisplayFinancialTransactionDetailModel(detail));
                }
            }

            RockConfig rockConfig = RockConfig.Load();

            List <DisplayAccountValueModel> sortedDisplayedAccountList = ScanningPageUtility.GetVisibleAccountsSortedAndFlattened();

            // now, add accounts that aren't part of the Transaction in case they want to split to different accounts
            foreach (var displayAccount in sortedDisplayedAccountList)
            {
                if (!displayFinancialTransactionDetailList.Any(a => a.AccountId == displayAccount.AccountId))
                {
                    FinancialTransactionDetail financialTransactionDetail = new FinancialTransactionDetail();
                    financialTransactionDetail.Guid      = Guid.NewGuid();
                    financialTransactionDetail.AccountId = displayAccount.AccountId;
                    financialTransactionDetail.Account   = displayAccount.Account;
                    displayFinancialTransactionDetailList.Add(new DisplayFinancialTransactionDetailModel(financialTransactionDetail));
                }
            }

            // show displayed accounts sorted by its position in sortedDisplayedAccountList
            displayFinancialTransactionDetailList = displayFinancialTransactionDetailList.OrderBy(a => sortedDisplayedAccountList.FirstOrDefault(s => s.AccountId == a.AccountId)?.DisplayIndex).ToList();

            this.lvAccountDetails.ItemsSource = displayFinancialTransactionDetailList;
            this.lblTotals.Content            = sum.ToString("C");
        }
        public static FinancialTransactionDetail Translate(ContributionDetail contributionDetail)
        {
            FinancialTransactionDetail detail = new FinancialTransactionDetail();

            detail.Id = Math.Abs(unchecked (( int )contributionDetail.Id));

            // Increment the id until we find one that is unqiue.
            while (!UsedDetailIds.Add(detail.Id))
            {
                detail.Id++;
            }

            detail.TransactionId    = IdMap[contributionDetail.ContributionId];
            detail.CreatedDateTime  = contributionDetail.CreatedDate;
            detail.ModifiedDateTime = contributionDetail.UpdatedDate;
            detail.AccountId        = Math.Abs(unchecked (( int )contributionDetail.AccountId));
            if (contributionDetail.Amount == 0)
            {
                string amount = contributionDetail.EncodedAmount;
                foreach (var trans in AmountTranslation)
                {
                    amount = amount.Replace(trans.Value, trans.Key);
                }
                try
                {
                    detail.Amount = Decimal.Parse(amount);
                }
                catch (Exception e)
                {
                    throw e;
                }
            }
            else
            {
                detail.Amount = contributionDetail.Amount;
            }

            return(detail);
        }
        private static FinancialTransactionDetail CreateFinancialTransactionDetail(
            int accountId,
            int transactionId,
            int number,
            DateTime transactionDateTime)
        {
            var transactionDetail = new FinancialTransactionDetail
            {
                TransactionId    = transactionId,
                AccountId        = accountId,
                Amount           = TRANSACTION_AMOUNT,
                Summary          = $"Giving Test {number}",
                EntityTypeId     = null,
                Guid             = Guid.NewGuid(),
                CreatedDateTime  = transactionDateTime,
                ModifiedDateTime = RockDateTime.Now
            };

            _transactionDetailService.Add(transactionDetail);
            _rockContext.SaveChanges(true);

            return(transactionDetail);
        }
        public static List <FinancialTransactionDetail> Translate(PCODonation inputDonation)
        {
            var transactionDetails = new List <FinancialTransactionDetail>();

            foreach (var inputTransactionDetail in inputDonation.designations)
            {
                var transactionDetail = new FinancialTransactionDetail();

                transactionDetail.Id = inputTransactionDetail.id;

                transactionDetail.AccountId = inputTransactionDetail.fundId;

                transactionDetail.Amount        = Convert.ToDecimal(inputTransactionDetail.amount_cents.Value / 100.00);
                transactionDetail.TransactionId = inputDonation.id;

                transactionDetail.CreatedDateTime = inputDonation.created_at;

                transactionDetail.ModifiedDateTime = inputDonation.updated_at;

                transactionDetails.Add(transactionDetail);
            }

            return(transactionDetails);
        }
Beispiel #15
0
        /// <summary>
        /// Process the data read from the card reader and generate the transaction.
        /// </summary>
        /// <param name="swipeData">The data read from the card.</param>
        private void ProcessSwipe(string swipeData)
        {
            try
            {
                using (var rockContext = new RockContext())
                {
                    // create swipe object
                    SwipePaymentInfo swipeInfo = new SwipePaymentInfo(swipeData);
                    swipeInfo.Amount = tbAmount.Text.AsDecimal();

                    // add comment to the transation
                    swipeInfo.Comment1 = PageParameter("Memo");

                    // get gateway
                    FinancialGateway financialGateway = null;
                    GatewayComponent gateway          = null;
                    Guid?            gatewayGuid      = GetAttributeValue("CreditCardGateway").AsGuidOrNull();
                    if (gatewayGuid.HasValue)
                    {
                        financialGateway = new FinancialGatewayService(rockContext).Get(gatewayGuid.Value);

                        if (financialGateway != null)
                        {
                            financialGateway.LoadAttributes(rockContext);
                        }

                        gateway = financialGateway.GetGatewayComponent();
                    }

                    if (gateway == null)
                    {
                        lSwipeErrors.Text = "<div class='alert alert-danger'>Invalid gateway provided. Please provide a gateway. Transaction not processed.</div>";
                        return;
                    }

                    //
                    // Process the transaction.
                    //
                    string errorMessage = string.Empty;
                    var    transaction  = gateway.Charge(financialGateway, swipeInfo, out errorMessage);

                    if (transaction == null)
                    {
                        lSwipeErrors.Text = String.Format("<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", errorMessage);
                        return;
                    }

                    _transactionCode = transaction.TransactionCode;

                    //
                    // Set some common information about the transaction.
                    //
                    transaction.AuthorizedPersonAliasId = new PersonService(rockContext).Get(SelectedPersonGuid).PrimaryAliasId;
                    transaction.TransactionDateTime     = RockDateTime.Now;
                    transaction.FinancialGatewayId      = financialGateway.Id;
                    transaction.TransactionTypeValueId  = DefinedValueCache.Read(GetAttributeValue("TransactionType")).Id;
                    transaction.SourceTypeValueId       = DefinedValueCache.Read(GetAttributeValue("Source")).Id;
                    transaction.Summary = swipeInfo.Comment1;

                    //
                    // Ensure we have payment details.
                    //
                    if (transaction.FinancialPaymentDetail == null)
                    {
                        transaction.FinancialPaymentDetail = new FinancialPaymentDetail();
                    }
                    transaction.FinancialPaymentDetail.SetFromPaymentInfo(swipeInfo, gateway, rockContext);

                    var transactionDetail = new FinancialTransactionDetail();
                    transactionDetail.Amount    = swipeInfo.Amount;
                    transactionDetail.AccountId = new FinancialAccountService(rockContext).Get(GetAttributeValue("Account").AsGuid()).Id;
                    transaction.TransactionDetails.Add(transactionDetail);

                    var batchService = new FinancialBatchService(rockContext);

                    // Get the batch
                    var batch = batchService.Get(
                        GetAttributeValue("BatchNamePrefix"),
                        swipeInfo.CurrencyTypeValue,
                        swipeInfo.CreditCardTypeValue,
                        transaction.TransactionDateTime.Value,
                        financialGateway.GetBatchTimeOffset());

                    var batchChanges = new List <string>();

                    if (batch.Id == 0)
                    {
                        batchChanges.Add("Generated the batch");
                        History.EvaluateChange(batchChanges, "Batch Name", string.Empty, batch.Name);
                        History.EvaluateChange(batchChanges, "Status", null, batch.Status);
                        History.EvaluateChange(batchChanges, "Start Date/Time", null, batch.BatchStartDateTime);
                        History.EvaluateChange(batchChanges, "End Date/Time", null, batch.BatchEndDateTime);
                    }

                    decimal newControlAmount = batch.ControlAmount + transaction.TotalAmount;
                    History.EvaluateChange(batchChanges, "Control Amount", batch.ControlAmount.FormatAsCurrency(), newControlAmount.FormatAsCurrency());
                    batch.ControlAmount = newControlAmount;

                    transaction.BatchId = batch.Id;
                    batch.Transactions.Add(transaction);

                    rockContext.WrapTransaction(() =>
                    {
                        rockContext.SaveChanges();

                        HistoryService.SaveChanges(
                            rockContext,
                            typeof(FinancialBatch),
                            Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(),
                            batch.Id,
                            batchChanges
                            );
                    });

                    ShowReceiptPanel();
                }
            }
            catch (Exception ex)
            {
                lSwipeErrors.Text = String.Format("<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", ex.Message);
            }
        }
        /// <summary>
        /// Processes a transaction.
        /// </summary>
        /// <param name="giftElement">The gift element.</param>
        /// <param name="batch">The batch.</param>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="envelopeAttributeId">The envelope attribute identifier.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        private ProcessStatus ProcessTransaction(XElement giftElement, int?batchId, int?envelopeAttributeId, int?binaryFileTypeId, out List <string> errorMessages)
        {
            errorMessages = new List <string>();

            // Get batch/sequence number first as they are used in any error messages
            string batchNo = GetChildElementValue(giftElement, "BatchNo");
            string seqNo   = GetChildElementValue(giftElement, "SequenceNo");

            try
            {
                using (var rockContext = new RockContext())
                {
                    // Check to see if accout/routing/check information is specified
                    string encryptedAccountNum = GetChildElementValue(giftElement, "DFIAcct");
                    string encryptedRoutingNum = GetChildElementValue(giftElement, "DFID");
                    string checkNum            = GetChildElementValue(giftElement, "CheckNum");

                    // Start to create the transaction
                    var txn = new FinancialTransaction();
                    txn.BatchId = batchId;
                    txn.TransactionTypeValueId = _transactionTypeContributionId;
                    txn.TransactionDateTime    = GetChildElementValue(giftElement, "GiftDate").AsDateTime();
                    txn.Summary = string.Format("{0}:{1}", batchNo, seqNo);
                    txn.FinancialPaymentDetail = new FinancialPaymentDetail();

                    // Try to find an person to associate with this account
                    int?personAliasId = null;
                    if (!string.IsNullOrWhiteSpace(encryptedAccountNum) && !string.IsNullOrWhiteSpace(encryptedRoutingNum))
                    {
                        // If account/routing information was included, use it to find matching person from Bank Account table
                        // A person will be selected if there is only ONE match found with same information.
                        var accountNum = DecryptAccountInformation(encryptedAccountNum);
                        var routingNum = DecryptAccountInformation(encryptedRoutingNum);

                        string checkMicrHashed = FinancialPersonBankAccount.EncodeAccountNumber(routingNum, accountNum);

                        if (!string.IsNullOrWhiteSpace(checkMicrHashed))
                        {
                            var matchedPersonIds = new FinancialPersonBankAccountService(rockContext)
                                                   .Queryable()
                                                   .Where(a => a.AccountNumberSecured == checkMicrHashed)
                                                   .Select(a => a.PersonAlias.PersonId)
                                                   .Distinct()
                                                   .ToList();

                            if (matchedPersonIds.Count() == 1)
                            {
                                personAliasId = new PersonAliasService(rockContext)
                                                .GetPrimaryAliasId(matchedPersonIds.First());
                            }
                        }

                        txn.MICRStatus     = MICRStatus.Success;
                        txn.CheckMicrParts = Encryption.EncryptString(string.Format("{0}_{1}_{2}", routingNum, accountNum, checkNum));
                        txn.FinancialPaymentDetail.CurrencyTypeValueId = _currencyTypeCheck;
                        txn.TransactionCode = checkNum;
                    }
                    else
                    {
                        // If account/routing number was NOT included, check for an envelope number, and if provided find first
                        // person with same envelope number (unlike account/routing number, this will automatically select first
                        // person when there are multiple people with same envelope number.
                        string envelopeNum = GetChildElementValue(giftElement, "EnvNum");
                        if (!string.IsNullOrWhiteSpace(envelopeNum))
                        {
                            int?personId = new AttributeValueService(rockContext)
                                           .Queryable().AsNoTracking()
                                           .Where(v =>
                                                  v.AttributeId == envelopeAttributeId &&
                                                  v.Value == envelopeNum)
                                           .OrderBy(v => v.EntityId)
                                           .Select(v => v.EntityId)
                                           .FirstOrDefault();

                            if (personId.HasValue)
                            {
                                personAliasId = new PersonAliasService(rockContext)
                                                .GetPrimaryAliasId(personId.Value);
                            }

                            txn.TransactionCode = envelopeNum;
                        }

                        txn.FinancialPaymentDetail.CurrencyTypeValueId = _currencyTypeCash;
                    }
                    txn.AuthorizedPersonAliasId = personAliasId;

                    // Save any images
                    if (binaryFileTypeId.HasValue)
                    {
                        SaveImage(txn, GetChildElementValue(giftElement, "CheckImgFront"), binaryFileTypeId.Value, string.Format("CheckImageFront_{0}:{1}", batchNo, seqNo));
                        SaveImage(txn, GetChildElementValue(giftElement, "CheckImgBack"), binaryFileTypeId.Value, string.Format("CheckImageFront_{0}:{1}", batchNo, seqNo));
                        SaveImage(txn, GetChildElementValue(giftElement, "EnvImgFront"), binaryFileTypeId.Value, string.Format("CheckImageFront_{0}:{1}", batchNo, seqNo));
                        SaveImage(txn, GetChildElementValue(giftElement, "EnvImgBack"), binaryFileTypeId.Value, string.Format("CheckImageFront_{0}:{1}", batchNo, seqNo));
                    }

                    // Loop through the purposes and create the transaction detail (account) records
                    var purposes = giftElement.Element("Purposes");
                    if (purposes != null)
                    {
                        foreach (var purpose in purposes.Descendants().Where(p => p.Name == "Purpose"))
                        {
                            FinancialTransactionDetail txnDetail = null;

                            int?    accountId = GetChildElementValue(purpose, "PurposeID").AsIntegerOrNull();
                            decimal?amount    = GetChildElementValue(purpose, "Amount").AsDecimalOrNull();

                            if (accountId.HasValue && amount.HasValue)
                            {
                                var account = new FinancialAccountService(rockContext).Get(accountId.Value);
                                if (account != null)
                                {
                                    txnDetail           = new FinancialTransactionDetail();
                                    txnDetail.AccountId = accountId.Value;
                                    txnDetail.Amount    = amount.Value;
                                    txn.TransactionDetails.Add(txnDetail);

                                    _totalAmount += amount.Value;
                                }
                            }

                            if (txnDetail == null)
                            {
                                errorMessages.Add(string.Format("Batch: {0}; Sequence: {1}; Error: Invalid Account (PurposeId:{2})", batchNo, seqNo, accountId));
                            }
                        }
                    }

                    if (errorMessages.Any())
                    {
                        return(ProcessStatus.Error);
                    }

                    // Save the transaction and update the batch control amount
                    new FinancialTransactionService(rockContext).Add(txn);
                    rockContext.SaveChanges();

                    return(personAliasId.HasValue ? ProcessStatus.Matched : ProcessStatus.Unmatched);
                }
            }

            catch (Exception ex)
            {
                errorMessages.Add(string.Format("Batch: {0}; Sequence: {1}; Error: {2}", batchNo, seqNo, ex.Message));
                return(ProcessStatus.Error);
            }
        }
        /// <summary>
        /// Handles the Click event of the btnNext control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void btnNext_Click( object sender, EventArgs e )
        {
            var rockContext = new RockContext();
            var financialTransactionService = new FinancialTransactionService( rockContext );
            var financialTransactionDetailService = new FinancialTransactionDetailService( rockContext );
            var financialPersonBankAccountService = new FinancialPersonBankAccountService( rockContext );
            int txnId = hfTransactionId.Value.AsInteger();
            var financialTransaction = financialTransactionService
                    .Queryable( "AuthorizedPersonAlias.Person,ProcessedByPersonAlias.Person" )
                    .FirstOrDefault( t => t.Id == txnId );

            // set the AuthorizedPersonId (the person who wrote the check, for example) to the if the SelectNew person (if selected) or person selected in the drop down (if there is somebody selected)
            int? authorizedPersonId = ppSelectNew.PersonId ?? ddlIndividual.SelectedValue.AsIntegerOrNull();

            var accountNumberSecured = hfCheckMicrHashed.Value;

            if ( cbTotalAmount.Text.AsDecimalOrNull().HasValue && !authorizedPersonId.HasValue )
            {
                nbSaveError.Text = "Transaction must be matched to a person when the amount is specified.";
                nbSaveError.Visible = true;
                return;
            }

            // if the transaction was previously matched, but user unmatched it, save it as an unmatched transaction and clear out the detail records (we don't want an unmatched transaction to have detail records)
            if ( financialTransaction != null &&
                financialTransaction.AuthorizedPersonAliasId.HasValue &&
                !authorizedPersonId.HasValue )
            {
                financialTransaction.AuthorizedPersonAliasId = null;
                foreach ( var detail in financialTransaction.TransactionDetails )
                {
                    financialTransactionDetailService.Delete( detail );
                }

                rockContext.SaveChanges();

                // if the transaction was unmatched, clear out the ProcessedBy fields since we didn't match the transaction and are moving on to process another transaction
                MarkTransactionAsNotProcessedByCurrentUser( hfTransactionId.Value.AsInteger() );
            }

            // if the transaction is matched to somebody, attempt to save it.  Otherwise, if the transaction was previously matched, but user unmatched it, save it as an unmatched transaction
            if ( financialTransaction != null && authorizedPersonId.HasValue )
            {
                bool requiresMicr = financialTransaction.CurrencyTypeValue.Guid == Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK.AsGuid();
                if ( requiresMicr && string.IsNullOrWhiteSpace( accountNumberSecured ) )
                {
                    // should be showing already, but just in case
                    nbNoMicrWarning.Visible = true;
                    return;
                }

                if ( cbTotalAmount.Text.AsDecimalOrNull() == null )
                {
                    nbSaveError.Text = "Total amount must be allocated to accounts.";
                    nbSaveError.Visible = true;
                    return;
                }

                int? personAliasId = new PersonAliasService( rockContext ).GetPrimaryAliasId( authorizedPersonId.Value );

                // if this transaction has an accountnumber associated with it (in other words, it's a scanned check), ensure there is a financialPersonBankAccount record
                if ( !string.IsNullOrWhiteSpace( accountNumberSecured ) )
                {
                    var financialPersonBankAccount = financialPersonBankAccountService.Queryable().Where( a => a.AccountNumberSecured == accountNumberSecured && a.PersonAlias.PersonId == authorizedPersonId.Value ).FirstOrDefault();
                    if ( financialPersonBankAccount == null )
                    {
                        if ( personAliasId.HasValue )
                        {
                            financialPersonBankAccount = new FinancialPersonBankAccount();
                            financialPersonBankAccount.PersonAliasId = personAliasId.Value;
                            financialPersonBankAccount.AccountNumberSecured = accountNumberSecured;

                            var checkMicrClearText = Encryption.DecryptString( financialTransaction.CheckMicrEncrypted );
                            var parts = checkMicrClearText.Split( '_' );
                            if ( parts.Length >= 2 )
                            {
                                financialPersonBankAccount.AccountNumberMasked = parts[1].Masked();
                            }

                            financialPersonBankAccountService.Add( financialPersonBankAccount );
                        }
                    }
                }

                if ( personAliasId.HasValue )
                {
                    financialTransaction.AuthorizedPersonAliasId = personAliasId;
                }

                // just in case this transaction is getting re-edited either by the same user, or somebody else, clean out any existing TransactionDetail records
                foreach ( var detail in financialTransaction.TransactionDetails.ToList() )
                {
                    financialTransactionDetailService.Delete( detail );
                }

                foreach ( var accountBox in rptAccounts.ControlsOfTypeRecursive<CurrencyBox>() )
                {
                    var amount = accountBox.Text.AsDecimalOrNull();

                    if ( amount.HasValue && amount.Value >= 0 )
                    {
                        var financialTransactionDetail = new FinancialTransactionDetail();
                        financialTransactionDetail.TransactionId = financialTransaction.Id;
                        financialTransactionDetail.AccountId = accountBox.Attributes["data-account-id"].AsInteger();
                        financialTransactionDetail.Amount = amount.Value;
                        financialTransactionDetailService.Add( financialTransactionDetail );
                    }
                }

                financialTransaction.ProcessedByPersonAliasId = this.CurrentPersonAlias.Id;
                financialTransaction.ProcessedDateTime = RockDateTime.Now;

                rockContext.SaveChanges();
            }
            else
            {
                // if the transaction was not matched, clear out the ProcessedBy fields since we didn't match the transaction and are moving on to process another transaction
                MarkTransactionAsNotProcessedByCurrentUser( hfTransactionId.Value.AsInteger() );
            }

            NavigateToTransaction( Direction.Next );
        }
        /// <summary>
        /// Shows the detail.
        /// </summary>
        /// <param name="transactionId">The transaction identifier.</param>
        public void ShowDetail( int transactionId, int? batchId )
        {
            FinancialTransaction txn = null;

            bool editAllowed = UserCanEdit;

            var rockContext = new RockContext();

            FinancialBatch batch = null;
            if ( batchId.HasValue )
            {
                batch = new FinancialBatchService( rockContext ).Get( batchId.Value );
            }

            BindDropdowns( rockContext );

            if ( !transactionId.Equals( 0 ) )
            {
                txn = GetTransaction( transactionId, rockContext );
                if ( !editAllowed && txn != null )
                {
                    editAllowed = txn.IsAuthorized( Authorization.EDIT, CurrentPerson );
                }
            }

            bool batchEditAllowed = true;

            if ( txn == null )
            {
                txn = new FinancialTransaction { Id = 0 };
                txn.FinancialPaymentDetail = new FinancialPaymentDetail();
                txn.BatchId = batchId;

                // Hide processor fields when adding a new transaction
                gpPaymentGateway.Visible = false;

                // Set values based on previously saved txn values
                int prevBatchId = Session["NewTxnDefault_BatchId"] as int? ?? 0;
                if ( prevBatchId == batchId )
                {
                    txn.TransactionDateTime = Session["NewTxnDefault_TransactionDateTime"] as DateTime?;
                    txn.TransactionTypeValueId = Session["NewTxnDefault_TransactionType"] as int? ?? 0;
                    txn.SourceTypeValueId = Session["NewTxnDefault_SourceType"] as int?;
                    txn.FinancialPaymentDetail.CurrencyTypeValueId = Session["NewTxnDefault_CurrencyType"] as int?;
                    txn.FinancialPaymentDetail.CreditCardTypeValueId = Session["NewTxnDefault_CreditCardType"] as int?;
                    int? accountId = Session["NewTxnDefault_Account"] as int?;
                    if ( accountId.HasValue )
                    {
                        var txnDetail = new FinancialTransactionDetail();
                        txnDetail.AccountId = accountId.Value;
                        txn.TransactionDetails.Add( txnDetail );
                    }
                }

            }
            else
            {
                gpPaymentGateway.Visible = true;

                if ( txn.Batch != null && txn.Batch.Status == BatchStatus.Closed )
                {
                    batchEditAllowed = false;
                }
            }

            hfTransactionId.Value = txn.Id.ToString();
            hfBatchId.Value = batchId.HasValue ? batchId.Value.ToString() : string.Empty;
            ShowNextButton( transactionId, batchId );

            bool readOnly = false;

            nbEditModeMessage.Text = string.Empty;

            lbEdit.Visible = editAllowed && batchEditAllowed;
            lbRefund.Visible = editAllowed && batchEditAllowed && txn.RefundDetails == null;
            lbAddTransaction.Visible = editAllowed && batch != null && batch.Status != BatchStatus.Closed;

            if ( !editAllowed )
            {
                readOnly = true;
                nbEditModeMessage.Text = EditModeMessage.ReadOnlyEditActionNotAllowed( FinancialTransaction.FriendlyTypeName );
            }
            else
            {
                if ( !batchEditAllowed )
                {
                    readOnly = true;
                    nbEditModeMessage.Text = string.Format( "<strong>Note</strong> Because this {0} belongs to a batch that is closed, editing is not enabled.", FinancialTransaction.FriendlyTypeName );
                }
            }

            txn.LoadAttributes( rockContext );
            txn.FinancialPaymentDetail.LoadAttributes(rockContext);

            if ( readOnly )
            {
                ShowReadOnlyDetails( txn );
            }
            else
            {
                if ( txn.Id > 0 )
                {
                    ShowReadOnlyDetails( txn );
                }
                else
                {
                    ShowEditDetails( txn, rockContext );
                }
            }

            lbSave.Visible = !readOnly;
        }
        /// <summary>
        /// Shows the account dialog.
        /// </summary>
        /// <param name="guid">The unique identifier.</param>
        private void ShowAccountDialog( Guid guid )
        {
            hfAccountGuid.Value = guid.ToString();

            var txnDetail = TransactionDetailsState.Where( d => d.Guid.Equals( guid ) ).FirstOrDefault();
            if ( txnDetail != null )
            {
                apAccount.SetValue( txnDetail.AccountId );
                tbAccountAmount.Text = txnDetail.Amount.ToString( "N2" );
                tbAccountSummary.Text = txnDetail.Summary;

                if ( txnDetail.Attributes == null )
                {
                    txnDetail.LoadAttributes();
                }
            }
            else
            {
                apAccount.SetValue( null );
                tbAccountAmount.Text = string.Empty;
                tbAccountSummary.Text = string.Empty;

                txnDetail = new FinancialTransactionDetail();
                txnDetail.LoadAttributes();
            }

            phAccountAttributeEdits.Controls.Clear();
            Helper.AddEditControls( txnDetail, phAccountAttributeEdits, true, mdAccount.ValidationGroup );

            ShowDialog( "ACCOUNT" );

            _focusControl = tbAccountAmount;
        }
        /// <summary>
        /// Processes the confirmation.
        /// </summary>
        /// <param name="errorMessage">The error message.</param>
        /// <returns></returns>
        private bool ProcessConfirmation( out string errorMessage )
        {
            var rockContext = new RockContext();
            if ( string.IsNullOrWhiteSpace( TransactionCode ) )
            {
                GatewayComponent gateway = null;
                var financialGateway = hfPaymentTab.Value == "ACH" ? _achGateway : _ccGateway;
                if ( financialGateway != null )
                {
                    gateway = financialGateway.GetGatewayComponent();
                }

                if ( gateway == null )
                {
                    errorMessage = "There was a problem creating the payment gateway information";
                    return false;
                }

                Person person = GetPerson( true );
                if ( person == null )
                {
                    errorMessage = "There was a problem creating the person information";
                    return false;
                }

                if ( !person.PrimaryAliasId.HasValue )
                {
                    errorMessage = "There was a problem creating the person's primary alias";
                    return false;
                }

                PaymentInfo paymentInfo = GetPaymentInfo();
                if ( paymentInfo == null )
                {
                    errorMessage = "There was a problem creating the payment information";
                    return false;
                }
                else
                {
                    paymentInfo.FirstName = person.FirstName;
                    paymentInfo.LastName = person.LastName;
                }

                if ( paymentInfo.CreditCardTypeValue != null )
                {
                    CreditCardTypeValueId = paymentInfo.CreditCardTypeValue.Id;
                }

                if ( _showCommmentEntry ) {
                    paymentInfo.Comment1 = !string.IsNullOrWhiteSpace(GetAttributeValue( "PaymentComment" )) ? string.Format("{0}: {1}", GetAttributeValue( "PaymentComment" ), txtCommentEntry.Text ) : txtCommentEntry.Text;
                }
                else
                {
                    paymentInfo.Comment1 = GetAttributeValue( "PaymentComment" );
                }

                PaymentSchedule schedule = GetSchedule();
                if ( schedule != null )
                {
                    schedule.PersonId = person.Id;

                    var scheduledTransaction = gateway.AddScheduledPayment( financialGateway, schedule, paymentInfo, out errorMessage );
                    if ( scheduledTransaction != null )
                    {
                        scheduledTransaction.TransactionFrequencyValueId = schedule.TransactionFrequencyValue.Id;
                        scheduledTransaction.AuthorizedPersonAliasId = person.PrimaryAliasId.Value;
                        scheduledTransaction.FinancialGatewayId = financialGateway.Id;

                        if ( scheduledTransaction.FinancialPaymentDetail == null )
                        {
                            scheduledTransaction.FinancialPaymentDetail = new FinancialPaymentDetail();
                        }
                        scheduledTransaction.FinancialPaymentDetail.SetFromPaymentInfo( paymentInfo, gateway, rockContext );

                        var changeSummary = new StringBuilder();
                        changeSummary.AppendFormat( "{0} starting {1}", schedule.TransactionFrequencyValue.Value, schedule.StartDate.ToShortDateString() );
                        changeSummary.AppendLine();
                        changeSummary.Append( paymentInfo.CurrencyTypeValue.Value );
                        if ( paymentInfo.CreditCardTypeValue != null )
                        {
                            changeSummary.AppendFormat( " - {0}", paymentInfo.CreditCardTypeValue.Value );
                        }
                        changeSummary.AppendFormat( " {0}", paymentInfo.MaskedNumber );
                        changeSummary.AppendLine();

                        foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) )
                        {
                            var transactionDetail = new FinancialScheduledTransactionDetail();
                            transactionDetail.Amount = account.Amount;
                            transactionDetail.AccountId = account.Id;
                            scheduledTransaction.ScheduledTransactionDetails.Add( transactionDetail );
                            changeSummary.AppendFormat( "{0}: {1}", account.Name, account.Amount.FormatAsCurrency() );
                            changeSummary.AppendLine();
                        }

                        var transactionService = new FinancialScheduledTransactionService( rockContext );
                        transactionService.Add( scheduledTransaction );
                        rockContext.SaveChanges();

                        // Add a note about the change
                        var noteType = NoteTypeCache.Read( Rock.SystemGuid.NoteType.SCHEDULED_TRANSACTION_NOTE.AsGuid() );
                        if ( noteType != null )
                        {
                            var noteService = new NoteService( rockContext );
                            var note = new Note();
                            note.NoteTypeId = noteType.Id;
                            note.EntityId = scheduledTransaction.Id;
                            note.Caption = "Created Transaction";
                            note.Text = changeSummary.ToString();
                            noteService.Add( note );
                        }
                        rockContext.SaveChanges();

                        ScheduleId = scheduledTransaction.GatewayScheduleId;
                        TransactionCode = scheduledTransaction.TransactionCode;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    var transaction = gateway.Charge( financialGateway, paymentInfo, out errorMessage );
                    if ( transaction != null )
                    {
                        var txnChanges = new List<string>();
                        txnChanges.Add( "Created Transaction" );

                        History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode );

                        transaction.AuthorizedPersonAliasId = person.PrimaryAliasId;
                        History.EvaluateChange( txnChanges, "Person", string.Empty, person.FullName );

                        transaction.TransactionDateTime = RockDateTime.Now;
                        History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime );

                        transaction.FinancialGatewayId = financialGateway.Id;
                        History.EvaluateChange( txnChanges, "Gateway", string.Empty, financialGateway.Name );

                        var txnType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ) );
                        transaction.TransactionTypeValueId = txnType.Id;
                        History.EvaluateChange( txnChanges, "Type", string.Empty, txnType.Value );

                        if ( transaction.FinancialPaymentDetail == null )
                        {
                            transaction.FinancialPaymentDetail = new FinancialPaymentDetail();
                        }
                        transaction.FinancialPaymentDetail.SetFromPaymentInfo( paymentInfo, gateway, rockContext, txnChanges );

                        Guid sourceGuid = Guid.Empty;
                        if ( Guid.TryParse( GetAttributeValue( "Source" ), out sourceGuid ) )
                        {
                            var source = DefinedValueCache.Read( sourceGuid );
                            if ( source != null )
                            {
                                transaction.SourceTypeValueId = source.Id;
                                History.EvaluateChange( txnChanges, "Source", string.Empty, source.Value );
                            }
                        }

                        foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) )
                        {
                            var transactionDetail = new FinancialTransactionDetail();
                            transactionDetail.Amount = account.Amount;
                            transactionDetail.AccountId = account.Id;
                            transaction.TransactionDetails.Add( transactionDetail );
                            History.EvaluateChange( txnChanges, account.Name, 0.0M.FormatAsCurrency(), transactionDetail.Amount.FormatAsCurrency() );
                        }

                        var batchService = new FinancialBatchService( rockContext );

                        // Get the batch
                        var batch = batchService.Get(
                            GetAttributeValue( "BatchNamePrefix" ),
                            paymentInfo.CurrencyTypeValue,
                            paymentInfo.CreditCardTypeValue,
                            transaction.TransactionDateTime.Value,
                            financialGateway.GetBatchTimeOffset() );

                        var batchChanges = new List<string>();

                        if ( batch.Id == 0 )
                        {
                            batchChanges.Add( "Generated the batch" );
                            History.EvaluateChange( batchChanges, "Batch Name", string.Empty, batch.Name );
                            History.EvaluateChange( batchChanges, "Status", null, batch.Status );
                            History.EvaluateChange( batchChanges, "Start Date/Time", null, batch.BatchStartDateTime );
                            History.EvaluateChange( batchChanges, "End Date/Time", null, batch.BatchEndDateTime );
                        }

                        decimal newControlAmount = batch.ControlAmount + transaction.TotalAmount;
                        History.EvaluateChange( batchChanges, "Control Amount", batch.ControlAmount.FormatAsCurrency(), newControlAmount.FormatAsCurrency() );
                        batch.ControlAmount = newControlAmount;

                        transaction.BatchId = batch.Id;
                        batch.Transactions.Add( transaction );

                        rockContext.SaveChanges();

                        HistoryService.SaveChanges(
                            rockContext,
                            typeof( FinancialBatch ),
                            Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(),
                            batch.Id,
                            batchChanges
                        );

                        HistoryService.SaveChanges(
                            rockContext,
                            typeof( FinancialBatch ),
                            Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(),
                            batch.Id,
                            txnChanges,
                            person.FullName,
                            typeof( FinancialTransaction ),
                            transaction.Id
                        );

                        SendReceipt( transaction.Id );

                        TransactionCode = transaction.TransactionCode;
                    }
                    else
                    {
                        return false;
                    }
                }

                tdTransactionCodeReceipt.Description = TransactionCode;
                tdTransactionCodeReceipt.Visible = !string.IsNullOrWhiteSpace( TransactionCode );

                tdScheduleId.Description = ScheduleId;
                tdScheduleId.Visible = !string.IsNullOrWhiteSpace( ScheduleId );

                tdNameReceipt.Description = paymentInfo.FullName;
                tdPhoneReceipt.Description = paymentInfo.Phone;
                tdEmailReceipt.Description = paymentInfo.Email;
                tdAddressReceipt.Description = string.Format( "{0} {1}, {2} {3}", paymentInfo.Street1, paymentInfo.City, paymentInfo.State, paymentInfo.PostalCode );

                rptAccountListReceipt.DataSource = SelectedAccounts.Where( a => a.Amount != 0 );
                rptAccountListReceipt.DataBind();

                tdTotalReceipt.Description = paymentInfo.Amount.ToString( "C" );

                tdPaymentMethodReceipt.Description = paymentInfo.CurrencyTypeValue.Description;
                tdAccountNumberReceipt.Description = paymentInfo.MaskedNumber;
                tdWhenReceipt.Description = schedule != null ? schedule.ToString() : "Today";

                // If there was a transaction code returned and this was not already created from a previous saved account,
                // show the option to save the account.
                if ( !( paymentInfo is ReferencePaymentInfo ) && !string.IsNullOrWhiteSpace( TransactionCode ) && gateway.SupportsSavedAccount( paymentInfo.CurrencyTypeValue ) )
                {
                    cbSaveAccount.Visible = true;
                    pnlSaveAccount.Visible = true;
                    txtSaveAccount.Visible = true;

                    // If current person does not have a login, have them create a username and password
                    phCreateLogin.Visible = !new UserLoginService( rockContext ).GetByPersonId( person.Id ).Any();
                }
                else
                {
                    pnlSaveAccount.Visible = false;
                }

                return true;
            }
            else
            {
                pnlDupWarning.Visible = true;
                divActions.Visible = false;
                errorMessage = string.Empty;
                return false;
            }
        }
        private bool SaveTransaction( GatewayComponent gateway, Registration registration, FinancialTransaction transaction, PaymentInfo paymentInfo, RockContext rockContext )
        {
            if ( transaction != null )
            {
                var txnChanges = new List<string>();
                txnChanges.Add( "Created Transaction" );

                History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode );

                transaction.AuthorizedPersonAliasId = registration.PersonAliasId;

                transaction.TransactionDateTime = RockDateTime.Now;
                History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime );

                transaction.FinancialGatewayId = RegistrationTemplate.FinancialGatewayId;
                History.EvaluateChange( txnChanges, "Gateway", string.Empty, RegistrationTemplate.FinancialGateway.Name );

                var txnType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_EVENT_REGISTRATION ) );
                transaction.TransactionTypeValueId = txnType.Id;
                History.EvaluateChange( txnChanges, "Type", string.Empty, txnType.Value );

                if ( transaction.FinancialPaymentDetail == null )
                {
                    transaction.FinancialPaymentDetail = new FinancialPaymentDetail();
                }

                DefinedValueCache currencyType = null;
                DefinedValueCache creditCardType = null;

                if ( paymentInfo != null )
                {
                    transaction.FinancialPaymentDetail.SetFromPaymentInfo( paymentInfo, gateway, rockContext, txnChanges );
                    currencyType = paymentInfo.CurrencyTypeValue;
                    creditCardType = paymentInfo.CreditCardTypeValue;
                }

                Guid sourceGuid = Guid.Empty;
                if ( Guid.TryParse( GetAttributeValue( "Source" ), out sourceGuid ) )
                {
                    var source = DefinedValueCache.Read( sourceGuid );
                    if ( source != null )
                    {
                        transaction.SourceTypeValueId = source.Id;
                        History.EvaluateChange( txnChanges, "Source", string.Empty, source.Value );
                    }
                }

                transaction.Summary = registration.GetSummary( RegistrationInstanceState );

                var transactionDetail = new FinancialTransactionDetail();
                transactionDetail.Amount = RegistrationState.PaymentAmount ?? 0.0m;
                transactionDetail.AccountId = RegistrationInstanceState.AccountId.Value;
                transactionDetail.EntityTypeId = EntityTypeCache.Read( typeof( Rock.Model.Registration ) ).Id;
                transactionDetail.EntityId = registration.Id;
                transaction.TransactionDetails.Add( transactionDetail );

                History.EvaluateChange( txnChanges, RegistrationInstanceState.Account.Name, 0.0M.FormatAsCurrency(), transactionDetail.Amount.FormatAsCurrency() );

                var batchChanges = new List<string>();

                rockContext.WrapTransaction( () =>
                {
                    var batchService = new FinancialBatchService( rockContext );

                    // determine batch prefix
                    string batchPrefix = string.Empty;
                    if ( !string.IsNullOrWhiteSpace( RegistrationTemplate.BatchNamePrefix ) )
                    {
                        batchPrefix = RegistrationTemplate.BatchNamePrefix;
                    }
                    else
                    {
                        batchPrefix = GetAttributeValue( "BatchNamePrefix" );
                    }

                    // Get the batch
                    var batch = batchService.Get(
                        batchPrefix,
                        currencyType,
                        creditCardType,
                        transaction.TransactionDateTime.Value,
                        RegistrationTemplate.FinancialGateway.GetBatchTimeOffset() );

                    if ( batch.Id == 0 )
                    {
                        batchChanges.Add( "Generated the batch" );
                        History.EvaluateChange( batchChanges, "Batch Name", string.Empty, batch.Name );
                        History.EvaluateChange( batchChanges, "Status", null, batch.Status );
                        History.EvaluateChange( batchChanges, "Start Date/Time", null, batch.BatchStartDateTime );
                        History.EvaluateChange( batchChanges, "End Date/Time", null, batch.BatchEndDateTime );
                    }

                    decimal newControlAmount = batch.ControlAmount + transaction.TotalAmount;
                    History.EvaluateChange( batchChanges, "Control Amount", batch.ControlAmount.FormatAsCurrency(), newControlAmount.FormatAsCurrency() );
                    batch.ControlAmount = newControlAmount;

                    transaction.BatchId = batch.Id;
                    batch.Transactions.Add( transaction );

                    rockContext.SaveChanges();
                } );

                if ( transaction.BatchId.HasValue )
                {
                    Task.Run( () =>
                        HistoryService.SaveChanges(
                            new RockContext(),
                            typeof( FinancialBatch ),
                            Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(),
                            transaction.BatchId.Value,
                            batchChanges, true, CurrentPersonAliasId )
                    );

                    Task.Run( () =>
                        HistoryService.SaveChanges(
                            new RockContext(),
                            typeof( FinancialBatch ),
                            Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(),
                            transaction.BatchId.Value,
                            txnChanges,
                            CurrentPerson != null ? CurrentPerson.FullName : string.Empty,
                            typeof( FinancialTransaction ),
                            transaction.Id, true, CurrentPersonAliasId )
                    );
                }

                List<string> registrationChanges = new List<string>();
                registrationChanges.Add( string.Format( "Made {0} payment", transaction.TotalAmount.FormatAsCurrency() ) );
                Task.Run( () =>
                    HistoryService.SaveChanges(
                        new RockContext(),
                        typeof( Registration ),
                        Rock.SystemGuid.Category.HISTORY_EVENT_REGISTRATION.AsGuid(),
                        registration.Id,
                        registrationChanges, true, CurrentPersonAliasId )
                );

                TransactionCode = transaction.TransactionCode;

                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// Processes the payments.
        /// </summary>
        /// <param name="gateway">The gateway.</param>
        /// <param name="batchNamePrefix">The batch name prefix.</param>
        /// <param name="payments">The payments.</param>
        /// <param name="batchUrlFormat">The batch URL format.</param>
        /// <returns></returns>
        public static string ProcessPayments( FinancialGateway gateway, string batchNamePrefix, List<Payment> payments, string batchUrlFormat = "" )
        {
            int totalPayments = 0;
            int totalAlreadyDownloaded = 0;
            int totalNoScheduledTransaction = 0;
            int totalAdded = 0;

            var batches = new List<FinancialBatch>();
            var batchSummary = new Dictionary<Guid, List<Payment>>();
            var initialControlAmounts = new Dictionary<Guid, decimal>();

            var allBatchChanges = new Dictionary<Guid, List<string>>();
            var allTxnChanges = new Dictionary<Guid, List<string>>();
            var txnPersonNames = new Dictionary<Guid, string>();

            using ( var rockContext = new RockContext() )
            {
                var accountService = new FinancialAccountService( rockContext );
                var txnService = new FinancialTransactionService( rockContext );
                var batchService = new FinancialBatchService( rockContext );
                var scheduledTxnService = new FinancialScheduledTransactionService( rockContext );

                var contributionTxnType = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid() );

                var defaultAccount = accountService.Queryable()
                    .Where( a =>
                        a.IsActive &&
                        !a.ParentAccountId.HasValue &&
                        ( !a.StartDate.HasValue || a.StartDate.Value <= RockDateTime.Now ) &&
                        ( !a.EndDate.HasValue || a.EndDate.Value >= RockDateTime.Now )
                        )
                    .OrderBy( a => a.Order )
                    .FirstOrDefault();

                var batchTxnChanges = new Dictionary<Guid, List<string>>();
                var batchBatchChanges = new Dictionary<Guid, List<string>>();

                foreach ( var payment in payments.Where( p => p.Amount > 0.0M ) )
                {
                    totalPayments++;

                    // Only consider transactions that have not already been added
                    if ( txnService.GetByTransactionCode( payment.TransactionCode ) == null )
                    {
                        var scheduledTransaction = scheduledTxnService.GetByScheduleId( payment.GatewayScheduleId );
                        if ( scheduledTransaction != null )
                        {
                            scheduledTransaction.IsActive = payment.ScheduleActive;

                            var txnChanges = new List<string>();

                            var transaction = new FinancialTransaction();
                            transaction.FinancialPaymentDetail = new FinancialPaymentDetail();

                            transaction.Guid = Guid.NewGuid();
                            allTxnChanges.Add( transaction.Guid, txnChanges );
                            txnChanges.Add( "Created Transaction (Downloaded from Gateway)" );

                            transaction.TransactionCode = payment.TransactionCode;
                            History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode );

                            transaction.TransactionDateTime = payment.TransactionDateTime;
                            History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime );

                            transaction.ScheduledTransactionId = scheduledTransaction.Id;

                            transaction.AuthorizedPersonAliasId = scheduledTransaction.AuthorizedPersonAliasId;
                            History.EvaluateChange( txnChanges, "Person", string.Empty, scheduledTransaction.AuthorizedPersonAlias.Person.FullName );
                            txnPersonNames.Add( transaction.Guid, scheduledTransaction.AuthorizedPersonAlias.Person.FullName );

                            transaction.FinancialGatewayId = gateway.Id;
                            History.EvaluateChange( txnChanges, "Gateway", string.Empty, gateway.Name );

                            transaction.TransactionTypeValueId = contributionTxnType.Id;
                            History.EvaluateChange( txnChanges, "Type", string.Empty, contributionTxnType.Value );

                            var currencyTypeValue = payment.CurrencyTypeValue;
                            var creditCardTypevalue = payment.CreditCardTypeValue;

                            if ( scheduledTransaction.FinancialPaymentDetail != null )
                            {
                                if ( currencyTypeValue == null && scheduledTransaction.FinancialPaymentDetail.CurrencyTypeValueId.HasValue )
                                {
                                    currencyTypeValue = DefinedValueCache.Read( scheduledTransaction.FinancialPaymentDetail.CurrencyTypeValueId.Value );
                                }

                                if ( creditCardTypevalue == null && scheduledTransaction.FinancialPaymentDetail.CreditCardTypeValueId.HasValue )
                                {
                                    creditCardTypevalue = DefinedValueCache.Read( scheduledTransaction.FinancialPaymentDetail.CreditCardTypeValueId.Value );
                                }

                                transaction.FinancialPaymentDetail.AccountNumberMasked = scheduledTransaction.FinancialPaymentDetail.AccountNumberMasked;
                                transaction.FinancialPaymentDetail.NameOnCardEncrypted = scheduledTransaction.FinancialPaymentDetail.NameOnCardEncrypted;
                                transaction.FinancialPaymentDetail.ExpirationMonthEncrypted = scheduledTransaction.FinancialPaymentDetail.ExpirationMonthEncrypted;
                                transaction.FinancialPaymentDetail.ExpirationYearEncrypted = scheduledTransaction.FinancialPaymentDetail.ExpirationYearEncrypted;
                            }

                            if ( currencyTypeValue != null )
                            {
                                transaction.FinancialPaymentDetail.CurrencyTypeValueId = currencyTypeValue.Id;
                                History.EvaluateChange( txnChanges, "Currency Type", string.Empty, currencyTypeValue.Value );
                            }
                            if ( creditCardTypevalue != null )
                            {
                                transaction.FinancialPaymentDetail.CreditCardTypeValueId = creditCardTypevalue.Id;
                                History.EvaluateChange( txnChanges, "Credit Card Type", string.Empty, creditCardTypevalue.Value );
                            }

                            //transaction.SourceTypeValueId = DefinedValueCache.Read( sourceGuid ).Id;

                            // Try to allocate the amount of the transaction based on the current scheduled transaction accounts
                            decimal remainingAmount = payment.Amount;
                            foreach ( var detail in scheduledTransaction.ScheduledTransactionDetails.Where( d => d.Amount != 0.0M ) )
                            {
                                var transactionDetail = new FinancialTransactionDetail();
                                transactionDetail.AccountId = detail.AccountId;

                                if ( detail.Amount <= remainingAmount )
                                {
                                    // If the configured amount for this account is less than or equal to the remaining
                                    // amount, allocate the configured amount
                                    transactionDetail.Amount = detail.Amount;
                                    remainingAmount -= detail.Amount;
                                }
                                else
                                {
                                    // If the configured amount is greater than the remaining amount, only allocate
                                    // the remaining amount
                                    transaction.Summary = "Note: Downloaded transaction amount was less than the configured allocation amounts for the Scheduled Transaction.";
                                    detail.Amount = remainingAmount;
                                    detail.Summary = "Note: The downloaded amount was not enough to apply the configured amount to this account.";
                                    remainingAmount = 0.0M;
                                }

                                transaction.TransactionDetails.Add( transactionDetail );

                                History.EvaluateChange( txnChanges, detail.Account.Name, 0.0M.ToString( "C2" ), transactionDetail.Amount.ToString( "C2" ) );
                                History.EvaluateChange( txnChanges, "Summary", string.Empty, transactionDetail.Summary );

                                if ( remainingAmount <= 0.0M )
                                {
                                    // If there's no amount left, break out of details
                                    break;
                                }
                            }

                            // If there's still amount left after allocating based on current config, add the remainder
                            // to the account that was configured for the most amount
                            if ( remainingAmount > 0.0M )
                            {
                                transaction.Summary = "Note: Downloaded transaction amount was greater than the configured allocation amounts for the Scheduled Transaction.";
                                var transactionDetail = transaction.TransactionDetails
                                    .OrderByDescending( d => d.Amount )
                                    .First();
                                if ( transactionDetail == null && defaultAccount != null )
                                {
                                    transactionDetail = new FinancialTransactionDetail();
                                    transactionDetail.AccountId = defaultAccount.Id;
                                }
                                if ( transactionDetail != null )
                                {
                                    transactionDetail.Amount += remainingAmount;
                                    transactionDetail.Summary = "Note: Extra amount was applied to this account.";
                                }

                                History.EvaluateChange( txnChanges, defaultAccount.Name, 0.0M.ToString( "C2" ), transactionDetail.Amount.ToString( "C2" ) );
                                History.EvaluateChange( txnChanges, "Summary", string.Empty, transactionDetail.Summary );
                            }

                            // Get the batch
                            var batch = batchService.Get(
                                batchNamePrefix,
                                currencyTypeValue,
                                creditCardTypevalue,
                                transaction.TransactionDateTime.Value,
                                gateway.GetBatchTimeOffset(),
                                batches );

                            var batchChanges = new List<string>();
                            if ( batch.Id != 0 )
                            {
                                initialControlAmounts.AddOrIgnore( batch.Guid, batch.ControlAmount );
                            }
                            batch.ControlAmount += transaction.TotalAmount;

                            batch.Transactions.Add( transaction );

                            // Add summary
                            if ( !batchSummary.ContainsKey( batch.Guid ) )
                            {
                                batchSummary.Add( batch.Guid, new List<Payment>() );
                            }
                            batchSummary[batch.Guid].Add( payment );

                            totalAdded++;
                        }
                        else
                        {
                            totalNoScheduledTransaction++;
                        }
                    }
                    else
                    {
                        totalAlreadyDownloaded++;
                    }
                }

                foreach ( var batch in batches )
                {
                    var batchChanges = new List<string>();
                    allBatchChanges.Add( batch.Guid, batchChanges );

                    if ( batch.Id == 0 )
                    {
                        batchChanges.Add( "Generated the batch" );
                        History.EvaluateChange( batchChanges, "Batch Name", string.Empty, batch.Name );
                        History.EvaluateChange( batchChanges, "Status", null, batch.Status );
                        History.EvaluateChange( batchChanges, "Start Date/Time", null, batch.BatchStartDateTime );
                        History.EvaluateChange( batchChanges, "End Date/Time", null, batch.BatchEndDateTime );
                    }

                    if ( initialControlAmounts.ContainsKey( batch.Guid ) )
                    {
                        History.EvaluateChange( batchChanges, "Control Amount", initialControlAmounts[batch.Guid].ToString( "C2" ), batch.ControlAmount.ToString( "C2" ) );
                    }
                }

                rockContext.WrapTransaction( () =>
                {
                    rockContext.SaveChanges();

                    foreach ( var batch in batches )
                    {
                        HistoryService.SaveChanges(
                            rockContext,
                            typeof( FinancialBatch ),
                            Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(),
                            batch.Id,
                            allBatchChanges[batch.Guid]
                        );

                        foreach ( var transaction in batch.Transactions )
                        {
                            if ( allTxnChanges.ContainsKey( transaction.Guid ) )
                            {
                                HistoryService.SaveChanges(
                                    rockContext,
                                    typeof( FinancialBatch ),
                                    Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(),
                                    batch.Id,
                                    allTxnChanges[transaction.Guid],
                                    txnPersonNames[transaction.Guid],
                                    typeof( FinancialTransaction ),
                                    transaction.Id
                                );
                            }
                        }
                    }

                    rockContext.SaveChanges();
                } );
            }

            StringBuilder sb = new StringBuilder();
            sb.AppendFormat( "<li>{0} {1} downloaded.</li>", totalPayments.ToString( "N0" ),
                ( totalPayments == 1 ? "payment" : "payments" ) );

            if ( totalAlreadyDownloaded > 0 )
            {
                sb.AppendFormat( "<li>{0} {1} previously downloaded and {2} already been added.</li>", totalAlreadyDownloaded.ToString( "N0" ),
                    ( totalAlreadyDownloaded == 1 ? "payment was" : "payments were" ),
                    ( totalAlreadyDownloaded == 1 ? "has" : "have" ) );
            }

            if ( totalNoScheduledTransaction > 0 )
            {
                sb.AppendFormat( "<li>{0} {1} could not be matched to an existing scheduled payment profile.</li>", totalNoScheduledTransaction.ToString( "N0" ),
                    ( totalNoScheduledTransaction == 1 ? "payment" : "payments" ) );
            }

            sb.AppendFormat( "<li>{0} {1} successfully added.</li>", totalAdded.ToString( "N0" ),
                ( totalAdded == 1 ? "payment was" : "payments were" ) );

            foreach ( var batchItem in batchSummary )
            {
                int items = batchItem.Value.Count;
                if (items > 0)
                {
                    var batch = batches
                        .Where( b => b.Guid.Equals( batchItem.Key ) )
                        .FirstOrDefault();

                    string batchName = string.Format("'{0} ({1})'", batch.Name, batch.BatchStartDateTime.Value.ToString("d"));
                    if ( !string.IsNullOrWhiteSpace( batchUrlFormat ) )
                    {
                        batchName = string.Format( "<a href='{0}'>{1}</a>", string.Format( batchUrlFormat, batch.Id ), batchName );
                    }

                    decimal sum = batchItem.Value.Select( p => p.Amount ).Sum();

                    string summaryformat = items == 1 ?
                        "<li>{0} transaction of {1} was added to the {2} batch.</li>" :
                        "<li>{0} transactions totaling {1} were added to the {2} batch</li>";

                    sb.AppendFormat( summaryformat, items.ToString( "N0" ), sum.ToString( "C2" ), batchName );
                }
            }

            return sb.ToString();
        }
Beispiel #23
0
        /// <summary>
        /// This method stores the transaction in the database along with the appropriate details and batch information.
        /// </summary>
        private FinancialTransaction SaveTransaction(Guid transactionGuid)
        {
            // if this is a future transaction, the payment hasn't been charged yet
            if (_payment == null && _automatedPaymentArgs.FutureProcessingDateTime.HasValue)
            {
                _payment = new Payment
                {
                    Status          = "PreProcessing",
                    StatusMessage   = "This transaction is scheduled to be processed in the future",
                    TransactionCode = _financialPersonSavedAccount.Id.ToStringSafe()
                };
            }

            // Create a new transaction or update the future transaction now that it has been charged
            var financialTransaction = _futureTransaction ?? new FinancialTransaction();

            financialTransaction.TransactionCode          = _payment.TransactionCode;
            financialTransaction.Guid                     = transactionGuid;
            financialTransaction.CreatedByPersonAliasId   = _currentPersonAliasId;
            financialTransaction.ScheduledTransactionId   = _automatedPaymentArgs.ScheduledTransactionId;
            financialTransaction.AuthorizedPersonAliasId  = _automatedPaymentArgs.AuthorizedPersonAliasId;
            financialTransaction.ShowAsAnonymous          = _automatedPaymentArgs.ShowAsAnonymous;
            financialTransaction.TransactionDateTime      = _automatedPaymentArgs.FutureProcessingDateTime.HasValue ? ( DateTime? )null : RockDateTime.Now;
            financialTransaction.FinancialGatewayId       = _financialGateway.Id;
            financialTransaction.TransactionTypeValueId   = _transactionType.Id;
            financialTransaction.Summary                  = string.Format("{0} {1}", financialTransaction.Summary, _referencePaymentInfo.Comment1).Trim();
            financialTransaction.SourceTypeValueId        = _financialSource.Id;
            financialTransaction.IsSettled                = _payment.IsSettled;
            financialTransaction.Status                   = _payment.Status;
            financialTransaction.StatusMessage            = _payment.StatusMessage;
            financialTransaction.SettledDate              = _payment.SettledDate;
            financialTransaction.ForeignKey               = _payment.ForeignKey;
            financialTransaction.FutureProcessingDateTime = _automatedPaymentArgs.FutureProcessingDateTime;


            financialTransaction.ForeignCurrencyCodeValueId = GetCurrencyCodeDefinedValueCache(_automatedPaymentArgs.AmountCurrencyCode)?.Id;

            // Create a new payment detail or update the future transaction's payment detail now that it has been charged
            var financialPaymentDetail = financialTransaction.FinancialPaymentDetail ?? new FinancialPaymentDetail();

            financialPaymentDetail.AccountNumberMasked           = _payment.AccountNumberMasked;
            financialPaymentDetail.NameOnCard                    = _payment.NameOnCard;
            financialPaymentDetail.ExpirationMonth               = _payment.ExpirationMonth;
            financialPaymentDetail.ExpirationYear                = _payment.ExpirationYear;
            financialPaymentDetail.CreatedByPersonAliasId        = _currentPersonAliasId;
            financialPaymentDetail.ForeignKey                    = _payment.ForeignKey;
            financialPaymentDetail.GatewayPersonIdentifier       = _financialPersonSavedAccount?.GatewayPersonIdentifier;
            financialPaymentDetail.FinancialPersonSavedAccountId = _financialPersonSavedAccount?.Id;

            if (_payment.CurrencyTypeValue != null)
            {
                financialPaymentDetail.CurrencyTypeValueId = _payment.CurrencyTypeValue.Id;
            }

            if (_payment.CreditCardTypeValue != null)
            {
                financialPaymentDetail.CreditCardTypeValueId = _payment.CreditCardTypeValue.Id;
            }

            financialPaymentDetail.SetFromPaymentInfo(_referencePaymentInfo, _automatedGatewayComponent, _rockContext);
            financialTransaction.FinancialPaymentDetail   = financialPaymentDetail;
            financialTransaction.FinancialPaymentDetailId = financialPaymentDetail.Id == 0 ? ( int? )null : financialPaymentDetail.Id;

            // Future transactions already have the appropriate FinancialTransactionDetail models
            if (_futureTransaction == null)
            {
                var doesHaveForeignCurrency = financialTransaction.ForeignCurrencyCodeValueId != null;

                foreach (var detailArgs in _automatedPaymentArgs.AutomatedPaymentDetails)
                {
                    var transactionDetail = new FinancialTransactionDetail
                    {
                        Amount    = detailArgs.Amount,
                        AccountId = detailArgs.AccountId
                    };

                    if (doesHaveForeignCurrency)
                    {
                        transactionDetail.ForeignCurrencyAmount = detailArgs.Amount;
                    }

                    financialTransaction.TransactionDetails.Add(transactionDetail);
                }

                if (doesHaveForeignCurrency)
                {
                    /*
                     * The amount coming from the gateway is always in the Organization's currency.
                     * As such the Amount value could be different than the original amount passed in if the
                     * specified currency code is different then the Organization's currency code.
                     */
                    financialTransaction.SetApportionedDetailAmounts(_payment.Amount);
                }
            }

            // New transactions and future transactions need fee info
            financialTransaction.SetApportionedFeesOnDetails(_payment.FeeAmount);

            // Get an existing or new batch according to the name prefix and payment type
            FinancialBatch batch;

            if (!financialTransaction.BatchId.HasValue)
            {
                batch = _financialBatchService.Get(
                    _automatedPaymentArgs.BatchNamePrefix ?? "Online Giving",
                    string.Empty,
                    _referencePaymentInfo.CurrencyTypeValue,
                    _referencePaymentInfo.CreditCardTypeValue,
                    financialTransaction.TransactionDateTime ?? financialTransaction.FutureProcessingDateTime.Value,
                    _financialGateway.GetBatchTimeOffset(),
                    _financialGateway.BatchDayOfWeek);
            }
            else
            {
                batch = _financialBatchService.Get(financialTransaction.BatchId.Value);
            }

            var batchChanges = new History.HistoryChangeList();
            var isNewBatch   = batch.Id == 0;

            // If this is a new Batch, SaveChanges so that we can get the Batch.Id and also
            // add history entries about the batch creation
            if (isNewBatch)
            {
                batchChanges.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Batch");
                History.EvaluateChange(batchChanges, "Batch Name", string.Empty, batch.Name);
                History.EvaluateChange(batchChanges, "Status", null, batch.Status);
                History.EvaluateChange(batchChanges, "Start Date/Time", null, batch.BatchStartDateTime);
                History.EvaluateChange(batchChanges, "End Date/Time", null, batch.BatchEndDateTime);

                _rockContext.SaveChanges();
            }

            if (_futureTransaction == null)
            {
                // Use the financialTransactionService to add the transaction instead of batch.Transactions
                // to avoid lazy-loading the transactions already associated with the batch
                financialTransaction.BatchId = batch.Id;
                _financialTransactionService.Add(financialTransaction);
            }

            _rockContext.SaveChanges();

            if (_futureTransaction == null)
            {
                // Update the batch control amount
                _financialBatchService.IncrementControlAmount(batch.Id, financialTransaction.TotalAmount, batchChanges);
                _rockContext.SaveChanges();
            }

            // Save the changes history for the batch
            HistoryService.SaveChanges(
                _rockContext,
                typeof(FinancialBatch),
                SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(),
                batch.Id,
                batchChanges
                );

            return(financialTransaction);
        }
Beispiel #24
0
        /// <summary>
        /// Exports any contributions.
        /// </summary>
        public static void ExportContributions()
        {
            try
            {
                // Retrieve & Output the Fund Accounts
                using (var dtFunds = GetTableData(SQL_FINANCIAL_ACCOUNTS))
                {
                    foreach (DataRow row in dtFunds.Rows)
                    {
                        FinancialAccount account = SkFinancialAccount.Translate(row);
                        if (account is null)
                        {
                            continue;
                        }

                        ImportPackage.WriteToPackage(account);
                    }
                }

                // Retrieve & Output the Batches
                using (var dtBatches = GetTableData(SQL_FINANCIAL_BATCHES))
                {
                    foreach (DataRow row in dtBatches.Rows)
                    {
                        FinancialBatch batch = SkFinancialBatch.Translate(row);
                        if (batch is null)
                        {
                            continue;
                        }

                        ImportPackage.WriteToPackage(batch);
                    }
                }

                // Retrieve & Output the Contributions
                using (var dtContributions = GetTableData(SQL_FINANCIAL_CONTRIBUTIONS))
                {
                    foreach (DataRow row in dtContributions.Rows)
                    {
                        FinancialTransaction transaction = SkFinancialContribution.Translate(row);
                        if (transaction is null)
                        {
                            continue;
                        }

                        ImportPackage.WriteToPackage(transaction);
                    }
                }

                // Retrieve & Output the Contribution Details
                using (var dtContributionDetails = GetTableData(SQL_FINANCIAL_CONTRIBUTIONDETAILS))
                {
                    foreach (DataRow row in dtContributionDetails.Rows)
                    {
                        FinancialTransactionDetail details = SkFinancialContributionDetail.Translate(row);
                        if (details is null)
                        {
                            continue;
                        }

                        ImportPackage.WriteToPackage(details);
                    }
                }
            }
            catch (Exception ex)
            {
                ErrorMessage = ex.Message;
            }
        }
Beispiel #25
0
        /// <summary>
        /// Processes the confirmation.
        /// </summary>
        /// <param name="errorMessage">The error message.</param>
        /// <returns></returns>
        private bool ProcessConfirmation( out string errorMessage )
        {
            if ( string.IsNullOrWhiteSpace( TransactionCode ) )
            {
                GatewayComponent gateway = hfPaymentTab.Value == "ACH" ? _achGateway : _ccGateway;
                if ( gateway == null )
                {
                    errorMessage = "There was a problem creating the payment gateway information";
                    return false;
                }

                Person person = GetPerson( true );
                if ( person == null )
                {
                    errorMessage = "There was a problem creating the person information";
                    return false;
                }

                PaymentInfo paymentInfo = GetPaymentInfo();
                if ( paymentInfo == null )
                {
                    errorMessage = "There was a problem creating the payment information";
                    return false;
                }
                else
                {
                    paymentInfo.FirstName = person.FirstName;
                    paymentInfo.LastName = person.LastName;
                }

                if ( paymentInfo.CreditCardTypeValue != null )
                {
                    CreditCardTypeValueId = paymentInfo.CreditCardTypeValue.Id;
                } 

                PaymentSchedule schedule = GetSchedule();
                if ( schedule != null )
                {
                    schedule.PersonId = person.Id;

                    var scheduledTransaction = gateway.AddScheduledPayment( schedule, paymentInfo, out errorMessage );
                    if ( scheduledTransaction != null )
                    {
                        scheduledTransaction.TransactionFrequencyValueId = schedule.TransactionFrequencyValue.Id;
                        scheduledTransaction.AuthorizedPersonId = person.Id;
                        scheduledTransaction.GatewayEntityTypeId = EntityTypeCache.Read( gateway.TypeGuid ).Id;

                        foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) )
                        {
                            var transactionDetail = new FinancialScheduledTransactionDetail();
                            transactionDetail.Amount = account.Amount;
                            transactionDetail.AccountId = account.Id;
                            scheduledTransaction.ScheduledTransactionDetails.Add( transactionDetail );
                        }

                        var transactionService = new FinancialScheduledTransactionService();
                        transactionService.Add( scheduledTransaction, CurrentPersonId );
                        transactionService.Save( scheduledTransaction, CurrentPersonId );

                        ScheduleId = scheduledTransaction.GatewayScheduleId;
                        TransactionCode = scheduledTransaction.TransactionCode;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    var transaction = gateway.Charge( paymentInfo, out errorMessage );
                    if ( transaction != null )
                    {
                        transaction.TransactionDateTime = DateTime.Now;
                        transaction.AuthorizedPersonId = person.Id;
                        transaction.GatewayEntityTypeId = gateway.TypeId;
                        transaction.Amount = paymentInfo.Amount;
                        transaction.TransactionTypeValueId = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION)).Id;
                        transaction.CurrencyTypeValueId = paymentInfo.CurrencyTypeValue.Id;
                        transaction.CreditCardTypeValueId = CreditCardTypeValueId;

                        Guid sourceGuid = Guid.Empty;
                        if (Guid.TryParse(GetAttributeValue("Source"), out sourceGuid))
                        {
                            transaction.SourceTypeValueId = DefinedValueCache.Read(sourceGuid).Id;
                        }
                        foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) )
                        {
                            var transactionDetail = new FinancialTransactionDetail();
                            transactionDetail.Amount = account.Amount;
                            transactionDetail.AccountId = account.Id;
                            transaction.TransactionDetails.Add( transactionDetail );
                        }

                        // Get the batch name
                        string ccSuffix = string.Empty;
                        if ( paymentInfo.CreditCardTypeValue != null )
                        {
                            ccSuffix = paymentInfo.CreditCardTypeValue.GetAttributeValue( "BatchNameSuffix" );
                        }
                        if ( string.IsNullOrWhiteSpace( ccSuffix ) )
                        {
                            ccSuffix = paymentInfo.CurrencyTypeValue.Name;
                        }
                        string batchName = GetAttributeValue( "BatchNamePrefix" ).Trim() + " " + ccSuffix;

                        using ( new UnitOfWorkScope() )
                        {
                            var batchService = new FinancialBatchService();
                            var batch = batchService.Queryable()
                                .Where( b =>
                                    b.Status == BatchStatus.Open &&
                                    b.BatchStartDateTime <= transaction.TransactionDateTime &&
                                    b.BatchEndDateTime > transaction.TransactionDateTime &&
                                    b.Name == batchName )
                                .FirstOrDefault();
                            if ( batch == null )
                            {
                                batch = new FinancialBatch();
                                batch.Name = batchName;
                                batch.Status = BatchStatus.Open;
                                batch.BatchStartDateTime = transaction.TransactionDateTime.Value.Date.Add( gateway.BatchTimeOffset );
                                if ( batch.BatchStartDateTime > transaction.TransactionDateTime )
                                {
                                    batch.BatchStartDateTime.Value.AddDays( -1 );
                                }
                                batch.BatchEndDateTime = batch.BatchStartDateTime.Value.AddDays( 1 ).AddMilliseconds( -1 );
                                batch.CreatedByPersonId = person.Id;
                                batchService.Add( batch, CurrentPersonId );
                                batchService.Save( batch, CurrentPersonId );

                                batch = batchService.Get( batch.Id );
                            }

                            batch.ControlAmount += transaction.Amount;
                            batchService.Save( batch, CurrentPersonId );

                            var transactionService = new FinancialTransactionService();
                            transaction.BatchId = batch.Id;
                            transactionService.Add( transaction, CurrentPersonId );
                            transactionService.Save( transaction, CurrentPersonId );
                        }

                        TransactionCode = transaction.TransactionCode;
                    }
                    else
                    {
                        return false;
                    }
                }

                tdTransactionCode.Description = TransactionCode;
                tdTransactionCode.Visible = !string.IsNullOrWhiteSpace( TransactionCode );

                tdScheduleId.Description = ScheduleId;
                tdScheduleId.Visible = !string.IsNullOrWhiteSpace( ScheduleId );

                // If there was a transaction code returned and this was not already created from a previous saved account, 
                // show the option to save the account.
                if ( !( paymentInfo is ReferencePaymentInfo ) && !string.IsNullOrWhiteSpace( TransactionCode ) )
                {
                    cbSaveAccount.Visible = true;
                    pnlSaveAccount.Visible = true;
                    txtSaveAccount.Visible = true;

                    // If current person does not have a login, have them create a username and password
                    phCreateLogin.Visible = !new UserLoginService().GetByPersonId( person.Id ).Any();
                }
                else
                {
                    pnlSaveAccount.Visible = false;
                }

                return true;
            }
            else
            {
                pnlDupWarning.Visible = true;
                errorMessage = string.Empty;
                return false;
            }
        }
        /// <summary>
        /// Handles the SaveClick event of the mdRefund control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void mdRefund_SaveClick( object sender, EventArgs e )
        {
            decimal refundAmount = tbRefundAmount.Text.AsDecimal();
            if ( refundAmount > 0.0m )
            {
                int? txnId = hfTransactionId.Value.AsIntegerOrNull();
                if ( txnId.HasValue )
                {
                    using ( var rockContext = new RockContext() )
                    {
                        var txnService = new FinancialTransactionService( rockContext );
                        var txn = txnService.Get( txnId.Value );
                        if ( txn != null && txn.Batch != null )
                        {
                            FinancialTransaction refundTxn = null;

                            if ( !string.IsNullOrWhiteSpace( txn.TransactionCode ) && txn.FinancialGateway != null &&
                                cbProcess.Visible && cbProcess.Checked )
                            {
                                var gateway = txn.FinancialGateway.GetGatewayComponent();
                                if ( gateway != null )
                                {
                                    string errorMessage = string.Empty;
                                    refundTxn = gateway.Credit( txn, refundAmount, tbRefundSummary.Text, out errorMessage );
                                    if ( refundTxn == null )
                                    {
                                        nbRefundError.Title = "Refund Error";
                                        nbRefundError.Text = string.Format( "<p>{0}</p>", errorMessage );
                                        nbRefundError.Visible = true;
                                        return;
                                    }
                                }
                                else
                                {
                                    nbRefundError.Title = "Gateway Error";
                                    nbRefundError.Text = "<p>Transaction has a valid gateway, but we could not use it.</p>";
                                    nbRefundError.Visible = true;
                                    return;
                                }
                            }
                            else
                            {
                                refundTxn = new FinancialTransaction();
                            }

                            refundTxn.AuthorizedPersonAliasId = txn.AuthorizedPersonAliasId;
                            refundTxn.TransactionDateTime = RockDateTime.Now;
                            refundTxn.FinancialGatewayId = txn.FinancialGatewayId;
                            refundTxn.TransactionTypeValueId = txn.TransactionTypeValueId;
                            if ( txn.FinancialPaymentDetail != null )
                            {
                                refundTxn.FinancialPaymentDetail = new FinancialPaymentDetail();
                                refundTxn.FinancialPaymentDetail.AccountNumberMasked = txn.FinancialPaymentDetail.AccountNumberMasked;
                                refundTxn.FinancialPaymentDetail.BillingLocationId = txn.FinancialPaymentDetail.BillingLocationId;
                                refundTxn.FinancialPaymentDetail.CreditCardTypeValueId = txn.FinancialPaymentDetail.CreditCardTypeValueId;
                                refundTxn.FinancialPaymentDetail.CurrencyTypeValueId = txn.FinancialPaymentDetail.CurrencyTypeValueId;
                                refundTxn.FinancialPaymentDetail.ExpirationMonthEncrypted = txn.FinancialPaymentDetail.ExpirationMonthEncrypted;
                                refundTxn.FinancialPaymentDetail.ExpirationYearEncrypted = txn.FinancialPaymentDetail.ExpirationYearEncrypted;
                                refundTxn.FinancialPaymentDetail.NameOnCardEncrypted = txn.FinancialPaymentDetail.NameOnCardEncrypted;
                            }

                            decimal remBalance = refundAmount;
                            foreach ( var account in txn.TransactionDetails.Where( a => a.Amount > 0 ) )
                            {
                                var transactionDetail = new FinancialTransactionDetail();
                                transactionDetail.AccountId = account.AccountId;
                                transactionDetail.EntityId = account.EntityId;
                                transactionDetail.EntityTypeId = account.EntityTypeId;
                                refundTxn.TransactionDetails.Add( transactionDetail );

                                if ( remBalance >= account.Amount )
                                {
                                    transactionDetail.Amount = 0 - account.Amount;
                                    remBalance -= account.Amount;
                                }
                                else
                                {
                                    transactionDetail.Amount = 0 - remBalance;
                                    remBalance = 0.0m;
                                }

                                if ( remBalance <= 0.0m )
                                {
                                    break;
                                }
                            }

                            if ( remBalance > 0 && refundTxn.TransactionDetails.Any() )
                            {
                                refundTxn.TransactionDetails.Last().Amount += remBalance;
                            }

                            var registrationEntityType = EntityTypeCache.Read( typeof( Rock.Model.Registration ) );
                            if ( registrationEntityType != null )
                            {
                                foreach ( var transactionDetail in refundTxn.TransactionDetails
                                    .Where( d =>
                                        d.EntityTypeId.HasValue &&
                                        d.EntityTypeId.Value == registrationEntityType.Id &&
                                        d.EntityId.HasValue ) )
                                {
                                    var registrationChanges = new List<string>();
                                    registrationChanges.Add( string.Format( "Processed refund for {0}.", transactionDetail.Amount.FormatAsCurrency() ) );
                                    HistoryService.SaveChanges(
                                        rockContext,
                                        typeof( Registration ),
                                        Rock.SystemGuid.Category.HISTORY_EVENT_REGISTRATION.AsGuid(),
                                        transactionDetail.EntityId.Value,
                                        registrationChanges
                                    );
                                }
                            }

                            refundTxn.RefundDetails = new FinancialTransactionRefund();
                            refundTxn.RefundDetails.RefundReasonValueId = ddlRefundReason.SelectedValueAsId();
                            refundTxn.RefundDetails.RefundReasonSummary = tbRefundSummary.Text;
                            refundTxn.RefundDetails.OriginalTransactionId = txn.Id;

                            string batchName = txn.Batch.Name;
                            string suffix = GetAttributeValue( "RefundBatchNameSuffix" );
                            if ( !string.IsNullOrWhiteSpace( suffix ) && !batchName.EndsWith( suffix ) )
                            {
                                batchName += suffix;
                            }

                            // Get the batch
                            var batchService = new FinancialBatchService( rockContext );
                            TimeSpan timespan = new TimeSpan();
                            if ( txn.FinancialGateway != null )
                            {
                                timespan = txn.FinancialGateway.GetBatchTimeOffset();
                            }
                            var batch = batchService.GetByNameAndDate( batchName, refundTxn.TransactionDateTime.Value, timespan );
                            decimal controlAmount = batch.ControlAmount + refundTxn.TotalAmount;
                            batch.ControlAmount = controlAmount;

                            refundTxn.BatchId = batch.Id;
                            batch.Transactions.Add( refundTxn );

                            rockContext.SaveChanges();

                            var updatedTxn = GetTransaction( txn.Id );
                            if ( updatedTxn != null )
                            {
                                updatedTxn.LoadAttributes( rockContext );
                                updatedTxn.FinancialPaymentDetail.LoadAttributes(rockContext);
                                ShowReadOnlyDetails( updatedTxn );
                            }
                        }
                        else
                        {
                            nbRefundError.Title = "Transaction Error";
                            nbRefundError.Text = "<p>Existing transaction does not hava a valid batch.</p>";
                            nbRefundError.Visible = true;
                            return;
                        }

                    }
                }
            }

            HideDialog();
        }
        /// <summary>
        /// Handles the SaveClick event of the mdAccount control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void mdAccount_SaveClick( object sender, EventArgs e )
        {
            Guid? guid = hfAccountGuid.Value.AsGuidOrNull();
            if ( guid.HasValue )
            {
                var txnDetail = TransactionDetailsState.Where( t => t.Guid.Equals( guid.Value ) ).FirstOrDefault();
                if ( txnDetail == null )
                {
                    txnDetail = new FinancialTransactionDetail();
                    TransactionDetailsState.Add( txnDetail );
                }
                txnDetail.AccountId = apAccount.SelectedValue.AsInteger();
                txnDetail.Amount = tbAccountAmount.Text.AsDecimal();
                txnDetail.Summary = tbAccountSummary.Text;

                txnDetail.LoadAttributes();
                Rock.Attribute.Helper.GetEditValues( phAccountAttributeEdits, txnDetail );
                foreach ( var attributeValue in txnDetail.AttributeValues )
                {
                    txnDetail.SetAttributeValue( attributeValue.Key, attributeValue.Value.Value );
                }

                BindAccounts();
            }

            HideDialog();
        }
        /// <summary>
        /// Handles the Click event of the lbSave control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void lbSave_Click( object sender, EventArgs e )
        {
            var rockContext = new RockContext();

            var txnService = new FinancialTransactionService( rockContext );
            var txnDetailService = new FinancialTransactionDetailService( rockContext );
            var txnImageService = new FinancialTransactionImageService( rockContext );
            var binaryFileService = new BinaryFileService( rockContext );

            FinancialTransaction txn = null;

            int? txnId = hfTransactionId.Value.AsIntegerOrNull();
            int? batchId = hfBatchId.Value.AsIntegerOrNull();

            var changes = new List<string>();

            if ( txnId.HasValue )
            {
                txn = txnService.Get( txnId.Value );
            }

            if ( txn == null )
            {
                txn = new FinancialTransaction();
                txnService.Add( txn );
                txn.BatchId = batchId;
                changes.Add( "Created transaction" );
            }

            if ( txn != null )
            {
                if ( txn.FinancialPaymentDetail == null )
                {
                    txn.FinancialPaymentDetail = new FinancialPaymentDetail();
                }

                string newPerson = ppAuthorizedPerson.PersonName;

                if ( batchId.HasValue )
                {
                    if ( !txn.AuthorizedPersonAliasId.Equals( ppAuthorizedPerson.PersonAliasId ) )
                    {
                        string prevPerson = ( txn.AuthorizedPersonAlias != null && txn.AuthorizedPersonAlias.Person != null ) ?
                            txn.AuthorizedPersonAlias.Person.FullName : string.Empty;
                        History.EvaluateChange( changes, "Person", prevPerson, newPerson );
                    }

                    History.EvaluateChange( changes, "Date/Time", txn.TransactionDateTime, dtTransactionDateTime.SelectedDateTime );
                    History.EvaluateChange( changes, "Type", GetDefinedValue( txn.TransactionTypeValueId ), GetDefinedValue( ddlTransactionType.SelectedValue.AsInteger() ) );
                    History.EvaluateChange( changes, "Source", GetDefinedValue( txn.SourceTypeValueId ), GetDefinedValue( ddlSourceType.SelectedValueAsInt() ) );

                    if ( !txn.FinancialGatewayId.Equals( gpPaymentGateway.SelectedValueAsInt() ) )
                    {
                        History.EvaluateChange( changes, "Gateway", GetFinancialGatewayName( txn.FinancialGatewayId, rockContext ), GetFinancialGatewayName( gpPaymentGateway.SelectedValueAsInt(), rockContext ) );
                    }

                    History.EvaluateChange( changes, "Transaction Code", txn.TransactionCode, tbTransactionCode.Text );
                    History.EvaluateChange( changes, "Currency Type", GetDefinedValue( txn.FinancialPaymentDetail.CurrencyTypeValueId ), GetDefinedValue( ddlCurrencyType.SelectedValueAsInt() ) );
                    History.EvaluateChange( changes, "Credit Card Type", GetDefinedValue( txn.FinancialPaymentDetail.CreditCardTypeValueId ), GetDefinedValue( ddlCreditCardType.SelectedValueAsInt() ) );
                    History.EvaluateChange( changes, "Summary", txn.Summary, tbSummary.Text );
                    History.EvaluateChange( changes, "Is Refund", ( txn.RefundDetails != null ), cbIsRefund.Checked );
                }

                txn.AuthorizedPersonAliasId = ppAuthorizedPerson.PersonAliasId;
                txn.TransactionDateTime = dtTransactionDateTime.SelectedDateTime;
                txn.TransactionTypeValueId = ddlTransactionType.SelectedValue.AsInteger();
                txn.SourceTypeValueId = ddlSourceType.SelectedValueAsInt();
                txn.FinancialGatewayId = gpPaymentGateway.SelectedValueAsInt();
                txn.TransactionCode = tbTransactionCode.Text;
                txn.FinancialPaymentDetail.CurrencyTypeValueId = ddlCurrencyType.SelectedValueAsInt();
                txn.FinancialPaymentDetail.CreditCardTypeValueId = ddlCreditCardType.SelectedValueAsInt();

                txn.Summary = tbSummary.Text;

                decimal totalAmount = TransactionDetailsState.Select( d => d.Amount ).ToList().Sum();
                if ( cbIsRefund.Checked && totalAmount > 0 )
                {
                    nbErrorMessage.Title = "Incorrect Refund Amount";
                    nbErrorMessage.Text = "<p>A refund should have a negative amount. Please unselect the refund option, or change amounts to be negative values.</p>";
                    nbErrorMessage.Visible = true;
                    return;
                }

                if ( cbIsRefund.Checked )
                {
                    if ( txn.RefundDetails != null )
                    {
                        txn.RefundDetails = new FinancialTransactionRefund();
                    }
                    txn.RefundDetails.RefundReasonValueId = ddlRefundReasonEdit.SelectedValueAsId();
                    txn.RefundDetails.RefundReasonSummary = tbRefundSummaryEdit.Text;
                }

                if ( !Page.IsValid || !txn.IsValid )
                {
                    return;
                }

                foreach ( var txnDetail in TransactionDetailsState )
                {
                    if ( !txnDetail.IsValid )
                    {
                        return;
                    }
                }

                rockContext.WrapTransaction( () =>
                {
                    // Save the transaction
                    rockContext.SaveChanges();

                    // Delete any transaction details that were removed
                    var txnDetailsInDB = txnDetailService.Queryable().Where( a => a.TransactionId.Equals( txn.Id ) ).ToList();
                    var deletedDetails = from txnDetail in txnDetailsInDB
                                         where !TransactionDetailsState.Select( d => d.Guid ).Contains( txnDetail.Guid )
                                         select txnDetail;
                    deletedDetails.ToList().ForEach( txnDetail =>
                    {
                        if ( batchId.HasValue )
                        {
                            History.EvaluateChange( changes, txnDetail.Account != null ? txnDetail.Account.Name : "Unknown", txnDetail.Amount.FormatAsCurrency(), string.Empty );
                        }
                        txnDetailService.Delete( txnDetail );
                    } );

                    // Save Transaction Details
                    foreach ( var editorTxnDetail in TransactionDetailsState )
                    {
                        string oldAccountName = string.Empty;
                        string newAccountName = string.Empty;
                        decimal oldAmount = 0.0M;
                        decimal newAmount = 0.0M;

                        // Add or Update the activity type
                        var txnDetail = txn.TransactionDetails.FirstOrDefault( d => d.Guid.Equals( editorTxnDetail.Guid ) );
                        if ( txnDetail != null )
                        {
                            oldAccountName = AccountName( txnDetail.AccountId );
                            oldAmount = txnDetail.Amount;
                        }
                        else
                        {
                            txnDetail = new FinancialTransactionDetail();
                            txnDetail.Guid = editorTxnDetail.Guid;
                            txn.TransactionDetails.Add( txnDetail );
                        }

                        newAccountName = AccountName( editorTxnDetail.AccountId );
                        newAmount = UseSimpleAccountMode ? tbSingleAccountAmount.Text.AsDecimal() : editorTxnDetail.Amount;

                        if ( batchId.HasValue )
                        {
                            if ( string.IsNullOrWhiteSpace(oldAccountName) )
                            {
                                History.EvaluateChange( changes, newAccountName, string.Empty, newAmount.FormatAsCurrency() );
                            }
                            else
                            {
                                if ( oldAccountName == newAccountName )
                                {
                                    if ( oldAmount != newAmount )
                                    {
                                        History.EvaluateChange( changes, oldAccountName, oldAmount.FormatAsCurrency(), newAmount.FormatAsCurrency() );
                                    }
                                }
                                else
                                {
                                    History.EvaluateChange( changes, oldAccountName, oldAmount.FormatAsCurrency(), string.Empty );
                                    History.EvaluateChange( changes, newAccountName, string.Empty, newAmount.FormatAsCurrency() );
                                }
                            }
                        }

                        txnDetail.AccountId = editorTxnDetail.AccountId;
                        txnDetail.Amount = newAmount;
                        txnDetail.Summary = editorTxnDetail.Summary;

                        if ( editorTxnDetail.AttributeValues != null )
                        {
                            txnDetail.LoadAttributes();
                            txnDetail.AttributeValues = editorTxnDetail.AttributeValues;
                            rockContext.SaveChanges();
                            txnDetail.SaveAttributeValues( rockContext );
                        }
                    }

                    // Delete any transaction images that were removed
                    var orphanedBinaryFileIds = new List<int>();
                    var txnImagesInDB = txnImageService.Queryable().Where( a => a.TransactionId.Equals( txn.Id ) ).ToList();
                    foreach ( var txnImage in txnImagesInDB.Where( i => !TransactionImagesState.Contains( i.BinaryFileId ) ) )
                    {
                        changes.Add( "Removed Image" );
                        orphanedBinaryFileIds.Add( txnImage.BinaryFileId );
                        txnImageService.Delete( txnImage );
                    }

                    // Save Transaction Images
                    int imageOrder = 0;
                    foreach ( var binaryFileId in TransactionImagesState )
                    {
                        // Add or Update the activity type
                        var txnImage = txnImagesInDB.FirstOrDefault( i => i.BinaryFileId == binaryFileId );
                        if ( txnImage == null )
                        {
                            changes.Add( "Added Image" );
                            txnImage = new FinancialTransactionImage();
                            txnImage.TransactionId = txn.Id;
                            txn.Images.Add( txnImage );
                        }
                        else
                        {
                            if ( txnImage.BinaryFileId != binaryFileId )
                            {
                                changes.Add( "Updated Image" );
                            }
                        }

                        txnImage.BinaryFileId = binaryFileId;
                        txnImage.Order = imageOrder;
                        imageOrder++;
                    }

                    rockContext.SaveChanges();

                    // Make sure updated binary files are not temporary
                    foreach ( var binaryFile in binaryFileService.Queryable().Where( f => TransactionImagesState.Contains( f.Id ) ) )
                    {
                        binaryFile.IsTemporary = false;
                    }

                    // Delete any orphaned images
                    foreach ( var binaryFile in binaryFileService.Queryable().Where( f => orphanedBinaryFileIds.Contains( f.Id ) ) )
                    {
                        binaryFileService.Delete( binaryFile );
                    }

                    // Update any attributes
                    txn.LoadAttributes(rockContext);
                    txn.FinancialPaymentDetail.LoadAttributes(rockContext);
                    Helper.GetEditValues(phAttributeEdits, txn);
                    Helper.GetEditValues(phPaymentAttributeEdits, txn.FinancialPaymentDetail);

                    // If the transaction is associated with a batch, update that batch's history
                    if ( batchId.HasValue )
                    {
                        HistoryService.SaveChanges(
                            rockContext,
                            typeof( FinancialBatch ),
                            Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(),
                            batchId.Value,
                            changes,
                            !string.IsNullOrWhiteSpace( newPerson ) ? newPerson : string.Format( "Transaction Id:{0}", txn.Id ),
                            typeof( FinancialTransaction ),
                            txn.Id
                        );
                    }

                    rockContext.SaveChanges();
                    txn.SaveAttributeValues(rockContext);
                    txn.FinancialPaymentDetail.SaveAttributeValues(rockContext);
                } );

                // Save selected options to session state in order to prefill values for next added txn
                Session["NewTxnDefault_BatchId"] = txn.BatchId;
                Session["NewTxnDefault_TransactionDateTime"] = txn.TransactionDateTime;
                Session["NewTxnDefault_TransactionType"] = txn.TransactionTypeValueId;
                Session["NewTxnDefault_SourceType"] = txn.SourceTypeValueId;
                Session["NewTxnDefault_CurrencyType"] = txn.FinancialPaymentDetail.CurrencyTypeValueId;
                Session["NewTxnDefault_CreditCardType"] = txn.FinancialPaymentDetail.CreditCardTypeValueId;
                if ( TransactionDetailsState.Count() == 1 )
                {
                    Session["NewTxnDefault_Account"] = TransactionDetailsState.First().AccountId;
                }
                else
                {
                    Session.Remove("NewTxnDefault_Account");
                }

                // Requery the batch to support EF navigation properties
                var savedTxn = GetTransaction( txn.Id );
                if ( savedTxn != null )
                {
                    savedTxn.LoadAttributes();
                    savedTxn.FinancialPaymentDetail.LoadAttributes();
                    ShowReadOnlyDetails( savedTxn );
                }
            }
        }
        /// <summary>
        /// Processes the payment.
        /// </summary>
        /// <param name="submitToGateway">if set to <c>true</c> [submit to gateway].</param>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="registration">The registration.</param>
        /// <param name="personAliasId">The person alias identifier.</param>
        /// <param name="amount">The amount.</param>
        /// <param name="errorMessage">The error message.</param>
        /// <returns></returns>
        private bool ProcessPayment( bool submitToGateway, RockContext rockContext, Registration registration, int? personAliasId, decimal amount, out string errorMessage )
        {
            FinancialTransaction transaction = null;

            var txnChanges = new List<string>();
            txnChanges.Add( "Created Transaction" );

            var registrationChanges = new List<string>();

            DefinedValueCache dvCurrencyType = null;
            DefinedValueCache dvCredCardType = null;

            if ( submitToGateway )
            {
                GatewayComponent gateway = null;
                if ( RegistrationTemplateState != null && RegistrationTemplateState.FinancialGateway != null )
                {
                    gateway = RegistrationTemplateState.FinancialGateway.GetGatewayComponent();
                }

                if ( gateway == null )
                {
                    errorMessage = "There was a problem creating the payment gateway information";
                    return false;
                }

                if ( registration == null || registration.RegistrationInstance == null || !registration.RegistrationInstance.AccountId.HasValue || registration.RegistrationInstance.Account == null )
                {
                    errorMessage = "There was a problem with the account configuration for this registration.";
                    return false;
                }

                var paymentInfo = new CreditCardPaymentInfo( txtCreditCard.Text, txtCVV.Text, mypExpiration.SelectedDate.Value );
                paymentInfo.NameOnCard = gateway != null && gateway.SplitNameOnCard ? txtCardFirstName.Text : txtCardName.Text;
                paymentInfo.LastNameOnCard = txtCardLastName.Text;

                paymentInfo.BillingStreet1 = acBillingAddress.Street1;
                paymentInfo.BillingStreet2 = acBillingAddress.Street2;
                paymentInfo.BillingCity = acBillingAddress.City;
                paymentInfo.BillingState = acBillingAddress.State;
                paymentInfo.BillingPostalCode = acBillingAddress.PostalCode;
                paymentInfo.BillingCountry = acBillingAddress.Country;

                paymentInfo.Amount = amount;
                paymentInfo.Email = registration.ConfirmationEmail;

                paymentInfo.FirstName = registration.FirstName;
                paymentInfo.LastName = registration.LastName;

                paymentInfo.Comment1 = string.Format( "{0} ({1})", registration.RegistrationInstance.Name, registration.RegistrationInstance.Account.GlCode );

                transaction = gateway.Charge( RegistrationTemplateState.FinancialGateway, paymentInfo, out errorMessage );
                if ( transaction != null )
                {
                    transaction.FinancialGatewayId = RegistrationTemplateState.FinancialGatewayId;
                    if ( transaction.FinancialPaymentDetail == null )
                    {
                        transaction.FinancialPaymentDetail = new FinancialPaymentDetail();
                    }
                    transaction.FinancialPaymentDetail.SetFromPaymentInfo( paymentInfo, gateway, rockContext, txnChanges );

                    dvCurrencyType = paymentInfo.CurrencyTypeValue;
                    dvCredCardType = paymentInfo.CreditCardTypeValue;

                    registrationChanges.Add( string.Format( "Processed payment of {0}.", amount.FormatAsCurrency() ) );
                }
            }
            else
            {
                errorMessage = string.Empty;
                transaction = new FinancialTransaction();
                transaction.FinancialPaymentDetail = new FinancialPaymentDetail();
                transaction.FinancialPaymentDetail.CurrencyTypeValueId = ddlCurrencyType.SelectedValueAsInt();
                transaction.FinancialPaymentDetail.CreditCardTypeValueId = ddlCreditCardType.SelectedValueAsInt();
                transaction.TransactionCode = tbTransactionCode.Text;

                registrationChanges.Add( string.Format( "Manually added payment of {0}.", amount.FormatAsCurrency() ) );
            }

            if ( transaction != null )
            {
                transaction.Summary = tbSummary.Text;

                History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode );

                transaction.AuthorizedPersonAliasId = personAliasId;

                transaction.TransactionDateTime = RockDateTime.Now;
                History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime );

                if ( transaction.FinancialGatewayId.HasValue )
                {
                    History.EvaluateChange( txnChanges, "Gateway", string.Empty, RegistrationTemplateState.FinancialGateway.Name );
                }

                var txnType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_EVENT_REGISTRATION ) );
                transaction.TransactionTypeValueId = txnType.Id;
                History.EvaluateChange( txnChanges, "Type", string.Empty, txnType.Value );

                Guid sourceGuid = Guid.Empty;
                if ( Guid.TryParse( GetAttributeValue( "Source" ), out sourceGuid ) )
                {
                    var source = DefinedValueCache.Read( sourceGuid );
                    if ( source != null )
                    {
                        transaction.SourceTypeValueId = source.Id;
                        History.EvaluateChange( txnChanges, "Source", string.Empty, source.Value );
                    }
                }

                var transactionDetail = new FinancialTransactionDetail();
                transactionDetail.Amount = amount;
                transactionDetail.AccountId = registration.RegistrationInstance.AccountId.Value;
                transactionDetail.EntityTypeId = EntityTypeCache.Read( typeof( Rock.Model.Registration ) ).Id;
                transactionDetail.EntityId = registration.Id;
                transaction.TransactionDetails.Add( transactionDetail );

                History.EvaluateChange( txnChanges, registration.RegistrationInstance.Account.Name, 0.0M.FormatAsCurrency(), transactionDetail.Amount.FormatAsCurrency() );

                var batchService = new FinancialBatchService( rockContext );

                // Get the batch
                var batch = batchService.Get(
                    GetAttributeValue( "BatchNamePrefix" ),
                    dvCurrencyType,
                    dvCredCardType,
                    transaction.TransactionDateTime.Value,
                    RegistrationTemplateState.FinancialGateway.GetBatchTimeOffset() );

                var batchChanges = new List<string>();

                if ( batch.Id == 0 )
                {
                    batchChanges.Add( "Generated the batch" );
                    History.EvaluateChange( batchChanges, "Batch Name", string.Empty, batch.Name );
                    History.EvaluateChange( batchChanges, "Status", null, batch.Status );
                    History.EvaluateChange( batchChanges, "Start Date/Time", null, batch.BatchStartDateTime );
                    History.EvaluateChange( batchChanges, "End Date/Time", null, batch.BatchEndDateTime );
                }

                decimal newControlAmount = batch.ControlAmount + transaction.TotalAmount;
                History.EvaluateChange( batchChanges, "Control Amount", batch.ControlAmount.FormatAsCurrency(), newControlAmount.FormatAsCurrency() );
                batch.ControlAmount = newControlAmount;

                transaction.BatchId = batch.Id;
                batch.Transactions.Add( transaction );

                rockContext.SaveChanges();

                HistoryService.SaveChanges(
                    rockContext,
                    typeof( FinancialBatch ),
                    Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(),
                    batch.Id,
                    batchChanges
                );

                HistoryService.SaveChanges(
                    rockContext,
                    typeof( FinancialBatch ),
                    Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(),
                    batch.Id,
                    txnChanges,
                    CurrentPerson != null ? CurrentPerson.FullName : string.Empty,
                    typeof( FinancialTransaction ),
                    transaction.Id
                );

                HistoryService.SaveChanges(
                    rockContext,
                    typeof( Registration ),
                    Rock.SystemGuid.Category.HISTORY_EVENT_REGISTRATION.AsGuid(),
                    registration.Id,
                    registrationChanges
                );

                return true;
            }
            else
            {
                return false;
            }
        }
Beispiel #30
0
        /// <summary>
        /// Handles the Click event of the lbSave control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void lbSave_Click( object sender, EventArgs e )
        {
            var rockContext = new RockContext();

            var txnService = new FinancialTransactionService( rockContext );
            var txnDetailService = new FinancialTransactionDetailService( rockContext );
            var txnImageService = new FinancialTransactionImageService( rockContext );
            var binaryFileService = new BinaryFileService( rockContext );

            FinancialTransaction txn = null;

            int? txnId = hfTransactionId.Value.AsIntegerOrNull();
            int? batchId = hfBatchId.Value.AsIntegerOrNull();

            if ( txnId.HasValue )
            {
                txn = txnService.Get( txnId.Value );
            }

            if ( txn == null && batchId.HasValue )
            {
                txn = new FinancialTransaction();
                txnService.Add( txn );
                txn.BatchId = batchId.Value;
            }

            if ( txn != null )
            {
                txn.AuthorizedPersonId = ppAuthorizedPerson.PersonId;
                txn.TransactionDateTime = dtTransactionDateTime.SelectedDateTime;
                txn.TransactionTypeValueId = ddlTransactionType.SelectedValue.AsInteger();
                txn.SourceTypeValueId = ddlSourceType.SelectedValueAsInt();

                Guid? gatewayGuid = cpPaymentGateway.SelectedValueAsGuid();
                if ( gatewayGuid.HasValue )
                {
                    var gatewayEntity = EntityTypeCache.Read( gatewayGuid.Value );
                    if ( gatewayEntity != null )
                    {
                        txn.GatewayEntityTypeId = gatewayEntity.Id;
                    }
                    else
                    {
                        txn.GatewayEntityTypeId = null;
                    }
                }
                else
                {
                    txn.GatewayEntityTypeId = null;
                }

                txn.TransactionCode = tbTransactionCode.Text;
                txn.CurrencyTypeValueId = ddlCurrencyType.SelectedValueAsInt();
                txn.CreditCardTypeValueId = ddlCreditCardType.SelectedValueAsInt();
                txn.Summary = tbSummary.Text;

                if ( !Page.IsValid || !txn.IsValid )
                {
                    return;
                }

                foreach ( var txnDetail in TransactionDetailsState )
                {
                    if ( !txnDetail.IsValid )
                    {
                        return;
                    }
                }

                foreach ( var txnImage in TransactionImagesState )
                {
                    if ( !txnImage.IsValid )
                    {
                        return;
                    }
                }

                rockContext.WrapTransaction( () =>
                {
                    // Save the transaction
                    rockContext.SaveChanges();

                    // Delete any transaction details that were removed
                    var txnDetailsInDB = txnDetailService.Queryable().Where( a => a.TransactionId.Equals( txn.Id ) ).ToList();
                    var deletedDetails = from txnDetail in txnDetailsInDB
                                         where !TransactionDetailsState.Select( d => d.Guid ).Contains( txnDetail.Guid )
                                         select txnDetail;
                    deletedDetails.ToList().ForEach( txnDetail =>
                    {
                        txnDetailService.Delete( txnDetail );
                    } );
                    rockContext.SaveChanges();

                    // Save Transaction Details
                    foreach ( var editorTxnDetail in TransactionDetailsState )
                    {
                        // Add or Update the activity type
                        var txnDetail = txn.TransactionDetails.FirstOrDefault( d => d.Guid.Equals( editorTxnDetail.Guid ) );
                        if ( txnDetail == null )
                        {
                            txnDetail = new FinancialTransactionDetail();
                            txnDetail.Guid = editorTxnDetail.Guid;
                            txn.TransactionDetails.Add( txnDetail );
                        }
                        txnDetail.AccountId = editorTxnDetail.AccountId;
                        txnDetail.Amount = editorTxnDetail.Amount;
                        txnDetail.Summary = editorTxnDetail.Summary;
                    }
                    rockContext.SaveChanges();

                    // Remove any images that do not have a binary file
                    foreach ( var txnImage in TransactionImagesState.Where( i => i.BinaryFileId == 0 ).ToList() )
                    {
                        TransactionImagesState.Remove( txnImage );
                    }

                    // Delete any transaction images that were removed
                    var txnImagesInDB = txnImageService.Queryable().Where( a => a.TransactionId.Equals( txn.Id ) ).ToList();
                    var deletedImages = from txnImage in txnImagesInDB
                                        where !TransactionImagesState.Select( d => d.Guid ).Contains( txnImage.Guid )
                                        select txnImage;
                    deletedImages.ToList().ForEach( txnImage =>
                    {
                        txnImageService.Delete( txnImage );
                    } );
                    rockContext.SaveChanges();

                    // Save Transaction Images
                    foreach ( var editorTxnImage in TransactionImagesState )
                    {
                        // Add or Update the activity type
                        var txnImage = txn.Images.FirstOrDefault( d => d.Guid.Equals( editorTxnImage.Guid ) );
                        if ( txnImage == null )
                        {
                            txnImage = new FinancialTransactionImage();
                            txnImage.Guid = editorTxnImage.Guid;
                            txn.Images.Add( txnImage );
                        }
                        txnImage.BinaryFileId = editorTxnImage.BinaryFileId;
                        txnImage.TransactionImageTypeValueId = editorTxnImage.TransactionImageTypeValueId;
                    }
                    rockContext.SaveChanges();

                    // Make sure updated binary files are not temporary
                    var savedBinaryFileIds = txn.Images.Select( i => i.BinaryFileId ).ToList();
                    foreach ( var binaryFile in binaryFileService.Queryable().Where( f => savedBinaryFileIds.Contains( f.Id ) ) )
                    {
                        binaryFile.IsTemporary = false;
                    }

                    // Delete any orphaned images
                    var orphanedBinaryFileIds = BinaryFileIds.Where( f => !savedBinaryFileIds.Contains( f ) );
                    foreach ( var binaryFile in binaryFileService.Queryable().Where( f => orphanedBinaryFileIds.Contains( f.Id ) ) )
                    {
                        binaryFileService.Delete( binaryFile );
                    }

                    rockContext.SaveChanges();

                } );

                // Requery the batch to support EF navigation properties
                var savedTxn = GetTransaction( txn.Id );
                ShowReadOnlyDetails( savedTxn );
            }
        }
Beispiel #31
0
        /// <summary>
        /// Maps the contribution.
        /// </summary>
        /// <param name="tableData">The table data.</param>
        /// <param name="totalRows">The total rows.</param>
        private void MapContribution(IQueryable <Row> tableData, long totalRows = 0)
        {
            var lookupContext = new RockContext();

            var transactionTypeContributionId = DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid(), lookupContext).Id;

            var currencyTypes          = DefinedTypeCache.Get(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE));
            var currencyTypeACH        = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH))).Id;
            var currencyTypeCash       = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH))).Id;
            var currencyTypeCheck      = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK))).Id;
            var currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD))).Id;
            var currencyTypeNonCash    = currencyTypes.DefinedValues.Where(dv => dv.Value.Equals("Non-Cash")).Select(dv => ( int? )dv.Id).FirstOrDefault();

            if (currencyTypeNonCash == null)
            {
                var newTenderNonCash = new DefinedValue
                {
                    Value         = "Non-Cash",
                    Description   = "Non-Cash",
                    DefinedTypeId = currencyTypes.Id
                };

                lookupContext.DefinedValues.Add(newTenderNonCash);
                lookupContext.SaveChanges();

                currencyTypeNonCash = newTenderNonCash.Id;
            }

            var creditCardTypes = DefinedTypeCache.Get(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE)).DefinedValues;

            var refundReasons = DefinedTypeCache.Get(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON), lookupContext).DefinedValues;

            var accountList = new FinancialAccountService(lookupContext).Queryable().AsNoTracking().ToList();

            int?defaultBatchId = null;

            if (ImportedBatches.ContainsKey(0))
            {
                defaultBatchId = ImportedBatches[0];
            }

            // Get all imported contributions
            var importedContributions = new FinancialTransactionService(lookupContext).Queryable().AsNoTracking()
                                        .Where(c => c.ForeignId != null)
                                        .ToDictionary(t => ( int )t.ForeignId, t => ( int? )t.Id);

            // List for batching new contributions
            var newTransactions = new List <FinancialTransaction>();

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

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

            ReportProgress(0, $"Verifying contribution import ({totalRows:N0} found, {importedContributions.Count:N0} already exist).");
            foreach (var row in tableData.Where(r => r != null))
            {
                var individualId   = row["Individual_ID"] as int?;
                var householdId    = row["Household_ID"] as int?;
                var contributionId = row["ContributionID"] as int?;

                if (contributionId.HasValue && !importedContributions.ContainsKey(( int )contributionId))
                {
                    var transaction = new FinancialTransaction
                    {
                        CreatedByPersonAliasId  = ImportPersonAliasId,
                        ModifiedByPersonAliasId = ImportPersonAliasId,
                        TransactionTypeValueId  = transactionTypeContributionId,
                        ForeignKey = contributionId.ToString(),
                        ForeignId  = contributionId
                    };

                    int?giverAliasId = null;
                    var personKeys   = GetPersonKeys(individualId, householdId);
                    if (personKeys != null && personKeys.PersonAliasId > 0)
                    {
                        giverAliasId = personKeys.PersonAliasId;
                        transaction.CreatedByPersonAliasId   = giverAliasId;
                        transaction.AuthorizedPersonAliasId  = giverAliasId;
                        transaction.ProcessedByPersonAliasId = giverAliasId;
                    }

                    var summary = row["Memo"] as string;
                    if (!string.IsNullOrWhiteSpace(summary))
                    {
                        transaction.Summary = summary;
                    }

                    var batchId = row["BatchID"] as int?;
                    if (batchId.HasValue && ImportedBatches.Any(b => b.Key.Equals(batchId)))
                    {
                        transaction.BatchId = ImportedBatches.FirstOrDefault(b => b.Key.Equals(batchId)).Value;
                    }
                    else
                    {
                        // use the default batch for any non-matching transactions
                        transaction.BatchId = defaultBatchId;
                    }

                    var receivedDate = row["Received_Date"] as DateTime?;
                    if (receivedDate.HasValue)
                    {
                        transaction.TransactionDateTime = receivedDate;
                        transaction.CreatedDateTime     = receivedDate;
                        transaction.ModifiedDateTime    = ImportDateTime;
                    }

                    var contributionFields = row.Columns.Select(c => c.Name).ToList();
                    var cardType           = contributionFields.Contains("Card_Type") ? row["Card_Type"] as string : string.Empty;
                    var cardLastFour       = contributionFields.Contains("Last_Four") ? row["Last_Four"] as string : string.Empty;
                    var contributionType   = contributionFields.Contains("Contribution_Type_Name") ? row["Contribution_Type_Name"] as string : string.Empty;

                    if (!string.IsNullOrWhiteSpace(contributionType))
                    {
                        // set default source to onsite, exceptions listed below
                        transaction.SourceTypeValueId = TransactionSourceTypeOnsiteId;

                        int?paymentCurrencyTypeId = null, creditCardTypeId = null;
                        switch (contributionType.ToLower())
                        {
                        case "cash":
                            paymentCurrencyTypeId = currencyTypeCash;
                            break;

                        case "check":
                            paymentCurrencyTypeId = currencyTypeCheck;
                            break;

                        case "ach":
                            paymentCurrencyTypeId         = currencyTypeACH;
                            transaction.SourceTypeValueId = TransactionSourceTypeWebsiteId;
                            break;

                        case "credit card":
                            paymentCurrencyTypeId         = currencyTypeCreditCard;
                            transaction.SourceTypeValueId = TransactionSourceTypeWebsiteId;

                            if (!string.IsNullOrWhiteSpace(cardType))
                            {
                                creditCardTypeId = creditCardTypes.Where(t => t.Value.Equals(cardType, StringComparison.OrdinalIgnoreCase))
                                                   .Select(t => ( int? )t.Id).FirstOrDefault();
                            }
                            break;

                        default:
                            paymentCurrencyTypeId = currencyTypeNonCash;
                            break;
                        }

                        var paymentDetail = new FinancialPaymentDetail
                        {
                            CreatedDateTime         = receivedDate,
                            CreatedByPersonAliasId  = giverAliasId,
                            ModifiedDateTime        = ImportDateTime,
                            ModifiedByPersonAliasId = giverAliasId,
                            CurrencyTypeValueId     = paymentCurrencyTypeId,
                            CreditCardTypeValueId   = creditCardTypeId,
                            AccountNumberMasked     = cardLastFour,
                            ForeignKey = contributionId.ToString(),
                            ForeignId  = contributionId
                        };

                        transaction.FinancialPaymentDetail = paymentDetail;
                    }

                    var checkNumber = row["Check_Number"] as string;
                    // if the check number is valid, put it in the transaction code
                    if (checkNumber.AsType <int?>().HasValue)
                    {
                        transaction.TransactionCode = checkNumber;
                    }
                    // check for SecureGive kiosk transactions
                    else if (!string.IsNullOrWhiteSpace(checkNumber) && checkNumber.StartsWith("SG"))
                    {
                        transaction.SourceTypeValueId = TransactionSourceTypeKioskId;
                    }

                    var fundName         = contributionFields.Contains("Fund_Name") ? row["Fund_Name"] as string : string.Empty;
                    var fundType         = contributionFields.Contains("Fund_type") ? row["Fund_type"] as string : string.Empty;
                    var subFund          = contributionFields.Contains("Sub_Fund_Name") ? row["Sub_Fund_Name"] as string : string.Empty;
                    var fundGLAccount    = contributionFields.Contains("Fund_GL_Account") ? row["Fund_GL_Account"] as string : string.Empty;
                    var subFundGLAccount = contributionFields.Contains("Sub_Fund_GL_Account") ? row["Sub_Fund_GL_Account"] as string : string.Empty;
                    var isFundActive     = contributionFields.Contains("Fund_Is_active") ? row["Fund_Is_active"] as string : null;
                    var statedValue      = row["Stated_Value"] as decimal?;
                    var amount           = row["Amount"] as decimal?;
                    if (!string.IsNullOrWhiteSpace(fundName) && amount.HasValue)
                    {
                        int transactionAccountId;
                        var parentAccount = accountList.FirstOrDefault(a => !a.CampusId.HasValue && a.Name.Equals(fundName.Truncate(50), StringComparison.OrdinalIgnoreCase));
                        if (parentAccount == null)
                        {
                            int?accountTypeDefinedTypeId = null;
                            if (!string.IsNullOrWhiteSpace(fundType))
                            {
                                accountTypeDefinedTypeId = LoadAccountTypeDefinedValue(lookupContext, fundType);
                            }
                            parentAccount = AddFinancialAccount(lookupContext, fundName, $"{fundName} imported {ImportDateTime}", fundGLAccount, null, null, isFundActive.AsBooleanOrNull(), receivedDate, fundName.RemoveSpecialCharacters(), accountTypeValueId: accountTypeDefinedTypeId);
                            accountList.Add(parentAccount);
                        }

                        if (!string.IsNullOrWhiteSpace(subFund))
                        {
                            int?campusFundId = null;
                            // assign a campus if the subfund is a campus fund
                            var campusFund = CampusList.FirstOrDefault(c => subFund.StartsWith(c.Name, StringComparison.OrdinalIgnoreCase) || subFund.StartsWith(c.ShortCode, StringComparison.OrdinalIgnoreCase));
                            if (campusFund != null)
                            {
                                // use full campus name as the subfund
                                subFund      = campusFund.Name;
                                campusFundId = campusFund.Id;
                            }

                            // add info to easily find/assign this fund in the view
                            subFund = $"{subFund} {fundName}";

                            var childAccount = accountList.FirstOrDefault(c => c.ParentAccountId == parentAccount.Id && c.Name.Equals(subFund.Truncate(50), StringComparison.OrdinalIgnoreCase));
                            if (childAccount == null)
                            {
                                // create a child account with a campusId if it was set
                                childAccount = AddFinancialAccount(lookupContext, subFund, $"{subFund} imported {ImportDateTime}", subFundGLAccount, campusFundId, parentAccount.Id, isFundActive.AsBooleanOrNull(), receivedDate, subFund.RemoveSpecialCharacters(), accountTypeValueId: parentAccount.AccountTypeValueId);
                                accountList.Add(childAccount);
                            }

                            transactionAccountId = childAccount.Id;
                        }
                        else
                        {
                            transactionAccountId = parentAccount.Id;
                        }

                        if (amount == 0 && statedValue.HasValue && statedValue != 0)
                        {
                            amount = statedValue;
                        }

                        var transactionDetail = new FinancialTransactionDetail
                        {
                            Amount          = ( decimal )amount,
                            CreatedDateTime = receivedDate,
                            AccountId       = transactionAccountId
                        };

                        transaction.TransactionDetails.Add(transactionDetail);

                        if (amount < 0)
                        {
                            transaction.RefundDetails = new FinancialTransactionRefund();
                            transaction.RefundDetails.CreatedDateTime     = receivedDate;
                            transaction.RefundDetails.RefundReasonValueId = refundReasons.Where(dv => summary != null && dv.Value.Contains(summary))
                                                                            .Select(dv => ( int? )dv.Id).FirstOrDefault();
                            transaction.RefundDetails.RefundReasonSummary = summary;
                        }
                    }

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

                    if (completedItems % ReportingNumber < 1)
                    {
                        SaveContributions(newTransactions);
                        newTransactions.Clear();
                        ReportPartialProgress();
                    }
                }
            }

            if (newTransactions.Any())
            {
                SaveContributions(newTransactions);
            }

            ReportProgress(100, $"Finished contribution import: {completedItems:N0} contributions imported.");
        }
Beispiel #32
0
        /// <summary>
        /// Maps the contribution.
        /// </summary>
        /// <param name="tableData">The table data.</param>
        /// <param name="selectedColumns">The selected columns.</param>
        private void MapContribution( IQueryable<Row> tableData, List<string> selectedColumns = null )
        {
            var lookupContext = new RockContext();
            int transactionEntityTypeId = EntityTypeCache.Read( "Rock.Model.FinancialTransaction" ).Id;
            var transactionTypeContributionId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ), lookupContext ).Id;

            var currencyTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE ) );
            int currencyTypeACH = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ) ) ).Id;
            int currencyTypeCash = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH ) ) ).Id;
            int currencyTypeCheck = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK ) ) ).Id;
            int currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ) ) ).Id;
            int? currencyTypeNonCash = currencyTypes.DefinedValues.Where( dv => dv.Value.Equals( "Non-Cash" ) ).Select( dv => (int?)dv.Id ).FirstOrDefault();
            if ( currencyTypeNonCash == null )
            {
                var newTenderNonCash = new DefinedValue();
                newTenderNonCash.Value = "Non-Cash";
                newTenderNonCash.Description = "Non-Cash";
                newTenderNonCash.DefinedTypeId = currencyTypes.Id;
                lookupContext.DefinedValues.Add( newTenderNonCash );
                lookupContext.SaveChanges();

                currencyTypeNonCash = newTenderNonCash.Id;
            }

            var creditCardTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE ) ).DefinedValues;

            int sourceTypeOnsite = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_ONSITE_COLLECTION ), lookupContext ).Id;
            int sourceTypeWebsite = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE ), lookupContext ).Id;
            int sourceTypeKiosk = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_KIOSK ), lookupContext ).Id;

            var refundReasons = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON ), lookupContext ).DefinedValues;

            var accountList = new FinancialAccountService( lookupContext ).Queryable().AsNoTracking().ToList();

            int? defaultBatchId = null;
            if ( ImportedBatches.ContainsKey( 0 ) )
            {
                defaultBatchId = ImportedBatches[0];
            }

            // Get all imported contributions
            var importedContributions = new FinancialTransactionService( lookupContext ).Queryable().AsNoTracking()
               .Where( c => c.ForeignId != null )
               .ToDictionary( t => (int)t.ForeignId, t => (int?)t.Id );

            // List for batching new contributions
            var newTransactions = new List<FinancialTransaction>();

            int completed = 0;
            int totalRows = tableData.Count();
            int percentage = ( totalRows - 1 ) / 100 + 1;
            ReportProgress( 0, string.Format( "Verifying contribution import ({0:N0} found, {1:N0} already exist).", totalRows, importedContributions.Count ) );
            foreach ( var row in tableData.Where( r => r != null ) )
            {
                int? individualId = row["Individual_ID"] as int?;
                int? householdId = row["Household_ID"] as int?;
                int? contributionId = row["ContributionID"] as int?;

                if ( contributionId != null && !importedContributions.ContainsKey( (int)contributionId ) )
                {
                    var transaction = new FinancialTransaction();
                    transaction.CreatedByPersonAliasId = ImportPersonAliasId;
                    transaction.ModifiedByPersonAliasId = ImportPersonAliasId;
                    transaction.TransactionTypeValueId = transactionTypeContributionId;
                    transaction.ForeignKey = contributionId.ToString();
                    transaction.ForeignId = contributionId;

                    int? giverAliasId = null;
                    var personKeys = GetPersonKeys( individualId, householdId );
                    if ( personKeys != null && personKeys.PersonAliasId > 0 )
                    {
                        giverAliasId = personKeys.PersonAliasId;
                        transaction.CreatedByPersonAliasId = giverAliasId;
                        transaction.AuthorizedPersonAliasId = giverAliasId;
                        transaction.ProcessedByPersonAliasId = giverAliasId;
                    }

                    string summary = row["Memo"] as string;
                    if ( summary != null )
                    {
                        transaction.Summary = summary;
                    }

                    int? batchId = row["BatchID"] as int?;
                    if ( batchId != null && ImportedBatches.Any( b => b.Key.Equals( batchId ) ) )
                    {
                        transaction.BatchId = ImportedBatches.FirstOrDefault( b => b.Key.Equals( batchId ) ).Value;
                    }
                    else
                    {
                        // use the default batch for any non-matching transactions
                        transaction.BatchId = defaultBatchId;
                    }

                    DateTime? receivedDate = row["Received_Date"] as DateTime?;
                    if ( receivedDate != null )
                    {
                        transaction.TransactionDateTime = receivedDate;
                        transaction.CreatedDateTime = receivedDate;
                        transaction.ModifiedDateTime = ImportDateTime;
                    }

                    string cardType = row["Card_Type"] as string;
                    string cardLastFour = row["Last_Four"] as string;
                    string contributionType = row["Contribution_Type_Name"].ToStringSafe().ToLower();
                    if ( contributionType != null )
                    {
                        // set default source to onsite, exceptions listed below
                        transaction.SourceTypeValueId = sourceTypeOnsite;

                        int? paymentCurrencyTypeId = null, creditCardTypeId = null;

                        if ( contributionType == "cash" )
                        {
                            paymentCurrencyTypeId = currencyTypeCash;
                        }
                        else if ( contributionType == "check" )
                        {
                            paymentCurrencyTypeId = currencyTypeCheck;
                        }
                        else if ( contributionType == "ach" )
                        {
                            paymentCurrencyTypeId = currencyTypeACH;
                            transaction.SourceTypeValueId = sourceTypeWebsite;
                        }
                        else if ( contributionType == "credit card" )
                        {
                            paymentCurrencyTypeId = currencyTypeCreditCard;
                            transaction.SourceTypeValueId = sourceTypeWebsite;

                            if ( cardType != null )
                            {
                                creditCardTypeId = creditCardTypes.Where( t => t.Value.Equals( cardType ) ).Select( t => (int?)t.Id ).FirstOrDefault();
                            }
                        }
                        else
                        {
                            paymentCurrencyTypeId = currencyTypeNonCash;
                        }

                        var paymentDetail = new FinancialPaymentDetail();
                        paymentDetail.CreatedDateTime = receivedDate;
                        paymentDetail.CreatedByPersonAliasId = giverAliasId;
                        paymentDetail.ModifiedDateTime = ImportDateTime;
                        paymentDetail.ModifiedByPersonAliasId = giverAliasId;
                        paymentDetail.CurrencyTypeValueId = paymentCurrencyTypeId;
                        paymentDetail.CreditCardTypeValueId = creditCardTypeId;
                        paymentDetail.AccountNumberMasked = cardLastFour;
                        paymentDetail.ForeignKey = contributionId.ToString();
                        paymentDetail.ForeignId = contributionId;

                        transaction.FinancialPaymentDetail = paymentDetail;
                    }

                    string checkNumber = row["Check_Number"] as string;
                    // if the check number is valid, put it in the transaction code
                    if ( checkNumber.AsType<int?>() != null )
                    {
                        transaction.TransactionCode = checkNumber;
                    }
                    // check for SecureGive kiosk transactions
                    else if ( !string.IsNullOrEmpty( checkNumber ) && checkNumber.StartsWith( "SG" ) )
                    {
                        transaction.SourceTypeValueId = sourceTypeKiosk;
                    }

                    string fundName = row["Fund_Name"] as string;
                    string subFund = row["Sub_Fund_Name"] as string;
                    string fundGLAccount = row["Fund_GL_Account"] as string;
                    string subFundGLAccount = row["Sub_Fund_GL_Account"] as string;
                    Boolean? isFundActive = row["Fund_Is_active"] as Boolean?;
                    decimal? statedValue = row["Stated_Value"] as decimal?;
                    decimal? amount = row["Amount"] as decimal?;
                    if ( fundName != null & amount != null )
                    {
                        int transactionAccountId;
                        var parentAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName ) && a.CampusId == null );
                        if ( parentAccount == null )
                        {
                            parentAccount = AddAccount( lookupContext, fundName, fundGLAccount, null, null, isFundActive );
                            accountList.Add( parentAccount );
                        }

                        if ( subFund != null )
                        {
                            int? campusFundId = null;
                            // assign a campus if the subfund is a campus fund
                            var campusFund = CampusList.FirstOrDefault( c => subFund.StartsWith( c.Name ) || subFund.StartsWith( c.ShortCode ) );
                            if ( campusFund != null )
                            {
                                // use full campus name as the subfund
                                subFund = campusFund.Name;
                                campusFundId = campusFund.Id;
                            }

                            // add info to easily find/assign this fund in the view
                            subFund = string.Format( "{0} {1}", subFund, fundName );

                            var childAccount = accountList.FirstOrDefault( c => c.Name.Equals( subFund ) && c.ParentAccountId == parentAccount.Id );
                            if ( childAccount == null )
                            {
                                // create a child account with a campusId if it was set
                                childAccount = AddAccount( lookupContext, subFund, subFundGLAccount, campusFundId, parentAccount.Id, isFundActive );
                                accountList.Add( childAccount );
                            }

                            transactionAccountId = childAccount.Id;
                        }
                        else
                        {
                            transactionAccountId = parentAccount.Id;
                        }

                        if ( amount == 0 && statedValue != null && statedValue != 0 )
                        {
                            amount = statedValue;
                        }

                        var transactionDetail = new FinancialTransactionDetail();
                        transactionDetail.Amount = (decimal)amount;
                        transactionDetail.CreatedDateTime = receivedDate;
                        transactionDetail.AccountId = transactionAccountId;
                        transaction.TransactionDetails.Add( transactionDetail );

                        if ( amount < 0 )
                        {
                            transaction.RefundDetails = new FinancialTransactionRefund();
                            transaction.RefundDetails.CreatedDateTime = receivedDate;
                            transaction.RefundDetails.RefundReasonValueId = refundReasons.Where( dv => summary != null && dv.Value.Contains( summary ) )
                                .Select( dv => (int?)dv.Id ).FirstOrDefault();
                            transaction.RefundDetails.RefundReasonSummary = summary;
                        }
                    }

                    newTransactions.Add( transaction );
                    completed++;
                    if ( completed % percentage < 1 )
                    {
                        int percentComplete = completed / percentage;
                        ReportProgress( percentComplete, string.Format( "{0:N0} contributions imported ({1}% complete).", completed, percentComplete ) );
                    }
                    else if ( completed % ReportingNumber < 1 )
                    {
                        SaveContributions( newTransactions );
                        newTransactions.Clear();
                        ReportPartialProgress();
                    }
                }
            }

            if ( newTransactions.Any() )
            {
                SaveContributions( newTransactions );
            }

            ReportProgress( 100, string.Format( "Finished contribution import: {0:N0} contributions imported.", completed ) );
        }
        /// <summary>
        /// Handles the Click event of the lbSave control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void lbSave_Click( object sender, EventArgs e )
        {
            var rockContext = new RockContext();

            var txnService = new FinancialTransactionService( rockContext );
            var txnDetailService = new FinancialTransactionDetailService( rockContext );
            var txnImageService = new FinancialTransactionImageService( rockContext );
            var binaryFileService = new BinaryFileService( rockContext );

            FinancialTransaction txn = null;

            int? txnId = hfTransactionId.Value.AsIntegerOrNull();
            int? batchId = hfBatchId.Value.AsIntegerOrNull();

            if ( txnId.HasValue )
            {
                txn = txnService.Get( txnId.Value );
            }

            if ( txn == null )
            {
                txn = new FinancialTransaction();
                txnService.Add( txn );
                txn.BatchId = batchId;
            }

            if ( txn != null )
            {
                if ( ppAuthorizedPerson.PersonId.HasValue )
                {
                    txn.AuthorizedPersonAliasId = ppAuthorizedPerson.PersonAliasId;
                }

                txn.TransactionDateTime = dtTransactionDateTime.SelectedDateTime;
                txn.TransactionTypeValueId = ddlTransactionType.SelectedValue.AsInteger();
                txn.SourceTypeValueId = ddlSourceType.SelectedValueAsInt();

                Guid? gatewayGuid = cpPaymentGateway.SelectedValueAsGuid();
                if ( gatewayGuid.HasValue )
                {
                    var gatewayEntity = EntityTypeCache.Read( gatewayGuid.Value );
                    if ( gatewayEntity != null )
                    {
                        txn.GatewayEntityTypeId = gatewayEntity.Id;
                    }
                    else
                    {
                        txn.GatewayEntityTypeId = null;
                    }
                }
                else
                {
                    txn.GatewayEntityTypeId = null;
                }

                txn.TransactionCode = tbTransactionCode.Text;
                txn.CurrencyTypeValueId = ddlCurrencyType.SelectedValueAsInt();
                txn.CreditCardTypeValueId = ddlCreditCardType.SelectedValueAsInt();
                txn.Summary = tbSummary.Text;

                if ( !Page.IsValid || !txn.IsValid )
                {
                    return;
                }

                foreach ( var txnDetail in TransactionDetailsState )
                {
                    if ( !txnDetail.IsValid )
                    {
                        return;
                    }
                }

                rockContext.WrapTransaction( () =>
                {
                    // Save the transaction
                    rockContext.SaveChanges();

                    // Delete any transaction details that were removed
                    var txnDetailsInDB = txnDetailService.Queryable().Where( a => a.TransactionId.Equals( txn.Id ) ).ToList();
                    var deletedDetails = from txnDetail in txnDetailsInDB
                                         where !TransactionDetailsState.Select( d => d.Guid ).Contains( txnDetail.Guid )
                                         select txnDetail;
                    deletedDetails.ToList().ForEach( txnDetail =>
                    {
                        txnDetailService.Delete( txnDetail );
                    } );
                    rockContext.SaveChanges();

                    // Save Transaction Details
                    foreach ( var editorTxnDetail in TransactionDetailsState )
                    {
                        // Add or Update the activity type
                        var txnDetail = txn.TransactionDetails.FirstOrDefault( d => d.Guid.Equals( editorTxnDetail.Guid ) );
                        if ( txnDetail == null )
                        {
                            txnDetail = new FinancialTransactionDetail();
                            txnDetail.Guid = editorTxnDetail.Guid;
                            txn.TransactionDetails.Add( txnDetail );
                        }
                        txnDetail.AccountId = editorTxnDetail.AccountId;
                        txnDetail.Amount = UseSimpleAccountMode ? tbSingleAccountAmount.Text.AsDecimal() : editorTxnDetail.Amount;
                        txnDetail.Summary = editorTxnDetail.Summary;
                    }
                    rockContext.SaveChanges();

                    // Delete any transaction images that were removed
                    var orphanedBinaryFileIds = new List<int>();
                    var txnImagesInDB = txnImageService.Queryable().Where( a => a.TransactionId.Equals( txn.Id ) ).ToList();
                    foreach ( var txnImage in txnImagesInDB.Where( i => !TransactionImagesState.Contains( i.BinaryFileId ) ) )
                    {
                        orphanedBinaryFileIds.Add( txnImage.BinaryFileId );
                        txnImageService.Delete( txnImage );
                    }

                    // Save Transaction Images
                    int imageOrder = 0;
                    foreach ( var binaryFileId in TransactionImagesState )
                    {
                        // Add or Update the activity type
                        var txnImage = txnImagesInDB.FirstOrDefault( i => i.BinaryFileId == binaryFileId );
                        if ( txnImage == null )
                        {
                            txnImage = new FinancialTransactionImage();
                            txnImage.TransactionId = txn.Id;
                            txn.Images.Add( txnImage );
                        }
                        txnImage.BinaryFileId = binaryFileId;
                        txnImage.Order = imageOrder;
                        imageOrder++;
                    }
                    rockContext.SaveChanges();

                    // Make sure updated binary files are not temporary
                    foreach ( var binaryFile in binaryFileService.Queryable().Where( f => TransactionImagesState.Contains( f.Id ) ) )
                    {
                        binaryFile.IsTemporary = false;
                    }

                    // Delete any orphaned images
                    foreach ( var binaryFile in binaryFileService.Queryable().Where( f => orphanedBinaryFileIds.Contains( f.Id ) ) )
                    {
                        binaryFileService.Delete( binaryFile );
                    }

                    rockContext.SaveChanges();

                } );

                // Save selected options to session state in order to prefill values for next added txn
                Session["NewTxnDefault_BatchId"] = txn.BatchId;
                Session["NewTxnDefault_TransactionDateTime"] = txn.TransactionDateTime;
                Session["NewTxnDefault_TransactionType"] = txn.TransactionTypeValueId;
                Session["NewTxnDefault_SourceType"] = txn.SourceTypeValueId;
                Session["NewTxnDefault_CurrencyType"] = txn.CurrencyTypeValueId;
                Session["NewTxnDefault_CreditCardType"] = txn.CreditCardTypeValueId;
                if ( TransactionDetailsState.Count() == 1 )
                {
                    Session["NewTxnDefault_Account"] = TransactionDetailsState.First().AccountId;
                }
                else
                {
                    Session.Remove("NewTxnDefault_Account");
                }

                // Requery the batch to support EF navigation properties
                var savedTxn = GetTransaction( txn.Id );
                ShowReadOnlyDetails( savedTxn );
            }
        }
Beispiel #34
0
        /// <summary>
        /// Writes to package.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="model">The model.</param>
        public static void WriteToPackage <T>(T model)
        {
            var typeName = model.GetType().Name;

            if (model is IImportModel)
            {
                var importModel = (IImportModel)model;
                // check if a textwriter is needed for this model type
                if (!textWriters.ContainsKey(typeName))
                {
                    if (!Directory.Exists(_packageDirectory))
                    {
                        InitalizePackageFolder();
                    }

                    textWriters.Add(typeName, (TextWriter)File.CreateText($@"{_packageDirectory}\{importModel.GetFileName()}"));

                    // if model is for person create related writers
                    if (importModel is Person)
                    {
                        // person attributes
                        var personAttributeValue = new PersonAttributeValue();
                        textWriters.Add(personAttributeValue.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{personAttributeValue.GetFileName()}"));

                        // person phones
                        var personPhone = new PersonPhone();
                        textWriters.Add(personPhone.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{personPhone.GetFileName()}"));

                        // person addresses
                        var personAddress = new PersonAddress();
                        textWriters.Add(personAddress.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{personAddress.GetFileName()}"));
                    }

                    // if model is for financial batch create related writers
                    if (importModel is FinancialBatch)
                    {
                        // financial transactions
                        var financialTransaction = new FinancialTransaction();
                        textWriters.Add(financialTransaction.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{financialTransaction.GetFileName()}"));

                        // financial transation details
                        var financialTransactionDetail = new FinancialTransactionDetail();
                        textWriters.Add(financialTransactionDetail.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{financialTransactionDetail.GetFileName()}"));
                    }

                    // if model is for financial transaction create related writers
                    if (importModel is FinancialTransaction)
                    {
                        // financial transation details
                        var financialTransactionDetail = new FinancialTransactionDetail();
                        textWriters.Add(financialTransactionDetail.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{financialTransactionDetail.GetFileName()}"));
                    }

                    // if model is for group create related writers
                    if (importModel is Group)
                    {
                        // group member
                        var groupMember = new GroupMember();
                        textWriters.Add(groupMember.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{groupMember.GetFileName()}"));

                        // group attributes
                        var groupAttributeValue = new GroupAttributeValue();
                        textWriters.Add(groupAttributeValue.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{groupAttributeValue.GetFileName()}"));

                        // group addresses
                        var groupAddress = new GroupAddress();
                        textWriters.Add(groupAddress.GetType().Name, (TextWriter)File.CreateText($@"{_packageDirectory}\{groupAddress.GetFileName()}"));
                    }
                }

                var txtWriter = textWriters[typeName];

                // check if a csvwriter is needed for this model type
                if (!csvWriters.ContainsKey(typeName))
                {
                    var newCsvWriter = new CsvWriter(txtWriter);
                    csvWriters.Add(typeName, newCsvWriter);
                    newCsvWriter.WriteHeader <T>();
                    //newCsvWriter.Configuration.QuoteAllFields = true;

                    // if model is for person create related writers
                    if (importModel is Person)
                    {
                        // person attributes
                        var personAttributeValue             = new PersonAttributeValue();
                        var newPersonAttributeValueCsvWriter = new CsvWriter(textWriters[personAttributeValue.GetType().Name]);
                        csvWriters.Add(personAttributeValue.GetType().Name, newPersonAttributeValueCsvWriter);
                        newPersonAttributeValueCsvWriter.WriteHeader <PersonAttributeValue>();

                        // person phones
                        var personPhone             = new PersonPhone();
                        var newPersonPhoneCsvWriter = new CsvWriter(textWriters[personPhone.GetType().Name]);
                        csvWriters.Add(personPhone.GetType().Name, newPersonPhoneCsvWriter);
                        newPersonPhoneCsvWriter.WriteHeader <PersonPhone>();

                        // person addresses
                        var personAddress             = new PersonAddress();
                        var newPersonAddressCsvWriter = new CsvWriter(textWriters[personAddress.GetType().Name]);
                        csvWriters.Add(personAddress.GetType().Name, newPersonAddressCsvWriter);
                        newPersonAddressCsvWriter.WriteHeader <PersonAddress>();
                    }

                    // if model is for financial batch create related writers
                    if (importModel is FinancialBatch)
                    {
                        // financial transaction
                        var financialTransaction             = new FinancialTransaction();
                        var newFinancialTransactionCsvWriter = new CsvWriter(textWriters[financialTransaction.GetType().Name]);
                        csvWriters.Add(financialTransaction.GetType().Name, newFinancialTransactionCsvWriter);
                        newFinancialTransactionCsvWriter.WriteHeader <FinancialTransaction>();

                        // financial transaction detail
                        var financialTransactionDetail             = new FinancialTransactionDetail();
                        var newFinancialTransactionDetailCsvWriter = new CsvWriter(textWriters[financialTransactionDetail.GetType().Name]);
                        csvWriters.Add(financialTransactionDetail.GetType().Name, newFinancialTransactionDetailCsvWriter);
                        newFinancialTransactionDetailCsvWriter.WriteHeader <FinancialTransactionDetail>();
                    }

                    //if model is for financial transaction, create related writers
                    if (importModel is FinancialTransaction)
                    {
                        // financial transaction detail
                        var financialTransactionDetail             = new FinancialTransactionDetail();
                        var newFinancialTransactionDetailCsvWriter = new CsvWriter(textWriters[financialTransactionDetail.GetType().Name]);
                        csvWriters.Add(financialTransactionDetail.GetType().Name, newFinancialTransactionDetailCsvWriter);
                        newFinancialTransactionDetailCsvWriter.WriteHeader <FinancialTransactionDetail>();
                    }

                    // if model is for group create related writers
                    if (importModel is Group)
                    {
                        // group member
                        var groupMember             = new GroupMember();
                        var newGroupMemberCsvWriter = new CsvWriter(textWriters[groupMember.GetType().Name]);
                        csvWriters.Add(groupMember.GetType().Name, newGroupMemberCsvWriter);
                        newGroupMemberCsvWriter.WriteHeader <GroupMember>();

                        // group attributes
                        var groupAttributeValue             = new GroupAttributeValue();
                        var newGroupAttributeValueCsvWriter = new CsvWriter(textWriters[groupAttributeValue.GetType().Name]);
                        csvWriters.Add(groupAttributeValue.GetType().Name, newGroupAttributeValueCsvWriter);
                        newGroupAttributeValueCsvWriter.WriteHeader <GroupAttributeValue>();

                        // group addresses
                        var groupAddress             = new GroupAddress();
                        var newGroupAddressCsvWriter = new CsvWriter(textWriters[groupAddress.GetType().Name]);
                        csvWriters.Add(groupAddress.GetType().Name, newGroupAddressCsvWriter);
                        newGroupAddressCsvWriter.WriteHeader <GroupAddress>();
                    }
                }

                var csvWriter = csvWriters[typeName];

                csvWriter.WriteRecord <T>(model);

                // if person model write out any related models
                if (importModel is Person)
                {
                    // person attributes
                    var personAttributeValue          = new PersonAttributeValue();
                    var csvPersonAttributeValueWriter = csvWriters[personAttributeValue.GetType().Name];

                    if (csvPersonAttributeValueWriter != null)
                    {
                        foreach (var attribute in ((Person)importModel).Attributes)
                        {
                            csvPersonAttributeValueWriter.WriteRecord(attribute);
                        }
                    }

                    // person phones
                    var personPhone          = new PersonPhone();
                    var csvPersonPhoneWriter = csvWriters[personPhone.GetType().Name];

                    if (csvPersonPhoneWriter != null)
                    {
                        foreach (var phone in ((Person)importModel).PhoneNumbers)
                        {
                            csvPersonPhoneWriter.WriteRecord(phone);
                        }
                    }

                    // person addresses
                    var personAddress          = new PersonAddress();
                    var csvPersonAddressWriter = csvWriters[personAddress.GetType().Name];

                    if (csvPersonAddressWriter != null)
                    {
                        foreach (var address in ((Person)importModel).Addresses)
                        {
                            csvPersonAddressWriter.WriteRecord(address);
                        }
                    }
                }

                // if financial model write out any related models
                if (importModel is FinancialBatch)
                {
                    // write out financial transactions and transaction details
                    var financialTransaction          = new FinancialTransaction();
                    var csvFinancialTransactionWriter = csvWriters[financialTransaction.GetType().Name];

                    var financialTransactionDetail          = new FinancialTransactionDetail();
                    var csvFinancialTransactionDetailWriter = csvWriters[financialTransactionDetail.GetType().Name];

                    if (csvFinancialTransactionWriter != null && csvFinancialTransactionDetailWriter != null)
                    {
                        foreach (var transaction in ((FinancialBatch)importModel).FinancialTransactions)
                        {
                            csvFinancialTransactionWriter.WriteRecord(transaction);

                            foreach (var transactionDetail in transaction.FinancialTransactionDetails)
                            {
                                csvFinancialTransactionDetailWriter.WriteRecord(transactionDetail);
                            }
                        }
                    }
                }

                // if financial Transaction model write out any related models
                if (importModel is FinancialTransaction)
                {
                    var financialTransactionDetail          = new FinancialTransactionDetail();
                    var csvFinancialTransactionDetailWriter = csvWriters[financialTransactionDetail.GetType().Name];

                    if (csvFinancialTransactionDetailWriter != null)
                    {
                        foreach (var transactionDetail in ((FinancialTransaction)importModel).FinancialTransactionDetails)
                        {
                            csvFinancialTransactionDetailWriter.WriteRecord(transactionDetail);
                        }
                    }
                }

                // if group model write out any related models
                if (importModel is Group)
                {
                    // group members
                    var groupMember          = new GroupMember();
                    var csvGroupMemberWriter = csvWriters[groupMember.GetType().Name];

                    if (csvGroupMemberWriter != null)
                    {
                        foreach (var groupMemberItem in ((Group)importModel).GroupMembers)
                        {
                            csvGroupMemberWriter.WriteRecord(groupMemberItem);
                        }
                    }

                    // group attributes
                    var groupAttributeValue           = new GroupAttributeValue();
                    var csvPersonAttributeValueWriter = csvWriters[groupAttributeValue.GetType().Name];

                    if (csvPersonAttributeValueWriter != null)
                    {
                        foreach (var attribute in ((Group)importModel).Attributes)
                        {
                            csvPersonAttributeValueWriter.WriteRecord(attribute);
                        }
                    }

                    // group addresses
                    var groupAddress          = new GroupAddress();
                    var csvGroupAddressWriter = csvWriters[groupAddress.GetType().Name];

                    if (csvGroupAddressWriter != null)
                    {
                        foreach (var address in ((Group)importModel).Addresses)
                        {
                            csvGroupAddressWriter.WriteRecord(address);
                        }
                    }
                }
            }
        }
Beispiel #35
0
        private void SaveTransaction(FinancialGateway financialGateway, GatewayComponent gateway, Person person, PaymentInfo paymentInfo, FinancialTransaction transaction, RockContext rockContext)
        {
            transaction.AuthorizedPersonAliasId = person.PrimaryAliasId;
            if (RockTransactionEntry != null)
            {
                RockCheckBox cbGiveAnonymouslyControl = (( RockCheckBox )(RockTransactionEntry.FindControl("cbGiveAnonymously")));
                if (cbGiveAnonymouslyControl != null)
                {
                    transaction.ShowAsAnonymous = cbGiveAnonymouslyControl.Checked;
                }
            }
            transaction.TransactionDateTime = RockDateTime.Now;
            transaction.FinancialGatewayId  = financialGateway.Id;

            var txnType = DefinedValueCache.Get(this.GetAttributeValue("TransactionType").AsGuidOrNull() ?? Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid());

            transaction.TransactionTypeValueId = txnType.Id;

            transaction.Summary = paymentInfo.Comment1;

            if (transaction.FinancialPaymentDetail == null)
            {
                transaction.FinancialPaymentDetail = new FinancialPaymentDetail();
            }
            transaction.FinancialPaymentDetail.SetFromPaymentInfo(paymentInfo, gateway, rockContext);

            Guid sourceGuid = Guid.Empty;

            if (Guid.TryParse(GetAttributeValue("Source"), out sourceGuid))
            {
                var source = DefinedValueCache.Get(sourceGuid);
                if (source != null)
                {
                    transaction.SourceTypeValueId = source.Id;
                }
            }

            var transactionEntity = this.GetTransactionEntity();

            foreach (var account in GetSelectedAccounts().Where(a => a.Amount > 0))
            {
                var transactionDetail = new FinancialTransactionDetail();
                transactionDetail.Amount    = account.Amount;
                transactionDetail.AccountId = account.Id;
                if (transactionEntity != null)
                {
                    transactionDetail.EntityTypeId = transactionEntity.TypeId;
                    transactionDetail.EntityId     = transactionEntity.Id;
                }

                transaction.TransactionDetails.Add(transactionDetail);
            }

            var batchService = new FinancialBatchService(rockContext);

            // Get the batch
            var batch = batchService.Get(
                GetAttributeValue("BatchNamePrefix"),
                paymentInfo.CurrencyTypeValue,
                paymentInfo.CreditCardTypeValue,
                transaction.TransactionDateTime.Value,
                financialGateway.GetBatchTimeOffset());

            var batchChanges = new History.HistoryChangeList();

            if (batch.Id == 0)
            {
                batchChanges.AddCustom("Add", "Record", "Generated the batch");
                History.EvaluateChange(batchChanges, "Batch Name", string.Empty, batch.Name);
                History.EvaluateChange(batchChanges, "Status", null, batch.Status);
                History.EvaluateChange(batchChanges, "Start Date/Time", null, batch.BatchStartDateTime);
                History.EvaluateChange(batchChanges, "End Date/Time", null, batch.BatchEndDateTime);
            }

            decimal newControlAmount = batch.ControlAmount + transaction.TotalAmount;

            History.EvaluateChange(batchChanges, "Control Amount", batch.ControlAmount.FormatAsCurrency(), newControlAmount.FormatAsCurrency());
            batch.ControlAmount = newControlAmount;

            transaction.BatchId = batch.Id;
            transaction.LoadAttributes(rockContext);

            var allowedTransactionAttributes = GetAttributeValue("AllowedTransactionAttributesFromURL").Split(',').AsGuidList().Select(x => AttributeCache.Get(x).Key);

            foreach (KeyValuePair <string, AttributeValueCache> attr in transaction.AttributeValues)
            {
                if (PageParameters().ContainsKey("Attribute_" + attr.Key) && allowedTransactionAttributes.Contains(attr.Key))
                {
                    attr.Value.Value = Server.UrlDecode(PageParameter("Attribute_" + attr.Key));
                }
            }

            batch.Transactions.Add(transaction);

            rockContext.SaveChanges();
            transaction.SaveAttributeValues();

            HistoryService.SaveChanges(
                rockContext,
                typeof(FinancialBatch),
                Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(),
                batch.Id,
                batchChanges
                );

            SendReceipt(transaction.Id);

            TransactionCode = transaction.TransactionCode;
        }
        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.Load" /> event.
        /// </summary>
        /// <param name="e">The <see cref="T:System.EventArgs" /> object that contains the event data.</param>
        protected override void OnLoad( EventArgs e )
        {
            if ( !Page.IsPostBack )
            {
                ShowDetail( PageParameter( "transactionId" ).AsInteger(), PageParameter( "batchId" ).AsIntegerOrNull() );
            }
            else
            {
                nbErrorMessage.Visible = false;
                nbRefundError.Visible = false;
                ShowDialog();

                if ( pnlEditDetails.Visible )
                {
                    // Add Transaction and Payment Detail attribute controls

                    FinancialTransaction txn;
                    var txnId = hfTransactionId.Value.AsIntegerOrNull();
                    if (txnId == 0) txnId = null;

                    // Get the current transaction if there is one
                    if (txnId.HasValue)
                    {
                        using (var rockContext = new RockContext())
                        {
                            txn = GetTransaction(hfTransactionId.Value.AsInteger(), rockContext);
                        }
                    }
                    else
                    {
                        txn = new FinancialTransaction();
                        txn.FinancialPaymentDetail = new FinancialPaymentDetail();
                    }

                    // Update the transaction's properties to match what is currently selected on the screen
                    // This allows the shown attributes to change during AutoPostBack events, based on any Qualifiers specified in the attributes
                    txn.FinancialPaymentDetail.CurrencyTypeValueId = ddlCurrencyType.SelectedValueAsInt();

                    txn.LoadAttributes();
                    txn.FinancialPaymentDetail.LoadAttributes();

                    phAttributeEdits.Controls.Clear();
                    Helper.AddEditControls(txn, phAttributeEdits, false);
                    phPaymentAttributeEdits.Controls.Clear();
                    Helper.AddEditControls(txn.FinancialPaymentDetail, phPaymentAttributeEdits, false);
                }
            }

            var txnDetail = new FinancialTransactionDetail();
            txnDetail.LoadAttributes();
            phAccountAttributeEdits.Controls.Clear();
            Helper.AddEditControls( txnDetail, phAccountAttributeEdits, true, mdAccount.ValidationGroup );
        }
Beispiel #37
0
        /// <summary>
        /// Handles the SaveClick event of the mdAccount control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void mdAccount_SaveClick( object sender, EventArgs e )
        {
            Guid? guid = hfAccountGuid.Value.AsGuidOrNull();
            if ( guid.HasValue )
            {
                var txnDetail = TransactionDetailsState.Where( t => t.Guid.Equals( guid.Value ) ).FirstOrDefault();
                if ( txnDetail == null )
                {
                    txnDetail = new FinancialTransactionDetail();
                    TransactionDetailsState.Add( txnDetail );
                }
                txnDetail.AccountId = ddlAccount.SelectedValue.AsInteger();
                txnDetail.Amount = tbAccountAmount.Text.AsDecimal();
                txnDetail.Summary = tbAccountSummary.Text;

                BindAccountsEditGrid();
            }

            HideDialog();
        }
Beispiel #38
0
 /// <summary>
 /// Initializes a new instance of the <see cref="FinancialTransactionDetailExport"/> class.
 /// </summary>
 /// <param name="financialTransactionDetail">The financial transaction detail.</param>
 public FinancialTransactionDetailExport(FinancialTransactionDetail financialTransactionDetail)
 {
     _financialTransactionDetail = financialTransactionDetail;
 }
Beispiel #39
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);
        }
Beispiel #40
0
        /// <summary>
        /// Maps the contribution.
        /// </summary>
        /// <param name="csvData">The table data.</param>
        private int MapContribution(CSVInstance csvData)
        {
            var lookupContext                 = new RockContext();
            int transactionEntityTypeId       = EntityTypeCache.Read("Rock.Model.FinancialTransaction").Id;
            var transactionTypeContributionId = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION), lookupContext).Id;

            var currencyTypes          = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE));
            int currencyTypeACH        = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH))).Id;
            int currencyTypeCash       = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH))).Id;
            int currencyTypeCheck      = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK))).Id;
            int currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD))).Id;
            int?currencyTypeNonCash    = currencyTypes.DefinedValues.Where(dv => dv.Value.Equals("Non-Cash")).Select(dv => (int?)dv.Id).FirstOrDefault();

            if (currencyTypeNonCash == null)
            {
                var newTenderNonCash = new DefinedValue();
                newTenderNonCash.Value         = "Non-Cash";
                newTenderNonCash.Description   = "Non-Cash";
                newTenderNonCash.DefinedTypeId = currencyTypes.Id;
                lookupContext.DefinedValues.Add(newTenderNonCash);
                lookupContext.SaveChanges();

                currencyTypeNonCash = newTenderNonCash.Id;
            }

            var creditCardTypes = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE)).DefinedValues;

            int sourceTypeOnsite  = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_ONSITE_COLLECTION), lookupContext).Id;
            int sourceTypeWebsite = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE), lookupContext).Id;
            int sourceTypeKiosk   = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_KIOSK), lookupContext).Id;

            var refundReasons = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON), lookupContext).DefinedValues;

            var accountList = new FinancialAccountService(lookupContext).Queryable().AsNoTracking().ToList();

            int?defaultBatchId = null;

            if (ImportedBatches.ContainsKey(0))
            {
                defaultBatchId = ImportedBatches[0];
            }

            // Get all imported contributions
            var importedContributions = new FinancialTransactionService(lookupContext).Queryable().AsNoTracking()
                                        .Where(c => c.ForeignId != null)
                                        .ToDictionary(t => (int)t.ForeignId, t => (int?)t.Id);

            // List for batching new contributions
            var newTransactions = new List <FinancialTransaction>();

            int completed = 0;

            ReportProgress(0, string.Format("Verifying contribution import ({0:N0} already exist).", importedContributions.Count));
            string[] row;
            // Uses a look-ahead enumerator: this call will move to the next record immediately
            while ((row = csvData.Database.FirstOrDefault()) != null)
            {
                string individualIdKey   = row[IndividualID];
                int?   individualId      = individualIdKey.AsType <int?>();
                string contributionIdKey = row[ContributionID];
                int?   contributionId    = contributionIdKey.AsType <int?>();

                if (contributionId != null && !importedContributions.ContainsKey((int)contributionId))
                {
                    var transaction = new FinancialTransaction();
                    transaction.CreatedByPersonAliasId  = ImportPersonAliasId;
                    transaction.ModifiedByPersonAliasId = ImportPersonAliasId;
                    transaction.TransactionTypeValueId  = transactionTypeContributionId;
                    transaction.ForeignKey = contributionId.ToString();
                    transaction.ForeignId  = contributionId;

                    int?giverAliasId = null;
                    var personKeys   = GetPersonKeys(individualId);
                    if (personKeys != null && personKeys.PersonAliasId > 0)
                    {
                        giverAliasId = personKeys.PersonAliasId;
                        transaction.CreatedByPersonAliasId   = giverAliasId;
                        transaction.AuthorizedPersonAliasId  = giverAliasId;
                        transaction.ProcessedByPersonAliasId = giverAliasId;
                    }

                    string summary = row[Memo] as string;
                    if (summary != null)
                    {
                        transaction.Summary = summary;
                    }

                    string batchIdKey = row[ContributionBatchID];
                    int?   batchId    = batchIdKey.AsType <int?>();
                    if (batchId != null && ImportedBatches.Any(b => b.Key.Equals(batchId)))
                    {
                        transaction.BatchId = ImportedBatches.FirstOrDefault(b => b.Key.Equals(batchId)).Value;
                    }
                    else
                    {
                        // use the default batch for any non-matching transactions
                        transaction.BatchId = defaultBatchId;
                    }

                    string   receivedDateKey = row[ReceivedDate];
                    DateTime?receivedDate    = receivedDateKey.AsType <DateTime?>();
                    if (receivedDate != null)
                    {
                        transaction.TransactionDateTime = receivedDate;
                        transaction.CreatedDateTime     = receivedDate;
                        transaction.ModifiedDateTime    = ImportDateTime;
                    }

                    string contributionType = row[ContributionTypeName].ToStringSafe().ToLower();
                    if (contributionType != null)
                    {
                        // set default source to onsite, exceptions listed below
                        transaction.SourceTypeValueId = sourceTypeOnsite;

                        int?paymentCurrencyTypeId = null, creditCardTypeId = null;

                        if (contributionType == "cash")
                        {
                            paymentCurrencyTypeId = currencyTypeCash;
                        }
                        else if (contributionType == "check")
                        {
                            paymentCurrencyTypeId = currencyTypeCheck;
                        }
                        else if (contributionType == "ach")
                        {
                            paymentCurrencyTypeId         = currencyTypeACH;
                            transaction.SourceTypeValueId = sourceTypeWebsite;
                        }
                        else if (contributionType == "credit card")
                        {
                            paymentCurrencyTypeId         = currencyTypeCreditCard;
                            transaction.SourceTypeValueId = sourceTypeWebsite;
                        }
                        else
                        {
                            paymentCurrencyTypeId = currencyTypeNonCash;
                        }

                        var paymentDetail = new FinancialPaymentDetail();
                        paymentDetail.CreatedDateTime         = receivedDate;
                        paymentDetail.CreatedByPersonAliasId  = giverAliasId;
                        paymentDetail.ModifiedDateTime        = ImportDateTime;
                        paymentDetail.ModifiedByPersonAliasId = giverAliasId;
                        paymentDetail.CurrencyTypeValueId     = paymentCurrencyTypeId;
                        paymentDetail.CreditCardTypeValueId   = creditCardTypeId;
                        paymentDetail.ForeignKey = contributionId.ToString();
                        paymentDetail.ForeignId  = contributionId;

                        transaction.FinancialPaymentDetail = paymentDetail;
                    }

                    string checkNumber = row[CheckNumber] as string;
                    // if the check number is valid, put it in the transaction code
                    if (checkNumber.AsType <int?>() != null)
                    {
                        transaction.TransactionCode = checkNumber;
                    }
                    // check for SecureGive kiosk transactions
                    else if (!string.IsNullOrEmpty(checkNumber) && checkNumber.StartsWith("SG"))
                    {
                        transaction.SourceTypeValueId = sourceTypeKiosk;
                    }

                    string  fundName         = row[FundName] as string;
                    string  subFund          = row[SubFundName] as string;
                    string  fundGLAccount    = row[FundGLAccount] as string;
                    string  subFundGLAccount = row[SubFundGLAccount] as string;
                    string  isFundActiveKey  = row[FundIsActive];
                    Boolean?isFundActive     = isFundActiveKey.AsType <Boolean?>();
                    string  statedValueKey   = row[StatedValue];
                    decimal?statedValue      = statedValueKey.AsType <decimal?>();
                    string  amountKey        = row[Amount];
                    decimal?amount           = amountKey.AsType <decimal?>();
                    if (fundName != null & amount != null)
                    {
                        int transactionAccountId;
                        var parentAccount = accountList.FirstOrDefault(a => a.Name.Equals(fundName) && a.CampusId == null);
                        if (parentAccount == null)
                        {
                            parentAccount = AddAccount(lookupContext, fundName, fundGLAccount, null, null, isFundActive);
                            accountList.Add(parentAccount);
                        }

                        if (!String.IsNullOrWhiteSpace(subFund))
                        {
                            int?campusFundId = null;
                            // assign a campus if the subfund is a campus fund
                            var campusFund = CampusList.FirstOrDefault(c => subFund.StartsWith(c.Name) || subFund.StartsWith(c.ShortCode));
                            if (campusFund != null)
                            {
                                // use full campus name as the subfund
                                subFund      = campusFund.Name;
                                campusFundId = campusFund.Id;
                            }

                            // add info to easily find/assign this fund in the view
                            subFund = string.Format("{0} {1}", subFund, fundName);

                            var childAccount = accountList.FirstOrDefault(c => c.Name.Equals(subFund) && c.ParentAccountId == parentAccount.Id);
                            if (childAccount == null)
                            {
                                // create a child account with a campusId if it was set
                                childAccount = AddAccount(lookupContext, subFund, subFundGLAccount, campusFundId, parentAccount.Id, isFundActive);
                                accountList.Add(childAccount);
                            }

                            transactionAccountId = childAccount.Id;
                        }
                        else
                        {
                            transactionAccountId = parentAccount.Id;
                        }

                        if (amount == 0 && statedValue != null && statedValue != 0)
                        {
                            amount = statedValue;
                        }

                        var transactionDetail = new FinancialTransactionDetail();
                        transactionDetail.Amount          = (decimal)amount;
                        transactionDetail.CreatedDateTime = receivedDate;
                        transactionDetail.AccountId       = transactionAccountId;
                        transaction.TransactionDetails.Add(transactionDetail);

                        if (amount < 0)
                        {
                            transaction.RefundDetails = new FinancialTransactionRefund();
                            transaction.RefundDetails.CreatedDateTime     = receivedDate;
                            transaction.RefundDetails.RefundReasonValueId = refundReasons.Where(dv => summary != null && dv.Value.Contains(summary))
                                                                            .Select(dv => (int?)dv.Id).FirstOrDefault();
                            transaction.RefundDetails.RefundReasonSummary = summary;
                        }
                    }

                    newTransactions.Add(transaction);
                    completed++;
                    if (completed % (ReportingNumber * 10) < 1)
                    {
                        ReportProgress(0, string.Format("{0:N0} contributions imported.", completed));
                    }
                    else if (completed % ReportingNumber < 1)
                    {
                        SaveContributions(newTransactions);
                        newTransactions.Clear();
                        ReportPartialProgress();
                    }
                }
            }

            if (newTransactions.Any())
            {
                SaveContributions(newTransactions);
            }

            ReportProgress(100, string.Format("Finished contribution import: {0:N0} contributions imported.", completed));
            return(completed);
        }
Beispiel #41
0
        /// <summary>
        /// Creates the giving records for the given parameters.
        /// </summary>
        /// <param name="personGuid">The person unique identifier.</param>
        /// <param name="startingDate">The starting date.</param>
        /// <param name="endDate">The end date.</param>
        /// <param name="frequency">The frequency (onetime, weekly, monthly).</param>
        /// <param name="percentGive">The percent give.</param>
        /// <param name="growRatePercent">The grow rate percent.</param>
        /// <param name="growFrequencyWeeks">The grow frequency weeks.</param>
        /// <param name="specialGiftPercent">The special gift percent.</param>
        /// <param name="accountAmountDict">The account amount dictionary.</param>
        /// <param name="circularImageList">A circular linked list of imageUrls to use for the fake contribution checks.</param>
        /// <param name="rockContexe">A rock context.</param>
        private void CreateGiving( Guid personGuid, DateTime startingDate, DateTime endDate, Frequency frequency, int percentGive, int growRatePercent, int growFrequencyWeeks, int specialGiftPercent, Dictionary<int, decimal> accountAmountDict, LinkedList<string> circularImageList, RockContext rockContext )
        {
            int weekNumber = 0;
            DateTime monthly = startingDate;

            var currencyTypeCheck = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK.AsGuid() );

            var imageUrlNode = circularImageList.First ?? null;
            // foreach weekend or monthly between the starting and ending date...
            for ( DateTime date = startingDate; date <= endDate; date = frequency == Frequency.weekly ? date.AddDays( 7 ) : frequency == Frequency.monthly ? date.AddMonths( 1 ) : endDate.AddDays(1) )
            {
                weekNumber = (int)(date - startingDate).TotalDays / 7;

                // increase by growRatePercent every growFrequencyWeeks
                if ( growFrequencyWeeks != 0 && growRatePercent != 0 && weekNumber !=0 && weekNumber % growFrequencyWeeks == 0 )
                {
                    var copy = accountAmountDict.ToDictionary( entry => entry.Key, entry => entry.Value );
                    foreach ( var item in accountAmountDict )
                    {
                        decimal amount = Math.Round( ( item.Value * 0.01M ) + item.Value, 0 );
                        copy[item.Key] = amount;
                    }
                    accountAmountDict = copy;
                }

                // randomized skip/missed weeks
                int summerFactor = ( 7 <= date.Month && date.Month <= 9 ) ? summerPercentFactor : 0;
                if ( _random.Next( 0, 100 ) > percentGive - summerFactor )
                {
                    continue; // skip this week
                }

                FinancialBatch batch;
                if ( _contributionBatches.ContainsKey( date ) )
                {
                    batch = _contributionBatches[date];
                }
                else
                {
                    batch = new FinancialBatch {
                        Id = 0,
                        Guid = Guid.NewGuid(),
                        BatchStartDateTime = date,
                        BatchEndDateTime = date,
                        Status = BatchStatus.Closed,
                        ControlAmount = 0,
                        Name = string.Format( "SampleData{0}", date.ToJavascriptMilliseconds() ),
                        CreatedByPersonAliasId = CurrentPerson.PrimaryAliasId };
                    _contributionBatches.Add( date, batch );
                }

                // Set up the new transaction
                FinancialTransaction financialTransaction = new FinancialTransaction
                {
                    TransactionTypeValueId = _transactionTypeContributionId,
                    Guid = Guid.NewGuid(),
                    TransactionDateTime = date,
                    AuthorizedPersonAliasId = _peopleAliasDictionary[personGuid]
                };

                financialTransaction.FinancialPaymentDetail = new FinancialPaymentDetail();
                financialTransaction.FinancialPaymentDetail.CurrencyTypeValueId = currencyTypeCheck.Id;
                financialTransaction.FinancialPaymentDetail.Guid = Guid.NewGuid();

                // Add a transaction detail record for each account they're donating to
                foreach ( var item in accountAmountDict )
                {
                    FinancialTransactionDetail transactionDetail = new FinancialTransactionDetail {
                        AccountId = item.Key,
                        Amount = item.Value,
                        Guid = Guid.NewGuid()
                    };

                    financialTransaction.TransactionDetails.Add( transactionDetail );
                }

                // Add the image to the transaction (if any)
                if ( imageUrlNode != null )
                {
                    FinancialTransactionImage transactionImage = new FinancialTransactionImage
                    {
                        BinaryFile = SaveImage( imageUrlNode.Value, _checkImageBinaryFileType, _checkImageBinaryFileTypeSettings, rockContext ),
                        Guid = Guid.NewGuid(),
                    };
                    financialTransaction.Images.Add( transactionImage );
                    imageUrlNode = imageUrlNode.Next ?? imageUrlNode.List.First;
                }

                // Update the batch with the new control amount
                batch.ControlAmount += financialTransaction.TotalAmount;
                batch.Transactions.Add( financialTransaction );
            }
        }
        /// <summary>
        /// Processes the payment.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="registration">The registration.</param>
        /// <param name="errorMessage">The error message.</param>
        /// <returns></returns>
        private bool ProcessPayment( RockContext rockContext, Registration registration, out string errorMessage )
        {
            GatewayComponent gateway = null;
            if ( RegistrationTemplate != null && RegistrationTemplate.FinancialGateway != null )
            {
                gateway = RegistrationTemplate.FinancialGateway.GetGatewayComponent();
            }

            if ( gateway == null )
            {
                errorMessage = "There was a problem creating the payment gateway information";
                return false;
            }

            if ( !RegistrationInstanceState.AccountId.HasValue || RegistrationInstanceState.Account == null )
            {
                errorMessage = "There was a problem with the account configuration for this " + RegistrationTerm.ToLower();
                return false;
            }

            PaymentInfo paymentInfo = null;
            if ( rblSavedCC.Items.Count > 0 && ( rblSavedCC.SelectedValueAsId() ?? 0 ) > 0 )
            {
                var savedAccount = new FinancialPersonSavedAccountService( new RockContext() ).Get( rblSavedCC.SelectedValueAsId().Value );
                if ( savedAccount != null )
                {
                    paymentInfo = savedAccount.GetReferencePayment();
                    paymentInfo.Amount = RegistrationState.PaymentAmount ?? 0.0m;
                }
                else
                {
                    errorMessage = "There was a problem retrieving the saved account";
                    return false;
                }
            }
            else
            {
                paymentInfo = GetCCPaymentInfo( gateway );
            }

            paymentInfo.Comment1 = string.Format( "{0} ({1})", RegistrationInstanceState.Name, RegistrationInstanceState.Account.GlCode );

            var transaction = gateway.Charge( RegistrationTemplate.FinancialGateway, paymentInfo, out errorMessage );
            if ( transaction != null )
            {
                var txnChanges = new List<string>();
                txnChanges.Add( "Created Transaction" );

                History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode );

                transaction.AuthorizedPersonAliasId = registration.PersonAliasId;

                transaction.TransactionDateTime = RockDateTime.Now;
                History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime );

                transaction.FinancialGatewayId = RegistrationTemplate.FinancialGatewayId;
                History.EvaluateChange( txnChanges, "Gateway", string.Empty, RegistrationTemplate.FinancialGateway.Name );

                var txnType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_EVENT_REGISTRATION ) );
                transaction.TransactionTypeValueId = txnType.Id;
                History.EvaluateChange( txnChanges, "Type", string.Empty, txnType.Value );

                if ( transaction.FinancialPaymentDetail == null )
                {
                    transaction.FinancialPaymentDetail = new FinancialPaymentDetail();
                }
                transaction.FinancialPaymentDetail.SetFromPaymentInfo( paymentInfo, gateway, rockContext, txnChanges );

                Guid sourceGuid = Guid.Empty;
                if ( Guid.TryParse( GetAttributeValue( "Source" ), out sourceGuid ) )
                {
                    var source = DefinedValueCache.Read( sourceGuid );
                    if ( source != null )
                    {
                        transaction.SourceTypeValueId = source.Id;
                        History.EvaluateChange( txnChanges, "Source", string.Empty, source.Value );
                    }
                }

                transaction.Summary = registration.GetSummary( RegistrationInstanceState );

                var transactionDetail = new FinancialTransactionDetail();
                transactionDetail.Amount = RegistrationState.PaymentAmount ?? 0.0m;
                transactionDetail.AccountId = RegistrationInstanceState.AccountId.Value;
                transactionDetail.EntityTypeId = EntityTypeCache.Read( typeof( Rock.Model.Registration ) ).Id;
                transactionDetail.EntityId = registration.Id;
                transaction.TransactionDetails.Add( transactionDetail );

                History.EvaluateChange( txnChanges, RegistrationInstanceState.Account.Name, 0.0M.FormatAsCurrency(), transactionDetail.Amount.FormatAsCurrency() );

                var batchChanges = new List<string>();

                rockContext.WrapTransaction( () =>
                {
                    var batchService = new FinancialBatchService( rockContext );

                    // Get the batch
                    var batch = batchService.Get(
                        GetAttributeValue( "BatchNamePrefix" ),
                        paymentInfo.CurrencyTypeValue,
                        paymentInfo.CreditCardTypeValue,
                        transaction.TransactionDateTime.Value,
                        RegistrationTemplate.FinancialGateway.GetBatchTimeOffset() );

                    if ( batch.Id == 0 )
                    {
                        batchChanges.Add( "Generated the batch" );
                        History.EvaluateChange( batchChanges, "Batch Name", string.Empty, batch.Name );
                        History.EvaluateChange( batchChanges, "Status", null, batch.Status );
                        History.EvaluateChange( batchChanges, "Start Date/Time", null, batch.BatchStartDateTime );
                        History.EvaluateChange( batchChanges, "End Date/Time", null, batch.BatchEndDateTime );
                    }

                    decimal newControlAmount = batch.ControlAmount + transaction.TotalAmount;
                    History.EvaluateChange( batchChanges, "Control Amount", batch.ControlAmount.FormatAsCurrency(), newControlAmount.FormatAsCurrency() );
                    batch.ControlAmount = newControlAmount;

                    transaction.BatchId = batch.Id;
                    batch.Transactions.Add( transaction );

                    rockContext.SaveChanges();
                } );

                if ( transaction.BatchId.HasValue )
                {
                    Task.Run( () =>
                        HistoryService.SaveChanges(
                            new RockContext(),
                            typeof( FinancialBatch ),
                            Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(),
                            transaction.BatchId.Value,
                            batchChanges, true, CurrentPersonAliasId )
                    );

                    Task.Run( () =>
                        HistoryService.SaveChanges(
                            new RockContext(),
                            typeof( FinancialBatch ),
                            Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(),
                            transaction.BatchId.Value,
                            txnChanges,
                            CurrentPerson != null ? CurrentPerson.FullName : string.Empty,
                            typeof( FinancialTransaction ),
                            transaction.Id, true, CurrentPersonAliasId )
                    );
                }

                List<string> registrationChanges = new List<string>();
                registrationChanges.Add( string.Format( "Made {0} payment", transaction.TotalAmount.FormatAsCurrency() ) );
                Task.Run( () =>
                    HistoryService.SaveChanges(
                        new RockContext(),
                        typeof( Registration ),
                        Rock.SystemGuid.Category.HISTORY_EVENT_REGISTRATION.AsGuid(),
                        registration.Id,
                        registrationChanges, true, CurrentPersonAliasId )
                );

                TransactionCode = transaction.TransactionCode;

                return true;
            }
            else
            {
                return false;
            }
        }
Beispiel #43
0
        /// <summary>
        /// Handles the Click event of the btnGive control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void btnGive_Click(object sender, EventArgs e)
        {
            Person person = FindPerson();

            using (new UnitOfWorkScope())
            {
                RockTransactionScope.WrapTransaction(() =>
                {
                    var groupLocationService = new GroupLocationService();
                    var groupMemberService   = new GroupMemberService();
                    var phoneService         = new PhoneNumberService();
                    var locationService      = new LocationService();
                    var groupService         = new GroupService();
                    GroupLocation groupLocation;
                    Location homeAddress;
                    Group familyGroup;

                    var homeLocationType = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.LOCATION_TYPE_HOME);
                    var addressList      = locationService.Queryable().Where(l => l.Street1 == txtStreet.Text &&
                                                                             l.City == txtCity.Text && l.State == ddlState.SelectedValue && l.Zip == txtZip.Text &&
                                                                             l.LocationTypeValueId == homeLocationType.Id).ToList();

                    if (!addressList.Any())
                    {
                        homeAddress = new Location();
                        locationService.Add(homeAddress, person.Id);
                    }
                    else
                    {
                        homeAddress = addressList.FirstOrDefault();
                    }

                    homeAddress.Street1             = txtStreet.Text ?? homeAddress.Street1;
                    homeAddress.City                = txtCity.Text ?? homeAddress.City;
                    homeAddress.State               = ddlState.SelectedValue ?? homeAddress.State;
                    homeAddress.Zip                 = txtZip.Text ?? homeAddress.Zip;
                    homeAddress.IsActive            = true;
                    homeAddress.IsLocation          = true;
                    homeAddress.Country             = "US";
                    homeAddress.LocationTypeValueId = homeLocationType.Id;
                    locationService.Save(homeAddress, person.Id);

                    GroupType familyGroupType = new GroupTypeService().Get(new Guid(Rock.SystemGuid.GroupType.GROUPTYPE_FAMILY));
                    var familyGroupList       = groupMemberService.Queryable().Where(g => g.PersonId == person.Id &&
                                                                                     g.Group.GroupType.Guid == familyGroupType.Guid).Select(g => g.Group).ToList();

                    if (!familyGroupList.Any())
                    {
                        familyGroup                = new Group();
                        familyGroup.IsActive       = true;
                        familyGroup.IsSystem       = false;
                        familyGroup.IsSecurityRole = false;
                        familyGroup.Name           = "The " + txtLastName.Text + " Family";
                        familyGroup.GroupTypeId    = familyGroupType.Id;
                        groupService.Add(familyGroup, person.Id);
                        groupService.Save(familyGroup, person.Id);

                        var familyMember         = new GroupMember();
                        familyMember.IsSystem    = false;
                        familyMember.GroupId     = familyGroup.Id;
                        familyMember.PersonId    = person.Id;
                        familyMember.GroupRoleId = new GroupRoleService().Get(new Guid(Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT)).Id;
                        groupMemberService.Add(familyMember, person.Id);
                        groupMemberService.Save(familyMember, person.Id);
                    }
                    else
                    {
                        familyGroup = familyGroupList.FirstOrDefault();
                    }

                    var groupLocationList = groupLocationService.Queryable().Where(g => g.GroupLocationTypeValueId == familyGroupType.Id &&
                                                                                   g.GroupId == familyGroup.Id).ToList();

                    if (!groupLocationList.Any())
                    {
                        groupLocation            = new GroupLocation();
                        groupLocation.GroupId    = familyGroup.Id;
                        groupLocation.LocationId = homeAddress.Id;
                        groupLocation.IsMailing  = true;
                        groupLocation.IsLocation = true;
                        groupLocation.GroupLocationTypeValueId = homeLocationType.Id;
                        groupLocationService.Add(groupLocation, person.Id);
                        groupLocationService.Save(groupLocation, person.Id);
                    }
                    else
                    {
                        groupLocation = groupLocationList.FirstOrDefault();
                    }

                    groupLocation.LocationId = homeAddress.Id;
                    groupLocationService.Save(groupLocation, person.Id);

                    var homePhoneType   = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_HOME);
                    string phoneNumeric = txtPhone.Text.AsNumeric();
                    if (!phoneService.Queryable().Where(n => n.PersonId == person.Id &&
                                                        n.NumberTypeValueId == homePhoneType.Id && n.Number == phoneNumeric).Any())
                    {
                        var homePhone                = new PhoneNumber();
                        homePhone.Number             = phoneNumeric;
                        homePhone.PersonId           = person.Id;
                        homePhone.IsSystem           = false;
                        homePhone.IsMessagingEnabled = false;
                        homePhone.IsUnlisted         = false;
                        homePhone.NumberTypeValueId  = homePhoneType.Id;
                        phoneService.Add(homePhone, person.Id);
                        phoneService.Save(homePhone, person.Id);
                    }
                });
            }

            var      amountList   = (Dictionary <FinancialAccount, Decimal>)Session["CachedAmounts"];
            var      profileId    = (int)Session["CachedProfileId"];
            Location giftLocation = new Location();

            var configValues = (Dictionary <string, object>)Session["CachedMergeFields"];

            configValues.Add("Date", DateTimeOffset.Now.ToString("MM/dd/yyyy hh:mm tt"));

            var receiptTemplate = GetAttributeValue("ReceiptMessage");

            lReceipt.Text = receiptTemplate.ResolveMergeFields(configValues);
            var    summaryTemplate = GetAttributeValue("SummaryMessage");
            string summaryMessage  = summaryTemplate.ResolveMergeFields(configValues);

            var creditProcessorId = GetAttributeValue("CreditCardProvider");
            var achProcessorId    = GetAttributeValue("Checking/ACHProvider");
            var gatewayService    = new FinancialGatewayService();
            FinancialGateway gateway;

            if (!string.IsNullOrEmpty(txtCreditCard.Text) && !string.IsNullOrWhiteSpace(creditProcessorId))
            {
                int creditId = Convert.ToInt32(creditProcessorId);
                gateway = new FinancialGatewayService().Get(creditId);
            }
            else if (!string.IsNullOrEmpty(txtAccountNumber.Text) && !string.IsNullOrWhiteSpace(achProcessorId))
            {
                int achId = Convert.ToInt32(achProcessorId);
                gateway = new FinancialGatewayService().Get(achId);
            }
            else
            {
                gateway = gatewayService.Queryable().FirstOrDefault();
            }

            // #TODO test card through gateway

            if (btnFrequency.SelectedIndex > -1 && btnFrequency.SelectedValueAsInt() != DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.TRANSACTION_FREQUENCY_TYPE_ONE_TIME).Id)
            {
                using (new UnitOfWorkScope())
                {
                    RockTransactionScope.WrapTransaction(() =>
                    {
                        var scheduledTransactionDetailService = new FinancialScheduledTransactionDetailService();
                        var scheduledTransactionService       = new FinancialScheduledTransactionService();
                        FinancialScheduledTransaction scheduledTransaction;
                        var detailList = amountList.ToList();

                        if (profileId > 0)
                        {
                            scheduledTransaction = scheduledTransactionService.Get(profileId);
                        }
                        else
                        {
                            scheduledTransaction = new FinancialScheduledTransaction();
                            scheduledTransactionService.Add(scheduledTransaction, person.Id);
                        }

                        DateTime startDate = (DateTime)dtpStartDate.SelectedDate;
                        if (startDate != null)
                        {
                            scheduledTransaction.StartDate = startDate;
                        }

                        scheduledTransaction.TransactionFrequencyValueId = (int)btnFrequency.SelectedValueAsInt();
                        scheduledTransaction.AuthorizedPersonId          = person.Id;
                        scheduledTransaction.IsActive = true;

                        if (!string.IsNullOrEmpty(txtCreditCard.Text))
                        {
                            scheduledTransaction.CardReminderDate = mypExpiration.SelectedDate;
                        }

                        if (chkLimitGifts.Checked && !string.IsNullOrWhiteSpace(txtLimitNumber.Text))
                        {
                            scheduledTransaction.NumberOfPayments = Convert.ToInt32(txtLimitNumber.Text);
                        }

                        foreach (var detail in amountList.ToList())
                        {
                            var scheduledTransactionDetail       = new FinancialScheduledTransactionDetail();
                            scheduledTransactionDetail.AccountId = detail.Key.Id;
                            scheduledTransactionDetail.Amount    = detail.Value;
                            scheduledTransactionDetail.ScheduledTransactionId = scheduledTransaction.Id;
                            scheduledTransactionDetailService.Add(scheduledTransactionDetail, person.Id);
                            scheduledTransactionDetailService.Save(scheduledTransactionDetail, person.Id);
                        }

                        // implement gateway charge()

                        scheduledTransactionService.Save(scheduledTransaction, person.Id);
                    });
                }
            }
            else
            {
                using (new UnitOfWorkScope())
                {
                    RockTransactionScope.WrapTransaction(() =>
                    {
                        var transactionService = new FinancialTransactionService();
                        var tdService          = new FinancialTransactionDetailService();
                        var transaction        = new FinancialTransaction();
                        var detailList         = amountList.ToList();

                        transaction.Summary = summaryMessage;
                        transaction.Amount  = detailList.Sum(d => d.Value);
                        transaction.TransactionTypeValueId = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION).Id;
                        transaction.TransactionDateTime    = DateTimeOffset.Now.DateTime;
                        transaction.AuthorizedPersonId     = person.Id;
                        transactionService.Add(transaction, person.Id);

                        foreach (var detail in detailList)
                        {
                            var td           = new FinancialTransactionDetail();
                            td.TransactionId = transaction.Id;
                            td.AccountId     = detail.Key.Id;
                            td.Amount        = detail.Value;
                            td.TransactionId = transaction.Id;
                            tdService.Add(td, person.Id);
                            tdService.Save(td, person.Id);
                        }

                        // #TODO implement gateway.charge()

                        transactionService.Save(transaction, person.Id);
                    });
                }
            }

            Session["CachedMergeFields"] = configValues;
            pnlConfirm.Visible           = false;
            pnlComplete.Visible          = true;
            pnlContribution.Update();
        }
        /// <summary>
        /// Handles the SaveClick event of the mdDetails control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void mdDetails_SaveClick( object sender, EventArgs e )
        {
            var rockContext = new RockContext();
            if ( !string.IsNullOrWhiteSpace( tbTransactionAmount.Text ) )
            {
                var ftdService = new FinancialTransactionDetailService( rockContext );
                FinancialTransactionDetail ftd = null;
                var transactionDetailId = int.Parse( hfIdValue.Value );
                if ( transactionDetailId > 0 )
                {
                    ftd = ftdService.Get( transactionDetailId );
                }
                else
                {
                    ftd = new FinancialTransactionDetail { Id = 0 };
                }

                ftd.TransactionId = hfIdTransValue.ValueAsInt();
                ftd.AccountId = int.Parse( ddlTransactionAccount.SelectedValue );
                ftd.Amount = decimal.Parse( tbTransactionAmount.Text );
                ftd.Summary = tbTransactionSummary.Text;

                if ( transactionDetailId == 0 )
                {
                    ftdService.Add( ftd );
                }

                rockContext.SaveChanges();
            }

            mdDetails.Hide();
            FinancialTransaction transaction = new FinancialTransaction();
            transaction = new FinancialTransactionService( rockContext ).Get( hfIdTransValue.ValueAsInt() );
            BindTransactionDetailGrid( transaction );
            LoadRelatedImages( transaction.Id );
        }
Beispiel #45
0
        /// <summary>
        /// Maps the contribution.
        /// </summary>
        /// <param name="tableData">The table data.</param>
        /// <param name="selectedColumns">The selected columns.</param>
        private void MapContribution(IQueryable <Row> tableData, List <string> selectedColumns = null)
        {
            var lookupContext                 = new RockContext();
            int transactionEntityTypeId       = EntityTypeCache.Read("Rock.Model.FinancialTransaction").Id;
            var transactionTypeContributionId = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION), lookupContext).Id;

            var currencyTypes          = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE));
            int currencyTypeACH        = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH))).Id;
            int currencyTypeCash       = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH))).Id;
            int currencyTypeCheck      = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK))).Id;
            int currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault(dv => dv.Guid.Equals(new Guid(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD))).Id;
            int?currencyTypeNonCash    = currencyTypes.DefinedValues.Where(dv => dv.Value.Equals("Non-Cash")).Select(dv => (int?)dv.Id).FirstOrDefault();

            if (currencyTypeNonCash == null)
            {
                var newTenderNonCash = new DefinedValue();
                newTenderNonCash.Value         = "Non-Cash";
                newTenderNonCash.Description   = "Non-Cash";
                newTenderNonCash.DefinedTypeId = currencyTypes.Id;
                lookupContext.DefinedValues.Add(newTenderNonCash);
                lookupContext.SaveChanges();

                currencyTypeNonCash = newTenderNonCash.Id;
            }

            var creditCardTypes = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE)).DefinedValues;

            int sourceTypeOnsite  = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_ONSITE_COLLECTION), lookupContext).Id;
            int sourceTypeWebsite = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE), lookupContext).Id;
            int sourceTypeKiosk   = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_KIOSK), lookupContext).Id;

            var refundReasons = DefinedTypeCache.Read(new Guid(Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON), lookupContext).DefinedValues;

            var accountList = new FinancialAccountService(lookupContext).Queryable().AsNoTracking().ToList();

            int?defaultBatchId = null;

            if (ImportedBatches.ContainsKey(0))
            {
                defaultBatchId = ImportedBatches[0];
            }

            // Get all imported contributions
            var importedContributions = new FinancialTransactionService(lookupContext).Queryable().AsNoTracking()
                                        .Where(c => c.ForeignId != null)
                                        .ToDictionary(t => (int)t.ForeignId, t => (int?)t.Id);

            // List for batching new contributions
            var newTransactions = new List <FinancialTransaction>();

            int completed  = 0;
            int totalRows  = tableData.Count();
            int percentage = (totalRows - 1) / 100 + 1;

            ReportProgress(0, string.Format("Verifying contribution import ({0:N0} found, {1:N0} already exist).", totalRows, importedContributions.Count));
            foreach (var row in tableData.Where(r => r != null))
            {
                int?individualId   = row["Individual_ID"] as int?;
                int?householdId    = row["Household_ID"] as int?;
                int?contributionId = row["ContributionID"] as int?;

                if (contributionId != null && !importedContributions.ContainsKey((int)contributionId))
                {
                    var transaction = new FinancialTransaction();
                    transaction.CreatedByPersonAliasId  = ImportPersonAliasId;
                    transaction.ModifiedByPersonAliasId = ImportPersonAliasId;
                    transaction.TransactionTypeValueId  = transactionTypeContributionId;
                    transaction.ForeignKey = contributionId.ToString();
                    transaction.ForeignId  = contributionId;

                    int?giverAliasId = null;
                    var personKeys   = GetPersonKeys(individualId, householdId);
                    if (personKeys != null && personKeys.PersonAliasId > 0)
                    {
                        giverAliasId = personKeys.PersonAliasId;
                        transaction.CreatedByPersonAliasId   = giverAliasId;
                        transaction.AuthorizedPersonAliasId  = giverAliasId;
                        transaction.ProcessedByPersonAliasId = giverAliasId;
                    }

                    string summary = row["Memo"] as string;
                    if (summary != null)
                    {
                        transaction.Summary = summary;
                    }

                    int?batchId = row["BatchID"] as int?;
                    if (batchId != null && ImportedBatches.Any(b => b.Key.Equals(batchId)))
                    {
                        transaction.BatchId = ImportedBatches.FirstOrDefault(b => b.Key.Equals(batchId)).Value;
                    }
                    else
                    {
                        // use the default batch for any non-matching transactions
                        transaction.BatchId = defaultBatchId;
                    }

                    DateTime?receivedDate = row["Received_Date"] as DateTime?;
                    if (receivedDate != null)
                    {
                        transaction.TransactionDateTime = receivedDate;
                        transaction.CreatedDateTime     = receivedDate;
                        transaction.ModifiedDateTime    = ImportDateTime;
                    }

                    string cardType         = row["Card_Type"] as string;
                    string cardLastFour     = row["Last_Four"] as string;
                    string contributionType = row["Contribution_Type_Name"].ToStringSafe().ToLower();
                    if (contributionType != null)
                    {
                        // set default source to onsite, exceptions listed below
                        transaction.SourceTypeValueId = sourceTypeOnsite;

                        int?paymentCurrencyTypeId = null, creditCardTypeId = null;

                        if (contributionType == "cash")
                        {
                            paymentCurrencyTypeId = currencyTypeCash;
                        }
                        else if (contributionType == "check")
                        {
                            paymentCurrencyTypeId = currencyTypeCheck;
                        }
                        else if (contributionType == "ach")
                        {
                            paymentCurrencyTypeId         = currencyTypeACH;
                            transaction.SourceTypeValueId = sourceTypeWebsite;
                        }
                        else if (contributionType == "credit card")
                        {
                            paymentCurrencyTypeId         = currencyTypeCreditCard;
                            transaction.SourceTypeValueId = sourceTypeWebsite;

                            if (cardType != null)
                            {
                                creditCardTypeId = creditCardTypes.Where(t => t.Value.Equals(cardType)).Select(t => (int?)t.Id).FirstOrDefault();
                            }
                        }
                        else
                        {
                            paymentCurrencyTypeId = currencyTypeNonCash;
                        }

                        var paymentDetail = new FinancialPaymentDetail();
                        paymentDetail.CreatedDateTime         = receivedDate;
                        paymentDetail.CreatedByPersonAliasId  = giverAliasId;
                        paymentDetail.ModifiedDateTime        = ImportDateTime;
                        paymentDetail.ModifiedByPersonAliasId = giverAliasId;
                        paymentDetail.CurrencyTypeValueId     = paymentCurrencyTypeId;
                        paymentDetail.CreditCardTypeValueId   = creditCardTypeId;
                        paymentDetail.AccountNumberMasked     = cardLastFour;
                        paymentDetail.ForeignKey = contributionId.ToString();
                        paymentDetail.ForeignId  = contributionId;

                        transaction.FinancialPaymentDetail = paymentDetail;
                    }

                    string checkNumber = row["Check_Number"] as string;
                    // if the check number is valid, put it in the transaction code
                    if (checkNumber.AsType <int?>() != null)
                    {
                        transaction.TransactionCode = checkNumber;
                    }
                    // check for SecureGive kiosk transactions
                    else if (!string.IsNullOrEmpty(checkNumber) && checkNumber.StartsWith("SG"))
                    {
                        transaction.SourceTypeValueId = sourceTypeKiosk;
                    }

                    string  fundName         = row["Fund_Name"] as string;
                    string  subFund          = row["Sub_Fund_Name"] as string;
                    string  fundGLAccount    = row["Fund_GL_Account"] as string;
                    string  subFundGLAccount = row["Sub_Fund_GL_Account"] as string;
                    Boolean?isFundActive     = row["Fund_Is_active"] as Boolean?;
                    decimal?statedValue      = row["Stated_Value"] as decimal?;
                    decimal?amount           = row["Amount"] as decimal?;
                    if (fundName != null & amount != null)
                    {
                        int transactionAccountId;
                        var parentAccount = accountList.FirstOrDefault(a => a.Name.Equals(fundName) && a.CampusId == null);
                        if (parentAccount == null)
                        {
                            parentAccount = AddAccount(lookupContext, fundName, fundGLAccount, null, null, isFundActive);
                            accountList.Add(parentAccount);
                        }

                        if (subFund != null)
                        {
                            int?campusFundId = null;
                            // assign a campus if the subfund is a campus fund
                            var campusFund = CampusList.FirstOrDefault(c => subFund.StartsWith(c.Name) || subFund.StartsWith(c.ShortCode));
                            if (campusFund != null)
                            {
                                // use full campus name as the subfund
                                subFund      = campusFund.Name;
                                campusFundId = campusFund.Id;
                            }

                            // add info to easily find/assign this fund in the view
                            subFund = string.Format("{0} {1}", subFund, fundName);

                            var childAccount = accountList.FirstOrDefault(c => c.Name.Equals(subFund) && c.ParentAccountId == parentAccount.Id);
                            if (childAccount == null)
                            {
                                // create a child account with a campusId if it was set
                                childAccount = AddAccount(lookupContext, subFund, subFundGLAccount, campusFundId, parentAccount.Id, isFundActive);
                                accountList.Add(childAccount);
                            }

                            transactionAccountId = childAccount.Id;
                        }
                        else
                        {
                            transactionAccountId = parentAccount.Id;
                        }

                        if (amount == 0 && statedValue != null && statedValue != 0)
                        {
                            amount = statedValue;
                        }

                        var transactionDetail = new FinancialTransactionDetail();
                        transactionDetail.Amount          = (decimal)amount;
                        transactionDetail.CreatedDateTime = receivedDate;
                        transactionDetail.AccountId       = transactionAccountId;
                        transaction.TransactionDetails.Add(transactionDetail);

                        if (amount < 0)
                        {
                            transaction.RefundDetails = new FinancialTransactionRefund();
                            transaction.RefundDetails.CreatedDateTime     = receivedDate;
                            transaction.RefundDetails.RefundReasonValueId = refundReasons.Where(dv => summary != null && dv.Value.Contains(summary))
                                                                            .Select(dv => (int?)dv.Id).FirstOrDefault();
                            transaction.RefundDetails.RefundReasonSummary = summary;
                        }
                    }

                    newTransactions.Add(transaction);
                    completed++;
                    if (completed % percentage < 1)
                    {
                        int percentComplete = completed / percentage;
                        ReportProgress(percentComplete, string.Format("{0:N0} contributions imported ({1}% complete).", completed, percentComplete));
                    }
                    else if (completed % ReportingNumber < 1)
                    {
                        SaveContributions(newTransactions);
                        newTransactions.Clear();
                        ReportPartialProgress();
                    }
                }
            }

            if (newTransactions.Any())
            {
                SaveContributions(newTransactions);
            }

            ReportProgress(100, string.Format("Finished contribution import: {0:N0} contributions imported.", completed));
        }
        /// <summary>
        /// Handles the Click event of the btnNext control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        protected void btnNext_Click(object sender, EventArgs e)
        {
            var rockContext = new RockContext();
            var financialTransactionService       = new FinancialTransactionService(rockContext);
            var financialTransactionDetailService = new FinancialTransactionDetailService(rockContext);
            var financialPersonBankAccountService = new FinancialPersonBankAccountService(rockContext);
            int txnId = hfTransactionId.Value.AsInteger();
            var financialTransaction = financialTransactionService
                                       .Queryable("AuthorizedPersonAlias.Person,ProcessedByPersonAlias.Person")
                                       .FirstOrDefault(t => t.Id == txnId);

            // set the AuthorizedPersonId (the person who wrote the check, for example) to the if the SelectNew person (if selected) or person selected in the drop down (if there is somebody selected)
            int?authorizedPersonId = ppSelectNew.PersonId ?? ddlIndividual.SelectedValue.AsIntegerOrNull();

            var accountNumberSecured = hfCheckMicrHashed.Value;

            if (cbTotalAmount.Text.AsDecimalOrNull().HasValue&& !authorizedPersonId.HasValue)
            {
                nbSaveError.Text    = "Transaction must be matched to a person when the amount is specified.";
                nbSaveError.Visible = true;
                return;
            }

            // if the transaction was previously matched, but user unmatched it, save it as an unmatched transaction and clear out the detail records (we don't want an unmatched transaction to have detail records)
            if (financialTransaction != null &&
                financialTransaction.AuthorizedPersonAliasId.HasValue &&
                !authorizedPersonId.HasValue)
            {
                financialTransaction.AuthorizedPersonAliasId = null;
                foreach (var detail in financialTransaction.TransactionDetails)
                {
                    financialTransactionDetailService.Delete(detail);
                }

                rockContext.SaveChanges();

                // if the transaction was unmatched, clear out the ProcessedBy fields since we didn't match the transaction and are moving on to process another transaction
                MarkTransactionAsNotProcessedByCurrentUser(hfTransactionId.Value.AsInteger());
            }

            // if the transaction is matched to somebody, attempt to save it.  Otherwise, if the transaction was previously matched, but user unmatched it, save it as an unmatched transaction
            if (financialTransaction != null && authorizedPersonId.HasValue)
            {
                bool requiresMicr = financialTransaction.CurrencyTypeValue.Guid == Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK.AsGuid();
                if (requiresMicr && string.IsNullOrWhiteSpace(accountNumberSecured))
                {
                    // should be showing already, but just in case
                    nbNoMicrWarning.Visible = true;
                    return;
                }

                if (cbTotalAmount.Text.AsDecimalOrNull() == null)
                {
                    nbSaveError.Text    = "Total amount must be allocated to accounts.";
                    nbSaveError.Visible = true;
                    return;
                }

                int?personAliasId = new PersonAliasService(rockContext).GetPrimaryAliasId(authorizedPersonId.Value);

                // if this transaction has an accountnumber associated with it (in other words, it's a scanned check), ensure there is a financialPersonBankAccount record
                if (!string.IsNullOrWhiteSpace(accountNumberSecured))
                {
                    var financialPersonBankAccount = financialPersonBankAccountService.Queryable().Where(a => a.AccountNumberSecured == accountNumberSecured && a.PersonAlias.PersonId == authorizedPersonId.Value).FirstOrDefault();
                    if (financialPersonBankAccount == null)
                    {
                        if (personAliasId.HasValue)
                        {
                            financialPersonBankAccount = new FinancialPersonBankAccount();
                            financialPersonBankAccount.PersonAliasId        = personAliasId.Value;
                            financialPersonBankAccount.AccountNumberSecured = accountNumberSecured;

                            var checkMicrClearText = Encryption.DecryptString(financialTransaction.CheckMicrEncrypted);
                            var parts = checkMicrClearText.Split('_');
                            if (parts.Length >= 2)
                            {
                                financialPersonBankAccount.AccountNumberMasked = parts[1].Masked();
                            }

                            financialPersonBankAccountService.Add(financialPersonBankAccount);
                        }
                    }
                }

                if (personAliasId.HasValue)
                {
                    financialTransaction.AuthorizedPersonAliasId = personAliasId;
                }

                // just in case this transaction is getting re-edited either by the same user, or somebody else, clean out any existing TransactionDetail records
                foreach (var detail in financialTransaction.TransactionDetails.ToList())
                {
                    financialTransactionDetailService.Delete(detail);
                }

                foreach (var accountBox in rptAccounts.ControlsOfTypeRecursive <CurrencyBox>())
                {
                    var amount = accountBox.Text.AsDecimalOrNull();

                    if (amount.HasValue && amount.Value >= 0)
                    {
                        var financialTransactionDetail = new FinancialTransactionDetail();
                        financialTransactionDetail.TransactionId = financialTransaction.Id;
                        financialTransactionDetail.AccountId     = accountBox.Attributes["data-account-id"].AsInteger();
                        financialTransactionDetail.Amount        = amount.Value;
                        financialTransactionDetailService.Add(financialTransactionDetail);
                    }
                }

                financialTransaction.ProcessedByPersonAliasId = this.CurrentPersonAlias.Id;
                financialTransaction.ProcessedDateTime        = RockDateTime.Now;

                rockContext.SaveChanges();
            }
            else
            {
                // if the transaction was not matched, clear out the ProcessedBy fields since we didn't match the transaction and are moving on to process another transaction
                MarkTransactionAsNotProcessedByCurrentUser(hfTransactionId.Value.AsInteger());
            }

            NavigateToTransaction(Direction.Next);
        }
        //
        // Swipe Panel Events
        //
        private void ProcessSwipe( string swipeData )
        {
            try
            {
                using ( var rockContext = new RockContext() )
                {
                    // create swipe object
                    SwipePaymentInfo swipeInfo = new SwipePaymentInfo( swipeData );
                    swipeInfo.Amount = this.Amounts.Sum( a => a.Value );

                    // if not anonymous then add contact info to the gateway transaction
                    if ( this.AnonymousGiverPersonAliasId != this.SelectedGivingUnit.PersonAliasId )
                    {
                        var giver = new PersonAliasService( rockContext ).Queryable( "Person, Person.PhoneNumbers" ).Where( p => p.Id == this.SelectedGivingUnit.PersonAliasId ).FirstOrDefault();
                        swipeInfo.FirstName = giver.Person.NickName;
                        swipeInfo.LastName = giver.Person.LastName;

                        if ( giver.Person.PhoneNumbers != null )
                        {
                            Guid homePhoneValueGuid = new Guid( Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_HOME );
                            var homephone = giver.Person.PhoneNumbers.Where( p => p.NumberTypeValue.Guid == homePhoneValueGuid ).FirstOrDefault();
                            if ( homephone != null )
                            {
                                swipeInfo.Phone = homephone.NumberFormatted;
                            }
                        }

                        var homeLocation = giver.Person.GetHomeLocation();

                        if ( homeLocation != null )
                        {
                            swipeInfo.Street1 = homeLocation.Street1;

                            if ( !string.IsNullOrWhiteSpace( homeLocation.Street2 ) )
                            {
                                swipeInfo.Street2 = homeLocation.Street2;
                            }

                            swipeInfo.City = homeLocation.City;
                            swipeInfo.State = homeLocation.State;
                            swipeInfo.PostalCode = homeLocation.PostalCode;
                        }

                    }

                    // add comment to the transation
                    swipeInfo.Comment1 = GetAttributeValue( "PaymentComment" );

                    // get gateway
                    FinancialGateway financialGateway = null;
                    GatewayComponent gateway = null;
                    Guid? gatewayGuid = GetAttributeValue( "CreditCardGateway" ).AsGuidOrNull();
                    if ( gatewayGuid.HasValue )
                    {
                        financialGateway = new FinancialGatewayService( rockContext ).Get( gatewayGuid.Value );
                        if ( financialGateway != null )
                        {
                            financialGateway.LoadAttributes( rockContext );
                        }
                        gateway = financialGateway.GetGatewayComponent();
                    }

                    if ( gateway != null )
                    {

                        string errorMessage = string.Empty;
                        var transaction = gateway.Charge( financialGateway, swipeInfo, out errorMessage );

                        if ( transaction != null )
                        {

                            var txnChanges = new List<string>();
                            txnChanges.Add( "Created Transaction (from kiosk)" );

                            _transactionCode = transaction.TransactionCode;
                            History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode );

                            var personName = new PersonAliasService( rockContext )
                                .Queryable().AsNoTracking()
                                .Where( a => a.Id == this.SelectedGivingUnit.PersonAliasId )
                                .Select( a => a.Person.NickName + " " + a.Person.LastName )
                                .FirstOrDefault();

                            transaction.AuthorizedPersonAliasId = this.SelectedGivingUnit.PersonAliasId;
                            History.EvaluateChange( txnChanges, "Person", string.Empty, personName );

                            transaction.TransactionDateTime = RockDateTime.Now;
                            History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime );

                            transaction.FinancialGatewayId = financialGateway.Id;
                            History.EvaluateChange( txnChanges, "Gateway", string.Empty, financialGateway.Name );

                            var txnType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ) );
                            transaction.TransactionTypeValueId = txnType.Id;
                            History.EvaluateChange( txnChanges, "Type", string.Empty, txnType.Value );

                            transaction.Summary = swipeInfo.Comment1;
                            History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.Summary );

                            if ( transaction.FinancialPaymentDetail == null )
                            {
                                transaction.FinancialPaymentDetail = new FinancialPaymentDetail();
                            }
                            transaction.FinancialPaymentDetail.SetFromPaymentInfo( swipeInfo, gateway, rockContext, txnChanges );

                            Guid sourceGuid = Guid.Empty;
                            if ( Guid.TryParse( GetAttributeValue( "Source" ), out sourceGuid ) )
                            {
                                var source = DefinedValueCache.Read( sourceGuid );
                                if ( source != null )
                                {
                                    transaction.SourceTypeValueId = source.Id;
                                    History.EvaluateChange( txnChanges, "Source", string.Empty, source.Value );
                                }
                            }

                            foreach ( var accountAmount in this.Amounts.Where( a => a.Value > 0 ) )
                            {
                                var transactionDetail = new FinancialTransactionDetail();
                                transactionDetail.Amount = accountAmount.Value;
                                transactionDetail.AccountId = accountAmount.Key;
                                transaction.TransactionDetails.Add( transactionDetail );
                                var account = new FinancialAccountService( rockContext ).Get( accountAmount.Key );
                                if ( account != null )
                                {
                                    History.EvaluateChange( txnChanges, account.Name, 0.0M.FormatAsCurrency(), transactionDetail.Amount.FormatAsCurrency() );
                                }
                            }

                            var batchService = new FinancialBatchService( rockContext );

                            // Get the batch
                            var batch = batchService.Get(
                                GetAttributeValue( "BatchNamePrefix" ),
                                swipeInfo.CurrencyTypeValue,
                                swipeInfo.CreditCardTypeValue,
                                transaction.TransactionDateTime.Value,
                                financialGateway.GetBatchTimeOffset() );

                            var batchChanges = new List<string>();

                            if ( batch.Id == 0 )
                            {
                                batchChanges.Add( "Generated the batch" );
                                History.EvaluateChange( batchChanges, "Batch Name", string.Empty, batch.Name );
                                History.EvaluateChange( batchChanges, "Status", null, batch.Status );
                                History.EvaluateChange( batchChanges, "Start Date/Time", null, batch.BatchStartDateTime );
                                History.EvaluateChange( batchChanges, "End Date/Time", null, batch.BatchEndDateTime );
                            }

                            decimal newControlAmount = batch.ControlAmount + transaction.TotalAmount;
                            History.EvaluateChange( batchChanges, "Control Amount", batch.ControlAmount.FormatAsCurrency(), newControlAmount.FormatAsCurrency() );
                            batch.ControlAmount = newControlAmount;

                            transaction.BatchId = batch.Id;
                            batch.Transactions.Add( transaction );

                            rockContext.WrapTransaction( () =>
                            {

                                rockContext.SaveChanges();
                                HistoryService.SaveChanges(
                                    rockContext,
                                    typeof( FinancialBatch ),
                                    Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(),
                                    batch.Id,
                                    batchChanges
                                );

                                HistoryService.SaveChanges(
                                    rockContext,
                                    typeof( FinancialBatch ),
                                    Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(),
                                    batch.Id,
                                    txnChanges,
                                    personName,
                                    typeof( FinancialTransaction ),
                                    transaction.Id
                                );
                            } );

                            // send receipt in one is configured and not giving anonymously
                            if ( !string.IsNullOrWhiteSpace( GetAttributeValue( "ReceiptEmail" ) ) && ( this.AnonymousGiverPersonAliasId != this.SelectedGivingUnit.PersonAliasId ) )
                            {
                                _receiptSent = true;

                                SendReceipt();
                            }

                            HidePanels();
                            ShowReceiptPanel();
                        }
                        else
                        {
                            lSwipeErrors.Text = String.Format( "<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", errorMessage );
                        }

                    }
                    else
                    {
                        lSwipeErrors.Text = "<div class='alert alert-danger'>Invalid gateway provided. Please provide a gateway. Transaction not processed.</div>";
                    }
                }
            }
            catch ( Exception ex )
            {
                lSwipeErrors.Text = String.Format( "<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", ex.Message );
            }
        }
Beispiel #48
0
        /// <summary>
        /// Maps the contribution.
        /// </summary>
        /// <param name="tableData">The table data.</param>
        /// <param name="selectedColumns">The selected columns.</param>
        private void MapContribution( IQueryable<Row> tableData, List<string> selectedColumns = null )
        {
            var lookupContext = new RockContext();
            int transactionEntityTypeId = EntityTypeCache.Read( "Rock.Model.FinancialTransaction" ).Id;
            var transactionTypeContributionId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ), lookupContext ).Id;
            var transactionTypeEventRegistrationId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_EVENT_REGISTRATION ), lookupContext ).Id;

            int currencyTypeACH = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ), lookupContext ).Id;
            int currencyTypeCash = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH ), lookupContext ).Id;
            int currencyTypeCheck = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK ), lookupContext ).Id;
            int currencyTypeCreditCard = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ), lookupContext ).Id;

            var refundReasons = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON ), lookupContext ).DefinedValues;

            List<FinancialPledge> pledgeList = new FinancialPledgeService( lookupContext ).Queryable().ToList();
            List<FinancialAccount> accountList = new FinancialAccountService( lookupContext ).Queryable().ToList();

            // Get all imported contributions
            var importedContributions = new FinancialTransactionService( lookupContext ).Queryable()
               .Select( t => new { ContributionId = t.ForeignId, TransactionId = t.Id } )
               .ToDictionary( t => t.ContributionId.AsType<int?>(), t => (int?)t.TransactionId );

            var householdAVList = new AttributeValueService( lookupContext ).Queryable().Where( av => av.AttributeId == HouseholdAttributeId ).ToList();

            // List for batching new contributions
            var newTransactions = new List<FinancialTransaction>();

            int completed = 0;
            int totalRows = tableData.Count();
            int percentage = ( totalRows - 1 ) / 100 + 1;
            ReportProgress( 0, string.Format( "Verifying contribution import ({0:N0} found, {1:N0} already exist).", totalRows, importedContributions.Count() ) );

            foreach ( var row in tableData )
            {
                int? individualId = row["Individual_ID"] as int?;
                int? householdId = row["Household_ID"] as int?;
                int? contributionId = row["ContributionID"] as int?;

                if ( contributionId != null && !importedContributions.ContainsKey( contributionId ) )
                {
                    var transaction = new FinancialTransaction();

                    string fundName = row["Fund_Name"] as string;

                    //Crossroads - Anything under a fund name that starts with Receipt - is an Event Registration.
                    if ( fundName.StartsWith( "Receipt -" ) ) { transaction.TransactionTypeValueId = transactionTypeEventRegistrationId; }
                    else { transaction.TransactionTypeValueId = transactionTypeContributionId; }

                    int? associatedPersonId;
                    if ( individualId != null ) { associatedPersonId = GetPersonAliasId( individualId, householdId ); } //will get the exact person if Individual Id is not null.
                    else { associatedPersonId = GetPersonId( householdAVList, householdId ); } //Will attempt to get the Head first, then Spouse, then Child. Will exclude Other and Visitor
                    if ( associatedPersonId != null )
                    {
                        transaction.AuthorizedPersonAliasId = associatedPersonId;
                        transaction.CreatedByPersonAliasId = ImportPersonAlias.Id;
                        transaction.ProcessedByPersonAliasId = associatedPersonId;
                        transaction.ForeignId = contributionId.ToString();

                        string summary = row["Memo"] as string;
                        if ( summary != null )
                        {
                            transaction.Summary = summary;
                        }

                        int? batchId = row["BatchID"] as int?;
                        if ( batchId != null && ImportedBatches.Any( b => b.Key == batchId ) )
                        {
                            transaction.BatchId = ImportedBatches.FirstOrDefault( b => b.Key == batchId ).Value;
                        }

                        DateTime? receivedDate = row["Received_Date"] as DateTime?;
                        if ( receivedDate != null )
                        {
                            transaction.TransactionDateTime = receivedDate;
                            transaction.CreatedDateTime = receivedDate;
                        }

                        bool isTypeNonCash = false;
                        string contributionType = row["Contribution_Type_Name"].ToString().ToLower();
                        if ( contributionType != null )
                        {
                            if ( contributionType == "ach" )
                            {
                                transaction.CurrencyTypeValueId = currencyTypeACH;
                            }
                            else if ( contributionType == "cash" )
                            {
                                transaction.CurrencyTypeValueId = currencyTypeCash;
                            }
                            else if ( contributionType == "check" )
                            {
                                transaction.CurrencyTypeValueId = currencyTypeCheck;
                            }
                            else if ( contributionType == "credit card" )
                            {
                                transaction.CurrencyTypeValueId = currencyTypeCreditCard;
                            }
                            else
                            {
                                isTypeNonCash = true;
                            }
                        }

                        string checkNumber = row["Check_Number"] as string;
                        if ( checkNumber != null && checkNumber.AsType<int?>() != null )
                        {
                            // routing & account set to zero
                            transaction.CheckMicrEncrypted = Encryption.EncryptString( string.Format( "{0}_{1}_{2}", 0, 0, checkNumber ) );
                        }

                        decimal? amount = row["Amount"] as decimal?;
                        if ( fundName != null & amount != null )
                        {
                            FinancialAccount matchingAccount = null;
                            int? parentAccountId = null;
                            string parentAccountName = String.Empty;
                            int? fundCampusId = null;
                            fundName = fundName.Trim();

                            string subFund = row["Sub_Fund_Name"] as string;
                            if ( subFund != null )
                            {
                                subFund = subFund.Trim();

                                // Check if subfund was used to mark a multi-site campus
                                fundCampusId = CampusList.Where( c => subFund.StartsWith( c.Name ) || subFund.StartsWith( c.ShortCode ) )
                                    .Select( c => (int?)c.Id ).FirstOrDefault();

                                // Matched a campus, check to see if an account exists for that campus already
                                if ( fundCampusId != null )
                                {
                                    matchingAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName )
                                        && a.CampusId != null && a.CampusId.Equals( fundCampusId ) );
                                }
                                else
                                {
                                    // No campus match, look for an account that matches parent name and subfund name
                                    matchingAccount = accountList.FirstOrDefault( a => a.ParentAccountId != null && a.ParentAccount.Name.Equals( fundName ) && a.Name.Equals( subFund ) );

                                    if ( matchingAccount == null )
                                    {
                                        // Check if a parent account exists already
                                        FinancialAccount parentAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName ) );
                                        if ( parentAccount == null )
                                        {

                                            parentAccount = AddAccount( lookupContext, fundName, fundCampusId );
                                            accountList.Add( parentAccount );
                                        }

                                        // set data for subfund to be created
                                        parentAccountId = parentAccount.Id;
                                        fundName = subFund;
                                        parentAccountName = parentAccount.Name;
                                    }
                                }
                            }
                            else
                            {
                                matchingAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName ) && a.CampusId == null );
                            }

                            if ( matchingAccount == null )
                            {

                                // No account matches, create the new account with campus Id and parent Id if they were set
                                matchingAccount = AddAccount( lookupContext, fundName, fundCampusId, parentAccountName, parentAccountId );

                                accountList.Add( matchingAccount );
                            }

                            var transactionDetail = new FinancialTransactionDetail();
                            transactionDetail.Amount = (decimal)amount;
                            transactionDetail.CreatedDateTime = receivedDate;
                            transactionDetail.AccountId = matchingAccount.Id;
                            transactionDetail.IsNonCash = isTypeNonCash;
                            transaction.TransactionDetails.Add( transactionDetail );

                            if ( amount < 0 )
                            {
                                var transactionRefund = new FinancialTransactionRefund();
                                transactionRefund.CreatedDateTime = receivedDate;
                                transactionRefund.RefundReasonSummary = summary;
                                transactionRefund.RefundReasonValueId = refundReasons.Where( dv => summary != null && dv.Value.Contains( summary ) )
                                    .Select( dv => (int?)dv.Id ).FirstOrDefault();
                                transaction.Refund = transactionRefund;
                            }
                        }

                        newTransactions.Add( transaction );
                        completed++;
                        if ( completed % percentage < 1 )
                        {
                            int percentComplete = completed / percentage;
                            ReportProgress( percentComplete, string.Format( "{0:N0} contributions imported ({1}% complete).", completed, percentComplete ) );
                        }
                        else if ( completed % ReportingNumber < 1 )
                        {
                            SaveContributions( newTransactions );
                            newTransactions.Clear();
                            ReportPartialProgress();
                        }
                    }
                }
            }

            if ( newTransactions.Any() )
            {
                SaveContributions( newTransactions );
            }

            ReportProgress( 100, string.Format( "Finished contribution import: {0:N0} contributions imported.", completed ) );
        }
Beispiel #49
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>
        /// Processes the payments.
        /// </summary>
        /// <param name="gateway">The gateway.</param>
        /// <param name="batchNamePrefix">The batch name prefix.</param>
        /// <param name="payments">The payments.</param>
        /// <param name="batchUrlFormat">The batch URL format.</param>
        /// <param name="receiptEmail">The receipt email.</param>
        /// <returns></returns>
        public static string ProcessPayments( FinancialGateway gateway, string batchNamePrefix, List<Payment> payments, string batchUrlFormat = "", Guid? receiptEmail = null )
        {
            int totalPayments = 0;
            int totalAlreadyDownloaded = 0;
            int totalNoScheduledTransaction = 0;
            int totalAdded = 0;
            int totalReversals = 0;
            int totalStatusChanges = 0;

            var batches = new List<FinancialBatch>();
            var batchSummary = new Dictionary<Guid, List<Decimal>>();
            var initialControlAmounts = new Dictionary<Guid, decimal>();

            var txnPersonNames = new Dictionary<Guid, string>();

            var gatewayComponent = gateway.GetGatewayComponent();

            var newTransactions = new List<FinancialTransaction>();

            using ( var rockContext = new RockContext() )
            {
                var accountService = new FinancialAccountService( rockContext );
                var txnService = new FinancialTransactionService( rockContext );
                var batchService = new FinancialBatchService( rockContext );
                var scheduledTxnService = new FinancialScheduledTransactionService( rockContext );

                var contributionTxnType = DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid() );

                var defaultAccount = accountService.Queryable()
                    .Where( a =>
                        a.IsActive &&
                        !a.ParentAccountId.HasValue &&
                        ( !a.StartDate.HasValue || a.StartDate.Value <= RockDateTime.Now ) &&
                        ( !a.EndDate.HasValue || a.EndDate.Value >= RockDateTime.Now )
                        )
                    .OrderBy( a => a.Order )
                    .FirstOrDefault();

                var batchTxnChanges = new Dictionary<Guid, List<string>>();
                var batchBatchChanges = new Dictionary<Guid, List<string>>();
                var scheduledTransactionIds = new List<int>();

                foreach ( var payment in payments.Where( p => p.Amount > 0.0M ) )
                {
                    totalPayments++;

                    var scheduledTransaction = scheduledTxnService.GetByScheduleId( payment.GatewayScheduleId );
                    if ( scheduledTransaction != null )
                    {
                        // Find existing payments with same transaction code
                        var txns = txnService
                            .Queryable( "TransactionDetails" )
                            .Where( t => t.TransactionCode == payment.TransactionCode )
                            .ToList();

                        // Calculate whether a transaction needs to be added
                        var txnAmount = CalculateTransactionAmount( payment, txns );
                        if ( txnAmount != 0.0M )
                        {
                            scheduledTransactionIds.Add( scheduledTransaction.Id );
                            if ( payment.ScheduleActive.HasValue )
                            {
                                scheduledTransaction.IsActive = payment.ScheduleActive.Value;
                            }

                            var transaction = new FinancialTransaction();
                            transaction.FinancialPaymentDetail = new FinancialPaymentDetail();

                            transaction.Guid = Guid.NewGuid();
                            transaction.TransactionCode = payment.TransactionCode;
                            transaction.TransactionDateTime = payment.TransactionDateTime;
                            transaction.Status = payment.Status;
                            transaction.StatusMessage = payment.StatusMessage;
                            transaction.ScheduledTransactionId = scheduledTransaction.Id;
                            transaction.AuthorizedPersonAliasId = scheduledTransaction.AuthorizedPersonAliasId;
                            transaction.SourceTypeValueId = scheduledTransaction.SourceTypeValueId;
                            txnPersonNames.Add( transaction.Guid, scheduledTransaction.AuthorizedPersonAlias.Person.FullName );
                            transaction.FinancialGatewayId = gateway.Id;
                            transaction.TransactionTypeValueId = contributionTxnType.Id;

                            if ( txnAmount < 0.0M )
                            {
                                transaction.Summary = "Reversal for previous transaction that failed during processing." + Environment.NewLine;
                            }

                            var currencyTypeValue = payment.CurrencyTypeValue;
                            var creditCardTypevalue = payment.CreditCardTypeValue;

                            if ( scheduledTransaction.FinancialPaymentDetail != null )
                            {
                                if ( currencyTypeValue == null && scheduledTransaction.FinancialPaymentDetail.CurrencyTypeValueId.HasValue )
                                {
                                    currencyTypeValue = DefinedValueCache.Read( scheduledTransaction.FinancialPaymentDetail.CurrencyTypeValueId.Value );
                                }

                                if ( creditCardTypevalue == null && scheduledTransaction.FinancialPaymentDetail.CreditCardTypeValueId.HasValue )
                                {
                                    creditCardTypevalue = DefinedValueCache.Read( scheduledTransaction.FinancialPaymentDetail.CreditCardTypeValueId.Value );
                                }

                                transaction.FinancialPaymentDetail.AccountNumberMasked = scheduledTransaction.FinancialPaymentDetail.AccountNumberMasked;
                                transaction.FinancialPaymentDetail.NameOnCardEncrypted = scheduledTransaction.FinancialPaymentDetail.NameOnCardEncrypted;
                                transaction.FinancialPaymentDetail.ExpirationMonthEncrypted = scheduledTransaction.FinancialPaymentDetail.ExpirationMonthEncrypted;
                                transaction.FinancialPaymentDetail.ExpirationYearEncrypted = scheduledTransaction.FinancialPaymentDetail.ExpirationYearEncrypted;
                                transaction.FinancialPaymentDetail.BillingLocationId = scheduledTransaction.FinancialPaymentDetail.BillingLocationId;
                            }

                            if ( currencyTypeValue != null )
                            {
                                transaction.FinancialPaymentDetail.CurrencyTypeValueId = currencyTypeValue.Id;
                            }
                            if ( creditCardTypevalue != null )
                            {
                                transaction.FinancialPaymentDetail.CreditCardTypeValueId = creditCardTypevalue.Id;
                            }

                            // Try to allocate the amount of the transaction based on the current scheduled transaction accounts
                            decimal remainingAmount = Math.Abs( txnAmount );
                            foreach ( var detail in scheduledTransaction.ScheduledTransactionDetails.Where( d => d.Amount != 0.0M ) )
                            {
                                var transactionDetail = new FinancialTransactionDetail();
                                transactionDetail.AccountId = detail.AccountId;

                                if ( detail.Amount <= remainingAmount )
                                {
                                    // If the configured amount for this account is less than or equal to the remaining
                                    // amount, allocate the configured amount
                                    transactionDetail.Amount = detail.Amount;
                                    remainingAmount -= detail.Amount;
                                }
                                else
                                {
                                    // If the configured amount is greater than the remaining amount, only allocate
                                    // the remaining amount
                                    transaction.Summary += "Note: Downloaded transaction amount was less than the configured allocation amounts for the Scheduled Transaction.";
                                    transactionDetail.Amount = remainingAmount;
                                    transactionDetail.Summary = "Note: The downloaded amount was not enough to apply the configured amount to this account.";
                                    remainingAmount = 0.0M;
                                }

                                transaction.TransactionDetails.Add( transactionDetail );

                                if ( remainingAmount <= 0.0M )
                                {
                                    // If there's no amount left, break out of details
                                    break;
                                }
                            }

                            // If there's still amount left after allocating based on current config, add the remainder
                            // to the account that was configured for the most amount
                            if ( remainingAmount > 0.0M )
                            {
                                transaction.Summary += "Note: Downloaded transaction amount was greater than the configured allocation amounts for the Scheduled Transaction.";
                                var transactionDetail = transaction.TransactionDetails
                                    .OrderByDescending( d => d.Amount )
                                    .FirstOrDefault();
                                if ( transactionDetail == null && defaultAccount != null )
                                {
                                    transactionDetail = new FinancialTransactionDetail();
                                    transactionDetail.AccountId = defaultAccount.Id;
                                    transaction.TransactionDetails.Add( transactionDetail );
                                }
                                if ( transactionDetail != null )
                                {
                                    transactionDetail.Amount += remainingAmount;
                                    transactionDetail.Summary = "Note: Extra amount was applied to this account.";
                                }
                            }

                            // If the amount to apply was negative, update all details to be negative (absolute value was used when allocating to accounts)
                            if ( txnAmount < 0.0M )
                            {
                                foreach ( var txnDetail in transaction.TransactionDetails )
                                {
                                    txnDetail.Amount = 0 - txnDetail.Amount;
                                }
                            }

                            // Get the batch
                            var batch = batchService.Get(
                                batchNamePrefix,
                                currencyTypeValue,
                                creditCardTypevalue,
                                transaction.TransactionDateTime.Value,
                                gateway.GetBatchTimeOffset(),
                                batches );

                            var batchChanges = new List<string>();
                            if ( batch.Id != 0 )
                            {
                                initialControlAmounts.AddOrIgnore( batch.Guid, batch.ControlAmount );
                            }
                            batch.ControlAmount += transaction.TotalAmount;

                            batch.Transactions.Add( transaction );

                            if ( txnAmount > 0.0M && receiptEmail.HasValue )
                            {
                                newTransactions.Add( transaction );
                            }

                            // Add summary
                            if ( !batchSummary.ContainsKey( batch.Guid ) )
                            {
                                batchSummary.Add( batch.Guid, new List<Decimal>() );
                            }
                            batchSummary[batch.Guid].Add( txnAmount );

                            if ( txnAmount > 0.0M )
                            {
                                totalAdded++;
                            }
                            else
                            {
                                totalReversals++;
                            }
                        }
                        else
                        {
                            totalAlreadyDownloaded++;

                            foreach ( var txn in txns.Where( t => t.Status != payment.Status || t.StatusMessage != payment.StatusMessage ) )
                            {
                                txn.Status = payment.Status;
                                txn.StatusMessage = payment.StatusMessage;
                                totalStatusChanges++;
                            }
                        }
                    }
                    else
                    {
                        totalNoScheduledTransaction++;
                    }
                }

                rockContext.SaveChanges();

                // Queue a transaction to update the status of all affected scheduled transactions
                var updatePaymentStatusTxn = new Rock.Transactions.UpdatePaymentStatusTransaction( gateway.Id, scheduledTransactionIds );
                Rock.Transactions.RockQueue.TransactionQueue.Enqueue( updatePaymentStatusTxn );

                if ( receiptEmail.HasValue )
                {
                    // Queue a transaction to send receipts
                    var newTransactionIds = newTransactions.Select( t => t.Id ).ToList();
                    var sendPaymentReceiptsTxn = new Rock.Transactions.SendPaymentReceipts( receiptEmail.Value, newTransactionIds );
                    Rock.Transactions.RockQueue.TransactionQueue.Enqueue( sendPaymentReceiptsTxn );
                }
            }

            StringBuilder sb = new StringBuilder();
            sb.AppendFormat( "<li>{0} {1} downloaded.</li>", totalPayments.ToString( "N0" ),
                ( totalPayments == 1 ? "payment" : "payments" ) );

            if ( totalAlreadyDownloaded > 0 )
            {
                sb.AppendFormat( "<li>{0} {1} previously downloaded and {2} already been added.</li>", totalAlreadyDownloaded.ToString( "N0" ),
                    ( totalAlreadyDownloaded == 1 ? "payment was" : "payments were" ),
                    ( totalAlreadyDownloaded == 1 ? "has" : "have" ) );
            }

            if ( totalStatusChanges > 0 )
            {
                sb.AppendFormat( "<li>{0} {1} previously downloaded but had a change of status.</li>", totalStatusChanges.ToString( "N0" ),
                ( totalStatusChanges == 1 ? "payment was" : "payments were" ) );
            }

            if ( totalNoScheduledTransaction > 0 )
            {
                sb.AppendFormat( "<li>{0} {1} could not be matched to an existing scheduled payment profile.</li>", totalNoScheduledTransaction.ToString( "N0" ),
                    ( totalNoScheduledTransaction == 1 ? "payment" : "payments" ) );
            }

            sb.AppendFormat( "<li>{0} {1} successfully added.</li>", totalAdded.ToString( "N0" ),
                ( totalAdded == 1 ? "payment was" : "payments were" ) );

            if ( totalReversals > 0 )
            {
                sb.AppendFormat( "<li>{0} {1} added as a reversal to a previous transaction.</li>", totalReversals.ToString( "N0" ),
                    ( totalReversals == 1 ? "payment was" : "payments were" ) );
            }

            if ( totalStatusChanges > 0 )
            {
                sb.AppendFormat( "<li>{0} {1} previously downloaded but had a change of status.</li>", totalStatusChanges.ToString( "N0" ),
                    ( totalStatusChanges == 1 ? "payment was" : "payments were" ) );
            }

            foreach ( var batchItem in batchSummary )
            {
                int items = batchItem.Value.Count;
                if ( items > 0 )
                {
                    var batch = batches
                        .Where( b => b.Guid.Equals( batchItem.Key ) )
                        .FirstOrDefault();

                    string batchName = string.Format( "'{0} ({1})'", batch.Name, batch.BatchStartDateTime.Value.ToString( "d" ) );
                    if ( !string.IsNullOrWhiteSpace( batchUrlFormat ) )
                    {
                        batchName = string.Format( "<a href='{0}'>{1}</a>", string.Format( batchUrlFormat, batch.Id ), batchName );
                    }

                    decimal sum = batchItem.Value.Sum();

                    string summaryformat = items == 1 ?
                        "<li>{0} transaction of {1} was added to the {2} batch.</li>" :
                        "<li>{0} transactions totaling {1} were added to the {2} batch</li>";

                    sb.AppendFormat( summaryformat, items.ToString( "N0" ), sum.FormatAsCurrency(), batchName );
                }
            }

            return sb.ToString();
        }
        /// <summary>
        /// Processes the confirmation.
        /// </summary>
        /// <param name="errorMessage">The error message.</param>
        /// <returns></returns>
        private bool ProcessConfirmation( out string errorMessage )
        {
            var rockContext = new RockContext();
            if ( string.IsNullOrWhiteSpace( TransactionCode ) )
            {
                GatewayComponent gateway = hfPaymentTab.Value == "ACH" ? _achGateway : _ccGateway;
                if ( gateway == null )
                {
                    errorMessage = "There was a problem creating the payment gateway information";
                    return false;
                }

                Person person = GetPerson( true );
                if ( person == null )
                {
                    errorMessage = "There was a problem creating the person information";
                    return false;
                }

                if ( !person.PrimaryAliasId.HasValue)
                {
                    errorMessage = "There was a problem creating the person's primary alias";
                    return false;
                }

                PaymentInfo paymentInfo = GetPaymentInfo();
                if ( paymentInfo == null )
                {
                    errorMessage = "There was a problem creating the payment information";
                    return false;
                }
                else
                {
                    paymentInfo.FirstName = person.FirstName;
                    paymentInfo.LastName = person.LastName;
                }

                if ( paymentInfo.CreditCardTypeValue != null )
                {
                    CreditCardTypeValueId = paymentInfo.CreditCardTypeValue.Id;
                }

                PaymentSchedule schedule = GetSchedule();
                if ( schedule != null )
                {
                    schedule.PersonId = person.Id;

                    var scheduledTransaction = gateway.AddScheduledPayment( schedule, paymentInfo, out errorMessage );
                    if ( scheduledTransaction != null  )
                    {
                        scheduledTransaction.TransactionFrequencyValueId = schedule.TransactionFrequencyValue.Id;
                        scheduledTransaction.AuthorizedPersonAliasId = person.PrimaryAliasId.Value;
                        scheduledTransaction.GatewayEntityTypeId = EntityTypeCache.Read( gateway.TypeGuid ).Id;
                        scheduledTransaction.CurrencyTypeValueId = paymentInfo.CurrencyTypeValue.Id;
                        scheduledTransaction.CreditCardTypeValueId = CreditCardTypeValueId;

                        var changeSummary = new StringBuilder();
                        changeSummary.AppendFormat( "{0} starting {1}", schedule.TransactionFrequencyValue.Value, schedule.StartDate.ToShortDateString() );
                        changeSummary.AppendLine();
                        changeSummary.Append( paymentInfo.CurrencyTypeValue.Value );
                        if (paymentInfo.CreditCardTypeValue != null)
                        {
                            changeSummary.AppendFormat( " - {0}", paymentInfo.CreditCardTypeValue.Value );
                        }
                        changeSummary.AppendFormat( " {0}", paymentInfo.MaskedNumber );
                        changeSummary.AppendLine();

                        foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) )
                        {
                            var transactionDetail = new FinancialScheduledTransactionDetail();
                            transactionDetail.Amount = account.Amount;
                            transactionDetail.AccountId = account.Id;
                            scheduledTransaction.ScheduledTransactionDetails.Add( transactionDetail );
                            changeSummary.AppendFormat( "{0}: {1:C2}", account.Name, account.Amount );
                            changeSummary.AppendLine();
                        }

                        var transactionService = new FinancialScheduledTransactionService( rockContext );
                        transactionService.Add( scheduledTransaction );
                        rockContext.SaveChanges();

                        // Add a note about the change
                        var noteTypeService = new NoteTypeService( rockContext );
                        var noteType = noteTypeService.Get( scheduledTransaction.TypeId, "Note" );

                        var noteService = new NoteService( rockContext );
                        var note = new Note();
                        note.NoteTypeId = noteType.Id;
                        note.EntityId = scheduledTransaction.Id;
                        note.Caption = "Created Transaction";
                        note.Text = changeSummary.ToString();
                        noteService.Add( note );

                        rockContext.SaveChanges();

                        ScheduleId = scheduledTransaction.GatewayScheduleId;
                        TransactionCode = scheduledTransaction.TransactionCode;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    var transaction = gateway.Charge( paymentInfo, out errorMessage );
                    if ( transaction != null )
                    {
                        transaction.TransactionDateTime = RockDateTime.Now;
                        transaction.AuthorizedPersonAliasId = person.PrimaryAliasId;
                        transaction.GatewayEntityTypeId = gateway.TypeId;
                        transaction.TransactionTypeValueId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ) ).Id;
                        transaction.CurrencyTypeValueId = paymentInfo.CurrencyTypeValue.Id;
                        transaction.CreditCardTypeValueId = CreditCardTypeValueId;

                        Guid sourceGuid = Guid.Empty;
                        if ( Guid.TryParse( GetAttributeValue( "Source" ), out sourceGuid ) )
                        {
                            transaction.SourceTypeValueId = DefinedValueCache.Read( sourceGuid ).Id;
                        }

                        foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) )
                        {
                            var transactionDetail = new FinancialTransactionDetail();
                            transactionDetail.Amount = account.Amount;
                            transactionDetail.AccountId = account.Id;
                            transaction.TransactionDetails.Add( transactionDetail );
                        }

                        var batchService = new FinancialBatchService( rockContext );

                        // Get the batch
                        var batch = batchService.Get(
                            GetAttributeValue( "BatchNamePrefix" ),
                            paymentInfo.CurrencyTypeValue,
                            paymentInfo.CreditCardTypeValue,
                            transaction.TransactionDateTime.Value,
                            gateway.BatchTimeOffset );

                        batch.ControlAmount += transaction.TotalAmount;

                        transaction.BatchId = batch.Id;
                        batch.Transactions.Add( transaction );
                        rockContext.SaveChanges();

                        TransactionCode = transaction.TransactionCode;
                    }
                    else
                    {
                        return false;
                    }
                }

                tdTransactionCodeReceipt.Description = TransactionCode;
                tdTransactionCodeReceipt.Visible = !string.IsNullOrWhiteSpace( TransactionCode );

                tdScheduleId.Description = ScheduleId;
                tdScheduleId.Visible = !string.IsNullOrWhiteSpace( ScheduleId );

                tdNameReceipt.Description = paymentInfo.FullName;
                tdPhoneReceipt.Description = paymentInfo.Phone;
                tdEmailReceipt.Description = paymentInfo.Email;
                tdAddressReceipt.Description = string.Format( "{0} {1}, {2} {3}", paymentInfo.Street1, paymentInfo.City, paymentInfo.State, paymentInfo.PostalCode );

                rptAccountListReceipt.DataSource = SelectedAccounts.Where( a => a.Amount != 0 );
                rptAccountListReceipt.DataBind();

                tdTotalReceipt.Description = paymentInfo.Amount.ToString( "C" );

                tdPaymentMethodReceipt.Description = paymentInfo.CurrencyTypeValue.Description;
                tdAccountNumberReceipt.Description = paymentInfo.MaskedNumber;
                tdWhenReceipt.Description = schedule != null ? schedule.ToString() : "Today";

                // If there was a transaction code returned and this was not already created from a previous saved account,
                // show the option to save the account.
                if ( !( paymentInfo is ReferencePaymentInfo ) && !string.IsNullOrWhiteSpace( TransactionCode ) )
                {
                    cbSaveAccount.Visible = true;
                    pnlSaveAccount.Visible = true;
                    txtSaveAccount.Visible = true;

                    // If current person does not have a login, have them create a username and password
                    phCreateLogin.Visible = !new UserLoginService( rockContext ).GetByPersonId( person.Id ).Any();
                }
                else
                {
                    pnlSaveAccount.Visible = false;
                }

                return true;
            }
            else
            {
                pnlDupWarning.Visible = true;
                divActions.Visible = false;
                errorMessage = string.Empty;
                return false;
            }
        }
Beispiel #52
0
        /// <summary>
        /// Maps the contribution.
        /// </summary>
        /// <param name="csvData">The table data.</param>
        private int MapContribution( CSVInstance csvData )
        {
            var lookupContext = new RockContext();
            int transactionEntityTypeId = EntityTypeCache.Read( "Rock.Model.FinancialTransaction" ).Id;
            var transactionTypeContributionId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ), lookupContext ).Id;

            var currencyTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE ) );
            int currencyTypeACH = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ) ) ).Id;
            int currencyTypeCash = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH ) ) ).Id;
            int currencyTypeCheck = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK ) ) ).Id;
            int currencyTypeCreditCard = currencyTypes.DefinedValues.FirstOrDefault( dv => dv.Guid.Equals( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ) ) ).Id;
            int? currencyTypeNonCash = currencyTypes.DefinedValues.Where( dv => dv.Value.Equals( "Non-Cash" ) ).Select( dv => ( int? )dv.Id ).FirstOrDefault();
            if ( currencyTypeNonCash == null )
            {
                var newTenderNonCash = new DefinedValue();
                newTenderNonCash.Value = "Non-Cash";
                newTenderNonCash.Description = "Non-Cash";
                newTenderNonCash.DefinedTypeId = currencyTypes.Id;
                lookupContext.DefinedValues.Add( newTenderNonCash );
                lookupContext.SaveChanges();

                currencyTypeNonCash = newTenderNonCash.Id;
            }

            var creditCardTypes = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE ) ).DefinedValues;

            int sourceTypeOnsite = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_ONSITE_COLLECTION ), lookupContext ).Id;
            int sourceTypeWebsite = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_WEBSITE ), lookupContext ).Id;
            int sourceTypeKiosk = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.FINANCIAL_SOURCE_TYPE_KIOSK ), lookupContext ).Id;

            var refundReasons = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON ), lookupContext ).DefinedValues;

            var accountList = new FinancialAccountService( lookupContext ).Queryable().AsNoTracking().ToList();

            int? defaultBatchId = null;
            if ( ImportedBatches.ContainsKey( 0 ) )
            {
                defaultBatchId = ImportedBatches[0];
            }

            // Get all imported contributions
            var importedContributions = new FinancialTransactionService( lookupContext ).Queryable().AsNoTracking()
               .Where( c => c.ForeignId != null )
               .ToDictionary( t => ( int )t.ForeignId, t => ( int? )t.Id );

            // List for batching new contributions
            var newTransactions = new List<FinancialTransaction>();

            int completed = 0;
            ReportProgress( 0, string.Format( "Verifying contribution import ({0:N0} already exist).", importedContributions.Count ) );
            string[] row;
            // Uses a look-ahead enumerator: this call will move to the next record immediately
            while ( (row = csvData.Database.FirstOrDefault()) != null )
            {
                string individualIdKey = row[IndividualID];
                int? individualId = individualIdKey.AsType<int?>();
                string contributionIdKey = row[ContributionID];
                int? contributionId = contributionIdKey.AsType<int?>();

                if ( contributionId != null && !importedContributions.ContainsKey( ( int )contributionId ) )
                {
                    var transaction = new FinancialTransaction();
                    transaction.CreatedByPersonAliasId = ImportPersonAliasId;
                    transaction.ModifiedByPersonAliasId = ImportPersonAliasId;
                    transaction.TransactionTypeValueId = transactionTypeContributionId;
                    transaction.ForeignKey = contributionId.ToString();
                    transaction.ForeignId = contributionId;

                    int? giverAliasId = null;
                    var personKeys = GetPersonKeys( individualId );
                    if ( personKeys != null && personKeys.PersonAliasId > 0 )
                    {
                        giverAliasId = personKeys.PersonAliasId;
                        transaction.CreatedByPersonAliasId = giverAliasId;
                        transaction.AuthorizedPersonAliasId = giverAliasId;
                        transaction.ProcessedByPersonAliasId = giverAliasId;
                    }
                    else if ( AnonymousGiverAliasId != null && AnonymousGiverAliasId > 0 )
                    {
                        giverAliasId = AnonymousGiverAliasId;
                        transaction.AuthorizedPersonAliasId = giverAliasId;
                        transaction.ProcessedByPersonAliasId = giverAliasId;
                    }

                    string summary = row[Memo] as string;
                    if ( !String.IsNullOrWhiteSpace( summary ) )
                    {
                        transaction.Summary = summary;
                    }

                    string batchIdKey = row[ContributionBatchID];
                    int? batchId = batchIdKey.AsType<int?>();
                    if ( batchId != null && ImportedBatches.Any( b => b.Key.Equals( batchId ) ) )
                    {
                        transaction.BatchId = ImportedBatches.FirstOrDefault( b => b.Key.Equals( batchId ) ).Value;
                    }
                    else
                    {
                        // use the default batch for any non-matching transactions
                        transaction.BatchId = defaultBatchId;
                    }

                    string receivedDateKey = row[ReceivedDate];
                    DateTime? receivedDate = receivedDateKey.AsType<DateTime?>();
                    if ( receivedDate != null )
                    {
                        transaction.TransactionDateTime = receivedDate;
                        transaction.CreatedDateTime = receivedDate;
                        transaction.ModifiedDateTime = ImportDateTime;
                    }

                    string contributionType = row[ContributionTypeName].ToStringSafe().ToLower();
                    if ( !String.IsNullOrWhiteSpace( contributionType ) )
                    {
                        // set default source to onsite, exceptions listed below
                        transaction.SourceTypeValueId = sourceTypeOnsite;

                        int? paymentCurrencyTypeId = null, creditCardTypeId = null;

                        if ( contributionType == "cash" )
                        {
                            paymentCurrencyTypeId = currencyTypeCash;
                        }
                        else if ( contributionType == "check" )
                        {
                            paymentCurrencyTypeId = currencyTypeCheck;
                        }
                        else if ( contributionType == "ach" )
                        {
                            paymentCurrencyTypeId = currencyTypeACH;
                            transaction.SourceTypeValueId = sourceTypeWebsite;
                        }
                        else if ( contributionType == "credit card" )
                        {
                            paymentCurrencyTypeId = currencyTypeCreditCard;
                            transaction.SourceTypeValueId = sourceTypeWebsite;
                        }
                        else
                        {
                            paymentCurrencyTypeId = currencyTypeNonCash;
                        }

                        var paymentDetail = new FinancialPaymentDetail();
                        paymentDetail.CreatedDateTime = receivedDate;
                        paymentDetail.CreatedByPersonAliasId = giverAliasId;
                        paymentDetail.ModifiedDateTime = ImportDateTime;
                        paymentDetail.ModifiedByPersonAliasId = giverAliasId;
                        paymentDetail.CurrencyTypeValueId = paymentCurrencyTypeId;
                        paymentDetail.CreditCardTypeValueId = creditCardTypeId;
                        paymentDetail.ForeignKey = contributionId.ToString();
                        paymentDetail.ForeignId = contributionId;

                        transaction.FinancialPaymentDetail = paymentDetail;
                    }

                    string checkNumber = row[CheckNumber] as string;
                    // if the check number is valid, put it in the transaction code
                    if ( checkNumber.AsType<int?>() != null )
                    {
                        transaction.TransactionCode = checkNumber;
                    }
                    // check for SecureGive kiosk transactions
                    else if ( !string.IsNullOrEmpty( checkNumber ) && checkNumber.StartsWith( "SG" ) )
                    {
                        transaction.SourceTypeValueId = sourceTypeKiosk;
                    }

                    string fundName = row[FundName] as string;
                    string subFund = row[SubFundName] as string;
                    string fundGLAccount = row[FundGLAccount] as string;
                    string subFundGLAccount = row[SubFundGLAccount] as string;
                    string isFundActiveKey = row[FundIsActive];
                    Boolean? isFundActive = isFundActiveKey.AsType<Boolean?>();
                    string isSubFundActiveKey = row[SubFundIsActive];
                    Boolean? isSubFundActive = isSubFundActiveKey.AsType<Boolean?>();
                    string statedValueKey = row[StatedValue];
                    decimal? statedValue = statedValueKey.AsType<decimal?>();
                    string amountKey = row[Amount];
                    decimal? amount = amountKey.AsType<decimal?>();
                    if ( !String.IsNullOrWhiteSpace( fundName ) & amount != null )
                    {
                        int transactionAccountId;
                        var parentAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName.Truncate( 50 ) ) && a.CampusId == null );
                        if ( parentAccount == null )
                        {
                            parentAccount = AddAccount( lookupContext, fundName, fundGLAccount, null, null, isFundActive );
                            accountList.Add( parentAccount );
                        }

                        if ( !String.IsNullOrWhiteSpace( subFund ) )
                        {
                            int? campusFundId = null;
                            // assign a campus if the subfund is a campus fund
                            var campusFund = CampusList.FirstOrDefault( c => subFund.StartsWith( c.Name ) || subFund.StartsWith( c.ShortCode ) );
                            if ( campusFund != null )
                            {
                                // use full campus name as the subfund
                                subFund = campusFund.Name;
                                campusFundId = campusFund.Id;
                            }

                            // add info to easily find/assign this fund in the view
                            subFund = string.Format( "{0} {1}", subFund, fundName );

                            var childAccount = accountList.FirstOrDefault( c => c.Name.Equals( subFund.Truncate( 50 ) ) && c.ParentAccountId == parentAccount.Id );
                            if ( childAccount == null )
                            {
                                // create a child account with a campusId if it was set
                                childAccount = AddAccount( lookupContext, subFund, subFundGLAccount, campusFundId, parentAccount.Id, isSubFundActive );
                                accountList.Add( childAccount );
                            }

                            transactionAccountId = childAccount.Id;
                        }
                        else
                        {
                            transactionAccountId = parentAccount.Id;
                        }

                        if ( amount == 0 && statedValue != null && statedValue != 0 )
                        {
                            amount = statedValue;
                        }

                        var transactionDetail = new FinancialTransactionDetail();
                        transactionDetail.Amount = ( decimal )amount;
                        transactionDetail.CreatedDateTime = receivedDate;
                        transactionDetail.AccountId = transactionAccountId;
                        transaction.TransactionDetails.Add( transactionDetail );

                        if ( amount < 0 )
                        {
                            transaction.RefundDetails = new FinancialTransactionRefund();
                            transaction.RefundDetails.CreatedDateTime = receivedDate;
                            transaction.RefundDetails.RefundReasonValueId = refundReasons.Where( dv => summary != null && dv.Value.Contains( summary ) )
                                .Select( dv => ( int? )dv.Id ).FirstOrDefault();
                            transaction.RefundDetails.RefundReasonSummary = summary;
                        }
                    }

                    newTransactions.Add( transaction );
                    completed++;
                    if ( completed % (ReportingNumber * 10) < 1 )
                    {
                        ReportProgress( 0, string.Format( "{0:N0} contributions imported.", completed ) );
                    }
                    else if ( completed % ReportingNumber < 1 )
                    {
                        SaveContributions( newTransactions );
                        newTransactions.Clear();
                        ReportPartialProgress();
                    }
                }
            }

            if ( newTransactions.Any() )
            {
                SaveContributions( newTransactions );
            }

            ReportProgress( 100, string.Format( "Finished contribution import: {0:N0} contributions imported.", completed ) );
            return completed;
        }
Beispiel #53
0
        /// <summary>
        /// Processes the payment.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="registration">The registration.</param>
        /// <param name="errorMessage">The error message.</param>
        /// <returns></returns>
        private bool ProcessPayment( RockContext rockContext, Registration registration, out string errorMessage )
        {
            GatewayComponent gateway = null;
            if ( RegistrationTemplate != null && RegistrationTemplate.FinancialGateway != null )
            {
                gateway = RegistrationTemplate.FinancialGateway.GetGatewayComponent();
            }

            if ( gateway == null )
            {
                errorMessage = "There was a problem creating the payment gateway information";
                return false;
            }

            if ( !RegistrationInstanceState.AccountId.HasValue || RegistrationInstanceState.Account == null )
            {
                errorMessage = "There was a problem with the account configuration for this " + RegistrationTerm.ToLower();
                return false;
            }

            var paymentInfo = new CreditCardPaymentInfo( txtCreditCard.Text, txtCVV.Text, mypExpiration.SelectedDate.Value );
            paymentInfo.NameOnCard = gateway != null && gateway.SplitNameOnCard ? txtCardFirstName.Text : txtCardName.Text;
            paymentInfo.LastNameOnCard = txtCardLastName.Text;

            paymentInfo.BillingStreet1 = acBillingAddress.Street1;
            paymentInfo.BillingStreet2 = acBillingAddress.Street2;
            paymentInfo.BillingCity = acBillingAddress.City;
            paymentInfo.BillingState = acBillingAddress.State;
            paymentInfo.BillingPostalCode = acBillingAddress.PostalCode;
            paymentInfo.BillingCountry = acBillingAddress.Country;

            paymentInfo.Amount = RegistrationState.PaymentAmount ?? 0.0m;
            paymentInfo.Email = RegistrationState.ConfirmationEmail;

            paymentInfo.FirstName = RegistrationState.FirstName;
            paymentInfo.LastName = RegistrationState.LastName;

            var transaction = gateway.Charge( RegistrationTemplate.FinancialGateway, paymentInfo, out errorMessage );
            if ( transaction != null )
            {
                var txnChanges = new List<string>();
                txnChanges.Add( "Created Transaction" );

                History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode );

                transaction.AuthorizedPersonAliasId = registration.PersonAliasId;

                transaction.TransactionDateTime = RockDateTime.Now;
                History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime );

                transaction.FinancialGatewayId = RegistrationTemplate.FinancialGatewayId;
                History.EvaluateChange( txnChanges, "Gateway", string.Empty, RegistrationTemplate.FinancialGateway.Name );

                var txnType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_EVENT_REGISTRATION ) );
                transaction.TransactionTypeValueId = txnType.Id;
                History.EvaluateChange( txnChanges, "Type", string.Empty, txnType.Value );

                if ( transaction.FinancialPaymentDetail == null )
                {
                    transaction.FinancialPaymentDetail = new FinancialPaymentDetail();
                }

                transaction.FinancialPaymentDetail.NameOnCardEncrypted = Rock.Security.Encryption.EncryptString( paymentInfo.NameOnCard );
                transaction.FinancialPaymentDetail.AccountNumberMasked = paymentInfo.MaskedNumber;
                transaction.FinancialPaymentDetail.ExpirationMonthEncrypted = Rock.Security.Encryption.EncryptString( paymentInfo.ExpirationDate.Month.ToString() );
                transaction.FinancialPaymentDetail.ExpirationYearEncrypted = Rock.Security.Encryption.EncryptString( paymentInfo.ExpirationDate.Year.ToString() );
                transaction.FinancialPaymentDetail.CurrencyTypeValueId = paymentInfo.CurrencyTypeValue.Id;

                History.EvaluateChange( txnChanges, "Currency Type", string.Empty, paymentInfo.CurrencyTypeValue.Value );

                transaction.FinancialPaymentDetail.CreditCardTypeValueId = paymentInfo.CreditCardTypeValue != null ? paymentInfo.CreditCardTypeValue.Id : (int?)null;
                if ( transaction.FinancialPaymentDetail.CreditCardTypeValueId.HasValue )
                {
                    var ccType = DefinedValueCache.Read( transaction.FinancialPaymentDetail.CreditCardTypeValueId.Value );
                    History.EvaluateChange( txnChanges, "Credit Card Type", string.Empty, ccType.Value );
                }

                Guid sourceGuid = Guid.Empty;
                if ( Guid.TryParse( GetAttributeValue( "Source" ), out sourceGuid ) )
                {
                    var source = DefinedValueCache.Read( sourceGuid );
                    if ( source != null )
                    {
                        transaction.SourceTypeValueId = source.Id;
                        History.EvaluateChange( txnChanges, "Source", string.Empty, source.Value );
                    }
                }

                transaction.Summary = registration.GetSummary( RegistrationInstanceState );

                var transactionDetail = new FinancialTransactionDetail();
                transactionDetail.Amount = RegistrationState.PaymentAmount ?? 0.0m;
                transactionDetail.AccountId = RegistrationInstanceState.AccountId.Value;
                transactionDetail.EntityTypeId = EntityTypeCache.Read( typeof( Rock.Model.Registration ) ).Id;
                transactionDetail.EntityId = registration.Id;
                transaction.TransactionDetails.Add( transactionDetail );

                History.EvaluateChange( txnChanges, RegistrationInstanceState.Account.Name, 0.0M.ToString( "C2" ), transactionDetail.Amount.ToString( "C2" ) );

                var batchService = new FinancialBatchService( rockContext );

                // Get the batch
                var batch = batchService.Get(
                    GetAttributeValue( "BatchNamePrefix" ),
                    paymentInfo.CurrencyTypeValue,
                    paymentInfo.CreditCardTypeValue,
                    transaction.TransactionDateTime.Value,
                    RegistrationTemplate.FinancialGateway.GetBatchTimeOffset() );

                var batchChanges = new List<string>();

                if ( batch.Id == 0 )
                {
                    batchChanges.Add( "Generated the batch" );
                    History.EvaluateChange( batchChanges, "Batch Name", string.Empty, batch.Name );
                    History.EvaluateChange( batchChanges, "Status", null, batch.Status );
                    History.EvaluateChange( batchChanges, "Start Date/Time", null, batch.BatchStartDateTime );
                    History.EvaluateChange( batchChanges, "End Date/Time", null, batch.BatchEndDateTime );
                }

                decimal newControlAmount = batch.ControlAmount + transaction.TotalAmount;
                History.EvaluateChange( batchChanges, "Control Amount", batch.ControlAmount.ToString( "C2" ), newControlAmount.ToString( "C2" ) );
                batch.ControlAmount = newControlAmount;

                transaction.BatchId = batch.Id;
                batch.Transactions.Add( transaction );

                rockContext.SaveChanges();

                HistoryService.SaveChanges(
                    rockContext,
                    typeof( FinancialBatch ),
                    Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(),
                    batch.Id,
                    batchChanges
                );

                HistoryService.SaveChanges(
                    rockContext,
                    typeof( FinancialBatch ),
                    Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(),
                    batch.Id,
                    txnChanges,
                    CurrentPerson != null ? CurrentPerson.FullName : string.Empty,
                    typeof( FinancialTransaction ),
                    transaction.Id
                );

                TransactionCode = transaction.TransactionCode;

                return true;
            }
            else
            {
                return false;
            }
        }
Beispiel #54
0
        /// <summary>Process all transactions (payments) from Service Reef.</summary>
        /// <param name="message">The message that is returned depending on the result.</param>
        /// <param name="state">The state of the process.</param>
        /// <returns><see cref="WorkerResultStatus"/></returns>
        public void Execute(IJobExecutionContext context)
        {
            RockContext                 dbContext                   = new RockContext();
            FinancialBatchService       financialBatchService       = new FinancialBatchService(dbContext);
            PersonService               personService               = new PersonService(dbContext);
            PersonAliasService          personAliasService          = new PersonAliasService(dbContext);
            FinancialAccountService     financialAccountService     = new FinancialAccountService(dbContext);
            FinancialAccountService     accountService              = new FinancialAccountService(dbContext);
            FinancialTransactionService financialTransactionService = new FinancialTransactionService(dbContext);
            FinancialGatewayService     financialGatewayService     = new FinancialGatewayService(dbContext);
            DefinedValueService         definedValueService         = new DefinedValueService(dbContext);
            DefinedTypeService          definedTypeService          = new DefinedTypeService(dbContext);
            TransactionService          transactionService          = new TransactionService(new PayPalReporting.Data.PayPalReportingContext());

            // Get the datamap for loading attributes
            JobDataMap dataMap = context.JobDetail.JobDataMap;

            String warnings = string.Empty;

            FinancialBatch batch       = null;
            Double         totalAmount = 0;
            var            total       = 1;
            var            processed   = 0;

            try
            {
                DateRange dateRange = Rock.Web.UI.Controls.SlidingDateRangePicker.CalculateDateRangeFromDelimitedValues(dataMap.GetString("DateRange") ?? "-1||");

                String            SRApiKey          = Encryption.DecryptString(dataMap.GetString("ServiceReefAPIKey"));
                String            SRApiSecret       = Encryption.DecryptString(dataMap.GetString("ServiceReefAPISecret"));
                String            SRApiUrl          = dataMap.GetString("ServiceReefAPIURL");
                DefinedValueCache transactionSource = DefinedValueCache.Read(dataMap.GetString("TransactionSource").AsGuid(), dbContext);
                DefinedValueCache connectionStatus  = DefinedValueCache.Read(dataMap.GetString("ConnectionStatus").AsGuid(), dbContext);
                DefinedValueCache contribution      = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION);

                // Setup some lookups
                DefinedTypeCache        creditCards = DefinedTypeCache.Read(Rock.SystemGuid.DefinedType.FINANCIAL_CREDIT_CARD_TYPE.AsGuid(), dbContext);
                DefinedTypeCache        tenderType  = DefinedTypeCache.Get(Rock.SystemGuid.DefinedType.FINANCIAL_CURRENCY_TYPE.AsGuid(), dbContext);
                FinancialAccount        specialFund = accountService.Get(dataMap.GetString("Account").AsGuid());
                FinancialGateway        gateway     = financialGatewayService.Get(dataMap.GetString("FinancialGateway").AsGuid());
                List <FinancialAccount> trips       = financialAccountService.Queryable().Where(fa => fa.ParentAccountId == specialFund.Id).OrderBy(fa => fa.Order).ToList();

                // Get the trips
                DefinedValueCache serviceReefAccountType = DefinedValueCache.Get(dataMap.Get("ServiceReefAccountType").ToString().AsGuid());

                // Setup the ServiceReef API Client
                var client = new RestClient(SRApiUrl);
                client.Authenticator = new HMACAuthenticator(SRApiKey, SRApiSecret);

                // Get all payments from ServiceReef
                var request = new RestRequest("v1/payments", Method.GET);
                request.AddParameter("pageSize", 100);
                if (dateRange.Start.HasValue)
                {
                    request.AddParameter("startDate", dateRange.Start.Value.ToString("o"));
                }
                if (dateRange.End.HasValue)
                {
                    request.AddParameter("endDate", dateRange.End.Value.ToString("o"));
                }
                request.AddParameter("page", 1);

                while (total > processed)
                {
                    var response = client.Execute <Contracts.Payments>(request);
                    if (response.StatusCode != System.Net.HttpStatusCode.OK)
                    {
                        throw new Exception("ServiceReef API Response: " + response.StatusDescription + " Content Length: " + response.ContentLength);
                    }
                    if (response.Data != null && response.Data.PageInfo != null)
                    {
                        total = response.Data.PageInfo.TotalRecords;
                        foreach (Contracts.Payments.Result result in response.Data.Results)
                        {
                            // Process the transaction
                            if (result.PaymentProcessorTransactionId != null)
                            {
                                if (result.FirstName == null || result.LastName == null)
                                {
                                    warnings += "Missing Firstname/Lastname for ServiceReef transaction Id: " + result.TransactionId + Environment.NewLine;
                                    processed++;
                                    continue;
                                }
                                FinancialAccount trip = null;
                                // Make sure we have a sub-account to go with this transaction
                                if (result.EventId > 0)
                                {
                                    trip = trips.Where(t => t.GlCode == result.EventCode && t.Url == result.EventUrl).FirstOrDefault();
                                }
                                if (trip == null)
                                {
                                    if (result.EventCode == null)
                                    {
                                        warnings += "Event Code is missing on the Service Reef Trip for ServiceReef transaction Id: " + result.TransactionId + Environment.NewLine;
                                        processed++;
                                        continue;
                                    }

                                    // Create the trip subaccount
                                    FinancialAccount tripFA = new FinancialAccount();
                                    tripFA.Name = result.EventName;
                                    // Name is limited to 50
                                    if (tripFA.Name.Length > 50)
                                    {
                                        tripFA.Name = tripFA.Name.Substring(0, 50);
                                    }
                                    tripFA.Description = "Service Reef Event.  Name: " + result.EventName + " ID: " + result.EventId;
                                    tripFA.GlCode      = result.EventCode;
                                    tripFA.Url         = result.EventUrl;
                                    tripFA.PublicName  = result.EventName;
                                    // Public Name is limited to 50
                                    if (tripFA.PublicName.Length > 50)
                                    {
                                        tripFA.PublicName = tripFA.PublicName.Substring(0, 50);
                                    }
                                    tripFA.IsTaxDeductible    = true;
                                    tripFA.IsPublic           = false;
                                    tripFA.ParentAccountId    = specialFund.Id;
                                    tripFA.Order              = specialFund.Order + 1;
                                    tripFA.AccountTypeValueId = serviceReefAccountType.Id;
                                    // Figure out what order it should be;
                                    foreach (FinancialAccount tmpTrip in trips)
                                    {
                                        if (tmpTrip.Name.CompareTo(tripFA.Name) < 0)
                                        {
                                            tripFA.Order++;
                                        }
                                    }

                                    financialAccountService.Add(tripFA);

                                    // Now save the trip
                                    dbContext.SaveChanges();
                                    // Increment all the rest of the Orders
                                    financialAccountService.Queryable().Where(fa => fa.Order >= tripFA.Order && fa.Id != tripFA.Id).ToList().ForEach(c => c.Order++);
                                    dbContext.SaveChanges();
                                    trips = financialAccountService.Queryable().Where(fa => fa.ParentAccountId == specialFund.Id).OrderBy(fa => fa.Order).ToList();
                                    trip  = tripFA;
                                }

                                FinancialTransaction tran = financialTransactionService.Queryable().Where(tx => tx.TransactionCode == result.PaymentProcessorTransactionId).FirstOrDefault();

                                // We haven't processed this before so get busy!
                                if (tran == null)
                                {
                                    tran = new FinancialTransaction();
                                    tran.FinancialPaymentDetail = new FinancialPaymentDetail();
                                    if (result.Type == "CreditCard")
                                    {
                                        tran.FinancialPaymentDetail.CurrencyTypeValueId = tenderType.DefinedValues.Where(t => t.Value == "Credit Card").FirstOrDefault().Id;
                                    }
                                    else
                                    {
                                        tran.TransactionTypeValueId = tenderType.DefinedValues.Where(t => t.Value == "Credit Card").FirstOrDefault().Id;
                                    }

                                    Person person = null;
                                    // Find the person this transaction belongs to
                                    // 1. First start by determining whether this was a person
                                    //    paying their application fee or contributing to themselves
                                    //    because then we can just use their member info
                                    if (result.UserId > 0 &&
                                        result.DonatedToUserId == result.UserId &&
                                        result.DonatedToFirstName == result.FirstName &&
                                        result.DonatedToLastName == result.LastName)
                                    {
                                        var memberRequest = new RestRequest("v1/members/{userId}", Method.GET);
                                        memberRequest.AddUrlSegment("userId", result.UserId.ToString());
                                        var memberResult = client.Execute <Contracts.Member>(memberRequest);
                                        if (memberResult.Data != null && memberResult.Data.ArenaId > 0)
                                        {
                                            try
                                            {
                                                Person personMatch = personAliasService.Queryable().Where(pa => pa.AliasPersonId == memberResult.Data.ArenaId).Select(pa => pa.Person).FirstOrDefault();
                                                if (personMatch == null)
                                                {
                                                    throw new Exception("Person not found: " + memberResult.Data.ArenaId);
                                                }
                                                person = personMatch;
                                            } catch (Exception e)
                                            {
                                                warnings += "Loading the person failed transaction id " + result.TransactionId + " for " + result.FirstName + " " + result.LastName + " with the following error: " + e.Message + Environment.NewLine;
                                                processed++;
                                                continue;
                                            }
                                        }
                                    }
                                    // 2. If we didn't get a person match via their Alias Id
                                    //    then just use the standard person match logic
                                    if (person == null)
                                    {
                                        String street1    = null;
                                        String postalCode = null;
                                        if (result.Address != null)
                                        {
                                            street1    = result.Address.Address1;
                                            postalCode = result.Address.Zip;
                                        }
                                        List <Person> matches = personService.GetByMatch(result.FirstName.Trim(), result.LastName.Trim(), null, result.Email, null, street1, postalCode).ToList();

                                        if (matches.Count > 1)
                                        {
                                            // Find the oldest member record in the list
                                            person = matches.Where(p => p.ConnectionStatusValue.Value == "Member").OrderBy(p => p.Id).FirstOrDefault();
                                            if (person == null)
                                            {
                                                // Find the oldest attendee record in the list
                                                person = matches.Where(p => p.ConnectionStatusValue.Value == "Attendee").OrderBy(p => p.Id).FirstOrDefault();
                                                if (person == null)
                                                {
                                                    person = matches.OrderBy(p => p.Id).First();
                                                }
                                            }
                                        }
                                        else if (matches.Count == 1)
                                        {
                                            person = matches.First();
                                        }
                                        else
                                        {
                                            // Create the person
                                            person           = new Person();
                                            person.FirstName = result.FirstName.Trim();
                                            person.LastName  = result.LastName.Trim();
                                            if (result.Email.IsValidEmail())
                                            {
                                                person.Email = result.Email.Trim();
                                            }
                                            person.RecordTypeValueId       = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_RECORD_TYPE_PERSON.AsGuid()).Id;
                                            person.ConnectionStatusValueId = connectionStatus.Id;
                                            person.RecordStatusValueId     = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_ACTIVE.AsGuid()).Id;
                                            Group         family   = PersonService.SaveNewPerson(person, dbContext);
                                            GroupLocation location = new GroupLocation();
                                            location.GroupLocationTypeValueId = DefinedValueCache.Read(Rock.SystemGuid.DefinedValue.GROUP_LOCATION_TYPE_HOME).Id;
                                            location.Location = new Location()
                                            {
                                                Street1    = result.Address.Address1,
                                                Street2    = result.Address.Address2,
                                                City       = result.Address.City,
                                                State      = result.Address.State,
                                                PostalCode = result.Address.Zip,
                                                Country    = result.Address.Country
                                            };
                                            family.CampusId = CampusCache.All().FirstOrDefault().Id;
                                            family.GroupLocations.Add(location);
                                            dbContext.SaveChanges();
                                        }
                                    }

                                    // Get details about the transaction from our PayPal report table
                                    Transaction tx = transactionService.Get(result.PaymentProcessorTransactionId);
                                    if (tx != null)
                                    {
                                        if (tx.TenderType.Contains("ACH"))
                                        {
                                            result.Type   = "ACH";
                                            result.Method = null;
                                        }
                                        else
                                        {
                                            result.Type   = "Credit Card";
                                            result.Method = tx.TenderType;
                                        }
                                    }
                                    else
                                    {
                                        // Defaults
                                        result.Type   = "Credit Card";
                                        result.Method = "Visa";

                                        warnings += "Unable to find transaction in _org_secc_PaypalReporting_Transaction table: " + result.TransactionId + Environment.NewLine;
                                    }

                                    // If we don't have a batch, create one
                                    if (batch == null)
                                    {
                                        batch = new FinancialBatch();
                                        batch.BatchStartDateTime = result.Date;
                                        batch.BatchEndDateTime   = DateTime.Now;
                                        batch.Name   = "Service Reef Payments";
                                        batch.Status = BatchStatus.Open;
                                        financialBatchService.Add(batch);
                                        dbContext.SaveChanges();
                                    }

                                    // Complete the FinancialTransaction
                                    tran.AuthorizedPersonAliasId = person.PrimaryAliasId;
                                    tran.BatchId             = batch.Id;
                                    tran.Summary             = "F" + specialFund.Id + ":$" + result.Amount.ToString();
                                    tran.TransactionDateTime = result.Date;
                                    tran.FinancialGatewayId  = gateway.Id;

                                    FinancialTransactionDetail financialTransactionDetail = new FinancialTransactionDetail();
                                    financialTransactionDetail.AccountId = trip.Id;
                                    financialTransactionDetail.Amount    = result.Amount.ToString().AsDecimal();
                                    tran.TransactionDetails.Add(financialTransactionDetail);
                                    tran.TransactionTypeValueId = contribution.Id;

                                    tran.FinancialPaymentDetail = new FinancialPaymentDetail();
                                    tran.FinancialPaymentDetail.CurrencyTypeValueId = tenderType.DefinedValues.Where(type => type.Value.ToLower() == result.Type.ToLower()).FirstOrDefault().Id;
                                    if (result.Method != null)
                                    {
                                        tran.FinancialPaymentDetail.CreditCardTypeValueId = creditCards.DefinedValues.Where(card => card.Value.ToLower() == result.Method.ToLower()).FirstOrDefault().Id;
                                    }
                                    tran.TransactionCode   = result.PaymentProcessorTransactionId;
                                    tran.SourceTypeValueId = transactionSource.Id;

                                    financialTransactionService.Add(tran);
                                    dbContext.SaveChanges();

                                    totalAmount += result.Amount;
                                }
                            }
                            processed++;
                        }
                    }
                    else
                    {
                        total = 0;
                    }
                    // Update the page number for the next request
                    var pageParam = request.Parameters.Where(p => p.Name == "page").FirstOrDefault();
                    pageParam.Value = (int)pageParam.Value + 1;
                }
            }
            catch (Exception ex)
            {
                throw new Exception("ServiceReef Job Failed", ex);
            } finally
            {
                if (batch != null && totalAmount > 0)
                {
                    batch.ControlAmount = (Decimal)totalAmount;
                }
                dbContext.SaveChanges();
            }
            if (warnings.Length > 0)
            {
                throw new Exception(warnings);
            }
            context.Result = "Successfully imported " + processed + " transactions.";
        }
Beispiel #55
0
        private void SaveTransaction( FinancialGateway financialGateway, GatewayComponent gateway, Person person, PaymentInfo paymentInfo, FinancialTransaction transaction, RockContext rockContext )
        {
            var txnChanges = new List<string>();
            txnChanges.Add( "Created Transaction" );

            History.EvaluateChange( txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode );

            transaction.AuthorizedPersonAliasId = person.PrimaryAliasId;
            History.EvaluateChange( txnChanges, "Person", string.Empty, person.FullName );

            transaction.TransactionDateTime = RockDateTime.Now;
            History.EvaluateChange( txnChanges, "Date/Time", null, transaction.TransactionDateTime );

            transaction.FinancialGatewayId = financialGateway.Id;
            History.EvaluateChange( txnChanges, "Gateway", string.Empty, financialGateway.Name );

            var txnType = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ) );
            transaction.TransactionTypeValueId = txnType.Id;
            History.EvaluateChange( txnChanges, "Type", string.Empty, txnType.Value );

            transaction.Summary = paymentInfo.Comment1;
            History.EvaluateChange( txnChanges, "Summary", string.Empty, transaction.Summary );

            if ( transaction.FinancialPaymentDetail == null )
            {
                transaction.FinancialPaymentDetail = new FinancialPaymentDetail();
            }
            transaction.FinancialPaymentDetail.SetFromPaymentInfo( paymentInfo, gateway, rockContext, txnChanges );

            Guid sourceGuid = Guid.Empty;
            if ( Guid.TryParse( GetAttributeValue( "Source" ), out sourceGuid ) )
            {
                var source = DefinedValueCache.Read( sourceGuid );
                if ( source != null )
                {
                    transaction.SourceTypeValueId = source.Id;
                    History.EvaluateChange( txnChanges, "Source", string.Empty, source.Value );
                }
            }

            foreach ( var account in SelectedAccounts.Where( a => a.Amount > 0 ) )
            {
                var transactionDetail = new FinancialTransactionDetail();
                transactionDetail.Amount = account.Amount;
                transactionDetail.AccountId = account.Id;
                transaction.TransactionDetails.Add( transactionDetail );
                History.EvaluateChange( txnChanges, account.Name, 0.0M.FormatAsCurrency(), transactionDetail.Amount.FormatAsCurrency() );
            }

            var batchService = new FinancialBatchService( rockContext );

            // Get the batch
            var batch = batchService.Get(
                GetAttributeValue( "BatchNamePrefix" ),
                paymentInfo.CurrencyTypeValue,
                paymentInfo.CreditCardTypeValue,
                transaction.TransactionDateTime.Value,
                financialGateway.GetBatchTimeOffset() );

            var batchChanges = new List<string>();

            if ( batch.Id == 0 )
            {
                batchChanges.Add( "Generated the batch" );
                History.EvaluateChange( batchChanges, "Batch Name", string.Empty, batch.Name );
                History.EvaluateChange( batchChanges, "Status", null, batch.Status );
                History.EvaluateChange( batchChanges, "Start Date/Time", null, batch.BatchStartDateTime );
                History.EvaluateChange( batchChanges, "End Date/Time", null, batch.BatchEndDateTime );
            }

            decimal newControlAmount = batch.ControlAmount + transaction.TotalAmount;
            History.EvaluateChange( batchChanges, "Control Amount", batch.ControlAmount.FormatAsCurrency(), newControlAmount.FormatAsCurrency() );
            batch.ControlAmount = newControlAmount;

            transaction.BatchId = batch.Id;
            batch.Transactions.Add( transaction );

            rockContext.SaveChanges();

            HistoryService.SaveChanges(
                rockContext,
                typeof( FinancialBatch ),
                Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(),
                batch.Id,
                batchChanges
            );

            HistoryService.SaveChanges(
                rockContext,
                typeof( FinancialBatch ),
                Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(),
                batch.Id,
                txnChanges,
                person.FullName,
                typeof( FinancialTransaction ),
                transaction.Id
            );

            SendReceipt( transaction.Id );

            TransactionCode = transaction.TransactionCode;
        }
        /// <summary>
        /// Shows the detail.
        /// </summary>
        /// <param name="transactionId">The transaction identifier.</param>
        public void ShowDetail( int transactionId, int? batchId )
        {
            // show or hide the add new transaction button depending if there is a batch id in the querystring
            lbAddTransaction.Visible = !string.IsNullOrWhiteSpace( PageParameter( "batchId" ) );

            FinancialTransaction txn = null;

            bool editAllowed = UserCanEdit;

            var rockContext = new RockContext();

            if ( !transactionId.Equals( 0 ) )
            {
                txn = GetTransaction( transactionId, rockContext );
                if ( !editAllowed && txn != null )
                {
                    editAllowed = txn.IsAuthorized( Authorization.EDIT, CurrentPerson );
                }
            }

            if ( txn == null )
            {
                txn = new FinancialTransaction { Id = 0 };
                txn.BatchId = batchId;

                // Hide processor fields when adding a new transaction
                cpPaymentGateway.Visible = false;
                tbTransactionCode.Visible = false;

                // Set values based on previously saved txn values
                int prevBatchId = Session["NewTxnDefault_BatchId"] as int? ?? 0;
                if ( prevBatchId == batchId )
                {
                    txn.TransactionDateTime = Session["NewTxnDefault_TransactionDateTime"] as DateTime?;
                    txn.TransactionTypeValueId = Session["NewTxnDefault_TransactionType"] as int? ?? 0;
                    txn.SourceTypeValueId = Session["NewTxnDefault_SourceType"] as int?;
                    txn.CurrencyTypeValueId = Session["NewTxnDefault_CurrencyType"] as int?;
                    txn.CreditCardTypeValueId = Session["NewTxnDefault_CreditCardType"] as int?;
                    int? accountId = Session["NewTxnDefault_Account"] as int?;
                    if ( accountId.HasValue )
                    {
                        var txnDetail = new FinancialTransactionDetail();
                        txnDetail.AccountId = accountId.Value;
                        txn.TransactionDetails.Add( txnDetail );
                    }
                }
            }
            else
            {
                cpPaymentGateway.Visible = true;
                tbTransactionCode.Visible = true;
            }

            hfTransactionId.Value = txn.Id.ToString();
            hfBatchId.Value = batchId.HasValue ? batchId.Value.ToString() : string.Empty;

            bool readOnly = false;

            nbEditModeMessage.Text = string.Empty;
            if ( !editAllowed )
            {
                readOnly = true;
                nbEditModeMessage.Text = EditModeMessage.ReadOnlyEditActionNotAllowed( FinancialTransaction.FriendlyTypeName );
                lbEdit.Visible = false;
                lbAddTransaction.Visible = false;
            }
            else
            {
                lbEdit.Visible = true;
                lbAddTransaction.Visible = true;
            }

            if ( readOnly )
            {
                ShowReadOnlyDetails( txn );
            }
            else
            {
                if ( txn.Id > 0 )
                {
                    ShowReadOnlyDetails( txn );
                }
                else
                {
                    ShowEditDetails( txn, rockContext );
                }
            }

            lbSave.Visible = !readOnly;
        }
Beispiel #57
0
        /// <summary>
        /// Writes to package.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="model">The model.</param>
        public static void WriteToPackage <T>(T model)
        {
            var typeName = model.GetType().Name;

            if (model is IImportModel)
            {
                var importModel = ( IImportModel )model;
                // check if a textwriter is needed for this model type
                if (!textWriters.ContainsKey(typeName))
                {
                    if (!Directory.Exists(_packageDirectory))
                    {
                        InitalizePackageFolder();
                    }

                    textWriters.Add(typeName, ( TextWriter )File.CreateText($@"{_packageDirectory}\{importModel.GetFileName()}"));

                    // if model is for person create related writers
                    if (importModel is Person)
                    {
                        // person attributes
                        var personAttributeValue = new PersonAttributeValue();
                        textWriters.Add(personAttributeValue.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{personAttributeValue.GetFileName()}"));

                        // person phones
                        var personPhone = new PersonPhone();
                        textWriters.Add(personPhone.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{personPhone.GetFileName()}"));

                        // person addresses
                        var personAddress = new PersonAddress();
                        textWriters.Add(personAddress.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{personAddress.GetFileName()}"));

                        // person search key
                        var personSearchKey = new PersonSearchKey();
                        textWriters.Add(personSearchKey.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{personSearchKey.GetFileName()}"));
                    }

                    if (importModel is PersonAttributeValue)
                    {
                        var personAttributeValue = new PersonAttributeValue();
                        textWriters.Add(personAttributeValue.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{personAttributeValue.GetFileName()}"));
                    }

                    // if model is for financial batch create related writers
                    if (importModel is FinancialBatch)
                    {
                        // financial transactions
                        var financialTransaction = new FinancialTransaction();
                        textWriters.Add(financialTransaction.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{financialTransaction.GetFileName()}"));

                        // financial transation details
                        var financialTransactionDetail = new FinancialTransactionDetail();
                        textWriters.Add(financialTransactionDetail.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{financialTransactionDetail.GetFileName()}"));
                    }

                    // if model is for financial transaction create related writers
                    if (importModel is FinancialTransaction)
                    {
                        // financial transation details
                        var financialTransactionDetail = new FinancialTransactionDetail();
                        textWriters.Add(financialTransactionDetail.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{financialTransactionDetail.GetFileName()}"));
                    }

                    // if model is for group create related writers
                    if (importModel is Group)
                    {
                        // group member
                        var groupMember = new GroupMember();
                        textWriters.Add(groupMember.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{groupMember.GetFileName()}"));

                        // group attributes
                        var groupAttributeValue = new GroupAttributeValue();
                        textWriters.Add(groupAttributeValue.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{groupAttributeValue.GetFileName()}"));

                        // group addresses
                        var groupAddress = new GroupAddress();
                        textWriters.Add(groupAddress.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{groupAddress.GetFileName()}"));
                    }

                    // if model is for business create related writers
                    if (importModel is Business)
                    {
                        // business attributes
                        var businessAttributeValue = new BusinessAttributeValue();
                        textWriters.Add(businessAttributeValue.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{businessAttributeValue.GetFileName()}"));

                        // business phones
                        var businessPhone = new BusinessPhone();
                        textWriters.Add(businessPhone.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{businessPhone.GetFileName()}"));

                        // business addresses
                        var businessAddress = new BusinessAddress();
                        textWriters.Add(businessAddress.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{businessAddress.GetFileName()}"));

                        // business contacts
                        var businessContact = new BusinessContact();
                        textWriters.Add(businessContact.GetType().Name, ( TextWriter )File.CreateText($@"{_packageDirectory}\{businessContact.GetFileName()}"));
                    }
                }

                var txtWriter = textWriters[typeName];

                // check if a csvwriter is needed for this model type
                if (!csvWriters.ContainsKey(typeName))
                {
                    var newCsvWriter = new CsvWriter(txtWriter);
                    csvWriters.Add(typeName, newCsvWriter);
                    newCsvWriter.WriteHeader <T>();
                    //newCsvWriter.Configuration.QuoteAllFields = true;

                    // if model is for person create related writers
                    if (importModel is Person)
                    {
                        // person attributes
                        var personAttributeValue             = new PersonAttributeValue();
                        var newPersonAttributeValueCsvWriter = new CsvWriter(textWriters[personAttributeValue.GetType().Name]);
                        csvWriters.Add(personAttributeValue.GetType().Name, newPersonAttributeValueCsvWriter);
                        newPersonAttributeValueCsvWriter.WriteHeader <PersonAttributeValue>();

                        // person phones
                        var personPhone             = new PersonPhone();
                        var newPersonPhoneCsvWriter = new CsvWriter(textWriters[personPhone.GetType().Name]);
                        csvWriters.Add(personPhone.GetType().Name, newPersonPhoneCsvWriter);
                        newPersonPhoneCsvWriter.WriteHeader <PersonPhone>();

                        // person addresses
                        var personAddress             = new PersonAddress();
                        var newPersonAddressCsvWriter = new CsvWriter(textWriters[personAddress.GetType().Name]);
                        csvWriters.Add(personAddress.GetType().Name, newPersonAddressCsvWriter);
                        newPersonAddressCsvWriter.WriteHeader <PersonAddress>();

                        // person search keys
                        var personSearchKey             = new PersonSearchKey();
                        var newPersonSearchKeyCsvWriter = new CsvWriter(textWriters[personSearchKey.GetType().Name]);
                        csvWriters.Add(personSearchKey.GetType().Name, newPersonSearchKeyCsvWriter);
                        newPersonSearchKeyCsvWriter.WriteHeader <PersonSearchKey>();
                    }

                    if (importModel is PersonAttributeValue)
                    {
                        var personAttributeValue             = new PersonAttributeValue();
                        var newPersonAttributeValueCsvWriter = new CsvWriter(textWriters[personAttributeValue.GetType().Name]);
                        csvWriters.Add(personAttributeValue.GetType().Name, newPersonAttributeValueCsvWriter);
                        newPersonAttributeValueCsvWriter.WriteHeader <PersonAttributeValue>();
                    }

                    // if model is for financial batch create related writers
                    if (importModel is FinancialBatch)
                    {
                        // financial transaction
                        var financialTransaction             = new FinancialTransaction();
                        var newFinancialTransactionCsvWriter = new CsvWriter(textWriters[financialTransaction.GetType().Name]);
                        csvWriters.Add(financialTransaction.GetType().Name, newFinancialTransactionCsvWriter);
                        newFinancialTransactionCsvWriter.WriteHeader <FinancialTransaction>();

                        // financial transaction detail
                        var financialTransactionDetail             = new FinancialTransactionDetail();
                        var newFinancialTransactionDetailCsvWriter = new CsvWriter(textWriters[financialTransactionDetail.GetType().Name]);
                        csvWriters.Add(financialTransactionDetail.GetType().Name, newFinancialTransactionDetailCsvWriter);
                        newFinancialTransactionDetailCsvWriter.WriteHeader <FinancialTransactionDetail>();
                    }

                    //if model is for financial transaction, create related writers
                    if (importModel is FinancialTransaction)
                    {
                        // financial transaction detail
                        var financialTransactionDetail             = new FinancialTransactionDetail();
                        var newFinancialTransactionDetailCsvWriter = new CsvWriter(textWriters[financialTransactionDetail.GetType().Name]);
                        csvWriters.Add(financialTransactionDetail.GetType().Name, newFinancialTransactionDetailCsvWriter);
                        newFinancialTransactionDetailCsvWriter.WriteHeader <FinancialTransactionDetail>();
                    }

                    // if model is for group create related writers
                    if (importModel is Group)
                    {
                        // group member
                        var groupMember             = new GroupMember();
                        var newGroupMemberCsvWriter = new CsvWriter(textWriters[groupMember.GetType().Name]);
                        csvWriters.Add(groupMember.GetType().Name, newGroupMemberCsvWriter);
                        newGroupMemberCsvWriter.WriteHeader <GroupMember>();

                        // group attributes
                        var groupAttributeValue             = new GroupAttributeValue();
                        var newGroupAttributeValueCsvWriter = new CsvWriter(textWriters[groupAttributeValue.GetType().Name]);
                        csvWriters.Add(groupAttributeValue.GetType().Name, newGroupAttributeValueCsvWriter);
                        newGroupAttributeValueCsvWriter.WriteHeader <GroupAttributeValue>();

                        // group addresses
                        var groupAddress             = new GroupAddress();
                        var newGroupAddressCsvWriter = new CsvWriter(textWriters[groupAddress.GetType().Name]);
                        csvWriters.Add(groupAddress.GetType().Name, newGroupAddressCsvWriter);
                        newGroupAddressCsvWriter.WriteHeader <GroupAddress>();
                    }

                    // if model is for business create related writers
                    if (importModel is Business)
                    {
                        // business attributes
                        var businessAttributeValue             = new BusinessAttributeValue();
                        var newBusinessAttributeValueCsvWriter = new CsvWriter(textWriters[businessAttributeValue.GetType().Name]);
                        csvWriters.Add(businessAttributeValue.GetType().Name, newBusinessAttributeValueCsvWriter);
                        newBusinessAttributeValueCsvWriter.WriteHeader <BusinessAttributeValue>();

                        // business phones
                        var businessPhone             = new BusinessPhone();
                        var newBusinessPhoneCsvWriter = new CsvWriter(textWriters[businessPhone.GetType().Name]);
                        csvWriters.Add(businessPhone.GetType().Name, newBusinessPhoneCsvWriter);
                        newBusinessPhoneCsvWriter.WriteHeader <BusinessPhone>();

                        // business addresses
                        var businessAddress             = new BusinessAddress();
                        var newBusinessAddressCsvWriter = new CsvWriter(textWriters[businessAddress.GetType().Name]);
                        csvWriters.Add(businessAddress.GetType().Name, newBusinessAddressCsvWriter);
                        newBusinessAddressCsvWriter.WriteHeader <BusinessAddress>();

                        // business Contacts
                        var businessContacts             = new BusinessContact();
                        var newBusinessContactsCsvWriter = new CsvWriter(textWriters[businessContacts.GetType().Name]);
                        csvWriters.Add(businessContacts.GetType().Name, newBusinessContactsCsvWriter);
                        newBusinessContactsCsvWriter.WriteHeader <BusinessContact>();
                    }
                }

                var csvWriter = csvWriters[typeName];

                csvWriter.WriteRecord <T>(model);

                // if person model write out any related models
                if (importModel is Person)
                {
                    // person attributes
                    var personAttributeValue          = new PersonAttributeValue();
                    var csvPersonAttributeValueWriter = csvWriters[personAttributeValue.GetType().Name];

                    if (csvPersonAttributeValueWriter != null)
                    {
                        foreach (var attribute in (( Person )importModel).Attributes)
                        {
                            csvPersonAttributeValueWriter.WriteRecord(attribute);
                        }
                    }

                    // person phones
                    var personPhone          = new PersonPhone();
                    var csvPersonPhoneWriter = csvWriters[personPhone.GetType().Name];

                    if (csvPersonPhoneWriter != null)
                    {
                        foreach (var phone in (( Person )importModel).PhoneNumbers)
                        {
                            csvPersonPhoneWriter.WriteRecord(phone);
                        }
                    }

                    // person addresses
                    var personAddress          = new PersonAddress();
                    var csvPersonAddressWriter = csvWriters[personAddress.GetType().Name];

                    if (csvPersonAddressWriter != null)
                    {
                        foreach (var address in (( Person )importModel).Addresses)
                        {
                            if ((( Person )importModel).FamilyId.HasValue)
                            {
                                var familyAddress = new FamilyAddress
                                {
                                    FamilyId   = (( Person )importModel).FamilyId.Value,
                                    Street1    = address.Street1,
                                    PostalCode = address.PostalCode.Left(5)
                                };

                                var index = _familyAddresses.FindIndex(a =>
                                                                       a.FamilyId == (( Person )importModel).FamilyId.Value &&
                                                                       a.Street1.Equals(address.Street1, StringComparison.OrdinalIgnoreCase) &&
                                                                       a.PostalCode.Equals(address.PostalCode.Left(5)));

                                if (index == -1)
                                {
                                    _familyAddresses.Add(familyAddress);
                                    csvPersonAddressWriter.WriteRecord(address);
                                }
                            }
                            else
                            {
                                csvPersonAddressWriter.WriteRecord(address);
                            }
                        }
                    }

                    // person search keys
                    var personSearchKey          = new PersonSearchKey();
                    var csvPersonSearchKeyWriter = csvWriters[personSearchKey.GetType().Name];

                    if (csvPersonSearchKeyWriter != null)
                    {
                        foreach (var searchKey in (( Person )importModel).PersonSearchKeys)
                        {
                            csvPersonSearchKeyWriter.WriteRecord(searchKey);
                        }
                    }
                }

                // if financial model write out any related models
                if (importModel is FinancialBatch)
                {
                    // write out financial transactions and transaction details
                    var financialTransaction          = new FinancialTransaction();
                    var csvFinancialTransactionWriter = csvWriters[financialTransaction.GetType().Name];

                    var financialTransactionDetail          = new FinancialTransactionDetail();
                    var csvFinancialTransactionDetailWriter = csvWriters[financialTransactionDetail.GetType().Name];

                    if (csvFinancialTransactionWriter != null && csvFinancialTransactionDetailWriter != null)
                    {
                        foreach (var transaction in (( FinancialBatch )importModel).FinancialTransactions)
                        {
                            csvFinancialTransactionWriter.WriteRecord(transaction);

                            foreach (var transactionDetail in transaction.FinancialTransactionDetails)
                            {
                                csvFinancialTransactionDetailWriter.WriteRecord(transactionDetail);
                            }
                        }
                    }
                }

                // if financial Transaction model write out any related models
                if (importModel is FinancialTransaction)
                {
                    var financialTransactionDetail          = new FinancialTransactionDetail();
                    var csvFinancialTransactionDetailWriter = csvWriters[financialTransactionDetail.GetType().Name];

                    if (csvFinancialTransactionDetailWriter != null)
                    {
                        foreach (var transactionDetail in (( FinancialTransaction )importModel).FinancialTransactionDetails)
                        {
                            csvFinancialTransactionDetailWriter.WriteRecord(transactionDetail);
                        }
                    }
                }

                // if group model write out any related models
                if (importModel is Group)
                {
                    // group members
                    var groupMember          = new GroupMember();
                    var csvGroupMemberWriter = csvWriters[groupMember.GetType().Name];

                    if (csvGroupMemberWriter != null)
                    {
                        foreach (var groupMemberItem in (( Group )importModel).GroupMembers)
                        {
                            csvGroupMemberWriter.WriteRecord(groupMemberItem);
                        }
                    }

                    // group attributes
                    var groupAttributeValue          = new GroupAttributeValue();
                    var csvGroupAttributeValueWriter = csvWriters[groupAttributeValue.GetType().Name];

                    if (csvGroupAttributeValueWriter != null)
                    {
                        foreach (var attribute in (( Group )importModel).Attributes)
                        {
                            csvGroupAttributeValueWriter.WriteRecord(attribute);
                        }
                    }

                    // group addresses
                    var groupAddress          = new GroupAddress();
                    var csvGroupAddressWriter = csvWriters[groupAddress.GetType().Name];

                    if (csvGroupAddressWriter != null)
                    {
                        foreach (var address in (( Group )importModel).Addresses)
                        {
                            csvGroupAddressWriter.WriteRecord(address);
                        }
                    }
                }

                // if business model write out any related models
                if (importModel is Business)
                {
                    // business attributes
                    var personBusinessValue             = new BusinessAttributeValue();
                    var csvBusinessAttributeValueWriter = csvWriters[personBusinessValue.GetType().Name];

                    if (csvBusinessAttributeValueWriter != null)
                    {
                        foreach (var attribute in (( Business )importModel).Attributes)
                        {
                            csvBusinessAttributeValueWriter.WriteRecord(attribute);
                        }
                    }

                    // business phones
                    var businessPhone          = new BusinessPhone();
                    var csvBusinessPhoneWriter = csvWriters[businessPhone.GetType().Name];

                    if (csvBusinessPhoneWriter != null)
                    {
                        foreach (var phone in (( Business )importModel).PhoneNumbers)
                        {
                            csvBusinessPhoneWriter.WriteRecord(phone);
                        }
                    }

                    // business addresses
                    var businessAddress          = new BusinessAddress();
                    var csvBusinessAddressWriter = csvWriters[businessAddress.GetType().Name];

                    if (csvBusinessAddressWriter != null)
                    {
                        foreach (var address in (( Business )importModel).Addresses)
                        {
                            csvBusinessAddressWriter.WriteRecord(address);
                        }
                    }

                    // business contacts
                    var businessContact          = new BusinessContact();
                    var csvBusinessContactWriter = csvWriters[businessContact.GetType().Name];

                    if (csvBusinessContactWriter != null)
                    {
                        foreach (var contact in (( Business )importModel).Contacts)
                        {
                            csvBusinessAddressWriter.WriteRecord(contact);
                        }
                    }
                }
            }
        }
Beispiel #58
0
        /// <summary>
        /// Maps the contribution.
        /// </summary>
        /// <param name="tableData">The table data.</param>
        /// <param name="selectedColumns">The selected columns.</param>
        private void MapContribution( IQueryable<Row> tableData, List<string> selectedColumns = null )
        {
            int transactionEntityTypeId = EntityTypeCache.Read( "Rock.Model.FinancialTransaction" ).Id;
            var accountService = new FinancialAccountService();
            var attributeService = new AttributeService();

            var transactionTypeContributionId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ) ).Id;

            int currencyTypeACH = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ) ).Id;
            int currencyTypeCash = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH ) ).Id;
            int currencyTypeCheck = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK ) ).Id;
            int currencyTypeCreditCard = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ) ).Id;

            List<DefinedValue> refundReasons = new DefinedValueService().Queryable().Where( dv => dv.DefinedType.Guid == new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON ) ).ToList();

            List<FinancialPledge> pledgeList = new FinancialPledgeService().Queryable().ToList();

            List<FinancialAccount> accountList = accountService.Queryable().ToList();

            // Add an Attribute for the unique F1 Contribution Id
            int contributionAttributeId = attributeService.Queryable().Where( a => a.EntityTypeId == transactionEntityTypeId
                && a.Key == "F1ContributionId" ).Select( a => a.Id ).FirstOrDefault();
            if ( contributionAttributeId == 0 )
            {
                var newContributionAttribute = new Rock.Model.Attribute();
                newContributionAttribute.Key = "F1ContributionId";
                newContributionAttribute.Name = "F1 Contribution Id";
                newContributionAttribute.FieldTypeId = IntegerFieldTypeId;
                newContributionAttribute.EntityTypeId = transactionEntityTypeId;
                newContributionAttribute.EntityTypeQualifierValue = string.Empty;
                newContributionAttribute.EntityTypeQualifierColumn = string.Empty;
                newContributionAttribute.Description = "The FellowshipOne identifier for the contribution that was imported";
                newContributionAttribute.DefaultValue = string.Empty;
                newContributionAttribute.IsMultiValue = false;
                newContributionAttribute.IsRequired = false;
                newContributionAttribute.Order = 0;

                attributeService.Add( newContributionAttribute, ImportPersonAlias );
                attributeService.Save( newContributionAttribute, ImportPersonAlias );
                contributionAttributeId = newContributionAttribute.Id;
            }

            var contributionAttribute = AttributeCache.Read( contributionAttributeId );

            // Get all imported contributions
            var importedContributions = new AttributeValueService().GetByAttributeId( contributionAttributeId )
               .Select( av => new { ContributionId = av.Value.AsType<int?>(), TransactionId = av.EntityId } )
               .ToDictionary( t => t.ContributionId, t => t.TransactionId );

            // List for batching new contributions
            var newTransactions = new List<FinancialTransaction>();

            int completed = 0;
            int totalRows = tableData.Count();
            int percentage = ( totalRows - 1 ) / 100 + 1;
            ReportProgress( 0, string.Format( "Checking contribution import ({0:N0} found, {1:N0} already exist).", totalRows, importedContributions.Count() ) );
            foreach ( var row in tableData )
            {
                int? individualId = row["Individual_ID"] as int?;
                int? householdId = row["Household_ID"] as int?;
                int? contributionId = row["ContributionID"] as int?;

                if ( contributionId != null && !importedContributions.ContainsKey( contributionId ) )
                {
                    var transaction = new FinancialTransaction();
                    transaction.TransactionTypeValueId = transactionTypeContributionId;
                    transaction.AuthorizedPersonId = GetPersonId( individualId, householdId );
                    transaction.CreatedByPersonAliasId = ImportPersonAlias.Id;
                    transaction.AuthorizedPersonId = GetPersonId( individualId, householdId );

                    string summary = row["Memo"] as string;
                    if ( summary != null )
                    {
                        transaction.Summary = summary;
                    }

                    int? batchId = row["BatchID"] as int?;
                    if ( batchId != null && ImportedBatches.Any( b => b.Key == batchId ) )
                    {
                        transaction.BatchId = ImportedBatches.FirstOrDefault( b => b.Key == batchId ).Value;
                    }

                    DateTime? receivedDate = row["Received_Date"] as DateTime?;
                    if ( receivedDate != null )
                    {
                        transaction.TransactionDateTime = receivedDate;
                        transaction.CreatedDateTime = receivedDate;
                    }

                    bool isTypeNonCash = false;
                    string contributionType = row["Contribution_Type_Name"] as string;
                    if ( contributionType != null )
                    {
                        if ( contributionType == "ACH" )
                        {
                            transaction.CurrencyTypeValueId = currencyTypeACH;
                        }
                        else if ( contributionType == "Cash" )
                        {
                            transaction.CurrencyTypeValueId = currencyTypeCash;
                        }
                        else if ( contributionType == "Check" )
                        {
                            transaction.CurrencyTypeValueId = currencyTypeCheck;
                        }
                        else if ( contributionType == "Credit Card" )
                        {
                            transaction.CurrencyTypeValueId = currencyTypeCreditCard;
                        }
                        else
                        {
                            isTypeNonCash = true;
                        }
                    }

                    string checkNumber = row["Check_Number"] as string;
                    if ( checkNumber != null && checkNumber.AsType<int?>() != null )
                    {
                        // routing & account set to zero
                        transaction.CheckMicrEncrypted = Encryption.EncryptString( string.Format( "{0}_{1}_{2}", 0, 0, checkNumber ) );
                    }

                    string fundName = row["Fund_Name"] as string;
                    string subFund = row["Sub_Fund_Name"] as string;
                    decimal? amount = row["Amount"] as decimal?;
                    if ( fundName != null & amount != null )
                    {
                        FinancialAccount matchingAccount = null;
                        fundName = fundName.Trim();

                        int? fundCampusId = null;
                        if ( subFund != null )
                        {
                            subFund = subFund.Trim();
                            fundCampusId = CampusList.Where( c => c.Name.StartsWith( subFund ) || c.ShortCode == subFund )
                                .Select( c => (int?)c.Id ).FirstOrDefault();

                            if ( fundCampusId != null )
                            {
                                matchingAccount = accountList.FirstOrDefault( a => a.Name.StartsWith( fundName )
                                    && a.CampusId != null && a.CampusId.Equals( fundCampusId ) );
                            }
                            else
                            {
                                matchingAccount = accountList.FirstOrDefault( a => a.Name.StartsWith( fundName ) && a.Name.StartsWith( subFund ) );
                            }
                        }
                        else
                        {
                            matchingAccount = accountList.FirstOrDefault( a => a.Name.StartsWith( fundName ) && a.CampusId == null );
                        }

                        if ( matchingAccount == null )
                        {
                            matchingAccount = new FinancialAccount();
                            matchingAccount.Name = fundName;
                            matchingAccount.PublicName = fundName;
                            matchingAccount.IsTaxDeductible = true;
                            matchingAccount.IsActive = true;
                            matchingAccount.CampusId = fundCampusId;
                            matchingAccount.CreatedByPersonAliasId = ImportPersonAlias.Id;

                            accountService.Add( matchingAccount );
                            accountService.Save( matchingAccount );
                            accountList.Add( matchingAccount );
                        }

                        var transactionDetail = new FinancialTransactionDetail();
                        transactionDetail.Amount = (decimal)amount;
                        transactionDetail.CreatedDateTime = receivedDate;
                        transactionDetail.AccountId = matchingAccount.Id;
                        transactionDetail.IsNonCash = isTypeNonCash;
                        transaction.TransactionDetails.Add( transactionDetail );

                        if ( amount < 0 )
                        {
                            var transactionRefund = new FinancialTransactionRefund();
                            transactionRefund.CreatedDateTime = receivedDate;
                            transactionRefund.RefundReasonSummary = summary;
                            transactionRefund.RefundReasonValueId = refundReasons.Where( dv => summary != null && dv.Name.Contains( summary ) )
                                .Select( dv => (int?)dv.Id ).FirstOrDefault();
                            transaction.Refund = transactionRefund;
                        }
                    }

                    // Other Attributes to create:
                    // Pledge_Drive_Name
                    // Stated_Value
                    // True_Value
                    // Liquidation_cost

                    transaction.Attributes = new Dictionary<string, AttributeCache>();
                    transaction.AttributeValues = new Dictionary<string, List<AttributeValue>>();
                    transaction.Attributes.Add( contributionAttribute.Key, contributionAttribute );
                    transaction.AttributeValues.Add( contributionAttribute.Key, new List<AttributeValue>() );
                    transaction.AttributeValues[contributionAttribute.Key].Add( new AttributeValue()
                    {
                        AttributeId = contributionAttribute.Id,
                        Value = contributionId.ToString(),
                        Order = 0
                    } );

                    newTransactions.Add( transaction );
                    completed++;
                    if ( completed % percentage < 1 )
                    {
                        int percentComplete = completed / percentage;
                        ReportProgress( percentComplete, string.Format( "{0:N0} contributions imported ({1}% complete).", completed, percentComplete ) );
                    }
                    else if ( completed % ReportingNumber < 1 )
                    {
                        RockTransactionScope.WrapTransaction( () =>
                        {
                            var transactionService = new FinancialTransactionService();
                            transactionService.RockContext.FinancialTransactions.AddRange( newTransactions );
                            transactionService.RockContext.SaveChanges();

                            var attributeValueService = new AttributeValueService();
                            foreach ( var contribution in newTransactions.Where( c => c.Attributes.Any() ) )
                            {
                                var attributeValue = contribution.AttributeValues[contributionAttribute.Key].FirstOrDefault();
                                if ( attributeValue != null )
                                {
                                    attributeValue.EntityId = contribution.Id;
                                    attributeValueService.RockContext.AttributeValues.Add( attributeValue );
                                }
                            }

                            attributeValueService.RockContext.SaveChanges();
                        } );

                        newTransactions.Clear();
                        ReportPartialProgress();
                    }
                }
            }

            if ( newTransactions.Any() )
            {
                RockTransactionScope.WrapTransaction( () =>
                {
                    var transactionService = new FinancialTransactionService();
                    transactionService.RockContext.FinancialTransactions.AddRange( newTransactions );
                    transactionService.RockContext.SaveChanges();

                    var attributeValueService = new AttributeValueService();
                    foreach ( var contribution in newTransactions.Where( c => c.Attributes.Any() ) )
                    {
                        var attributeValue = contribution.AttributeValues[contributionAttribute.Key].FirstOrDefault();
                        if ( attributeValue != null )
                        {
                            attributeValue.EntityId = contribution.Id;
                            attributeValueService.RockContext.AttributeValues.Add( attributeValue );
                        }
                    }

                    attributeValueService.RockContext.SaveChanges();
                } );
            }

            ReportProgress( 100, string.Format( "Finished contribution import: {0:N0} contributions imported.", completed ) );
        }
        //
        // Swipe Panel Events
        //

        private void ProcessSwipe(string swipeData)
        {
            try
            {
                using (var rockContext = new RockContext())
                {
                    // create swipe object
                    SwipePaymentInfo swipeInfo = new SwipePaymentInfo(swipeData);
                    swipeInfo.Amount = this.Amounts.Sum(a => a.Value);

                    // if not anonymous then add contact info to the gateway transaction
                    if (this.AnonymousGiverPersonAliasId != this.SelectedGivingUnit.PersonAliasId)
                    {
                        var giver = new PersonAliasService(rockContext).Queryable("Person, Person.PhoneNumbers").Where(p => p.Id == this.SelectedGivingUnit.PersonAliasId).FirstOrDefault();
                        swipeInfo.FirstName = giver.Person.NickName;
                        swipeInfo.LastName  = giver.Person.LastName;

                        if (giver.Person.PhoneNumbers != null)
                        {
                            Guid homePhoneValueGuid = new Guid(Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_HOME);
                            var  homephone          = giver.Person.PhoneNumbers.Where(p => p.NumberTypeValue.Guid == homePhoneValueGuid).FirstOrDefault();
                            if (homephone != null)
                            {
                                swipeInfo.Phone = homephone.NumberFormatted;
                            }
                        }

                        var homeLocation = giver.Person.GetHomeLocation();

                        if (homeLocation != null)
                        {
                            swipeInfo.Street1 = homeLocation.Street1;

                            if (!string.IsNullOrWhiteSpace(homeLocation.Street2))
                            {
                                swipeInfo.Street2 = homeLocation.Street2;
                            }

                            swipeInfo.City       = homeLocation.City;
                            swipeInfo.State      = homeLocation.State;
                            swipeInfo.PostalCode = homeLocation.PostalCode;
                        }
                    }

                    // add comment to the transation
                    swipeInfo.Comment1 = GetAttributeValue("PaymentComment");

                    // get gateway
                    FinancialGateway financialGateway = null;
                    GatewayComponent gateway          = null;
                    Guid?            gatewayGuid      = GetAttributeValue("CreditCardGateway").AsGuidOrNull();
                    if (gatewayGuid.HasValue)
                    {
                        financialGateway = new FinancialGatewayService(rockContext).Get(gatewayGuid.Value);
                        if (financialGateway != null)
                        {
                            financialGateway.LoadAttributes(rockContext);
                        }
                        gateway = financialGateway.GetGatewayComponent();
                    }

                    if (gateway != null)
                    {
                        string errorMessage = string.Empty;
                        var    transaction  = gateway.Charge(financialGateway, swipeInfo, out errorMessage);

                        if (transaction != null)
                        {
                            var txnChanges = new List <string>();
                            txnChanges.Add("Created Transaction (from kiosk)");

                            _transactionCode = transaction.TransactionCode;
                            History.EvaluateChange(txnChanges, "Transaction Code", string.Empty, transaction.TransactionCode);

                            var personName = new PersonAliasService(rockContext)
                                             .Queryable().AsNoTracking()
                                             .Where(a => a.Id == this.SelectedGivingUnit.PersonAliasId)
                                             .Select(a => a.Person.NickName + " " + a.Person.LastName)
                                             .FirstOrDefault();

                            transaction.AuthorizedPersonAliasId = this.SelectedGivingUnit.PersonAliasId;
                            History.EvaluateChange(txnChanges, "Person", string.Empty, personName);

                            transaction.TransactionDateTime = RockDateTime.Now;
                            History.EvaluateChange(txnChanges, "Date/Time", null, transaction.TransactionDateTime);

                            transaction.FinancialGatewayId = financialGateway.Id;
                            History.EvaluateChange(txnChanges, "Gateway", string.Empty, financialGateway.Name);

                            var txnType = DefinedValueCache.Read(new Guid(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION));
                            transaction.TransactionTypeValueId = txnType.Id;
                            History.EvaluateChange(txnChanges, "Type", string.Empty, txnType.Value);

                            transaction.Summary = swipeInfo.Comment1;
                            History.EvaluateChange(txnChanges, "Transaction Code", string.Empty, transaction.Summary);

                            if (transaction.FinancialPaymentDetail == null)
                            {
                                transaction.FinancialPaymentDetail = new FinancialPaymentDetail();
                            }
                            transaction.FinancialPaymentDetail.SetFromPaymentInfo(swipeInfo, gateway, rockContext, txnChanges);

                            Guid sourceGuid = Guid.Empty;
                            if (Guid.TryParse(GetAttributeValue("Source"), out sourceGuid))
                            {
                                var source = DefinedValueCache.Read(sourceGuid);
                                if (source != null)
                                {
                                    transaction.SourceTypeValueId = source.Id;
                                    History.EvaluateChange(txnChanges, "Source", string.Empty, source.Value);
                                }
                            }

                            foreach (var accountAmount in this.Amounts.Where(a => a.Value > 0))
                            {
                                var transactionDetail = new FinancialTransactionDetail();
                                transactionDetail.Amount    = accountAmount.Value;
                                transactionDetail.AccountId = accountAmount.Key;
                                transaction.TransactionDetails.Add(transactionDetail);
                                var account = new FinancialAccountService(rockContext).Get(accountAmount.Key);
                                if (account != null)
                                {
                                    History.EvaluateChange(txnChanges, account.Name, 0.0M.FormatAsCurrency(), transactionDetail.Amount.FormatAsCurrency());
                                }
                            }

                            var batchService = new FinancialBatchService(rockContext);

                            // Get the batch
                            var batch = batchService.Get(
                                GetAttributeValue("BatchNamePrefix"),
                                swipeInfo.CurrencyTypeValue,
                                swipeInfo.CreditCardTypeValue,
                                transaction.TransactionDateTime.Value,
                                financialGateway.GetBatchTimeOffset());

                            var batchChanges = new List <string>();

                            if (batch.Id == 0)
                            {
                                batchChanges.Add("Generated the batch");
                                History.EvaluateChange(batchChanges, "Batch Name", string.Empty, batch.Name);
                                History.EvaluateChange(batchChanges, "Status", null, batch.Status);
                                History.EvaluateChange(batchChanges, "Start Date/Time", null, batch.BatchStartDateTime);
                                History.EvaluateChange(batchChanges, "End Date/Time", null, batch.BatchEndDateTime);
                            }

                            decimal newControlAmount = batch.ControlAmount + transaction.TotalAmount;
                            History.EvaluateChange(batchChanges, "Control Amount", batch.ControlAmount.FormatAsCurrency(), newControlAmount.FormatAsCurrency());
                            batch.ControlAmount = newControlAmount;

                            transaction.BatchId = batch.Id;
                            batch.Transactions.Add(transaction);

                            rockContext.WrapTransaction(() =>
                            {
                                rockContext.SaveChanges();
                                HistoryService.SaveChanges(
                                    rockContext,
                                    typeof(FinancialBatch),
                                    Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(),
                                    batch.Id,
                                    batchChanges
                                    );

                                HistoryService.SaveChanges(
                                    rockContext,
                                    typeof(FinancialBatch),
                                    Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(),
                                    batch.Id,
                                    txnChanges,
                                    personName,
                                    typeof(FinancialTransaction),
                                    transaction.Id
                                    );
                            });

                            // send receipt in one is configured and not giving anonymously
                            if (!string.IsNullOrWhiteSpace(GetAttributeValue("ReceiptEmail")) && (this.AnonymousGiverPersonAliasId != this.SelectedGivingUnit.PersonAliasId))
                            {
                                _receiptSent = true;

                                SendReceipt();
                            }

                            HidePanels();
                            ShowReceiptPanel();
                        }
                        else
                        {
                            lSwipeErrors.Text = String.Format("<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", errorMessage);
                        }
                    }
                    else
                    {
                        lSwipeErrors.Text = "<div class='alert alert-danger'>Invalid gateway provided. Please provide a gateway. Transaction not processed.</div>";
                    }
                }
            }
            catch (Exception ex)
            {
                lSwipeErrors.Text = String.Format("<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", ex.Message);
            }
        }
Beispiel #60
0
        /// <summary>
        /// Maps the contribution.
        /// </summary>
        /// <param name="tableData">The table data.</param>
        /// <param name="selectedColumns">The selected columns.</param>
        private void MapContribution( IQueryable<Row> tableData, List<string> selectedColumns = null )
        {
            var lookupContext = new RockContext();
            int transactionEntityTypeId = EntityTypeCache.Read( "Rock.Model.FinancialTransaction" ).Id;
            var transactionTypeContributionId = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION ), lookupContext ).Id;

            int currencyTypeACH = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_ACH ), lookupContext ).Id;
            int currencyTypeCash = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CASH ), lookupContext ).Id;
            int currencyTypeCheck = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CHECK ), lookupContext ).Id;
            int currencyTypeCreditCard = DefinedValueCache.Read( new Guid( Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD ), lookupContext ).Id;

            var refundReasons = DefinedTypeCache.Read( new Guid( Rock.SystemGuid.DefinedType.FINANCIAL_TRANSACTION_REFUND_REASON ), lookupContext ).DefinedValues;

            var accountList = new FinancialAccountService( lookupContext ).Queryable().ToList();

            // Get all imported contributions
            var importedContributions = new FinancialTransactionService( lookupContext ).Queryable()
               .Where( c => c.ForeignId != null )
               .ToDictionary( t => t.ForeignId.AsType<int>(), t => (int?)t.Id );

            // List for batching new contributions
            var newTransactions = new List<FinancialTransaction>();

            int completed = 0;
            int totalRows = tableData.Count();
            int percentage = ( totalRows - 1 ) / 100 + 1;
            ReportProgress( 0, string.Format( "Verifying contribution import ({0:N0} found, {1:N0} already exist).", totalRows, importedContributions.Count ) );
            foreach ( var row in tableData.Where( r => r != null ) )
            {
                int? individualId = row["Individual_ID"] as int?;
                int? householdId = row["Household_ID"] as int?;
                int? contributionId = row["ContributionID"] as int?;

                if ( contributionId != null && !importedContributions.ContainsKey( (int)contributionId ) )
                {
                    var transaction = new FinancialTransaction();
                    transaction.CreatedByPersonAliasId = ImportPersonAlias.Id;
                    transaction.TransactionTypeValueId = transactionTypeContributionId;
                    transaction.ForeignId = contributionId.ToString();

                    var personKeys = GetPersonKeys( individualId, householdId, includeVisitors: false );
                    if ( personKeys != null )
                    {
                        transaction.AuthorizedPersonAliasId = personKeys.PersonAliasId;
                        transaction.ProcessedByPersonAliasId = personKeys.PersonAliasId;
                    }

                    string summary = row["Memo"] as string;
                    if ( summary != null )
                    {
                        transaction.Summary = summary;
                    }

                    int? batchId = row["BatchID"] as int?;
                    if ( batchId != null && ImportedBatches.Any( b => b.Key.Equals( batchId ) ) )
                    {
                        transaction.BatchId = ImportedBatches.FirstOrDefault( b => b.Key.Equals( batchId ) ).Value;
                    }

                    DateTime? receivedDate = row["Received_Date"] as DateTime?;
                    if ( receivedDate != null )
                    {
                        transaction.TransactionDateTime = receivedDate;
                        transaction.CreatedDateTime = receivedDate;
                    }

                    bool isTypeNonCash = false;
                    string contributionType = row["Contribution_Type_Name"].ToString().ToLower();
                    if ( contributionType != null )
                    {
                        if ( contributionType == "ach" )
                        {
                            transaction.CurrencyTypeValueId = currencyTypeACH;
                        }
                        else if ( contributionType == "cash" )
                        {
                            transaction.CurrencyTypeValueId = currencyTypeCash;
                        }
                        else if ( contributionType == "check" )
                        {
                            transaction.CurrencyTypeValueId = currencyTypeCheck;
                        }
                        else if ( contributionType == "credit card" )
                        {
                            transaction.CurrencyTypeValueId = currencyTypeCreditCard;
                        }
                        else
                        {
                            isTypeNonCash = true;
                        }
                    }

                    string checkNumber = row["Check_Number"] as string;
                    if ( checkNumber != null && checkNumber.AsType<int?>() != null )
                    {
                        // set the transaction code to the check number
                        transaction.TransactionCode = checkNumber;
                    }

                    string fundName = row["Fund_Name"] as string;
                    string subFund = row["Sub_Fund_Name"] as string;
                    decimal? amount = row["Amount"] as decimal?;
                    if ( fundName != null & amount != null )
                    {
                        int transactionAccountId;
                        var parentAccount = accountList.FirstOrDefault( a => a.Name.Equals( fundName ) && a.CampusId == null );
                        if ( parentAccount == null )
                        {
                            parentAccount = AddAccount( lookupContext, fundName, null, null );
                            accountList.Add( parentAccount );
                        }

                        if ( subFund != null )
                        {
                            int? campusFundId = null;
                            // assign a campus if the subfund is a campus fund
                            var campusFund = CampusList.FirstOrDefault( c => subFund.StartsWith( c.Name ) || subFund.StartsWith( c.ShortCode ) );
                            if ( campusFund != null )
                            {
                                // use full campus name as the subfund
                                subFund = campusFund.Name;
                                campusFundId = campusFund.Id;
                            }

                            // add info to easily find/assign this fund in the view
                            subFund = string.Format( "{0} {1}", subFund, fundName );

                            var childAccount = accountList.FirstOrDefault( c => c.Name.Equals( subFund ) && c.ParentAccountId == parentAccount.Id );
                            if ( childAccount == null )
                            {
                                // create a child account with a campusId if it was set
                                childAccount = AddAccount( lookupContext, subFund, campusFundId, parentAccount.Id );
                                accountList.Add( childAccount );
                            }

                            transactionAccountId = childAccount.Id;
                        }
                        else
                        {
                            transactionAccountId = parentAccount.Id;
                        }

                        var transactionDetail = new FinancialTransactionDetail();
                        transactionDetail.Amount = (decimal)amount;
                        transactionDetail.CreatedDateTime = receivedDate;
                        transactionDetail.AccountId = transactionAccountId;
                        transactionDetail.IsNonCash = isTypeNonCash;
                        transaction.TransactionDetails.Add( transactionDetail );

                        if ( amount < 0 )
                        {
                            var transactionRefund = new FinancialTransactionRefund();
                            transactionRefund.CreatedDateTime = receivedDate;
                            transactionRefund.RefundReasonSummary = summary;
                            transactionRefund.RefundReasonValueId = refundReasons.Where( dv => summary != null && dv.Value.Contains( summary ) )
                                .Select( dv => (int?)dv.Id ).FirstOrDefault();
                            transaction.Refund = transactionRefund;
                        }
                    }

                    newTransactions.Add( transaction );
                    completed++;
                    if ( completed % percentage < 1 )
                    {
                        int percentComplete = completed / percentage;
                        ReportProgress( percentComplete, string.Format( "{0:N0} contributions imported ({1}% complete).", completed, percentComplete ) );
                    }
                    else if ( completed % ReportingNumber < 1 )
                    {
                        SaveContributions( newTransactions );
                        newTransactions.Clear();
                        ReportPartialProgress();
                    }
                }
            }

            if ( newTransactions.Any() )
            {
                SaveContributions( newTransactions );
            }

            ReportProgress( 100, string.Format( "Finished contribution import: {0:N0} contributions imported.", completed ) );
        }