Пример #1
0
        // helper functional methods (like BindGrid(), etc.)
        private void ShowContent()
        {
            List <Dictionary <string, object> > scheduleSummaries = new List <Dictionary <string, object> >();

            // get scheduled transactions for current user
            if (CurrentPerson != null)
            {
                var rockContext = new RockContext();
                FinancialScheduledTransactionService transactionService = new FinancialScheduledTransactionService(rockContext);

                var schedules = transactionService.Queryable("ScheduledTransactionDetails.Account")
                                .Where(s => s.AuthorizedPersonAlias.Person.GivingId == CurrentPerson.GivingId && s.IsActive == true);

                foreach (FinancialScheduledTransaction schedule in schedules)
                {
                    string errorMsgs = string.Empty;
                    transactionService.GetStatus(schedule, out errorMsgs);

                    decimal totalAmount = 0;

                    Dictionary <string, object> scheduleSummary = new Dictionary <string, object>();
                    scheduleSummary.Add("Id", schedule.Id);
                    scheduleSummary.Add("Guid", schedule.Guid);
                    scheduleSummary.Add("StartDate", schedule.StartDate);
                    scheduleSummary.Add("EndDate", schedule.EndDate);
                    scheduleSummary.Add("NextPaymentDate", schedule.NextPaymentDate);

                    if (schedule.NextPaymentDate.HasValue)
                    {
                        scheduleSummary.Add("DaysTillNextPayment", (schedule.NextPaymentDate.Value - DateTime.Now).Days);
                    }
                    else
                    {
                        scheduleSummary.Add("DaysTillNextPayment", null);
                    }

                    DateTime?lastPaymentDate = schedule.Transactions.Max(t => t.TransactionDateTime);
                    scheduleSummary.Add("LastPaymentDate", lastPaymentDate);

                    if (lastPaymentDate.HasValue)
                    {
                        scheduleSummary.Add("DaysSinceLastPayment", (DateTime.Now - lastPaymentDate.Value).Days);
                    }
                    else
                    {
                        scheduleSummary.Add("DaysSinceLastPayment", null);
                    }

                    scheduleSummary.Add("CurrencyType", (schedule.FinancialPaymentDetail != null && schedule.FinancialPaymentDetail.CurrencyTypeValue != null) ? schedule.FinancialPaymentDetail.CurrencyTypeValue.Value : "");
                    scheduleSummary.Add("CreditCardType", (schedule.FinancialPaymentDetail != null && schedule.FinancialPaymentDetail.CreditCardTypeValue != null) ? schedule.FinancialPaymentDetail.CreditCardTypeValue.Value : "");
                    scheduleSummary.Add("UrlEncryptedKey", schedule.UrlEncodedKey);
                    scheduleSummary.Add("Frequency", schedule.TransactionFrequencyValue.Value);
                    scheduleSummary.Add("FrequencyDescription", schedule.TransactionFrequencyValue.Description);

                    List <Dictionary <string, object> > summaryDetails = new List <Dictionary <string, object> >();

                    foreach (FinancialScheduledTransactionDetail detail in schedule.ScheduledTransactionDetails)
                    {
                        Dictionary <string, object> detailSummary = new Dictionary <string, object>();
                        detailSummary.Add("AccountId", detail.Id);
                        detailSummary.Add("AccountName", detail.Account.Name);
                        detailSummary.Add("Amount", detail.Amount);
                        detailSummary.Add("Summary", detail.Summary);

                        summaryDetails.Add(detailSummary);

                        totalAmount += detail.Amount;
                    }

                    scheduleSummary.Add("ScheduledAmount", totalAmount);
                    scheduleSummary.Add("TransactionDetails", summaryDetails);

                    scheduleSummaries.Add(scheduleSummary);
                }

                rockContext.SaveChanges();
            }

            // added linked pages to mergefields
            Dictionary <string, object> linkedPages = new Dictionary <string, object>();

            linkedPages.Add("ManageScheduledTransactionsPage", LinkedPageRoute("ManageScheduledTransactionsPage"));
            linkedPages.Add("TransactionHistoryPage", LinkedPageRoute("TransactionHistoryPage"));
            linkedPages.Add("TransactionEntryPage", LinkedPageRoute("TransactionEntryPage"));



            var scheduleValues = new Dictionary <string, object>();

            scheduleValues.Add("ScheduledTransactions", scheduleSummaries.ToList());
            scheduleValues.Add("LinkedPages", linkedPages);
            // TODO: When support for "Person" is not supported anymore (should use "CurrentPerson" instead), remove this line
            scheduleValues.Add("Person", CurrentPerson);
            scheduleValues.Add("CurrentPerson", CurrentPerson);

            string content = GetAttributeValue("Template").ResolveMergeFields(scheduleValues);

            lContent.Text = content;
        }
        /// <summary>
        /// Migrates the scheduled transaction notes to history.
        /// </summary>
        public void MigrateScheduledTransactionNotesToHistory()
        {
            var rockContext = new RockContext();

            rockContext.Database.CommandTimeout = _commandTimeout;
            var noteService       = new NoteService(rockContext);
            var historyCategoryId = CategoryCache.Get(Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid())?.Id;
            var entityTypeIdScheduledTransaction = EntityTypeCache.GetId(Rock.SystemGuid.EntityType.FINANCIAL_SCHEDULED_TRANSACTION.AsGuid());
            var noteTypeIdScheduledTransaction   = NoteTypeCache.GetId(Rock.SystemGuid.NoteType.SCHEDULED_TRANSACTION_NOTE.AsGuid());

            if (!historyCategoryId.HasValue || !entityTypeIdScheduledTransaction.HasValue || !noteTypeIdScheduledTransaction.HasValue)
            {
                return;
            }

            var historyService = new HistoryService(rockContext);

            var historyQuery      = historyService.Queryable().Where(a => a.EntityTypeId == entityTypeIdScheduledTransaction.Value);
            var captionsToConvert = new string[]
            {
                "Created Transaction"
                , "Updated Transaction"
                , "Cancelled Transaction"
                , "Reactivated Transaction"
            };

            var notesToConvertToHistory = noteService.Queryable()
                                          .Where(a => a.NoteTypeId == noteTypeIdScheduledTransaction.Value && captionsToConvert.Contains(a.Caption) && a.EntityId.HasValue)
                                          .Where(a => !historyQuery.Any(h => h.EntityId == a.EntityId));

            var notesToConvertToSummaryList = noteService.Queryable()
                                              .Where(a => a.NoteTypeId == noteTypeIdScheduledTransaction.Value && a.Caption == "Created Transaction" && !string.IsNullOrEmpty(a.Text) && a.EntityId.HasValue)
                                              .AsNoTracking().ToList();

            List <History> historyRecordsToInsert = notesToConvertToHistory.AsNoTracking()
                                                    .ToList()
                                                    .Select(n =>
            {
                var historyRecord = new History
                {
                    CategoryId              = historyCategoryId.Value,
                    EntityTypeId            = entityTypeIdScheduledTransaction.Value,
                    EntityId                = n.EntityId.Value,
                    Guid                    = Guid.NewGuid(),
                    CreatedByPersonAliasId  = n.CreatedByPersonAliasId,
                    ModifiedByPersonAliasId = n.ModifiedByPersonAliasId,
                    CreatedDateTime         = n.CreatedDateTime,
                    ModifiedDateTime        = n.ModifiedDateTime
                };

                if (n.Caption == "Cancelled Transaction")
                {
                    historyRecord.Verb       = "MODIFY";
                    historyRecord.ChangeType = "Property";
                    historyRecord.ValueName  = "Is Active";
                    historyRecord.NewValue   = "False";
                }
                else if (n.Caption == "Reactivated Transaction")
                {
                    historyRecord.Verb       = "MODIFY";
                    historyRecord.ChangeType = "Property";
                    historyRecord.ValueName  = "Is Active";
                    historyRecord.NewValue   = "True";
                }
                else if (n.Caption == "Updated Transaction")
                {
                    historyRecord.Verb      = "MODIFY";
                    historyRecord.ValueName = "Transaction";
                }
                else
                {
                    historyRecord.Verb       = "ADD";
                    historyRecord.ChangeType = "Record";
                    historyRecord.ValueName  = "Transaction";
                }

                return(historyRecord);
            }).ToList();

            rockContext.BulkInsert(historyRecordsToInsert);
            var qryNotesToDelete = noteService.Queryable().Where(a => a.NoteTypeId == noteTypeIdScheduledTransaction && captionsToConvert.Contains(a.Caption));

            rockContext.BulkDelete(qryNotesToDelete);

            foreach (var noteToConvertToSummary in notesToConvertToSummaryList)
            {
                using (var updatedSummaryContext = new RockContext())
                {
                    var scheduledTransactionService = new FinancialScheduledTransactionService(updatedSummaryContext);
                    var scheduledTransaction        = scheduledTransactionService.Get(noteToConvertToSummary.EntityId.Value);
                    if (scheduledTransaction != null && scheduledTransaction.Summary.IsNullOrWhiteSpace())
                    {
                        scheduledTransaction.Summary = noteToConvertToSummary.Text;
                        updatedSummaryContext.SaveChanges(disablePrePostProcessing: true);
                    }
                }
            }
        }
        /// <summary>
        /// Binds the grid.
        /// </summary>
        private void BindGrid(bool isExporting = false)
        {
            int?personId      = null;
            int?givingGroupId = null;

            bool validRequest = false;

            if (TargetPerson != null)
            {
                personId      = TargetPerson.Id;
                givingGroupId = TargetPerson.GivingGroupId;
                validRequest  = true;
            }
            else
            {
                int personEntityTypeId = EntityTypeCache.Read("Rock.Model.Person").Id;
                if (!ContextTypesRequired.Any(e => e.Id == personEntityTypeId))
                {
                    validRequest = true;
                }
            }

            if (validRequest)
            {
                var rockContext = new RockContext();
                var qry         = new FinancialScheduledTransactionService(rockContext)
                                  .Queryable("ScheduledTransactionDetails,FinancialPaymentDetail.CurrencyTypeValue,FinancialPaymentDetail.CreditCardTypeValue")
                                  .AsNoTracking();

                // Valid Accounts
                var accountGuids = GetAttributeValue("Accounts").SplitDelimitedValues().AsGuidList();
                if (accountGuids.Any())
                {
                    qry = qry.Where(t => t.ScheduledTransactionDetails.Any(d => accountGuids.Contains(d.Account.Guid)));
                }

                // Amount Range
                var nre = new NumberRangeEditor();
                nre.DelimitedValues = gfSettings.GetUserPreference("Amount");
                if (nre.LowerValue.HasValue)
                {
                    qry = qry.Where(t => t.ScheduledTransactionDetails.Sum(d => d.Amount) >= nre.LowerValue.Value);
                }

                if (nre.UpperValue.HasValue)
                {
                    qry = qry.Where(t => t.ScheduledTransactionDetails.Sum(d => d.Amount) <= nre.UpperValue.Value);
                }

                // Frequency
                int?frequencyTypeId = gfSettings.GetUserPreference("Frequency").AsIntegerOrNull();
                if (frequencyTypeId.HasValue)
                {
                    qry = qry.Where(t => t.TransactionFrequencyValueId == frequencyTypeId.Value);
                }

                // Date Range
                var drp = new DateRangePicker();
                drp.DelimitedValues = gfSettings.GetUserPreference("Created");
                if (drp.LowerValue.HasValue)
                {
                    qry = qry.Where(t => t.CreatedDateTime >= drp.LowerValue.Value);
                }

                if (drp.UpperValue.HasValue)
                {
                    DateTime upperDate = drp.UpperValue.Value.Date.AddDays(1);
                    qry = qry.Where(t => t.CreatedDateTime < upperDate);
                }

                // Account Id
                int accountId = int.MinValue;
                if (int.TryParse(gfSettings.GetUserPreference("Account"), out accountId) && ddlAccount.Visible)
                {
                    qry = qry.Where(t => t.ScheduledTransactionDetails.Any(d => d.AccountId == accountId));
                }

                // Active only (no filter)
                if (string.IsNullOrWhiteSpace(gfSettings.GetUserPreference("Include Inactive")))
                {
                    qry = qry.Where(t => t.IsActive);
                }

                if (givingGroupId.HasValue)
                {
                    //  Person contributes with family
                    qry = qry.Where(t => t.AuthorizedPersonAlias.Person.GivingGroupId == givingGroupId);
                }
                else if (personId.HasValue)
                {
                    // Person contributes individually
                    qry = qry.Where(t => t.AuthorizedPersonAlias.PersonId == personId);
                }

                SortProperty sortProperty = gList.SortProperty;
                if (sortProperty != null)
                {
                    if (sortProperty.Property == "Amount")
                    {
                        if (sortProperty.Direction == SortDirection.Ascending)
                        {
                            qry = qry.OrderBy(t => t.ScheduledTransactionDetails.Sum(d => (decimal?)d.Amount) ?? 0.00M);
                        }
                        else
                        {
                            qry = qry.OrderByDescending(t => t.ScheduledTransactionDetails.Sum(d => (decimal?)d.Amount) ?? 0.0M);
                        }
                    }
                    else
                    {
                        qry = qry.Sort(sortProperty);
                    }
                }
                else
                {
                    qry = qry
                          .OrderBy(t => t.AuthorizedPersonAlias.Person.LastName)
                          .ThenBy(t => t.AuthorizedPersonAlias.Person.NickName)
                          .ThenByDescending(t => t.IsActive)
                          .ThenByDescending(t => t.StartDate);
                }

                _isExporting = isExporting;

                gList.SetLinqDataSource <FinancialScheduledTransaction>(qry);
                gList.DataBind();

                _isExporting = false;
            }
        }
Пример #4
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Execute(IJobExecutionContext context)
        {
            var        rockContext = new RockContext();
            JobDataMap dataMap     = context.JobDetail.JobDataMap;

            // Get the details for the email that we'll be sending out.
            Guid?systemEmailGuid            = dataMap.GetString("ExpiringCreditCardEmail").AsGuidOrNull();
            SystemEmailService emailService = new SystemEmailService(rockContext);
            SystemEmail        systemEmail  = null;

            if (systemEmailGuid.HasValue)
            {
                systemEmail = emailService.Get(systemEmailGuid.Value);
            }

            if (systemEmail == null)
            {
                throw new Exception("Expiring credit card email is missing.");
            }

            // Fetch the configured Workflow once if one was set, we'll use it later.
            Guid?workflowGuid = dataMap.GetString("Workflow").AsGuidOrNull();
            WorkflowTypeCache workflowType = null;
            var workflowService            = new WorkflowService(rockContext);

            if (workflowGuid != null)
            {
                workflowType = WorkflowTypeCache.Get(workflowGuid.Value);
            }

            var qry = new FinancialScheduledTransactionService(rockContext)
                      .Queryable("ScheduledTransactionDetails,FinancialPaymentDetail.CurrencyTypeValue,FinancialPaymentDetail.CreditCardTypeValue")
                      .Where(t => t.IsActive && t.FinancialPaymentDetail.ExpirationMonthEncrypted != null &&
                             (t.EndDate == null || t.EndDate > DateTime.Now))
                      .AsNoTracking();

            // Get the current month and year
            DateTime now     = DateTime.Now;
            int      month   = now.Month;
            int      year    = now.Year;
            int      counter = 0;
            var      errors  = new List <string>();

            foreach (var transaction in qry)
            {
                int?expirationMonthDecrypted = Encryption.DecryptString(transaction.FinancialPaymentDetail.ExpirationMonthEncrypted).AsIntegerOrNull();
                int?expirationYearDecrypted  = Encryption.DecryptString(transaction.FinancialPaymentDetail.ExpirationYearEncrypted).AsIntegerOrNull();
                if (expirationMonthDecrypted.HasValue && expirationMonthDecrypted.HasValue)
                {
                    string acctNum = string.Empty;

                    if (!string.IsNullOrEmpty(transaction.FinancialPaymentDetail.AccountNumberMasked) && transaction.FinancialPaymentDetail.AccountNumberMasked.Length >= 4)
                    {
                        acctNum = transaction.FinancialPaymentDetail.AccountNumberMasked.Substring(transaction.FinancialPaymentDetail.AccountNumberMasked.Length - 4);
                    }

                    int warningYear  = expirationYearDecrypted.Value;
                    int warningMonth = expirationMonthDecrypted.Value - 1;
                    if (warningMonth == 0)
                    {
                        warningYear -= 1;
                        warningMonth = 12;
                    }

                    string warningDate        = warningMonth.ToString() + warningYear.ToString();
                    string currentMonthString = month.ToString() + year.ToString();

                    if (warningDate == currentMonthString)
                    {
                        // as per ISO7813 https://en.wikipedia.org/wiki/ISO/IEC_7813
                        var expirationDate = string.Format("{0:D2}/{1:D2}", expirationMonthDecrypted, expirationYearDecrypted);

                        var recipients  = new List <RockEmailMessageRecipient>();
                        var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null);
                        var person      = transaction.AuthorizedPersonAlias.Person;

                        if (!person.IsEmailActive || person.Email.IsNullOrWhiteSpace() || person.EmailPreference == EmailPreference.DoNotEmail)
                        {
                            continue;
                        }

                        mergeFields.Add("Person", person);
                        mergeFields.Add("Card", acctNum);
                        mergeFields.Add("Expiring", expirationDate);
                        recipients.Add(new RockEmailMessageRecipient(person, mergeFields));

                        var emailMessage = new RockEmailMessage(systemEmail.Guid);
                        emailMessage.SetRecipients(recipients);

                        var emailErrors = new List <string>();
                        emailMessage.Send(out emailErrors);
                        errors.AddRange(emailErrors);

                        // Start workflow for this person
                        if (workflowType != null)
                        {
                            Dictionary <string, string> attributes = new Dictionary <string, string>();
                            attributes.Add("Person", transaction.AuthorizedPersonAlias.Guid.ToString());
                            attributes.Add("Card", acctNum);
                            attributes.Add("Expiring", expirationDate);
                            StartWorkflow(workflowService, workflowType, attributes, string.Format("{0} (scheduled transaction Id: {1})", person.FullName, transaction.Id));
                        }

                        counter++;
                    }
                }
            }

            context.Result = string.Format("{0} scheduled credit card transactions were examined with {1} notice(s) sent.", qry.Count(), counter);

            if (errors.Any())
            {
                StringBuilder sb = new StringBuilder();
                sb.AppendLine();
                sb.Append(string.Format("{0} Errors: ", errors.Count()));
                errors.ForEach(e => { sb.AppendLine(); sb.Append(e); });
                string errorMessage = sb.ToString();
                context.Result += errorMessage;
                var         exception = new Exception(errorMessage);
                HttpContext context2  = HttpContext.Current;
                ExceptionLogService.LogException(exception, context2);
                throw exception;
            }
        }
Пример #5
0
        protected void btnDownload_Click(object sender, EventArgs e)
        {
            string batchNamePrefix           = GetAttributeValue("BatchNamePrefix");
            Guid?  receiptEmail              = GetAttributeValue("ReceiptEmail").AsGuidOrNull();
            Guid?  failedPaymentEmail        = GetAttributeValue("FailedPaymentEmail").AsGuidOrNull();
            Guid?  failedPaymentWorkflowType = GetAttributeValue("FailedPaymentWorkflow").AsGuidOrNull();

            DateTime?startDateTime = drpDates.LowerValue;
            DateTime?endDateTime   = drpDates.UpperValue;

            if (startDateTime.HasValue && endDateTime.HasValue && endDateTime.Value.CompareTo(startDateTime.Value) >= 0)
            {
                var financialGateway = GetSelectedGateway();
                if (financialGateway != null)
                {
                    var gateway = financialGateway.GetGatewayComponent();
                    if (gateway != null)
                    {
                        DateTime start = startDateTime.Value;
                        DateTime end   = endDateTime.Value.AddDays(1);

                        string errorMessage = string.Empty;
                        var    payments     = gateway.GetPayments(financialGateway, start, end, out errorMessage);

                        if (string.IsNullOrWhiteSpace(errorMessage))
                        {
                            var qryParam = new Dictionary <string, string>();
                            qryParam.Add("batchId", "9999");
                            string batchUrlFormat = LinkedPageUrl("BatchDetailPage", qryParam).Replace("9999", "{0}");

                            string resultSummary = FinancialScheduledTransactionService.ProcessPayments(financialGateway, batchNamePrefix, payments, batchUrlFormat, receiptEmail, failedPaymentEmail, failedPaymentWorkflowType);

                            if (!string.IsNullOrWhiteSpace(resultSummary))
                            {
                                nbSuccess.Text = string.Format("<ul>{0}</ul>", resultSummary);
                            }
                            else
                            {
                                nbSuccess.Text = string.Format("There were not any transactions downloaded.", resultSummary);
                            }
                            nbSuccess.Visible = true;
                        }
                        else
                        {
                            ShowError(errorMessage);
                        }
                    }
                    else
                    {
                        ShowError("Selected Payment Gateway does not have a valid payment processor!");
                    }
                }
                else
                {
                    ShowError("Please select a valid Payment Gateway!");
                }
            }
            else
            {
                ShowError("Please select a valid Date Range!");
            }
        }
        /// <summary>
        /// Updates the scheduled payment.
        /// </summary>
        /// <param name="usePaymentToken">if set to <c>true</c> [use payment token].</param>
        /// <param name="paymentToken">The payment token.</param>
        protected void UpdateScheduledPayment(bool usePaymentToken, string paymentToken = null)
        {
            var giftTerm = this.GetAttributeValue(AttributeKey.GiftTerm);

            if (dtpStartDate.SelectedDate <= RockDateTime.Today)
            {
                nbUpdateScheduledPaymentWarning.Visible = true;
                nbUpdateScheduledPaymentWarning.Text    = string.Format("When scheduling a {0}, make sure the starting date is in the future (after today)", giftTerm.ToLower());
                return;
            }

            var rockContext = new RockContext();

            var  financialScheduledTransactionService       = new FinancialScheduledTransactionService(rockContext);
            var  financialScheduledTransactionDetailService = new FinancialScheduledTransactionDetailService(rockContext);
            Guid scheduledTransactionGuid      = hfScheduledTransactionGuid.Value.AsGuid();
            var  financialScheduledTransaction = financialScheduledTransactionService.Get(scheduledTransactionGuid);

            financialScheduledTransaction.StartDate = dtpStartDate.SelectedDate.Value;
            financialScheduledTransaction.TransactionFrequencyValueId = ddlFrequency.SelectedValue.AsInteger();

            ReferencePaymentInfo referencePaymentInfo;

            var person = financialScheduledTransaction.AuthorizedPersonAlias.Person;

            string errorMessage;

            var financialGateway                      = this.FinancialGateway;
            var financialGatewayComponent             = this.FinancialGatewayComponent;
            var existingPaymentOrPersonSavedAccountId = rblExistingPaymentOrPersonSavedAccount.SelectedValue.AsInteger();

            bool useExistingPaymentMethod = pnlUseExistingPaymentNoSavedAccounts.Visible || existingPaymentOrPersonSavedAccountId == 0;
            bool useSavedAccount          = pnlUseExistingPaymentWithSavedAccounts.Visible && existingPaymentOrPersonSavedAccountId > 0;

            if (usePaymentToken)
            {
                referencePaymentInfo           = new ReferencePaymentInfo();
                referencePaymentInfo.FirstName = person.FirstName;
                referencePaymentInfo.LastName  = person.LastName;

                referencePaymentInfo.UpdateAddressFieldsFromAddressControl(acBillingAddress);

                referencePaymentInfo.ReferenceNumber = paymentToken;

                var customerToken = financialGatewayComponent.CreateCustomerAccount(this.FinancialGateway, referencePaymentInfo, out errorMessage);

                if (errorMessage.IsNotNullOrWhiteSpace() || customerToken.IsNullOrWhiteSpace())
                {
                    nbMessage.NotificationBoxType = NotificationBoxType.Danger;
                    nbMessage.Text    = errorMessage ?? "Unknown Error";
                    nbMessage.Visible = true;
                    return;
                }

                referencePaymentInfo.GatewayPersonIdentifier = customerToken;
            }
            else if (useExistingPaymentMethod)
            {
                // use save payment method as original transaction
                referencePaymentInfo = new ReferencePaymentInfo();
                referencePaymentInfo.GatewayPersonIdentifier       = financialScheduledTransaction.FinancialPaymentDetail.GatewayPersonIdentifier;
                referencePaymentInfo.FinancialPersonSavedAccountId = financialScheduledTransaction.FinancialPaymentDetail.FinancialPersonSavedAccountId;
            }
            else if (useSavedAccount)
            {
                var savedAccount = new FinancialPersonSavedAccountService(rockContext).Get(existingPaymentOrPersonSavedAccountId);
                if (savedAccount != null)
                {
                    referencePaymentInfo = savedAccount.GetReferencePayment();
                }
                else
                {
                    // shouldn't happen
                    throw new Exception("Unable to determine Saved Account");
                }
            }
            else
            {
                // shouldn't happen
                throw new Exception("Unable to determine payment method");
            }

            var selectedAccountAmounts = caapPromptForAccountAmounts.AccountAmounts.Where(a => a.Amount.HasValue && a.Amount.Value != 0).Select(a => new { a.AccountId, Amount = a.Amount.Value }).ToArray();

            referencePaymentInfo.Amount = selectedAccountAmounts.Sum(a => a.Amount);

            var originalGatewayScheduleId = financialScheduledTransaction.GatewayScheduleId;

            try
            {
                financialScheduledTransaction.FinancialPaymentDetail.ClearPaymentInfo();
                var successfullyUpdated = financialGatewayComponent.UpdateScheduledPayment(financialScheduledTransaction, referencePaymentInfo, out errorMessage);

                if (!successfullyUpdated)
                {
                    nbMessage.NotificationBoxType = NotificationBoxType.Danger;
                    nbMessage.Text    = errorMessage ?? "Unknown Error";
                    nbMessage.Visible = true;
                    return;
                }

                financialScheduledTransaction.FinancialPaymentDetail.SetFromPaymentInfo(referencePaymentInfo, financialGatewayComponent as GatewayComponent, rockContext);

                var selectedAccountIds        = selectedAccountAmounts.Select(a => a.AccountId).ToArray();
                var deletedTransactionDetails = financialScheduledTransaction.ScheduledTransactionDetails.ToList().Where(a => !selectedAccountIds.Contains(a.AccountId)).ToList();

                foreach (var deletedTransactionDetail in deletedTransactionDetails)
                {
                    financialScheduledTransaction.ScheduledTransactionDetails.Remove(deletedTransactionDetail);
                    financialScheduledTransactionDetailService.Delete(deletedTransactionDetail);
                }

                foreach (var selectedAccountAmount in selectedAccountAmounts)
                {
                    var scheduledTransactionDetail = financialScheduledTransaction.ScheduledTransactionDetails.FirstOrDefault(a => a.AccountId == selectedAccountAmount.AccountId);
                    if (scheduledTransactionDetail == null)
                    {
                        scheduledTransactionDetail           = new FinancialScheduledTransactionDetail();
                        scheduledTransactionDetail.AccountId = selectedAccountAmount.AccountId;
                        financialScheduledTransaction.ScheduledTransactionDetails.Add(scheduledTransactionDetail);
                    }

                    scheduledTransactionDetail.Amount = selectedAccountAmount.Amount;
                }

                rockContext.SaveChanges();
                Task.Run(() => ScheduledGiftWasModifiedMessage.PublishScheduledTransactionEvent(financialScheduledTransaction.Id, ScheduledGiftEventTypes.ScheduledGiftUpdated));
            }
            catch (Exception)
            {
                // if the GatewayScheduleId was updated, but there was an exception,
                // make sure we save the  financialScheduledTransaction record with the updated GatewayScheduleId so we don't orphan it
                if (financialScheduledTransaction.GatewayScheduleId.IsNotNullOrWhiteSpace() && (originalGatewayScheduleId != financialScheduledTransaction.GatewayScheduleId))
                {
                    rockContext.SaveChanges();
                }

                throw;
            }

            var mergeFields = LavaHelper.GetCommonMergeFields(this.RockPage, this.CurrentPerson, new CommonMergeFieldsOptions {
                GetLegacyGlobalMergeFields = false
            });
            var finishLavaTemplate = this.GetAttributeValue(AttributeKey.FinishLavaTemplate);

            // re-fetch financialScheduledTransaction with a new RockContext from database to ensure that lazy loaded fields will be populated
            using (var rockContextForSummary = new RockContext())
            {
                if (pnlHostedPaymentControl.Visible && hfSaveNewAccount.Value.AsInteger() == 1 && tbSaveAccount.Text.IsNotNullOrWhiteSpace())
                {
                    SaveNewFinancialPersonSavedAccount(financialScheduledTransaction);
                }

                financialScheduledTransaction = new FinancialScheduledTransactionService(rockContextForSummary).Get(scheduledTransactionGuid);

                mergeFields.Add("Transaction", financialScheduledTransaction);
                mergeFields.Add("Person", financialScheduledTransaction.AuthorizedPersonAlias.Person);
                mergeFields.Add("PaymentDetail", financialScheduledTransaction.FinancialPaymentDetail);
                mergeFields.Add("BillingLocation", financialScheduledTransaction.FinancialPaymentDetail.BillingLocation);

                pnlPromptForChanges.Visible   = false;
                pnlTransactionSummary.Visible = true;

                lTransactionSummaryHTML.Text = finishLavaTemplate.ResolveMergeFields(mergeFields);
            }
        }
Пример #7
0
        /// <summary>
        /// Executes the specified context.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <exception cref="Exception">
        /// One or more exceptions occurred while downloading transactions..." + Environment.NewLine + exceptionMsgs.AsDelimited( Environment.NewLine )
        /// </exception>
        public virtual void Execute(IJobExecutionContext context)
        {
            var exceptionMsgs = new List <string>();

            // get the job map
            var dataMap = context.JobDetail.JobDataMap;
            var scheduledPaymentsProcessed = 0;

            Guid?receiptEmail              = dataMap.GetString(AttributeKey.ReceiptEmail).AsGuidOrNull();
            Guid?failedPaymentEmail        = dataMap.GetString(AttributeKey.FailedPaymentEmail).AsGuidOrNull();
            Guid?failedPaymentWorkflowType = dataMap.GetString(AttributeKey.FailedPaymentWorkflow).AsGuidOrNull();
            int  daysBack = dataMap.GetString(AttributeKey.DaysBack).AsIntegerOrNull() ?? 1;

            DateTime today            = RockDateTime.Today;
            TimeSpan daysBackTimeSpan = new TimeSpan(daysBack, 0, 0, 0);

            string batchNamePrefix = dataMap.GetString(AttributeKey.BatchNamePrefix);


            using (var rockContext = new RockContext())
            {
                var targetGatewayQuery = new FinancialGatewayService(rockContext).Queryable().Where(g => g.IsActive).AsNoTracking();

                var targetGatewayGuid = dataMap.GetString(AttributeKey.TargetGateway).AsGuidOrNull();
                if (targetGatewayGuid.HasValue)
                {
                    targetGatewayQuery = targetGatewayQuery.Where(g => g.Guid == targetGatewayGuid.Value);
                }

                foreach (var financialGateway in targetGatewayQuery.ToList())
                {
                    try
                    {
                        financialGateway.LoadAttributes(rockContext);

                        var gateway = financialGateway.GetGatewayComponent();
                        if (gateway == null)
                        {
                            continue;
                        }

                        DateTime endDateTime = today.Add(financialGateway.GetBatchTimeOffset());

                        // If the calculated end time has not yet occurred, use the previous day.
                        endDateTime = RockDateTime.Now.CompareTo(endDateTime) >= 0 ? endDateTime : endDateTime.AddDays(-1);

                        DateTime startDateTime = endDateTime.Subtract(daysBackTimeSpan);

                        string errorMessage = string.Empty;
                        var    payments     = gateway.GetPayments(financialGateway, startDateTime, endDateTime, out errorMessage);

                        if (string.IsNullOrWhiteSpace(errorMessage))
                        {
                            FinancialScheduledTransactionService.ProcessPayments(financialGateway, batchNamePrefix, payments, string.Empty, receiptEmail, failedPaymentEmail, failedPaymentWorkflowType);
                            scheduledPaymentsProcessed += payments.Count();
                        }
                        else
                        {
                            throw new Exception(errorMessage);
                        }
                    }
                    catch (Exception ex)
                    {
                        ExceptionLogService.LogException(ex, null);
                        exceptionMsgs.Add(ex.Message);
                    }
                }
            }

            if (exceptionMsgs.Any())
            {
                throw new Exception("One or more exceptions occurred while downloading transactions..." + Environment.NewLine + exceptionMsgs.AsDelimited(Environment.NewLine));
            }

            context.Result = string.Format("{0} payments processed", scheduledPaymentsProcessed);
        }
Пример #8
0
        /// <summary>
        /// Updates the scheduled payment.
        /// </summary>
        /// <param name="usePaymentToken">if set to <c>true</c> [use payment token].</param>
        /// <param name="paymentToken">The payment token.</param>
        protected void UpdateScheduledPayment(bool usePaymentToken, string paymentToken = null)
        {
            var giftTerm = this.GetAttributeValue(AttributeKey.GiftTerm);

            if (dtpStartDate.SelectedDate <= RockDateTime.Today)
            {
                nbUpdateScheduledPaymentWarning.Visible = true;
                nbUpdateScheduledPaymentWarning.Text    = string.Format("When scheduling a {0}, make sure the starting date is in the future (after today)", giftTerm.ToLower());
                return;
            }

            var rockContext = new RockContext();

            var financialScheduledTransactionService       = new FinancialScheduledTransactionService(rockContext);
            var financialScheduledTransactionDetailService = new FinancialScheduledTransactionDetailService(rockContext);
            int scheduledTransactionId        = hfScheduledTransactionId.Value.AsInteger();
            var financialScheduledTransaction = financialScheduledTransactionService.Get(scheduledTransactionId);

            financialScheduledTransaction.StartDate = dtpStartDate.SelectedDate.Value;
            financialScheduledTransaction.TransactionFrequencyValueId = ddlFrequency.SelectedValue.AsInteger();

            ReferencePaymentInfo referencePaymentInfo;

            var person = financialScheduledTransaction.AuthorizedPersonAlias.Person;

            string errorMessage;

            var financialGateway          = this.FinancialGateway;
            var financialGatewayComponent = this.FinancialGatewayComponent;

            if (usePaymentToken)
            {
                referencePaymentInfo           = new ReferencePaymentInfo();
                referencePaymentInfo.FirstName = person.FirstName;
                referencePaymentInfo.LastName  = person.LastName;

                referencePaymentInfo.UpdateAddressFieldsFromAddressControl(acBillingAddress);

                referencePaymentInfo.ReferenceNumber = paymentToken;

                var customerToken = financialGatewayComponent.CreateCustomerAccount(this.FinancialGateway, referencePaymentInfo, out errorMessage);

                if (errorMessage.IsNotNullOrWhiteSpace() || customerToken.IsNullOrWhiteSpace())
                {
                    nbMessage.NotificationBoxType = NotificationBoxType.Danger;
                    nbMessage.Text    = errorMessage ?? "Unknown Error";
                    nbMessage.Visible = true;
                    return;
                }

                referencePaymentInfo.GatewayPersonIdentifier = customerToken;
            }
            else
            {
                var savedAccountId = ddlPersonSavedAccount.SelectedValue.AsInteger();

                var savedAccount = new FinancialPersonSavedAccountService(rockContext).Get(savedAccountId);
                if (savedAccount != null)
                {
                    referencePaymentInfo = savedAccount.GetReferencePayment();
                }
                else
                {
                    throw new Exception("Unable to determine Saved Account");
                }
            }

            var selectedAccountAmounts = caapPromptForAccountAmounts.AccountAmounts.Where(a => a.Amount.HasValue && a.Amount.Value != 0).Select(a => new { a.AccountId, Amount = a.Amount.Value }).ToArray();

            referencePaymentInfo.Amount = selectedAccountAmounts.Sum(a => a.Amount);

            var successfullyUpdated = financialGatewayComponent.UpdateScheduledPayment(financialScheduledTransaction, referencePaymentInfo, out errorMessage);

            if (!successfullyUpdated)
            {
                nbMessage.NotificationBoxType = NotificationBoxType.Danger;
                nbMessage.Text    = errorMessage ?? "Unknown Error";
                nbMessage.Visible = true;
                return;
            }

            financialScheduledTransaction.FinancialPaymentDetail.SetFromPaymentInfo(referencePaymentInfo, financialGatewayComponent as GatewayComponent, rockContext);

            var selectedAccountIds        = selectedAccountAmounts.Select(a => a.AccountId).ToArray();
            var deletedTransactionDetails = financialScheduledTransaction.ScheduledTransactionDetails.ToList().Where(a => !selectedAccountIds.Contains(a.AccountId)).ToList();

            foreach (var deletedTransactionDetail in deletedTransactionDetails)
            {
                financialScheduledTransaction.ScheduledTransactionDetails.Remove(deletedTransactionDetail);
                financialScheduledTransactionDetailService.Delete(deletedTransactionDetail);
            }

            foreach (var selectedAccountAmount in selectedAccountAmounts)
            {
                var scheduledTransactionDetail = financialScheduledTransaction.ScheduledTransactionDetails.FirstOrDefault(a => a.AccountId == selectedAccountAmount.AccountId);
                if (scheduledTransactionDetail == null)
                {
                    scheduledTransactionDetail           = new FinancialScheduledTransactionDetail();
                    scheduledTransactionDetail.AccountId = selectedAccountAmount.AccountId;
                    financialScheduledTransaction.ScheduledTransactionDetails.Add(scheduledTransactionDetail);
                }

                scheduledTransactionDetail.Amount = selectedAccountAmount.Amount;
            }

            rockContext.SaveChanges();

            var mergeFields = LavaHelper.GetCommonMergeFields(this.RockPage, this.CurrentPerson, new CommonMergeFieldsOptions {
                GetLegacyGlobalMergeFields = false
            });
            var finishLavaTemplate = this.GetAttributeValue(AttributeKey.FinishLavaTemplate);

            mergeFields.Add("Transaction", financialScheduledTransaction);
            mergeFields.Add("Person", financialScheduledTransaction.AuthorizedPersonAlias.Person);
            mergeFields.Add("PaymentDetail", financialScheduledTransaction.FinancialPaymentDetail);
            mergeFields.Add("BillingLocation", financialScheduledTransaction.FinancialPaymentDetail.BillingLocation);

            pnlPromptForChanges.Visible   = false;
            pnlTransactionSummary.Visible = true;

            lTransactionSummaryHTML.Text = finishLavaTemplate.ResolveMergeFields(mergeFields);
        }
        /// <summary>
        /// Shows the details.
        /// </summary>
        private void ShowDetails()
        {
            var rockContext          = new RockContext();
            var scheduledTransaction = this.GetFinancialScheduledTransaction(rockContext);

            if (scheduledTransaction == null)
            {
                // Note: Also verified in OnInit
                ShowConfigurationMessage(NotificationBoxType.Warning, "Warning", "Scheduled Transaction not found.");
                return;
            }

            var    financialScheduledTransactionService = new FinancialScheduledTransactionService(rockContext);
            string errorMessages;

            if (!financialScheduledTransactionService.GetStatus(scheduledTransaction, out errorMessages))
            {
                ShowConfigurationMessage(NotificationBoxType.Danger, "Error", errorMessages);
                return;
            }

            hfScheduledTransactionGuid.Value = scheduledTransaction.Guid.ToString();

            List <int> selectableAccountIds = new FinancialAccountService(rockContext).GetByGuids(this.GetAttributeValues(AttributeKey.AccountsToDisplay).AsGuidList()).Select(a => a.Id).ToList();

            CampusAccountAmountPicker.AccountIdAmount[] accountAmounts = scheduledTransaction.ScheduledTransactionDetails.Select(a => new CampusAccountAmountPicker.AccountIdAmount(a.AccountId, a.Amount)).ToArray();

            // if the scheduledTransaction already has Multiple Account, enabled multi account mode. Otherwise, only enabled multi account based on the block setting.
            var hasMultipleAccounts = accountAmounts.Length > 1;

            bool enableMultiAccount = hasMultipleAccounts || this.GetAttributeValue(AttributeKey.EnableMultiAccount).AsBoolean();

            if (enableMultiAccount)
            {
                caapPromptForAccountAmounts.AmountEntryMode = CampusAccountAmountPicker.AccountAmountEntryMode.MultipleAccounts;
            }
            else
            {
                caapPromptForAccountAmounts.AmountEntryMode = CampusAccountAmountPicker.AccountAmountEntryMode.SingleAccount;
            }

            caapPromptForAccountAmounts.AskForCampusIfKnown = this.GetAttributeValue(AttributeKey.AskForCampusIfKnown).AsBoolean();

            caapPromptForAccountAmounts.SelectableAccountIds = selectableAccountIds.ToArray();

            if (!caapPromptForAccountAmounts.SelectableAccountIds.Any())
            {
                ShowConfigurationMessage(NotificationBoxType.Warning, "Configuration", "At least one Financial Account must be selected in the configuration for this block.");
                pnlPromptForChanges.Visible = false;
                return;
            }

            if (this.FinancialGateway == null)
            {
                ShowConfigurationMessage(NotificationBoxType.Warning, "Configuration", "Unable to determine the financial gateway for this scheduled transaction.");
                pnlPromptForChanges.Visible = false;
                return;
            }

            if (this.FinancialGatewayComponent == null || !(this.FinancialGatewayComponent is IHostedGatewayComponent))
            {
                ShowConfigurationMessage(NotificationBoxType.Danger, "Configuration", "This page is not configured to allow edits for the payment gateway associated with the selected transaction.");
                pnlPromptForChanges.Visible = false;
                return;
            }

            caapPromptForAccountAmounts.AccountAmounts = accountAmounts;

            var targetPerson = scheduledTransaction.AuthorizedPersonAlias.Person;

            SetAccountPickerCampus(targetPerson);

            int oneTimeFrequencyId = DefinedValueCache.GetId(Rock.SystemGuid.DefinedValue.TRANSACTION_FREQUENCY_ONE_TIME.AsGuid()) ?? 0;

            ddlFrequency.Items.Clear();
            var supportedFrequencies = this.FinancialGatewayComponent.SupportedPaymentSchedules;

            foreach (var supportedFrequency in supportedFrequencies)
            {
                // If this isn't a one-time scheduled transaction, don't allow changing scheduled transaction to a one-time,
                if (scheduledTransaction.TransactionFrequencyValueId == oneTimeFrequencyId || supportedFrequency.Id != oneTimeFrequencyId)
                {
                    ddlFrequency.Items.Add(new ListItem(supportedFrequency.Value, supportedFrequency.Id.ToString()));
                }
            }

            ddlFrequency.SetValue(scheduledTransaction.TransactionFrequencyValueId);

            /* 2020-02-26 MDP: Payment prompt behavior..
             *  - No Saved Accounts
             *      - Show text with existing payment method with a 'Change' link.
             *      - If 'Change' is clicked, existing payment info prompt will disappear and hosted payment will be displayed
             *  - Has Saved Accounts
             *      - Show RadioButtons with first item with the existing payment as the option, followed by saved accounts
             *      - Then under the RadioButtons show a 'Add Method'.
             *      - If 'Add Method' is clicked, RadioButtons will disappear and hosted payment will be displayed
             */

            string paymentName;

            if (scheduledTransaction.FinancialPaymentDetail.FinancialPersonSavedAccountId.HasValue)
            {
                paymentName = scheduledTransaction.FinancialPaymentDetail.FinancialPersonSavedAccount.Name;
            }
            else
            {
                paymentName = scheduledTransaction.FinancialPaymentDetail.CurrencyTypeValue?.Value;
            }

            string existingPaymentInfoDisplayText;

            if (scheduledTransaction.FinancialPaymentDetail.ExpirationDate.IsNotNullOrWhiteSpace())
            {
                existingPaymentInfoDisplayText = $"Existing Payment Method - {paymentName} ({scheduledTransaction.FinancialPaymentDetail.AccountNumberMasked} Expires: {scheduledTransaction.FinancialPaymentDetail.ExpirationDate})";
            }
            else
            {
                existingPaymentInfoDisplayText = $"Existing Payment Method - {paymentName} ({scheduledTransaction.FinancialPaymentDetail.AccountNumberMasked})";
            }

            lUseExistingPaymentMethodNoSavedAccounts.Text = existingPaymentInfoDisplayText;

            var personSavedAccountList = GetSavedAccounts();

            pnlHostedPaymentControl.Visible = false;

            if (personSavedAccountList.Any())
            {
                pnlUseExistingPaymentWithSavedAccounts.Visible = true;
                pnlUseExistingPaymentNoSavedAccounts.Visible   = false;
                BindPersonSavedAccounts(personSavedAccountList);
                rblExistingPaymentOrPersonSavedAccount.Items.Insert(0, new ListItem(existingPaymentInfoDisplayText, "0"));

                // default to using existing payment method
                rblExistingPaymentOrPersonSavedAccount.SetValue(0);
            }
            else
            {
                // no saved account, so just prompt for payment info (or using existing payment info)
                pnlUseExistingPaymentNoSavedAccounts.Visible   = true;
                pnlUseExistingPaymentWithSavedAccounts.Visible = false;
            }

            dtpStartDate.SelectedDate = scheduledTransaction.NextPaymentDate;

            // NOTE: Depending on the Gateway, the earliest date could be more than 1-2+ days in the future
            var earliestScheduledStartDate = FinancialGatewayComponent.GetEarliestScheduledStartDate(FinancialGateway);

            if (dtpStartDate.SelectedDate.HasValue && dtpStartDate.SelectedDate.Value < earliestScheduledStartDate)
            {
                dtpStartDate.SelectedDate = earliestScheduledStartDate;
            }

            var person = scheduledTransaction.AuthorizedPersonAlias.Person;

            Location billingLocation = null;

            // default to the billing location of the scheduled transaction, or the mailing location if unable to get a billing location from the scheduled transaction.
            if (scheduledTransaction.FinancialPaymentDetail != null)
            {
                billingLocation = scheduledTransaction.FinancialPaymentDetail.BillingLocation;
            }

            if (billingLocation == null)
            {
                billingLocation = person.GetMailingLocation();
            }

            acBillingAddress.SetValues(billingLocation);
        }
Пример #10
0
        /// <summary>
        /// Gets the message data for a <see cref="ScheduledGiftWasModifiedMessage"/>.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="scheduledTransactionId">The scheduled transaction identifier.</param>
        /// <param name="personSearchKeyTypeGuid">The person search key type unique identifier.</param>
        /// <param name="gatewaySupportedCardTypesDefinedValueGuid">[Optional] The <see cref="Guid"/> of the <see cref="DefinedValue"/> that indicates the credit card types supported by the <see cref="FinancialGateway"/> for a specified currency.</param>
        /// <param name="gatewayCurrencyUnitMultiple">[Optional] The <see cref="Guid"/> of the <see cref="DefinedValue"/> that indicates the "unit multiple" (e.g., 100 for dollars) of the currency specified by the gatway.</param>
        /// <returns></returns>
        private static ScheduledGiftWasModifiedMessageData GetScheduledGiftWasModifiedMessageData(RockContext rockContext, int scheduledTransactionId, Guid?personSearchKeyTypeGuid, Guid?gatewaySupportedCardTypesDefinedValueGuid, Guid?gatewayCurrencyUnitMultiple)
        {
            var status        = "success";
            var statusMessage = string.Empty;

            var scheduledTransactionService = new FinancialScheduledTransactionService(rockContext);
            var scheduledTransaction        = scheduledTransactionService.Queryable()
                                              .AsNoTracking()
                                              .Where(s => s.Id == scheduledTransactionId)
                                              .FirstOrDefault();

            var data = new ScheduledGiftWasModifiedMessageData
            {
                Person = new TransactionPersonView
                {
                    PrimaryAliasId = scheduledTransaction.AuthorizedPersonAliasId,
                    Id             = scheduledTransaction.AuthorizedPersonAlias.Person.Id,
                    Guid           = scheduledTransaction.Guid,
                    FirstName      = scheduledTransaction.AuthorizedPersonAlias.Person.FirstName,
                    NickName       = scheduledTransaction.AuthorizedPersonAlias.Person.NickName,
                    LastName       = scheduledTransaction.AuthorizedPersonAlias.Person.LastName,
                    Email          = scheduledTransaction.AuthorizedPersonAlias.Person.Email,
                    ForeignId      = scheduledTransaction.AuthorizedPersonAlias.Person.ForeignId,
                },
                FinancialScheduledTransaction = new ScheduledTransactionView
                {
                    Id   = scheduledTransaction.Id,
                    Guid = scheduledTransaction.Guid,
                    CreditCardTypeValueId = scheduledTransaction.FinancialPaymentDetail.CreditCardTypeValueId,
                    CurrencyTypeValueId   = scheduledTransaction.FinancialPaymentDetail.CurrencyTypeValueId,
                    ForeignCurrencyCode   = new TransactionCurrencyCodeView
                    {
                        ValueId = scheduledTransaction.ForeignCurrencyCodeValueId,
                    },
                    ScheduledTransactionId    = scheduledTransaction.Id,
                    TransactionFrequencyValue = new TransactionFrequencyView {
                        ValueId = scheduledTransaction.TransactionFrequencyValueId,
                    },
                    SourceTypeValueId      = scheduledTransaction.SourceTypeValueId,
                    Status                 = status,
                    StatusMessage          = statusMessage,
                    TransactionCode        = scheduledTransaction.TransactionCode,
                    TransactionTypeValueId = scheduledTransaction.TransactionTypeValueId,
                    ForeignKey             = scheduledTransaction.ForeignKey,
                    Details                = scheduledTransaction.ScheduledTransactionDetails.Select(d => new ScheduledTransactionDetailView
                    {
                        Id                = d.Id,
                        Guid              = d.Guid,
                        AccountId         = d.AccountId,
                        AccountName       = d.Account.Name,
                        PublicAccountName = d.Account.PublicName,

                        /* Shaun Cummings - September 10, 2021
                         *
                         * For scheduled transactions, if the transaction has a ForeignCurrencyCode, the Amount property
                         * reflects the amount in that foreign currency.
                         * */
                        Amount = d.Amount
                    }).ToList()
                }
            };

            if (data != null)
            {
                data.Person.HydratePersonData(rockContext, data.Address, personSearchKeyTypeGuid);
                data.FinancialScheduledTransaction.HydrateDefinedValues(gatewaySupportedCardTypesDefinedValueGuid, gatewayCurrencyUnitMultiple);
            }

            return(data);
        }
Пример #11
0
        /// <summary>
        /// Handles the Click event of the btnMigrateScheduledTransactions 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 btnMigrateScheduledTransactions_Click(object sender, EventArgs e)
        {
            var rockContext = new RockContext();

            var binaryFileService = new BinaryFileService(rockContext);
            var binaryFileId      = fuScheduleImportFile.BinaryFileId;

            BinaryFile binaryFile = null;

            if (binaryFileId.HasValue)
            {
                binaryFile = binaryFileService.Get(binaryFileId.Value);
            }

            Dictionary <string, string> subscriptionImportRecordLookup = null;

            var importData = binaryFile.ContentsToString();

            StringReader stringReader = new StringReader(importData);
            CsvReader    csvReader    = new CsvReader(stringReader);

            csvReader.Configuration.HasHeaderRecord = false;

            subscriptionImportRecordLookup = csvReader.GetRecords <SubscriptionCustomerImportRecord>().ToDictionary(k => k.NMISubscriptionId, v => v.PiCustomerId);

            var financialGatewayService = new FinancialGatewayService(rockContext);
            var nmiFinancialGatewayId   = ddlNMIGateway.SelectedValue.AsInteger();
            var nmiFinancialGateway     = financialGatewayService.Get(nmiFinancialGatewayId);
            var nmiGatewayComponent     = nmiFinancialGateway.GetGatewayComponent();
            var piFinancialGatewayId    = ddlPiGateway.SelectedValue.AsInteger();
            var piFinancialGateway      = financialGatewayService.Get(piFinancialGatewayId);
            var piGatewayComponent      = piFinancialGateway.GetGatewayComponent() as IHostedGatewayComponent;

            var financialScheduledTransactionService = new FinancialScheduledTransactionService(rockContext);

            // Get the ScheduledTransaction with NoTracking. If we need to update it, we'll track it with a different rockContext then save it.
            // Limit to active subscriptions that have a NextPaymentDate (onetime or canceled schedules might not have a NextPaymentDate)
            var scheduledTransactions = financialScheduledTransactionService.Queryable().Where(a => a.FinancialGatewayId == nmiFinancialGatewayId & a.IsActive && a.NextPaymentDate.HasValue).AsNoTracking().ToList();

            var earliestPiStartDate = piGatewayComponent.GetEarliestScheduledStartDate(piFinancialGateway);
            var oneTimeFrequencyId  = DefinedValueCache.GetId(Rock.SystemGuid.DefinedValue.TRANSACTION_FREQUENCY_ONE_TIME.AsGuid());

            string errorMessage;

            var scheduledTransactionResultsBuilder = new StringBuilder();

            var scheduledTransactionCount    = scheduledTransactions.Count();
            var scheduledTransactionProgress = 0;

            // Migrating Scheduled Transactions might take a while. Each migrated Scheduled Payment may take a half second or so to create on the Pi Gateway.
            var importTask = new Task(() =>
            {
                // wait a little so the browser can render and start listening to events
                Task.Delay(1000).Wait();
                _hubContext.Clients.All.setButtonVisibilty(this.SignalRNotificationKey, false);

                foreach (var scheduledTransaction in scheduledTransactions)
                {
                    System.Threading.Thread.Sleep(1000);

                    UpdateProgressMessage(string.Format("Migrating Scheduled Transactions: {0} of {1}", scheduledTransactionProgress, scheduledTransactionCount), " ");

                    scheduledTransactionProgress++;
                    var nmiSubscriptionId = scheduledTransaction.GatewayScheduleId;
                    var nmiCustomerId     = scheduledTransaction.ForeignKey;
                    var piCustomerId      = subscriptionImportRecordLookup.GetValueOrNull(nmiSubscriptionId);
                    if (piCustomerId == null)
                    {
                        scheduledTransactionResultsBuilder.AppendFormat(
                            "WARNING: No Pi CustomerId found for Financial Scheduled Transaction with Id: {0} which is associated NMI SubscriptionId: '{1}'" + Environment.NewLine,
                            scheduledTransaction.Id,
                            nmiSubscriptionId
                            );
                        continue;
                    }

                    // Pi requires that NextPaymentDate is in the Future (using UTC). That math is done in the gateway implementation...
                    // if the NextPayment null or earlier than whatever Pi considers the earliest start date, see if we can fix that up by calling GetStatus
                    if (scheduledTransaction.NextPaymentDate == null || scheduledTransaction.NextPaymentDate < earliestPiStartDate)
                    {
                        financialScheduledTransactionService.GetStatus(scheduledTransaction, out errorMessage);
                    }

                    if (scheduledTransaction.NextPaymentDate == null)
                    {
                        // Shouldn't happen, but just in case
                        scheduledTransactionResultsBuilder.AppendFormat(
                            "WARNING: Unknown NextPaymentDate for FinancialScheduledTransaction.Id: {0} NMI SubscriptionId: '{1}'" + Environment.NewLine,
                            scheduledTransaction.Id,
                            nmiSubscriptionId
                            );
                        continue;
                    }


                    if (scheduledTransaction.NextPaymentDate < earliestPiStartDate)
                    {
                        if ((scheduledTransaction.NextPaymentDate > RockDateTime.Today) && earliestPiStartDate.Subtract(scheduledTransaction.NextPaymentDate.Value).TotalDays <= 2)
                        {
                            // if the NextPaymentDate is after Today but before the Earliest Pi Start Date, it'll be off by less than 24 hrs, so just reschedule it for the Earliest Pi Start Date
                            scheduledTransaction.NextPaymentDate = earliestPiStartDate;
                        }
                        else
                        {
                            // if the NextPaymentDate is still too early AFTER getting the most recent status, then we can't safely figure it out, so report it
                            scheduledTransactionResultsBuilder.AppendFormat(
                                "WARNING: NextPaymentDate of {0} for FinancialScheduledTransaction.Id: {1} and NMI SubscriptionId: '{2}' must have a NextPaymentDate of at least {3}." + Environment.NewLine,
                                scheduledTransaction.NextPaymentDate,
                                scheduledTransaction.Id,
                                nmiSubscriptionId,
                                earliestPiStartDate
                                );
                        }
                    }

                    // create a subscription in the Pi System, then cancel the one on the NMI system
                    PaymentSchedule paymentSchedule = new PaymentSchedule
                    {
                        TransactionFrequencyValue = DefinedValueCache.Get(scheduledTransaction.TransactionFrequencyValueId),
                        StartDate = scheduledTransaction.NextPaymentDate.Value,
                        PersonId  = scheduledTransaction.AuthorizedPersonAlias.PersonId
                    };

                    ReferencePaymentInfo referencePaymentInfo = new ReferencePaymentInfo
                    {
                        GatewayPersonIdentifier = piCustomerId,
                        Description             = string.Format("Migrated from NMI SubscriptionID:{0}", nmiSubscriptionId)
                    };

                    var piGateway = (piGatewayComponent as PiGateway);
                    string alreadyMigratedPiSubscriptionId = null;

                    if (piGateway != null)
                    {
                        var customerPiSubscriptions     = piGateway.SearchCustomerSubscriptions(piFinancialGateway, piCustomerId);
                        alreadyMigratedPiSubscriptionId = customerPiSubscriptions.Data.Where(a => a.Description.Contains(referencePaymentInfo.Description)).Select(a => a.Customer.Id).FirstOrDefault();
                    }

                    if (string.IsNullOrEmpty(alreadyMigratedPiSubscriptionId))
                    {
                        // hasn't already been migrated, so go ahead and migrate it
                        var tempFinancialScheduledTransaction = piGatewayComponent.AddScheduledPayment(piFinancialGateway, paymentSchedule, referencePaymentInfo, out errorMessage);
                        if (tempFinancialScheduledTransaction != null)
                        {
                            ////////////#### DISABLE this when debugger #####
                            nmiGatewayComponent.CancelScheduledPayment(scheduledTransaction, out errorMessage);

                            // update the scheduled transaction to point to the Pi scheduled transaction
                            using (var updateRockContext = new RockContext())
                            {
                                // Attach the person to the updateRockContext so that it'll be tracked/saved using updateRockContext
                                updateRockContext.FinancialScheduledTransactions.Attach(scheduledTransaction);
                                scheduledTransaction.TransactionCode    = tempFinancialScheduledTransaction.TransactionCode;
                                scheduledTransaction.GatewayScheduleId  = tempFinancialScheduledTransaction.GatewayScheduleId;
                                scheduledTransaction.FinancialGatewayId = tempFinancialScheduledTransaction.FinancialGatewayId;
                                updateRockContext.SaveChanges();
                            }

                            scheduledTransactionResultsBuilder.AppendFormat(
                                "SUCCESS: Scheduled Transaction migration succeeded. (FinancialScheduledTransaction.Id: {0}, NMI SubscriptionId: '{1}', Pi CustomerId: {2}, Pi SubscriptionId: {3})" + Environment.NewLine,
                                scheduledTransaction.Id,
                                nmiSubscriptionId,
                                piCustomerId,
                                scheduledTransaction.GatewayScheduleId
                                );
                        }
                        else
                        {
                            scheduledTransactionResultsBuilder.AppendFormat(
                                "ERROR: Scheduled Transaction migration failed. ErrorMessage: {0}, FinancialScheduledTransaction.Id: {1}, NMI SubscriptionId: '{2}', Pi CustomerId: {3}" + Environment.NewLine,
                                errorMessage,
                                scheduledTransaction.Id,
                                nmiSubscriptionId,
                                piCustomerId
                                );
                        }
                    }
                    else
                    {
                        scheduledTransactionResultsBuilder.AppendFormat(
                            "INFO: Scheduled Transaction already migrated to PI. FinancialScheduledTransaction.Id: {0}, NMI SubscriptionId: '{1}', Pi SubscriptionId: '{2}', Pi CustomerId: {3}" + Environment.NewLine,
                            scheduledTransaction.Id,
                            nmiSubscriptionId,
                            alreadyMigratedPiSubscriptionId,
                            piCustomerId
                            );
                    }
                }
            });

            string importResult = string.Empty;

            importTask.ContinueWith((c) =>
            {
                if (c.Exception != null)
                {
                    ExceptionLogService.LogException(c.Exception);
                    scheduledTransactionResultsBuilder.AppendLine(string.Format("EXCEPTION: {0}", c.Exception.Flatten().Message));
                    importResult = "EXCEPTION";
                    UpdateProgressMessage(importResult, scheduledTransactionResultsBuilder.ToString());
                }
                else
                {
                    importResult = "Migrate Scheduled Transactions Completed Successfully";
                    UpdateProgressMessage(importResult, scheduledTransactionResultsBuilder.ToString());
                }

                this.SetBlockUserPreference("MigrateScheduledTransactionsResultSummary", importResult);
                this.SetBlockUserPreference("MigrateScheduledTransactionsResultDetails", scheduledTransactionResultsBuilder.ToString());
            });

            importTask.Start();

            nbMigrateScheduledTransactions.Visible = false;

            // wait for 5 seconds to see if this happens fast enough to do without Signal R. Otherwise, let the importTask continue and send progress to Signal R.
            var waitResult = importTask.Wait(5000);

            if (waitResult)
            {
                // wait just a little bit to make sure the importResult gets set
                System.Threading.Thread.Sleep(1000);

                nbMigrateScheduledTransactions.Visible             = true;
                nbMigrateScheduledTransactions.Title               = "Success";
                nbMigrateScheduledTransactions.NotificationBoxType = Rock.Web.UI.Controls.NotificationBoxType.Success;

                var resultDetails = scheduledTransactionResultsBuilder.ToString();
                if (resultDetails.Contains("ERROR") || resultDetails.Contains("WARNING"))
                {
                    nbMigrateScheduledTransactions.Title = "Completed with Warnings";
                    nbMigrateScheduledTransactions.NotificationBoxType = Rock.Web.UI.Controls.NotificationBoxType.Info;
                }

                nbMigrateScheduledTransactions.Text    = importResult;
                nbMigrateScheduledTransactions.Details = resultDetails.ConvertCrLfToHtmlBr();
            }
        }
        /// <summary>
        /// Handles the ItemDataBound event of the rptSavedAccounts control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="RepeaterItemEventArgs"/> instance containing the event data.</param>
        protected void rptSavedAccounts_ItemDataBound(object sender, RepeaterItemEventArgs e)
        {
            var financialPersonSavedAccount = e.Item.DataItem as FinancialPersonSavedAccount;

            if (financialPersonSavedAccount == null)
            {
                return;
            }

            var lSavedAccountName = e.Item.FindControl("lSavedAccountName") as Literal;

            var pnlCreditCardInfo      = e.Item.FindControl("pnlSavedAccountCreditCardInfo") as Panel;
            var lOtherCurrencyTypeInfo = e.Item.FindControl("lSavedAccountOtherCurrencyTypeInfo") as Literal;

            var lSavedAccountCardTypeLast4   = e.Item.FindControl("lSavedAccountCardTypeLast4") as Literal;
            var lSavedAccountExpiration      = e.Item.FindControl("lSavedAccountExpiration") as Literal;
            var lSavedAccountInUseStatusHtml = e.Item.FindControl("lSavedAccountInUseStatusHtml") as Literal;
            var btnSavedAccountDelete        = e.Item.FindControl("btnSavedAccountDelete") as LinkButton;

            lSavedAccountName.Text = financialPersonSavedAccount.Name;
            var financialPaymentDetail = financialPersonSavedAccount.FinancialPaymentDetail;

            string creditCardType      = null;
            string accountNumberMasked = financialPaymentDetail?.AccountNumberMasked;

            if (financialPaymentDetail?.CreditCardTypeValueId != null)
            {
                creditCardType = DefinedValueCache.GetValue(financialPaymentDetail.CreditCardTypeValueId.Value);
            }

            var currencyTypeIdCreditCard = DefinedValueCache.GetId(Rock.SystemGuid.DefinedValue.CURRENCY_TYPE_CREDIT_CARD.AsGuid());

            if (financialPaymentDetail?.CurrencyTypeValueId == currencyTypeIdCreditCard)
            {
                pnlCreditCardInfo.Visible      = true;
                lOtherCurrencyTypeInfo.Visible = false;

                if (accountNumberMasked.IsNotNullOrWhiteSpace() && accountNumberMasked.Length >= 4)
                {
                    var last4 = accountNumberMasked.Substring(accountNumberMasked.Length - 4);
                    lSavedAccountCardTypeLast4.Text = $"{creditCardType} - {last4}";
                }
                else
                {
                    lSavedAccountCardTypeLast4.Text = creditCardType;
                }

                lSavedAccountExpiration.Text = $"Exp: {financialPaymentDetail.ExpirationDate}";
            }
            else
            {
                pnlCreditCardInfo.Visible      = false;
                lOtherCurrencyTypeInfo.Visible = true;
                lOtherCurrencyTypeInfo.Text    = financialPaymentDetail?.CurrencyTypeValue?.Value;
            }

            var cardIsExpired = financialPaymentDetail.CardExpirationDate.HasValue && financialPaymentDetail.CardExpirationDate.Value < RockDateTime.Now;

            var cardInUse = new FinancialScheduledTransactionService(new RockContext()).Queryable().Where(a => a.FinancialPaymentDetailId.HasValue &&
                                                                                                          a.IsActive &&
                                                                                                          a.FinancialPaymentDetail.FinancialPersonSavedAccountId.HasValue &&
                                                                                                          a.FinancialPaymentDetail.FinancialPersonSavedAccountId.Value == financialPersonSavedAccount.Id).Any();

            btnSavedAccountDelete.Visible         = !cardInUse;
            btnSavedAccountDelete.CommandArgument = financialPersonSavedAccount.Guid.ToString();

            if (cardIsExpired)
            {
                lSavedAccountInUseStatusHtml.Text = "<span class='text-xs text-danger text-nowrap'>Expired</span>";
            }
            else
            {
                if (cardInUse)
                {
                    lSavedAccountInUseStatusHtml.Text = "<span class='text-xs text-success text-nowrap'>In Use</span>";
                }
                else
                {
                    lSavedAccountInUseStatusHtml.Text = "<span class='text-xs text-muted text-nowrap'>Not In Use</span>";
                }
            }
        }
Пример #13
0
        /// <summary>
        /// Sends the expired credit card notices.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <returns></returns>
        /// <exception cref="Exception">Expiring credit card email is missing.</exception>
        private SendExpiredCreditCardNoticesResult SendExpiredCreditCardNotices(IJobExecutionContext context)
        {
            var dataMap     = context.JobDetail.JobDataMap;
            var rockContext = new RockContext();

            // Get the details for the email that we'll be sending out.
            Guid?systemEmailGuid = dataMap.GetString(AttributeKey.ExpiringCreditCardEmail).AsGuidOrNull();
            SystemCommunication systemCommunication = null;

            if (systemEmailGuid.HasValue)
            {
                var systemCommunicationService = new SystemCommunicationService(rockContext);
                systemCommunication = systemCommunicationService.Get(systemEmailGuid.Value);
            }

            if (systemCommunication == null)
            {
                throw new Exception("Expiring credit card email is missing.");
            }

            // Fetch the configured Workflow once if one was set, we'll use it later.
            Guid?workflowGuid = dataMap.GetString(AttributeKey.Workflow).AsGuidOrNull();
            WorkflowTypeCache workflowType    = null;
            WorkflowService   workflowService = new WorkflowService(rockContext);

            if (workflowGuid != null)
            {
                workflowType = WorkflowTypeCache.Get(workflowGuid.Value);
            }

            var financialScheduledTransactionQuery = new FinancialScheduledTransactionService(rockContext).Queryable()
                                                     .Where(t => t.IsActive && t.FinancialPaymentDetail.ExpirationMonthEncrypted != null && (t.EndDate == null || t.EndDate > DateTime.Now))
                                                     .AsNoTracking();

            List <ScheduledTransactionInfo> scheduledTransactionInfoList = financialScheduledTransactionQuery.Select(a => new ScheduledTransactionInfo
            {
                Id = a.Id,
                FinancialPaymentDetail    = a.FinancialPaymentDetail,
                AuthorizedPersonAliasGuid = a.AuthorizedPersonAlias.Guid,
                Person = a.AuthorizedPersonAlias.Person
            }).ToList();

            // Get the current month and year
            DateTime now          = DateTime.Now;
            int      currentMonth = now.Month;
            int      currentYYYY  = now.Year;

            // get the common merge fields once, so we don't have to keep calling it for every person, then create a new mergeFields for each person, starting with a copy of the common merge fields
            var commonMergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null);

            var result = new SendExpiredCreditCardNoticesResult
            {
                ExaminedCount = scheduledTransactionInfoList.Count()
            };

            foreach (ScheduledTransactionInfo scheduledTransactionInfo in scheduledTransactionInfoList.OrderByDescending(a => a.Id))
            {
                int?expirationMonth = scheduledTransactionInfo.FinancialPaymentDetail.ExpirationMonth;
                int?expirationYYYY  = scheduledTransactionInfo.FinancialPaymentDetail.ExpirationYear;
                if (!expirationMonth.HasValue || !expirationMonth.HasValue)
                {
                    continue;
                }

                int warningYear  = expirationYYYY.Value;
                int warningMonth = expirationMonth.Value - 1;
                if (warningMonth == 0)
                {
                    warningYear -= 1;
                    warningMonth = 12;
                }

                if ((warningYear == currentYYYY) && (warningMonth == currentMonth))
                {
                    string maskedCardNumber = string.Empty;

                    if (!string.IsNullOrEmpty(scheduledTransactionInfo.FinancialPaymentDetail.AccountNumberMasked) && scheduledTransactionInfo.FinancialPaymentDetail.AccountNumberMasked.Length >= 4)
                    {
                        maskedCardNumber = scheduledTransactionInfo.FinancialPaymentDetail.AccountNumberMasked.Substring(scheduledTransactionInfo.FinancialPaymentDetail.AccountNumberMasked.Length - 4);
                    }

                    string expirationDateMMYYFormatted = scheduledTransactionInfo.FinancialPaymentDetail?.ExpirationDate;

                    var recipients = new List <RockEmailMessageRecipient>();

                    var person = scheduledTransactionInfo.Person;

                    if (!person.IsEmailActive || person.Email.IsNullOrWhiteSpace() || person.EmailPreference == EmailPreference.DoNotEmail)
                    {
                        continue;
                    }

                    // make a mergeFields for this person, starting with copy of the commonFieldFields
                    var mergeFields = new Dictionary <string, object>(commonMergeFields);
                    mergeFields.Add("Person", person);
                    mergeFields.Add("Card", maskedCardNumber);
                    mergeFields.Add("Expiring", expirationDateMMYYFormatted);

                    recipients.Add(new RockEmailMessageRecipient(person, mergeFields));

                    var emailMessage = new RockEmailMessage(systemCommunication);
                    emailMessage.SetRecipients(recipients);
                    emailMessage.Send(out List <string> emailErrors);

                    if (emailErrors.Any())
                    {
                        var errorLines = new StringBuilder();
                        errorLines.AppendLine(string.Empty);
                        foreach (string error in emailErrors)
                        {
                            errorLines.AppendLine(error);
                        }

                        // Provide better identifying context in case the errors are too vague.
                        var exception = new Exception($"Unable to send email (Person ID = {person.Id}).{errorLines}");

                        result.EmailSendExceptions.Add(exception);
                    }
                    else
                    {
                        result.NoticesSentCount++;
                    }

                    // Start workflow for this person
                    if (workflowType != null)
                    {
                        Dictionary <string, string> attributes = new Dictionary <string, string>();
                        attributes.Add("Person", scheduledTransactionInfo.AuthorizedPersonAliasGuid.ToString());
                        attributes.Add("Card", maskedCardNumber);
                        attributes.Add("Expiring", expirationDateMMYYFormatted);
                        attributes.Add("FinancialScheduledTransactionId", scheduledTransactionInfo.Id.ToString());

                        StartWorkflow(workflowService, workflowType, attributes, $"{person.FullName} (scheduled transaction Id: {scheduledTransactionInfo.Id})");
                    }
                }
            }

            return(result);
        }
        /// <summary>
        /// Binds the scheduled transactions.
        /// </summary>
        private void BindScheduledTransactions()
        {
            var rockContext = new RockContext();
            var financialScheduledTransactionService = new FinancialScheduledTransactionService(rockContext);
            var qry = financialScheduledTransactionService
                      .Queryable("ScheduledTransactionDetails,FinancialPaymentDetail.CurrencyTypeValue,FinancialPaymentDetail.CreditCardTypeValue")
                      .AsNoTracking();

            // Valid Accounts
            var accountGuids = GetAttributeValue(AttributeKey.Accounts).SplitDelimitedValues().AsGuidList();

            if (accountGuids.Any())
            {
                qry = qry.Where(t => t.ScheduledTransactionDetails.Any(d => accountGuids.Contains(d.Account.Guid)));
            }



            if (Person.GivingGroupId.HasValue)
            {
                // Person contributes with family
                qry = qry.Where(t => t.AuthorizedPersonAlias.Person.GivingGroupId == Person.GivingGroupId);
            }
            else
            {
                // Person contributes individually
                qry = qry.Where(t => t.AuthorizedPersonAlias.PersonId == Person.Id);
            }

            // only show the button if there some in active scheduled transactions
            btnShowInactiveScheduledTransactions.Visible = qry.Any(a => !a.IsActive);

            var includeInactive = hfShowInactiveScheduledTransactions.Value.AsBoolean();

            if (!includeInactive)
            {
                btnShowInactiveScheduledTransactions.Text = "Show Inactive";
                qry = qry.Where(t => t.IsActive);
            }
            else
            {
                // if including Inactive, show both Active and Inactive
                btnShowInactiveScheduledTransactions.Text = "Hide Inactive";
            }

            qry = qry
                  .OrderBy(t => t.AuthorizedPersonAlias.Person.LastName)
                  .ThenBy(t => t.AuthorizedPersonAlias.Person.NickName)
                  .ThenByDescending(t => t.IsActive)
                  .ThenByDescending(t => t.StartDate);

            var scheduledTransactionList = qry.ToList();

            foreach (var schedule in scheduledTransactionList)
            {
                try
                {
                    // This will ensure we have the most recent status, even if the schedule hasn't been making payments.
                    string errorMessage;
                    financialScheduledTransactionService.GetStatus(schedule, out errorMessage);
                }
                catch (Exception ex)
                {
                    // log and ignore
                    LogException(ex);
                }
            }

            rptScheduledTransaction.DataSource = scheduledTransactionList;
            rptScheduledTransaction.DataBind();
        }
Пример #15
0
        /// <summary>
        /// Binds the profile.
        /// </summary>
        /// <param name="profileId">The profile id.</param>
        protected void BindGivingProfile(int profileId)
        {
            DateTime currentDate    = DateTimeOffset.Now.DateTime;
            var      accountService = new FinancialAccountService();
            var      activeAccounts = accountService.Queryable().Where(f => f.IsActive &&
                                                                       (f.StartDate == null || f.StartDate <= currentDate) &&
                                                                       (f.EndDate == null || f.EndDate <= currentDate) &&
                                                                       f.PublicName != null && f.PublicName != "");
            var accountGuids = GetAttributeValues("DefaultAccounts").Select(Guid.Parse).ToList();
            var scheduledTransactionService = new FinancialScheduledTransactionService();
            var transactionList             = new Dictionary <FinancialAccount, decimal>();
            FinancialScheduledTransaction scheduledTransaction;

            if (profileId != 0 && scheduledTransactionService.TryGet(profileId, out scheduledTransaction))
            {   // Retrieve Transaction
                btnFrequency.SelectedValue = scheduledTransaction.TransactionFrequencyValue.Id.ToString();
                divFrequency.Visible       = true;
                dtpStartDate.SelectedDate  = scheduledTransaction.StartDate;
                divRecurrence.Visible      = true;
                divLimitGifts.Visible      = true;

                if (scheduledTransaction.NumberOfPayments != null)
                {
                    chkLimitGifts.Checked  = true;
                    txtLimitNumber.Text    = scheduledTransaction.NumberOfPayments.ToString();
                    divLimitNumber.Visible = true;
                }

                foreach (var details in scheduledTransaction.ScheduledTransactionDetails)
                {
                    transactionList.Add(details.Account, details.Amount);
                }
            }
            else
            {   // New Transaction
                IQueryable <FinancialAccount> selectedAccounts = activeAccounts;

                if (accountGuids.Any())
                {
                    selectedAccounts = selectedAccounts.Where(a => accountGuids.Contains(a.Guid));
                }

                var campusId = btnCampusList.SelectedValueAsInt();
                selectedAccounts = selectedAccounts.Where(f => f.CampusId == campusId ||
                                                          (f.CampusId == null && f.ChildAccounts.Count() == 0));

                foreach (var account in selectedAccounts)
                {
                    transactionList.Add(account, 0M);
                }
            }

            if (activeAccounts.Count() > transactionList.Count() && Convert.ToBoolean(GetAttributeValue("AdditionalAccounts")))
            {
                var unselectedAccounts = activeAccounts.Where(a => !accountGuids.Contains(a.Guid)).ToList();

                if (unselectedAccounts.Any())
                {
                    btnAddAccount.DataTextField  = "PublicName";
                    btnAddAccount.DataValueField = "Id";
                    btnAddAccount.DataSource     = unselectedAccounts.ToList();
                    btnAddAccount.DataBind();
                }
            }
            else
            {
                divAddAccount.Visible = false;
            }

            Session["CachedAmounts"]   = transactionList;
            Session["CachedProfileId"] = profileId;
            rptAccountList.DataSource  = transactionList;
            rptAccountList.DataBind();
            spnTotal.InnerText = transactionList.Sum(d => d.Value).ToString("f2");
        }
Пример #16
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);

            // #TODO test card through gateway

            if (btnFrequency.SelectedIndex > -1 && btnFrequency.SelectedValueAsInt() > 0)
            {
                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();
        }