/// <summary> /// Method that will be called on an entity immediately before the item is saved by context /// </summary> /// <param name="dbContext"></param> /// <param name="entry"></param> public override void PreSaveChanges(Rock.Data.DbContext dbContext, DbEntityEntry entry) { var rockContext = ( RockContext )dbContext; HistoryChangeList = new History.HistoryChangeList(); var scheduledTransaction = this.ScheduledTransaction ?? new FinancialScheduledTransactionService(dbContext as RockContext).Get(this.ScheduledTransactionId); switch (entry.State) { case EntityState.Added: { string acct = History.GetValue <FinancialAccount>(this.Account, this.AccountId, rockContext); HistoryChangeList.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, acct).SetNewValue(Amount.FormatAsCurrency(scheduledTransaction?.ForeignCurrencyCodeValueId)); break; } case EntityState.Modified: { string acct = History.GetValue <FinancialAccount>(this.Account, this.AccountId, rockContext); int?accountId = this.Account != null ? this.Account.Id : this.AccountId; int?origAccountId = entry.OriginalValues["AccountId"].ToStringSafe().AsIntegerOrNull(); if (!accountId.Equals(origAccountId)) { History.EvaluateChange(HistoryChangeList, "Account", History.GetValue <FinancialAccount>(null, origAccountId, rockContext), acct); } var originalCurrencyCodeValueId = scheduledTransaction?.ForeignCurrencyCodeValueId; if (scheduledTransaction != null) { var originalScheduledTransactionEntry = rockContext.ChangeTracker .Entries <FinancialScheduledTransaction>() .Where(s => ( int )s.OriginalValues["Id"] == scheduledTransaction.Id) .FirstOrDefault(); if (originalScheduledTransactionEntry != null) { originalCurrencyCodeValueId = ( int? )originalScheduledTransactionEntry.OriginalValues["ForeignCurrencyCodeValueId"]; } } History.EvaluateChange(HistoryChangeList, acct + " Amount", entry.OriginalValues["Amount"].ToStringSafe().AsDecimal().FormatAsCurrency(originalCurrencyCodeValueId), Amount.FormatAsCurrency(scheduledTransaction?.ForeignCurrencyCodeValueId)); History.EvaluateChange(HistoryChangeList, acct + " Fee Coverage Amount", (entry.OriginalValues["FeeCoverageAmount"] as int?).FormatAsCurrency(), FeeCoverageAmount.FormatAsCurrency()); break; } case EntityState.Deleted: { string acct = History.GetValue <FinancialAccount>(this.Account, this.AccountId, rockContext); HistoryChangeList.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, acct).SetOldValue(Amount.FormatAsCurrency(scheduledTransaction?.ForeignCurrencyCodeValueId)); break; } } base.PreSaveChanges(dbContext, entry); }
/// <summary> /// Pres the save. /// </summary> /// <param name="dbContext">The database context.</param> /// <param name="entry"></param> public override void PreSaveChanges(Rock.Data.DbContext dbContext, DbEntityEntry entry) { var rockContext = (RockContext)dbContext; BinaryFileService binaryFileService = new BinaryFileService(rockContext); var binaryFile = binaryFileService.Get(BinaryFileId); HistoryChangeList = new History.HistoryChangeList(); switch (entry.State) { case EntityState.Added: { // if there is an binaryfile (image) associated with this, make sure that it is flagged as IsTemporary=False if (binaryFile.IsTemporary) { binaryFile.IsTemporary = false; } HistoryChangeList.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Image"); break; } case EntityState.Modified: { // if there is an binaryfile (image) associated with this, make sure that it is flagged as IsTemporary=False if (binaryFile.IsTemporary) { binaryFile.IsTemporary = false; } HistoryChangeList.AddChange(History.HistoryVerb.Modify, History.HistoryChangeType.Record, "Image"); break; } case EntityState.Deleted: { // if deleting, and there is an binaryfile (image) associated with this, make sure that it is flagged as IsTemporary=true // so that it'll get cleaned up if (!binaryFile.IsTemporary) { binaryFile.IsTemporary = true; } HistoryChangeList.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "Image"); break; } } base.PreSaveChanges(dbContext, entry); }
/// <summary> /// Adds the new home location. /// </summary> /// <param name="ncoaHistory">The NCOA history.</param> /// <param name="locationService">The location service.</param> /// <param name="groupLocationService">The group location service.</param> /// <param name="homeValueId">The home value identifier.</param> /// <param name="changes">The changes.</param> /// <param name="isMailingLocation">Is the location a mailing location.</param> /// <param name="isMappedLocation">Is the location a mapped location.</param> /// <returns></returns> private bool AddNewHomeLocation(NcoaHistory ncoaHistory, LocationService locationService, GroupLocationService groupLocationService, int?homeValueId, History.HistoryChangeList changes, bool isMailingLocation, bool isMappedLocation) { if (homeValueId.HasValue) { var location = locationService.Get( ncoaHistory.UpdatedStreet1, ncoaHistory.UpdatedStreet2, ncoaHistory.UpdatedCity, ncoaHistory.UpdatedState, ncoaHistory.UpdatedPostalCode, ncoaHistory.UpdatedCountry); var groupLocation = new GroupLocation(); groupLocation.Location = location; groupLocation.IsMailingLocation = isMailingLocation; groupLocation.IsMappedLocation = isMappedLocation; groupLocation.GroupId = ncoaHistory.FamilyId; groupLocation.GroupLocationTypeValueId = homeValueId.Value; groupLocation.IsMailingLocation = true; groupLocationService.Add(groupLocation); changes.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Property, "Location").SetNewValue(groupLocation.Location.ToString()).SourceOfChange = "NCOA Request"; return(true); } return(false); }
/// <summary> /// Marks an address as previous location. /// </summary> /// <param name="ncoaHistory">The NCOA history.</param> /// <param name="groupLocationService">The group location service.</param> /// <param name="previousValueId">The previous value identifier.</param> /// <param name="changes">The changes.</param> /// <returns></returns> public GroupLocation MarkAsPreviousLocation(NcoaHistory ncoaHistory, GroupLocationService groupLocationService, int?previousValueId, History.HistoryChangeList changes) { if (ncoaHistory.LocationId.HasValue && previousValueId.HasValue) { var groupLocation = groupLocationService.Queryable() .Where(gl => gl.GroupId == ncoaHistory.FamilyId && gl.LocationId == ncoaHistory.LocationId && gl.Location.Street1 == ncoaHistory.OriginalStreet1) .FirstOrDefault(); if (groupLocation != null) { if (groupLocation.GroupLocationTypeValueId != previousValueId.Value) { changes.AddChange(History.HistoryVerb.Modify, History.HistoryChangeType.Property, $"Location Type for {groupLocation.Location} ").SetNewValue("Previous").SourceOfChange = "NCOA Request"; groupLocation.GroupLocationTypeValueId = previousValueId.Value; } return(groupLocation); } } return(null); }
/// <summary> /// Method that will be called on an entity immediately before the item is saved by context /// </summary> /// <param name="dbContext"></param> /// <param name="entry"></param> public override void PreSaveChanges(Rock.Data.DbContext dbContext, DbEntityEntry entry) { var rockContext = ( RockContext )dbContext; HistoryChangeList = new History.HistoryChangeList(); switch (entry.State) { case EntityState.Added: { string acct = History.GetValue <FinancialAccount>(this.Account, this.AccountId, rockContext); HistoryChangeList.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, acct).SetNewValue(Amount.FormatAsCurrency()); break; } case EntityState.Modified: { string acct = History.GetValue <FinancialAccount>(this.Account, this.AccountId, rockContext); int?accountId = this.Account != null ? this.Account.Id : this.AccountId; int?origAccountId = entry.OriginalValues["AccountId"].ToStringSafe().AsIntegerOrNull(); if (!accountId.Equals(origAccountId)) { History.EvaluateChange(HistoryChangeList, "Account", History.GetValue <FinancialAccount>(null, origAccountId, rockContext), acct); } History.EvaluateChange(HistoryChangeList, acct, entry.OriginalValues["Amount"].ToStringSafe().AsDecimal().FormatAsCurrency(), Amount.FormatAsCurrency()); History.EvaluateChange(HistoryChangeList, acct, entry.OriginalValues["FeeAmount"].ToStringSafe().AsDecimal().FormatAsCurrency(), FeeAmount.FormatAsCurrency()); History.EvaluateChange(HistoryChangeList, acct, entry.OriginalValues["FeeCoverageAmount"].ToStringSafe().AsDecimal().FormatAsCurrency(), FeeCoverageAmount.FormatAsCurrency()); break; } case EntityState.Deleted: { string acct = History.GetValue <FinancialAccount>(this.Account, this.AccountId, rockContext); HistoryChangeList.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, acct).SetOldValue(Amount.FormatAsCurrency()); break; } } base.PreSaveChanges(dbContext, entry); }
/// <summary> /// Handles the Delete event of the gRegistrations control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RowEventArgs"/> instance containing the event data.</param> protected void gRegistrations_Delete(object sender, RowEventArgs e) { using (var rockContext = new RockContext()) { var registrationService = new RegistrationService(rockContext); var registration = registrationService.Get(e.RowKeyId); if (registration != null) { int registrationInstanceId = registration.RegistrationInstanceId; if (!UserCanEdit && !registration.IsAuthorized("Register", CurrentPerson) && !registration.IsAuthorized(Authorization.EDIT, this.CurrentPerson) && !registration.IsAuthorized(Authorization.ADMINISTRATE, this.CurrentPerson)) { mdDeleteWarning.Show("You are not authorized to delete this registration.", ModalAlertType.Information); return; } string errorMessage; if (!registrationService.CanDelete(registration, out errorMessage)) { mdRegistrationsGridWarning.Show(errorMessage, ModalAlertType.Information); return; } var changes = new History.HistoryChangeList(); changes.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "Registration"); rockContext.WrapTransaction(() => { HistoryService.SaveChanges( rockContext, typeof(Registration), Rock.SystemGuid.Category.HISTORY_EVENT_REGISTRATION.AsGuid(), registration.Id, changes); registrationService.Delete(registration); rockContext.SaveChanges(); }); hfHasPayments.Value = this.RegistrationInstanceHasPayments.ToString(); } } BindRegistrationsGrid(); }
/// <summary> /// Handles the Delete event of the gBatchList control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RowEventArgs"/> instance containing the event data.</param> protected void gBatchList_Delete(object sender, RowEventArgs e) { var rockContext = new RockContext(); var batchService = new FinancialBatchService(rockContext); var transactionService = new FinancialTransactionService(rockContext); var batch = batchService.Get(e.RowKeyId); if (batch != null) { if (batch.IsAuthorized(Rock.Security.Authorization.DELETE, CurrentPerson)) { string errorMessage; if (!batchService.CanDelete(batch, out errorMessage)) { mdGridWarning.Show(errorMessage, ModalAlertType.Information); return; } rockContext.WrapTransaction(() => { foreach (var txn in transactionService.Queryable() .Where(t => t.BatchId == batch.Id)) { transactionService.Delete(txn); } var changes = new History.HistoryChangeList(); changes.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "Batch"); HistoryService.SaveChanges( rockContext, typeof(FinancialBatch), Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), batch.Id, changes); batchService.Delete(batch); rockContext.SaveChanges(); }); } else { mdGridWarning.Show("You are not authorized to delete the selected batch.", ModalAlertType.Warning); } } BindGrid(); }
/// <summary> /// Method that will be called on an entity immediately after the item is saved /// </summary> /// <param name="dbContext">The database context.</param> public override void PostSaveChanges(Data.DbContext dbContext) { if (HistoryChangeList.Any()) { HistoryService.SaveChanges(( RockContext )dbContext, typeof(FinancialTransaction), Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(), this.TransactionId, HistoryChangeList, true, this.ModifiedByPersonAliasId); var txn = new FinancialTransactionService(( RockContext )dbContext).GetSelect(this.TransactionId, s => new { s.Id, s.BatchId }); if (txn != null && txn.BatchId != null) { var batchHistory = new History.HistoryChangeList(); batchHistory.AddChange(History.HistoryVerb.Modify, History.HistoryChangeType.Record, $"Transaction ID:{txn.Id}"); HistoryService.SaveChanges(( RockContext )dbContext, typeof(FinancialBatch), Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(), txn.BatchId.Value, batchHistory, string.Empty, typeof(FinancialTransaction), this.TransactionId, true, this.ModifiedByPersonAliasId, dbContext.SourceOfChange); } } base.PostSaveChanges(dbContext); }
/// <summary> /// Method that will be called on an entity immediately after the item is saved by context /// </summary> /// <param name="dbContext">The database context.</param> public override void PostSaveChanges(Data.DbContext dbContext) { if (HistoryChangeList.Any()) { foreach (var txn in new FinancialTransactionService((RockContext)dbContext) .Queryable().AsNoTracking() .Where(t => t.FinancialPaymentDetailId == this.Id) .Select(t => new { t.Id, t.BatchId }) .ToList()) { HistoryService.SaveChanges((RockContext)dbContext, typeof(FinancialTransaction), Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(), txn.Id, HistoryChangeList, true, this.ModifiedByPersonAliasId, dbContext.SourceOfChange); var batchHistory = new History.HistoryChangeList(); batchHistory.AddChange(History.HistoryVerb.Modify, History.HistoryChangeType.Property, "Transaction"); HistoryService.SaveChanges((RockContext)dbContext, typeof(FinancialBatch), Rock.SystemGuid.Category.HISTORY_FINANCIAL_TRANSACTION.AsGuid(), txn.BatchId.Value, batchHistory, string.Empty, typeof(FinancialTransaction), txn.Id, true, this.ModifiedByPersonAliasId, dbContext.SourceOfChange); } } base.PostSaveChanges(dbContext); }
public void AddConnectionStatusChangeHistoryBulkTestData() { var dataContext = new RockContext(); //this.ThrowIfTestHistoryDataExists( dataContext, _TestDataSourceOfChange ); // Add Connection Status Change History Entries. var personService = new PersonService(dataContext); var personQuery = personService.Queryable() .AsNoTracking() .Where(x => !x.IsSystem) .Take(_BulkHistoryMaxPeople).ToList(); var statusType = DefinedTypeCache.Get(SystemGuid.DefinedType.PERSON_CONNECTION_STATUS); var statusValues = statusType.DefinedValues.Select(x => x.Id).ToList(); int?toStatusId; int?fromStatusId; var rng = new Random(); var adminPerson = this.GetAdminPersonOrThrow(personService); // For each person, add a random number of status changes over a random period of time prior to today. int entriesAdded = 0; foreach (var person in personQuery) { var historyChanges = new History.HistoryChangeList(); var numberOfChanges = rng.Next(_BulkHistoryMinChangesPerPerson, _BulkHistoryMaxChangesPerPerson + 1); // Distribute the changes evenly throughout a random period of days. var changePeriodInDays = rng.Next(1, _BulkHistoryMaxPeriodInDays + 1); //var firstDate = lastDate.AddDays( changePeriodInDays * -1 ); decimal dayIncrement = Decimal.Divide(changePeriodInDays, numberOfChanges); decimal dayOffset = 0; DateTime dateOfChange; // = _HistoryTestEndDate; // Set the initial value to the current status. fromStatusId = person.ConnectionStatusValueId; for (int i = 1; i <= numberOfChanges; i++) { dateOfChange = _BulkHistoryEndDate.AddDays(( int )dayOffset * -1); dayOffset = dayOffset + dayIncrement; // Set the target status for this change to be the status prior to the most recent status change. // This is to ensure that the status changes form a logical sequence. toStatusId = fromStatusId; do { fromStatusId = statusValues.GetRandomElement(); }while (toStatusId == fromStatusId); var historyEntry = historyChanges.AddChange(History.HistoryVerb.Modify, History.HistoryChangeType.Property, "Connection Status") .SetNewValue(toStatusId.ToStringSafe()) .SetOldValue(fromStatusId.ToStringSafe()) .SetRawValues(fromStatusId.ToStringSafe(), toStatusId.ToStringSafe()) .SetDateOfChange(dateOfChange) .SetSourceOfChange(_TestDataSourceOfChange); entriesAdded++; Debug.Print($"Added History Entry [Entry#={entriesAdded}, PersonId={person.Id}, Date={dateOfChange}, OldValue={fromStatusId}, NewValue={toStatusId}"); } dataContext = new RockContext(); HistoryService.SaveChanges(dataContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_DEMOGRAPHIC_CHANGES.AsGuid(), person.Id, historyChanges, true, adminPerson.PrimaryAliasId, _TestDataSourceOfChange); } Debug.Print($"Create Data completed: { entriesAdded } history entries created."); Assert.IsTrue(entriesAdded > 0, "No history entries created."); }
/// <summary> /// Executes the specified workflow. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="action">The action.</param> /// <param name="entity">The entity.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> public override bool Execute(RockContext rockContext, WorkflowAction action, Object entity, out List <string> errorMessages) { errorMessages = new List <string>(); // get person int?personId = null; string personAttributeValue = GetAttributeValue(action, "Person"); Guid? guidPersonAttribute = personAttributeValue.AsGuidOrNull(); if (guidPersonAttribute.HasValue) { var attributePerson = AttributeCache.Get(guidPersonAttribute.Value, rockContext); if (attributePerson != null && attributePerson.FieldType.Class == "Rock.Field.Types.PersonFieldType") { string attributePersonValue = action.GetWorkflowAttributeValue(guidPersonAttribute.Value); if (!string.IsNullOrWhiteSpace(attributePersonValue)) { Guid personAliasGuid = attributePersonValue.AsGuid(); if (!personAliasGuid.IsEmpty()) { personId = new PersonAliasService(rockContext).Queryable() .Where(a => a.Guid.Equals(personAliasGuid)) .Select(a => a.PersonId) .FirstOrDefault(); if (personId == null) { errorMessages.Add(string.Format("Person could not be found for selected value ('{0}')!", guidPersonAttribute.ToString())); return(false); } } } } } if (personId == null) { errorMessages.Add("The attribute used to provide the person was invalid, or not of type 'Person'."); return(false); } // determine the phone type to edit DefinedValueCache phoneType = null; var phoneTypeAttributeValue = action.GetWorkflowAttributeValue(GetAttributeValue(action, "PhoneTypeAttribute").AsGuid()); if (phoneTypeAttributeValue != null) { phoneType = DefinedValueCache.Get(phoneTypeAttributeValue.AsGuid()); } if (phoneType == null) { phoneType = DefinedValueCache.Get(GetAttributeValue(action, "PhoneType").AsGuid()); } if (phoneType == null) { errorMessages.Add("The phone type to be updated was not selected."); return(false); } // get the ignore blank setting var ignoreBlanks = GetActionAttributeValue(action, "IgnoreBlankValues").AsBoolean(true); // get the new phone number value string phoneNumberValue = GetAttributeValue(action, "PhoneNumber"); Guid? phoneNumberValueGuid = phoneNumberValue.AsGuidOrNull(); if (phoneNumberValueGuid.HasValue) { phoneNumberValue = action.GetWorkflowAttributeValue(phoneNumberValueGuid.Value); } else { phoneNumberValue = phoneNumberValue.ResolveMergeFields(GetMergeFields(action)); } phoneNumberValue = PhoneNumber.CleanNumber(phoneNumberValue); // gets value indicating if phone number is unlisted string unlistedValue = GetAttributeValue(action, "Unlisted"); Guid? unlistedValueGuid = unlistedValue.AsGuidOrNull(); if (unlistedValueGuid.HasValue) { unlistedValue = action.GetWorkflowAttributeValue(unlistedValueGuid.Value); } else { unlistedValue = unlistedValue.ResolveMergeFields(GetMergeFields(action)); } bool?unlisted = unlistedValue.AsBooleanOrNull(); // gets value indicating if messaging should be enabled for phone number string smsEnabledValue = GetAttributeValue(action, "MessagingEnabled"); Guid? smsEnabledValueGuid = smsEnabledValue.AsGuidOrNull(); if (smsEnabledValueGuid.HasValue) { smsEnabledValue = action.GetWorkflowAttributeValue(smsEnabledValueGuid.Value); } else { smsEnabledValue = smsEnabledValue.ResolveMergeFields(GetMergeFields(action)); } bool?smsEnabled = smsEnabledValue.AsBooleanOrNull(); bool updated = false; bool newPhoneNumber = false; var phoneNumberService = new PhoneNumberService(rockContext); var phoneNumber = phoneNumberService.Queryable() .Where(n => n.PersonId == personId.Value && n.NumberTypeValueId == phoneType.Id) .FirstOrDefault(); string oldValue = string.Empty; if (phoneNumber == null) { phoneNumber = new PhoneNumber { NumberTypeValueId = phoneType.Id, PersonId = personId.Value }; newPhoneNumber = true; updated = true; } else { oldValue = phoneNumber.NumberFormattedWithCountryCode; } if (!string.IsNullOrWhiteSpace(phoneNumberValue) || !ignoreBlanks) { updated = updated || phoneNumber.Number != phoneNumberValue; phoneNumber.Number = phoneNumberValue; } if (unlisted.HasValue) { updated = updated || phoneNumber.IsUnlisted != unlisted.Value; phoneNumber.IsUnlisted = unlisted.Value; } if (smsEnabled.HasValue) { updated = updated || phoneNumber.IsMessagingEnabled != smsEnabled.Value; phoneNumber.IsMessagingEnabled = smsEnabled.Value; } if (updated) { if (oldValue != phoneNumber.NumberFormattedWithCountryCode) { var changes = new History.HistoryChangeList(); changes.AddChange(History.HistoryVerb.Modify, History.HistoryChangeType.Record, "Phone").SetSourceOfChange($"{action.ActionTypeCache.ActivityType.WorkflowType.Name} workflow"); HistoryService.SaveChanges(rockContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_DEMOGRAPHIC_CHANGES.AsGuid(), personId.Value, changes, false); } if (phoneNumber.Number.IsNullOrWhiteSpace()) { if (!newPhoneNumber) { phoneNumberService.Delete(phoneNumber); } } else { if (newPhoneNumber) { phoneNumberService.Add(phoneNumber); } } rockContext.SaveChanges(); if (action.Activity != null && action.Activity.Workflow != null) { var workflowType = action.Activity.Workflow.WorkflowTypeCache; if (workflowType != null && workflowType.LoggingLevel == WorkflowLoggingLevel.Action) { var person = new PersonService(rockContext).Get(personId.Value); action.AddLogEntry(string.Format("Updated {0} phone for {1} to {2}.", phoneType.Value, person.FullName, phoneNumber.NumberFormattedWithCountryCode)); } } } return(true); }
/// <summary> /// Sends the specified communication. /// </summary> /// <param name="communication">The communication.</param> /// <param name="mediumEntityTypeId">The medium entity type identifier.</param> /// <param name="mediumAttributes">The medium attributes.</param> public override void Send(Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes) { using (var communicationRockContext = new RockContext()) { // Requery the Communication communication = new CommunicationService(communicationRockContext) .Queryable().Include(a => a.CreatedByPersonAlias.Person).Include(a => a.CommunicationTemplate) .FirstOrDefault(c => c.Id == communication.Id); // If there are no pending recipients than just exit the method if (communication != null && communication.Status == Model.CommunicationStatus.Approved && (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0)) { var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable(); if (!qryRecipients .Where(r => r.CommunicationId == communication.Id && r.Status == Model.CommunicationRecipientStatus.Pending && r.MediumEntityTypeId.HasValue && r.MediumEntityTypeId.Value == mediumEntityTypeId) .Any()) { return; } } var currentPerson = communication.CreatedByPersonAlias?.Person; var globalAttributes = GlobalAttributesCache.Get(); string publicAppRoot = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash(); var mergeFields = Lava.LavaHelper.GetCommonMergeFields(null, currentPerson); var cssInliningEnabled = communication.CommunicationTemplate?.CssInliningEnabled ?? false; string fromAddress = string.IsNullOrWhiteSpace(communication.FromEmail) ? globalAttributes.GetValue("OrganizationEmail") : communication.FromEmail; string fromName = string.IsNullOrWhiteSpace(communication.FromName) ? globalAttributes.GetValue("OrganizationName") : communication.FromName; // Resolve any possible merge fields in the from address fromAddress = fromAddress.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands); fromName = fromName.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands); Parameter replyTo = new Parameter(); // Reply To if (communication.ReplyToEmail.IsNotNullOrWhiteSpace()) { // Resolve any possible merge fields in the replyTo address replyTo.Name = "h:Reply-To"; replyTo.Type = ParameterType.GetOrPost; replyTo.Value = communication.ReplyToEmail.ResolveMergeFields(mergeFields, currentPerson); } var personEntityTypeId = EntityTypeCache.Get("Rock.Model.Person").Id; var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id; var communicationCategoryGuid = Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(); RestRequest restRequest = null; // Loop through recipients and send the email bool recipientFound = true; while (recipientFound) { var recipientRockContext = new RockContext(); var recipient = Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext); // This means we are done, break the loop if (recipient == null) { recipientFound = false; break; } // Not valid save the obj with the status messages then go to the next one if (!ValidRecipient(recipient, communication.IsBulkCommunication)) { recipientRockContext.SaveChanges(); continue; } try { // Create merge field dictionary var mergeObjects = recipient.CommunicationMergeValues(mergeFields); // Create the request obj restRequest = new RestRequest(GetAttributeValue("Resource"), Method.POST); restRequest.AddParameter("domian", GetAttributeValue("Domain"), ParameterType.UrlSegment); // ReplyTo if (communication.ReplyToEmail.IsNotNullOrWhiteSpace()) { restRequest.AddParameter(replyTo); } // From restRequest.AddParameter("from", new MailAddress(fromAddress, fromName).ToString()); // To restRequest.AddParameter("to", new MailAddress(recipient.PersonAlias.Person.Email, recipient.PersonAlias.Person.FullName).ToString()); // Safe sender checks CheckSafeSender(restRequest, fromAddress, globalAttributes.GetValue("OrganizationEmail")); // CC if (communication.CCEmails.IsNotNullOrWhiteSpace()) { string[] ccRecipients = communication.CCEmails.ResolveMergeFields(mergeObjects, currentPerson).Replace(";", ",").Split(','); foreach (var ccRecipient in ccRecipients) { restRequest.AddParameter("cc", ccRecipient); } } // BCC if (communication.BCCEmails.IsNotNullOrWhiteSpace()) { string[] bccRecipients = communication.BCCEmails.ResolveMergeFields(mergeObjects, currentPerson).Replace(";", ",").Split(','); foreach (var bccRecipient in bccRecipients) { restRequest.AddParameter("bcc", bccRecipient); } } // Subject string subject = ResolveText(communication.Subject, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); restRequest.AddParameter("subject", subject); // Body Plain Text if (mediumAttributes.ContainsKey("DefaultPlainText")) { string plainText = ResolveText(mediumAttributes["DefaultPlainText"], currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); if (!string.IsNullOrWhiteSpace(plainText)) { AlternateView plainTextView = AlternateView.CreateAlternateViewFromString(plainText, new ContentType(MediaTypeNames.Text.Plain)); restRequest.AddParameter("text", plainTextView); } } // Body HTML string htmlBody = communication.Message; // Get the unsubscribe content and add a merge field for it if (communication.IsBulkCommunication && mediumAttributes.ContainsKey("UnsubscribeHTML")) { string unsubscribeHtml = ResolveText(mediumAttributes["UnsubscribeHTML"], currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); mergeObjects.AddOrReplace("UnsubscribeOption", unsubscribeHtml); htmlBody = ResolveText(htmlBody, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); // Resolve special syntax needed if option was included in global attribute if (Regex.IsMatch(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]")) { htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", unsubscribeHtml); } // Add the unsubscribe option at end if it wasn't included in content if (!htmlBody.Contains(unsubscribeHtml)) { htmlBody += unsubscribeHtml; } } else { htmlBody = ResolveText(htmlBody, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", string.Empty); } if (!string.IsNullOrWhiteSpace(htmlBody)) { if (cssInliningEnabled) { // move styles inline to help it be compatible with more email clients htmlBody = htmlBody.ConvertHtmlStylesToInlineAttributes(); } // add the main Html content to the email restRequest.AddParameter("html", htmlBody); } // Headers AddAdditionalHeaders(restRequest, new Dictionary <string, string>() { { "communication_recipient_guid", recipient.Guid.ToString() } }); // Attachments foreach (var attachment in communication.GetAttachments(CommunicationType.Email).Select(a => a.BinaryFile)) { MemoryStream ms = new MemoryStream(); attachment.ContentStream.CopyTo(ms); restRequest.AddFile("attachment", ms.ToArray(), attachment.FileName); } // Send the email // Send it RestClient restClient = new RestClient { BaseUrl = new Uri(GetAttributeValue("BaseURL")), Authenticator = new HttpBasicAuthenticator("api", GetAttributeValue("APIKey")) }; // Call the API and get the response Response = restClient.Execute(restRequest); // Update recipient status and status note recipient.Status = Response.StatusCode == HttpStatusCode.OK ? CommunicationRecipientStatus.Delivered : CommunicationRecipientStatus.Failed; recipient.StatusNote = Response.StatusDescription; recipient.TransportEntityTypeName = this.GetType().FullName; // Log it try { var historyChangeList = new History.HistoryChangeList(); historyChangeList.AddChange( History.HistoryVerb.Sent, History.HistoryChangeType.Record, $"Communication") .SetRelatedData(fromName, communicationEntityTypeId, communication.Id) .SetCaption(subject); HistoryService.SaveChanges(recipientRockContext, typeof(Rock.Model.Person), communicationCategoryGuid, recipient.PersonAlias.PersonId, historyChangeList, false, communication.SenderPersonAliasId); } catch (Exception ex) { ExceptionLogService.LogException(ex, null); } } catch (Exception ex) { ExceptionLogService.LogException(ex); recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Exception: " + ex.Messages().AsDelimited(" => "); } recipientRockContext.SaveChanges(); } } }
/// <summary> /// Method that will be called on an entity immediately before the item is saved by context. Takes /// care of logging any particular change history for user login. /// </summary> /// <param name="dbContext"></param> /// <param name="entry"></param> public override void PreSaveChanges(Rock.Data.DbContext dbContext, DbEntityEntry entry) { var rockContext = ( RockContext )dbContext; HistoryChanges = new History.HistoryChangeList(); switch (entry.State) { case EntityState.Added: { // Get the authentication provider entity type var entityType = EntityTypeCache.Get(this.EntityTypeId ?? 0); var change = HistoryChanges.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Authentication Provider").SetNewValue(entityType?.FriendlyName); // Don't log Pin Authentication user names. var isUserNameSensitive = (entityType?.Guid == Rock.SystemGuid.EntityType.AUTHENTICATION_PIN.AsGuid()) ? true : false; if (isUserNameSensitive) { change.SetCaption("User Account"); } History.EvaluateChange(HistoryChanges, "User Login", string.Empty, UserName, isUserNameSensitive); History.EvaluateChange(HistoryChanges, "Is Confirmed", null, IsConfirmed); History.EvaluateChange(HistoryChanges, "Is Password Change Required", null, IsPasswordChangeRequired); History.EvaluateChange(HistoryChanges, "Is Locked Out", null, IsLockedOut); break; } case EntityState.Modified: { var entityType = EntityTypeCache.Get(this.EntityTypeId ?? 0); // Don't log Pin Authentication user names. var isUserNameSensitive = (entityType?.Guid == Rock.SystemGuid.EntityType.AUTHENTICATION_PIN.AsGuid()) ? true : false; History.EvaluateChange(HistoryChanges, "User Login", entry.OriginalValues["UserName"].ToStringSafe(), UserName, isUserNameSensitive); History.EvaluateChange(HistoryChanges, "Is Confirmed", entry.OriginalValues["IsConfirmed"].ToStringSafe().AsBooleanOrNull(), IsConfirmed); History.EvaluateChange(HistoryChanges, "Is Password Change Required", entry.OriginalValues["IsPasswordChangeRequired"].ToStringSafe().AsBooleanOrNull(), IsPasswordChangeRequired); History.EvaluateChange(HistoryChanges, "Is Locked Out", entry.OriginalValues["IsLockedOut"].ToStringSafe().AsBooleanOrNull(), IsLockedOut); History.EvaluateChange(HistoryChanges, "Password", entry.OriginalValues["Password"].ToStringSafe(), Password, true); // Did the provider type change? int?origEntityTypeId = entry.OriginalValues["EntityTypeId"].ToStringSafe().AsIntegerOrNull(); int?entityTypeId = EntityType != null ? EntityType.Id : EntityTypeId; if (!entityTypeId.Equals(origEntityTypeId)) { var origProviderType = EntityTypeCache.Get(origEntityTypeId ?? 0)?.FriendlyName; var providerType = EntityTypeCache.Get(this.EntityTypeId ?? 0)?.FriendlyName; History.EvaluateChange(HistoryChanges, "User Login", origProviderType, providerType); } // Change the caption if this is a sensitive user account if (HistoryChanges.Count > 0 && isUserNameSensitive) { var change = HistoryChanges.FirstOrDefault(); change.SetCaption("User Account"); } break; } case EntityState.Deleted: { // By this point EF has stripped out some of the data we need to save history // Reload the data using a new context. RockContext newRockContext = new RockContext(); var userLogin = new UserLoginService(newRockContext).Get(this.Id); if (userLogin != null && userLogin.PersonId != null) { try { var entityType = EntityTypeCache.Get(userLogin.EntityTypeId ?? 0); var isUserNameSensitive = (entityType?.Guid == Rock.SystemGuid.EntityType.AUTHENTICATION_PIN.AsGuid()) ? true : false; if (!isUserNameSensitive) { HistoryChanges.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "User Login").SetOldValue(userLogin.UserName); HistoryService.SaveChanges(newRockContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_ACTIVITY.AsGuid(), userLogin.PersonId.Value, HistoryChanges, UserName, typeof(UserLogin), this.Id, true, userLogin.ModifiedByPersonAliasId, null); } else { HistoryChanges.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "Authentication Provider").SetOldValue(entityType?.FriendlyName).SetCaption("User Account"); HistoryService.SaveChanges(newRockContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_ACTIVITY.AsGuid(), userLogin.PersonId.Value, HistoryChanges, entityType?.FriendlyName, typeof(UserLogin), this.Id, true, userLogin.ModifiedByPersonAliasId, null); } } catch (Exception ex) { // Just log the problem and move on... ExceptionLogService.LogException(ex); } } HistoryChanges.Clear(); return; } } base.PreSaveChanges(dbContext, entry); }
// // Swipe Panel Events // private void ProcessSwipe(string swipeData) { try { using (var rockContext = new RockContext()) { // create swipe object SwipePaymentInfo swipeInfo = new SwipePaymentInfo(swipeData); swipeInfo.Amount = this.Amounts.Sum(a => a.Value); var txnType = DefinedValueCache.Get(new Guid(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION)); swipeInfo.TransactionTypeValueId = txnType.Id; // if not anonymous then add contact info to the gateway transaction if (this.AnonymousGiverPersonAliasId != this.SelectedGivingUnit.PersonAliasId) { var giver = new PersonAliasService(rockContext).Queryable("Person, Person.PhoneNumbers").Where(p => p.Id == this.SelectedGivingUnit.PersonAliasId).FirstOrDefault(); swipeInfo.FirstName = giver.Person.NickName; swipeInfo.LastName = giver.Person.LastName; if (giver.Person.PhoneNumbers != null) { Guid homePhoneValueGuid = new Guid(Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_HOME); var homephone = giver.Person.PhoneNumbers.Where(p => p.NumberTypeValue.Guid == homePhoneValueGuid).FirstOrDefault(); if (homephone != null) { swipeInfo.Phone = homephone.NumberFormatted; } } var homeLocation = giver.Person.GetHomeLocation(); if (homeLocation != null) { swipeInfo.Street1 = homeLocation.Street1; if (!string.IsNullOrWhiteSpace(homeLocation.Street2)) { swipeInfo.Street2 = homeLocation.Street2; } swipeInfo.City = homeLocation.City; swipeInfo.State = homeLocation.State; swipeInfo.PostalCode = homeLocation.PostalCode; } } // add comment to the transaction swipeInfo.Comment1 = GetAttributeValue("PaymentComment"); // get gateway FinancialGateway financialGateway = null; GatewayComponent gateway = null; Guid? gatewayGuid = GetAttributeValue("CreditCardGateway").AsGuidOrNull(); if (gatewayGuid.HasValue) { financialGateway = new FinancialGatewayService(rockContext).Get(gatewayGuid.Value); if (financialGateway != null) { financialGateway.LoadAttributes(rockContext); } gateway = financialGateway.GetGatewayComponent(); } if (gateway != null) { string errorMessage = string.Empty; var transaction = gateway.Charge(financialGateway, swipeInfo, out errorMessage); if (transaction != null) { _transactionCode = transaction.TransactionCode; var personName = new PersonAliasService(rockContext) .Queryable().AsNoTracking() .Where(a => a.Id == this.SelectedGivingUnit.PersonAliasId) .Select(a => a.Person.NickName + " " + a.Person.LastName) .FirstOrDefault(); transaction.AuthorizedPersonAliasId = this.SelectedGivingUnit.PersonAliasId; transaction.TransactionDateTime = RockDateTime.Now; transaction.FinancialGatewayId = financialGateway.Id; transaction.TransactionTypeValueId = txnType.Id; transaction.Summary = swipeInfo.Comment1; if (transaction.FinancialPaymentDetail == null) { transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); } transaction.FinancialPaymentDetail.SetFromPaymentInfo(swipeInfo, gateway, rockContext); Guid sourceGuid = Guid.Empty; if (Guid.TryParse(GetAttributeValue("Source"), out sourceGuid)) { var source = DefinedValueCache.Get(sourceGuid); if (source != null) { transaction.SourceTypeValueId = source.Id; } } foreach (var accountAmount in this.Amounts.Where(a => a.Value > 0)) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.Amount = accountAmount.Value; transactionDetail.AccountId = accountAmount.Key; transaction.TransactionDetails.Add(transactionDetail); var account = new FinancialAccountService(rockContext).Get(accountAmount.Key); } var batchService = new FinancialBatchService(rockContext); // Get the batch var batch = batchService.Get( GetAttributeValue("BatchNamePrefix"), swipeInfo.CurrencyTypeValue, swipeInfo.CreditCardTypeValue, transaction.TransactionDateTime.Value, financialGateway.GetBatchTimeOffset()); var batchChanges = new History.HistoryChangeList(); if (batch.Id == 0) { batchChanges.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Batch"); History.EvaluateChange(batchChanges, "Batch Name", string.Empty, batch.Name); History.EvaluateChange(batchChanges, "Status", null, batch.Status); History.EvaluateChange(batchChanges, "Start Date/Time", null, batch.BatchStartDateTime); History.EvaluateChange(batchChanges, "End Date/Time", null, batch.BatchEndDateTime); } decimal newControlAmount = batch.ControlAmount + transaction.TotalAmount; History.EvaluateChange(batchChanges, "Control Amount", batch.ControlAmount.FormatAsCurrency(), newControlAmount.FormatAsCurrency()); batch.ControlAmount = newControlAmount; transaction.BatchId = batch.Id; batch.Transactions.Add(transaction); rockContext.WrapTransaction(() => { rockContext.SaveChanges(); HistoryService.SaveChanges( rockContext, typeof(FinancialBatch), Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), batch.Id, batchChanges ); }); // send receipt in one is configured and not giving anonymously if (!string.IsNullOrWhiteSpace(GetAttributeValue("ReceiptEmail")) && (this.AnonymousGiverPersonAliasId != this.SelectedGivingUnit.PersonAliasId)) { _receiptSent = true; SendReceipt(); } HidePanels(); ShowReceiptPanel(); } else { lSwipeErrors.Text = String.Format("<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", errorMessage); } } else { lSwipeErrors.Text = "<div class='alert alert-danger'>Invalid gateway provided. Please provide a gateway. Transaction not processed.</div>"; } } } catch (Exception ex) { lSwipeErrors.Text = String.Format("<div class='alert alert-danger'>An error occurred while process this transaction. Message: {0}</div>", ex.Message); } }
/// <summary> /// Handles the Click event of the lbSave control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param> protected void lbSave_Click(object sender, EventArgs e) { var rockContext = new RockContext(); var batchService = new FinancialBatchService(rockContext); FinancialBatch batch = null; var changes = new History.HistoryChangeList(); int batchId = hfBatchId.Value.AsInteger(); if (batchId == 0) { batch = new FinancialBatch(); batchService.Add(batch); changes.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Batch"); } else { batch = batchService.Get(batchId); } if (batch != null) { if (dvpBatchName.Visible) { History.EvaluateChange(changes, "Batch Name", batch.Name, dvpBatchName.SelectedItem.Text); batch.Name = dvpBatchName.SelectedItem.Text; } else { History.EvaluateChange(changes, "Batch Name", batch.Name, tbName.Text); batch.Name = tbName.Text; } BatchStatus batchStatus = (BatchStatus)ddlStatus.SelectedIndex; string errorMessage; if (!batch.IsValidBatchStatusChange(batch.Status, batchStatus, this.CurrentPerson, out errorMessage)) { cvBatch.IsValid = false; cvBatch.ErrorMessage = errorMessage; return; } History.EvaluateChange(changes, "Status", batch.Status, batchStatus); batch.Status = batchStatus; CampusCache oldCampus = null; if (batch.CampusId.HasValue) { oldCampus = CampusCache.Get(batch.CampusId.Value); } CampusCache newCampus = null; if (campCampus.SelectedCampusId.HasValue) { newCampus = CampusCache.Get(campCampus.SelectedCampusId.Value); } History.EvaluateChange(changes, "Campus", oldCampus != null ? oldCampus.Name : "None", newCampus != null ? newCampus.Name : "None"); batch.CampusId = campCampus.SelectedCampusId; DateTime?startDateTime = dtpStart.SelectedDateTimeIsBlank ? null : dtpStart.SelectedDateTime; History.EvaluateChange(changes, "Start Date/Time", batch.BatchStartDateTime, startDateTime); batch.BatchStartDateTime = startDateTime; DateTime?endDateTime; if (dtpEnd.SelectedDateTimeIsBlank && batch.BatchStartDateTime.HasValue) { endDateTime = batch.BatchStartDateTime.Value.AddDays(1); } else { endDateTime = dtpEnd.SelectedDateTimeIsBlank ? null : dtpEnd.SelectedDateTime; } History.EvaluateChange(changes, "End Date/Time", batch.BatchEndDateTime, endDateTime); batch.BatchEndDateTime = endDateTime; decimal controlAmount = tbControlAmount.Text.AsDecimal(); History.EvaluateChange(changes, "Control Amount", batch.ControlAmount.FormatAsCurrency(), controlAmount.FormatAsCurrency()); batch.ControlAmount = controlAmount; int?controlItemCount = nbControlItemCount.Text.AsIntegerOrNull(); History.EvaluateChange(changes, "Control Item Count", batch.ControlItemCount.FormatAsCurrency(), controlItemCount.FormatAsCurrency()); batch.ControlItemCount = controlItemCount; History.EvaluateChange(changes, "Accounting System Code", batch.AccountingSystemCode, tbAccountingCode.Text); batch.AccountingSystemCode = tbAccountingCode.Text; History.EvaluateChange(changes, "Notes", batch.Note, tbNote.Text); batch.Note = tbNote.Text; cvBatch.IsValid = batch.IsValid; if (!Page.IsValid || !batch.IsValid) { cvBatch.ErrorMessage = batch.ValidationResults.Select(a => a.ErrorMessage).ToList().AsDelimited("<br />"); return; } batch.LoadAttributes(rockContext); Rock.Attribute.Helper.GetEditValues(phAttributes, batch); rockContext.WrapTransaction(() => { if (rockContext.SaveChanges() > 0) { if (changes.Any()) { pdAuditDetails.SetEntity(batch, ResolveRockUrl("~")); HistoryService.SaveChanges( rockContext, typeof(FinancialBatch), Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), batch.Id, changes); } } }); batch.SaveAttributeValues(rockContext); if (batchId == 0) { // If created a new batch, navigate to same page so that transaction list displays correctly var pageReference = CurrentPageReference; pageReference.Parameters.AddOrReplace("batchId", batch.Id.ToString()); NavigateToPage(pageReference); } else { hfBatchId.SetValue(batch.Id); // Requery the batch to support EF navigation properties var savedBatch = GetBatch(batch.Id); ShowReadonlyDetails(savedBatch); // If there is a batch context item, update the context's properties with new values var contextObjects = new Dictionary <string, object>(); foreach (var contextEntityType in RockPage.GetContextEntityTypes()) { var contextEntity = RockPage.GetCurrentContext(contextEntityType); if (contextEntity is FinancialBatch) { var contextBatch = contextEntity as FinancialBatch; contextBatch.CopyPropertiesFrom(batch); } } // Then refresh transaction list RockPage.UpdateBlocks("~/Blocks/Finance/TransactionList.ascx"); } } }
/// <summary> /// Method that will be called on an entity immediately before the item is saved by context /// </summary> /// <param name="dbContext"></param> /// <param name="entry"></param> public override void PreSaveChanges(Data.DbContext dbContext, DbEntityEntry entry) { var rockContext = (RockContext)dbContext; HistoryChangeList = new History.HistoryChangeList(); switch (entry.State) { case System.Data.Entity.EntityState.Added: { HistoryChangeList.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Group").SetNewValue(Name); History.EvaluateChange(HistoryChangeList, "Name", string.Empty, Name); History.EvaluateChange(HistoryChangeList, "Description", string.Empty, Description); History.EvaluateChange(HistoryChangeList, "Group Type", (int?)null, GroupType, GroupTypeId); History.EvaluateChange(HistoryChangeList, "Campus", (int?)null, Campus, CampusId); History.EvaluateChange(HistoryChangeList, "Security Role", (bool?)null, IsSecurityRole); History.EvaluateChange(HistoryChangeList, "Active", (bool?)null, IsActive); History.EvaluateChange(HistoryChangeList, "Allow Guests", (bool?)null, AllowGuests); History.EvaluateChange(HistoryChangeList, "Public", (bool?)null, IsPublic); History.EvaluateChange(HistoryChangeList, "Group Capacity", (int?)null, GroupCapacity); // if this is a new record, but is saved with IsActive=False, set the InactiveDateTime if it isn't set already if (!this.IsActive) { this.InactiveDateTime = this.InactiveDateTime ?? RockDateTime.Now; } break; } case System.Data.Entity.EntityState.Modified: { var originalIsActive = entry.OriginalValues["IsActive"].ToStringSafe().AsBoolean(); History.EvaluateChange(HistoryChangeList, "Name", entry.OriginalValues["Name"].ToStringSafe(), Name); History.EvaluateChange(HistoryChangeList, "Description", entry.OriginalValues["Description"].ToStringSafe(), Description); History.EvaluateChange(HistoryChangeList, "Group Type", entry.OriginalValues["GroupTypeId"].ToStringSafe().AsIntegerOrNull(), GroupType, GroupTypeId); History.EvaluateChange(HistoryChangeList, "Campus", entry.OriginalValues["CampusId"].ToStringSafe().AsIntegerOrNull(), Campus, CampusId); History.EvaluateChange(HistoryChangeList, "Security Role", entry.OriginalValues["IsSecurityRole"].ToStringSafe().AsBoolean(), IsSecurityRole); History.EvaluateChange(HistoryChangeList, "Active", originalIsActive, IsActive); History.EvaluateChange(HistoryChangeList, "Allow Guests", entry.OriginalValues["AllowGuests"].ToStringSafe().AsBooleanOrNull(), AllowGuests); History.EvaluateChange(HistoryChangeList, "Public", entry.OriginalValues["IsPublic"].ToStringSafe().AsBoolean(), IsPublic); History.EvaluateChange(HistoryChangeList, "Group Capacity", entry.OriginalValues["GroupCapacity"].ToStringSafe().AsIntegerOrNull(), GroupCapacity); History.EvaluateChange(HistoryChangeList, "Archived", entry.OriginalValues["IsArchived"].ToStringSafe().AsBoolean(), this.IsArchived); // IsActive was modified, set the InactiveDateTime if it changed to Inactive, or set it to NULL if it changed to Active if (originalIsActive != this.IsActive) { if (!this.IsActive) { // if the caller didn't already set InactiveDateTime, set it to now this.InactiveDateTime = this.InactiveDateTime ?? RockDateTime.Now; } else { this.InactiveDateTime = null; } } break; } case System.Data.Entity.EntityState.Deleted: { HistoryChangeList.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, null); // manually delete any grouprequirements of this group since it can't be cascade deleted var groupRequirementService = new GroupRequirementService(rockContext); var groupRequirements = groupRequirementService.Queryable().Where(a => a.GroupId.HasValue && a.GroupId == this.Id).ToList(); if (groupRequirements.Any()) { groupRequirementService.DeleteRange(groupRequirements); } // manually set any attendance search group ids to null var attendanceService = new AttendanceService(rockContext); var attendancesToNullSearchResultGroupId = attendanceService.Queryable() .Where(a => a.SearchResultGroupId.HasValue && a.SearchResultGroupId.Value == this.Id); dbContext.BulkUpdate(attendancesToNullSearchResultGroupId, a => new Attendance { SearchResultGroupId = null }); // since we can't put a CascadeDelete on both Attendance.Occurrence.GroupId and Attendance.OccurrenceId, manually delete all Attendance records associated with this GroupId var attendancesToDelete = attendanceService.Queryable() .Where(a => a.Occurrence.GroupId.HasValue && a.Occurrence.GroupId.Value == this.Id); if (attendancesToDelete.Any()) { dbContext.BulkDelete(attendancesToDelete); } break; } } base.PreSaveChanges(dbContext, entry); }
/// <summary> /// This method stores the transaction in the database along with the appropriate details and batch information. /// </summary> private FinancialTransaction SaveTransaction(Guid transactionGuid) { // if this is a future transaction, the payment hasn't been charged yet if (_payment == null && _automatedPaymentArgs.FutureProcessingDateTime.HasValue) { _payment = new Payment { Status = "PreProcessing", StatusMessage = "This transaction is scheduled to be processed in the future", TransactionCode = _financialPersonSavedAccount.Id.ToStringSafe() }; } // Create a new transaction or update the future transaction now that it has been charged var financialTransaction = _futureTransaction ?? new FinancialTransaction(); financialTransaction.TransactionCode = _payment.TransactionCode; financialTransaction.Guid = transactionGuid; financialTransaction.CreatedByPersonAliasId = _currentPersonAliasId; financialTransaction.ScheduledTransactionId = _automatedPaymentArgs.ScheduledTransactionId; financialTransaction.AuthorizedPersonAliasId = _automatedPaymentArgs.AuthorizedPersonAliasId; financialTransaction.ShowAsAnonymous = _automatedPaymentArgs.ShowAsAnonymous; financialTransaction.TransactionDateTime = _automatedPaymentArgs.FutureProcessingDateTime.HasValue ? ( DateTime? )null : RockDateTime.Now; financialTransaction.FinancialGatewayId = _financialGateway.Id; financialTransaction.TransactionTypeValueId = _transactionType.Id; financialTransaction.Summary = string.Format("{0} {1}", financialTransaction.Summary, _referencePaymentInfo.Comment1).Trim(); financialTransaction.SourceTypeValueId = _financialSource.Id; financialTransaction.IsSettled = _payment.IsSettled; financialTransaction.Status = _payment.Status; financialTransaction.StatusMessage = _payment.StatusMessage; financialTransaction.SettledDate = _payment.SettledDate; financialTransaction.ForeignKey = _payment.ForeignKey; financialTransaction.FutureProcessingDateTime = _automatedPaymentArgs.FutureProcessingDateTime; financialTransaction.ForeignCurrencyCodeValueId = GetCurrencyCodeDefinedValueCache(_automatedPaymentArgs.AmountCurrencyCode)?.Id; // Create a new payment detail or update the future transaction's payment detail now that it has been charged var financialPaymentDetail = financialTransaction.FinancialPaymentDetail ?? new FinancialPaymentDetail(); financialPaymentDetail.AccountNumberMasked = _payment.AccountNumberMasked; financialPaymentDetail.NameOnCard = _payment.NameOnCard; financialPaymentDetail.ExpirationMonth = _payment.ExpirationMonth; financialPaymentDetail.ExpirationYear = _payment.ExpirationYear; financialPaymentDetail.CreatedByPersonAliasId = _currentPersonAliasId; financialPaymentDetail.ForeignKey = _payment.ForeignKey; financialPaymentDetail.GatewayPersonIdentifier = _financialPersonSavedAccount?.GatewayPersonIdentifier; financialPaymentDetail.FinancialPersonSavedAccountId = _financialPersonSavedAccount?.Id; if (_payment.CurrencyTypeValue != null) { financialPaymentDetail.CurrencyTypeValueId = _payment.CurrencyTypeValue.Id; } if (_payment.CreditCardTypeValue != null) { financialPaymentDetail.CreditCardTypeValueId = _payment.CreditCardTypeValue.Id; } financialPaymentDetail.SetFromPaymentInfo(_referencePaymentInfo, _automatedGatewayComponent, _rockContext); financialTransaction.FinancialPaymentDetail = financialPaymentDetail; financialTransaction.FinancialPaymentDetailId = financialPaymentDetail.Id == 0 ? ( int? )null : financialPaymentDetail.Id; // Future transactions already have the appropriate FinancialTransactionDetail models if (_futureTransaction == null) { var doesHaveForeignCurrency = financialTransaction.ForeignCurrencyCodeValueId != null; foreach (var detailArgs in _automatedPaymentArgs.AutomatedPaymentDetails) { var transactionDetail = new FinancialTransactionDetail { Amount = detailArgs.Amount, AccountId = detailArgs.AccountId }; if (doesHaveForeignCurrency) { transactionDetail.ForeignCurrencyAmount = detailArgs.Amount; } financialTransaction.TransactionDetails.Add(transactionDetail); } if (doesHaveForeignCurrency) { /* * The amount coming from the gateway is always in the Organization's currency. * As such the Amount value could be different than the original amount passed in if the * specified currency code is different then the Organization's currency code. */ financialTransaction.SetApportionedDetailAmounts(_payment.Amount); } } // New transactions and future transactions need fee info financialTransaction.SetApportionedFeesOnDetails(_payment.FeeAmount); // Get an existing or new batch according to the name prefix and payment type FinancialBatch batch; if (!financialTransaction.BatchId.HasValue) { batch = _financialBatchService.Get( _automatedPaymentArgs.BatchNamePrefix ?? "Online Giving", string.Empty, _referencePaymentInfo.CurrencyTypeValue, _referencePaymentInfo.CreditCardTypeValue, financialTransaction.TransactionDateTime ?? financialTransaction.FutureProcessingDateTime.Value, _financialGateway.GetBatchTimeOffset(), _financialGateway.BatchDayOfWeek); } else { batch = _financialBatchService.Get(financialTransaction.BatchId.Value); } var batchChanges = new History.HistoryChangeList(); var isNewBatch = batch.Id == 0; // If this is a new Batch, SaveChanges so that we can get the Batch.Id and also // add history entries about the batch creation if (isNewBatch) { batchChanges.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Batch"); History.EvaluateChange(batchChanges, "Batch Name", string.Empty, batch.Name); History.EvaluateChange(batchChanges, "Status", null, batch.Status); History.EvaluateChange(batchChanges, "Start Date/Time", null, batch.BatchStartDateTime); History.EvaluateChange(batchChanges, "End Date/Time", null, batch.BatchEndDateTime); _rockContext.SaveChanges(); } if (_futureTransaction == null) { // Use the financialTransactionService to add the transaction instead of batch.Transactions // to avoid lazy-loading the transactions already associated with the batch financialTransaction.BatchId = batch.Id; _financialTransactionService.Add(financialTransaction); } _rockContext.SaveChanges(); if (_futureTransaction == null) { // Update the batch control amount _financialBatchService.IncrementControlAmount(batch.Id, financialTransaction.TotalAmount, batchChanges); _rockContext.SaveChanges(); } // Save the changes history for the batch HistoryService.SaveChanges( _rockContext, typeof(FinancialBatch), SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), batch.Id, batchChanges ); return(financialTransaction); }
/// <summary> /// This method is called in the /// <see cref="M:Rock.Data.Model`1.PreSaveChanges(Rock.Data.DbContext,System.Data.Entity.Infrastructure.DbEntityEntry,System.Data.Entity.EntityState)" /> /// method. Use it to populate <see cref="P:Rock.Data.Model`1.HistoryItems" /> if needed. /// These history items are queued to be written into the database post save (so that they /// are only written if the save actually occurs). /// </summary> /// <param name="dbContext">The database context.</param> /// <param name="entry">The entry.</param> /// <param name="state">The state.</param> protected override void BuildHistoryItems(Data.DbContext dbContext, DbEntityEntry entry, EntityState state) { // Sometimes, especially if the model is being deleted, some properties might not be // populated, but we can query to try to get their original value. We need to use a new // rock context to get the actual value from the DB var rockContext = new RockContext(); var service = new FinancialPersonSavedAccountService(rockContext); var originalModel = service.Queryable("PersonAlias, FinancialPaymentDetail") .FirstOrDefault(fpsa => fpsa.Id == Id); // Use the original value for the person alias or the new value if that is not set var personId = (originalModel?.PersonAlias ?? PersonAlias)?.PersonId; if (!personId.HasValue) { // If this model is new, it won't have any virtual properties hydrated or an original // record in the database if (PersonAliasId.HasValue) { var personAliasService = new PersonAliasService(rockContext); var personAlias = personAliasService.Get(PersonAliasId.Value); personId = personAlias?.PersonId; } // We can't log history if we don't know who the saved account belongs to if (!personId.HasValue) { return; } } History.HistoryVerb verb; switch (state) { case EntityState.Added: verb = History.HistoryVerb.Add; break; case EntityState.Deleted: verb = History.HistoryVerb.Delete; break; default: // As of now, there is no requirement to log other events return; } var historyChangeList = new History.HistoryChangeList(); historyChangeList.AddChange(verb, History.HistoryChangeType.Record, "Financial Person Saved Account"); HistoryItems = HistoryService.GetChanges( typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON.AsGuid(), personId.Value, historyChangeList, GetNameForHistory(originalModel?.FinancialPaymentDetail ?? FinancialPaymentDetail), typeof(FinancialPersonSavedAccount), Id, dbContext.GetCurrentPersonAlias()?.Id, dbContext.SourceOfChange); }
public void AddConnectionStatusChangeHistoryTestData() { this.RemoveConnectionStatusChangeHistoryTestData(); var dataContext = new RockContext(); this.ThrowIfTestHistoryDataExists(dataContext, _TestDataSourceOfChange); var memberConnectionStatusId = GetStatusValueIdOrThrow("Member"); var attenderConnectionStatusId = GetStatusValueIdOrThrow("Attendee"); var visitorConnectionStatusId = GetStatusValueIdOrThrow("Visitor"); var prospectConnectionStatusId = GetStatusValueIdOrThrow("Web Prospect"); var personService = new PersonService(dataContext); var personList = personService.Queryable() .AsNoTracking() .Where(x => !x.IsSystem) .Take(_BulkHistoryMaxPeople) .ToList(); var currentDate = _BulkHistoryEndDate; var rng = new Random(); var adminPerson = this.GetAdminPersonOrThrow(personService); // Create new change history entries for each person. int entriesAdded = 0; History.HistoryChange historyEntry; foreach (var person in personList) { var historyChanges = new History.HistoryChangeList(); var dateOfChange = currentDate; if (person.ConnectionStatusValueId == memberConnectionStatusId) { // For each Person who has a Connection Status of Member, add prior change events for Visitor --> Attendee --> Member. // Add a change for Attendee --> Member. dateOfChange = dateOfChange.AddDays(rng.Next(1, 365) * -1); historyEntry = historyChanges.AddChange(History.HistoryVerb.Modify, History.HistoryChangeType.Property, "Connection Status") .SetOldValue("Attendee") .SetNewValue("Member") .SetRawValues(attenderConnectionStatusId.ToString(), memberConnectionStatusId.ToString()) .SetDateOfChange(dateOfChange) .SetSourceOfChange(_TestDataSourceOfChange); // Add a change for Visitor --> Attendee. // This change record has only the OldValue and NewValue, compatible with records created prior to Rock v1.8 dateOfChange = dateOfChange.AddDays(rng.Next(1, 365) * -1); historyEntry = historyChanges.AddChange(History.HistoryVerb.Modify, History.HistoryChangeType.Property, "Connection Status") .SetOldValue("Visitor") .SetNewValue("Attendee") .SetDateOfChange(dateOfChange) .SetSourceOfChange(_TestDataSourceOfChange); entriesAdded += 2; } else if (person.ConnectionStatusValueId == visitorConnectionStatusId) { // For each Person who has a Connection Status of Visitor, add prior change events for Web Prospect --> Visitor. dateOfChange = dateOfChange.AddDays(rng.Next(1, 365) * -1); historyEntry = historyChanges.AddChange(History.HistoryVerb.Modify, History.HistoryChangeType.Property, "Connection Status") .SetOldValue("Web Prospect") .SetNewValue("Visitor") .SetRawValues(prospectConnectionStatusId.ToString(), visitorConnectionStatusId.ToString()) .SetDateOfChange(dateOfChange) .SetSourceOfChange(_TestDataSourceOfChange); entriesAdded += 1; } Debug.Print($"Processed History Entries... [PersonId={person.Id}, Date={dateOfChange}]"); HistoryService.SaveChanges(dataContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_DEMOGRAPHIC_CHANGES.AsGuid(), person.Id, historyChanges, true, adminPerson.PrimaryAliasId, _TestDataSourceOfChange); } Debug.Print($"Create Data completed: { entriesAdded } history entries created."); Assert.IsTrue(entriesAdded > 0, "No history entries created."); }
/// <summary> /// Process a refund for a transaction. /// </summary> /// <param name="transaction">The refund transaction.</param> /// <param name="amount">The amount.</param> /// <param name="reasonValueId">The reason value identifier.</param> /// <param name="summary">The summary.</param> /// <param name="process">if set to <c>true</c> [process].</param> /// <param name="batchNameSuffix">The batch name suffix.</param> /// <param name="errorMessage">The error message.</param> /// <returns></returns> public FinancialTransaction ProcessRefund(FinancialTransaction transaction, decimal?amount, int?reasonValueId, string summary, bool process, string batchNameSuffix, out string errorMessage) { errorMessage = string.Empty; // Validate parameters if (transaction == null) { errorMessage = "A valid transaction is required"; return(null); } if (transaction.Batch == null) { errorMessage = "Transaction must belong to a batch"; return(null); } if (!amount.HasValue || amount.Value <= 0.0m) { amount = transaction.TotalAmount; } if (!amount.HasValue || amount.Value <= 0.0m) { errorMessage = string.Format("Amount must be greater than {0}", 0.0m.FormatAsCurrency()); return(null); } FinancialTransaction refundTransaction = null; // If processing the refund through gateway, get the gateway component and process a "Credit" transaction. if (process) { if (transaction.FinancialGateway == null || transaction.TransactionCode.IsNullOrWhiteSpace()) { errorMessage = "When processing the refund through the Gateway, the transaction must have a valid Gateway and Transaction Code"; return(null); } var gatewayComponent = transaction.FinancialGateway.GetGatewayComponent(); if (gatewayComponent == null) { errorMessage = "Could not get the Gateway component in order to process the refund"; return(null); } refundTransaction = gatewayComponent.Credit(transaction, amount.Value, summary, out errorMessage); if (refundTransaction == null) { return(null); } } else { refundTransaction = new FinancialTransaction(); } refundTransaction.AuthorizedPersonAliasId = transaction.AuthorizedPersonAliasId; refundTransaction.TransactionDateTime = RockDateTime.Now; refundTransaction.FinancialGatewayId = transaction.FinancialGatewayId; refundTransaction.TransactionTypeValueId = transaction.TransactionTypeValueId; refundTransaction.SourceTypeValueId = transaction.SourceTypeValueId; if (transaction.FinancialPaymentDetail != null) { refundTransaction.FinancialPaymentDetail = new FinancialPaymentDetail(); refundTransaction.FinancialPaymentDetail.AccountNumberMasked = transaction.FinancialPaymentDetail.AccountNumberMasked; refundTransaction.FinancialPaymentDetail.BillingLocationId = transaction.FinancialPaymentDetail.BillingLocationId; refundTransaction.FinancialPaymentDetail.CreditCardTypeValueId = transaction.FinancialPaymentDetail.CreditCardTypeValueId; refundTransaction.FinancialPaymentDetail.CurrencyTypeValueId = transaction.FinancialPaymentDetail.CurrencyTypeValueId; refundTransaction.FinancialPaymentDetail.ExpirationMonthEncrypted = transaction.FinancialPaymentDetail.ExpirationMonthEncrypted; refundTransaction.FinancialPaymentDetail.ExpirationYearEncrypted = transaction.FinancialPaymentDetail.ExpirationYearEncrypted; refundTransaction.FinancialPaymentDetail.NameOnCardEncrypted = transaction.FinancialPaymentDetail.NameOnCardEncrypted; } decimal remainingBalance = amount.Value; foreach (var account in transaction.TransactionDetails.Where(a => a.Amount > 0)) { var transactionDetail = new FinancialTransactionDetail(); transactionDetail.AccountId = account.AccountId; transactionDetail.EntityId = account.EntityId; transactionDetail.EntityTypeId = account.EntityTypeId; refundTransaction.TransactionDetails.Add(transactionDetail); if (remainingBalance >= account.Amount) { transactionDetail.Amount = 0 - account.Amount; remainingBalance -= account.Amount; } else { transactionDetail.Amount = 0 - remainingBalance; remainingBalance = 0.0m; } if (remainingBalance <= 0.0m) { break; } } if (remainingBalance > 0 && refundTransaction.TransactionDetails.Any()) { refundTransaction.TransactionDetails.Last().Amount += remainingBalance; } var rockContext = this.Context as Rock.Data.RockContext; var registrationEntityType = EntityTypeCache.Get(typeof(Rock.Model.Registration)); if (registrationEntityType != null) { foreach (var transactionDetail in refundTransaction.TransactionDetails .Where(d => d.EntityTypeId.HasValue && d.EntityTypeId.Value == registrationEntityType.Id && d.EntityId.HasValue)) { var registrationChanges = new History.HistoryChangeList(); registrationChanges.AddChange(History.HistoryVerb.Process, History.HistoryChangeType.Record, $"{transactionDetail.Amount.FormatAsCurrency()} Refund"); HistoryService.SaveChanges( rockContext, typeof(Registration), Rock.SystemGuid.Category.HISTORY_EVENT_REGISTRATION.AsGuid(), transactionDetail.EntityId.Value, registrationChanges ); } } refundTransaction.RefundDetails = new FinancialTransactionRefund(); refundTransaction.RefundDetails.RefundReasonValueId = reasonValueId; refundTransaction.RefundDetails.RefundReasonSummary = summary; refundTransaction.RefundDetails.OriginalTransactionId = transaction.Id; string batchName = transaction.Batch.Name; if (batchNameSuffix.IsNotNullOrWhiteSpace() && !batchName.EndsWith(batchNameSuffix)) { batchName += batchNameSuffix; } // Get the batch var batchService = new FinancialBatchService(rockContext); TimeSpan timespan = new TimeSpan(); if (transaction.FinancialGateway != null) { timespan = transaction.FinancialGateway.GetBatchTimeOffset(); } var batch = batchService.GetByNameAndDate(batchName, refundTransaction.TransactionDateTime.Value, timespan); // If this is a new Batch, SaveChanges so that we can get the Batch.Id if (batch.Id == 0) { rockContext.SaveChanges(); } refundTransaction.BatchId = batch.Id; Add(refundTransaction); rockContext.SaveChanges(); batchService.IncrementControlAmount(batch.Id, refundTransaction.TotalAmount, null); rockContext.SaveChanges(); return(refundTransaction); }
/// <summary> /// Handles the Click event of the btnSave 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 btnSave_Click(object sender, EventArgs e) { if (RegistrantState != null) { RockContext rockContext = new RockContext(); var personService = new PersonService(rockContext); var registrantService = new RegistrationRegistrantService(rockContext); var registrantFeeService = new RegistrationRegistrantFeeService(rockContext); var registrationTemplateFeeService = new RegistrationTemplateFeeService(rockContext); var registrationTemplateFeeItemService = new RegistrationTemplateFeeItemService(rockContext); RegistrationRegistrant registrant = null; if (RegistrantState.Id > 0) { registrant = registrantService.Get(RegistrantState.Id); } var previousRegistrantPersonIds = registrantService.Queryable().Where(a => a.RegistrationId == RegistrantState.RegistrationId) .Where(r => r.PersonAlias != null) .Select(r => r.PersonAlias.PersonId) .ToList(); bool newRegistrant = false; var registrantChanges = new History.HistoryChangeList(); if (registrant == null) { newRegistrant = true; registrant = new RegistrationRegistrant(); registrant.RegistrationId = RegistrantState.RegistrationId; registrantService.Add(registrant); registrantChanges.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Registrant"); } if (!registrant.PersonAliasId.Equals(ppPerson.PersonAliasId)) { string prevPerson = (registrant.PersonAlias != null && registrant.PersonAlias.Person != null) ? registrant.PersonAlias.Person.FullName : string.Empty; string newPerson = ppPerson.PersonName; newRegistrant = true; History.EvaluateChange(registrantChanges, "Person", prevPerson, newPerson); } int?personId = ppPerson.PersonId.Value; registrant.PersonAliasId = ppPerson.PersonAliasId.Value; // Get the name of registrant for history string registrantName = "Unknown"; if (ppPerson.PersonId.HasValue) { var person = personService.Get(ppPerson.PersonId.Value); if (person != null) { registrantName = person.FullName; } } // set their status (wait list / registrant) registrant.OnWaitList = !tglWaitList.Checked; History.EvaluateChange(registrantChanges, "Cost", registrant.Cost, cbCost.Text.AsDecimal()); registrant.Cost = cbCost.Text.AsDecimal(); History.EvaluateChange(registrantChanges, "Discount Applies", registrant.DiscountApplies, cbDiscountApplies.Checked); registrant.DiscountApplies = cbDiscountApplies.Checked; if (!Page.IsValid) { return; } // Remove/delete any registrant fees that are no longer in UI with quantity foreach (var dbFee in registrant.Fees.ToList()) { if (!RegistrantState.FeeValues.Keys.Contains(dbFee.RegistrationTemplateFeeId) || RegistrantState.FeeValues[dbFee.RegistrationTemplateFeeId] == null || !RegistrantState.FeeValues[dbFee.RegistrationTemplateFeeId] .Any(f => f.RegistrationTemplateFeeItemId == dbFee.RegistrationTemplateFeeItemId && f.Quantity > 0)) { var feeOldValue = string.Format("'{0}' Fee (Quantity:{1:N0}, Cost:{2:C2}, Option:{3}", dbFee.RegistrationTemplateFee.Name, dbFee.Quantity, dbFee.Cost, dbFee.Option); registrantChanges.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "Fee").SetOldValue(feeOldValue); registrant.Fees.Remove(dbFee); registrantFeeService.Delete(dbFee); } } // Add/Update any of the fees from UI foreach (var uiFee in RegistrantState.FeeValues.Where(f => f.Value != null)) { foreach (var uiFeeOption in uiFee.Value) { var dbFee = registrant.Fees .Where(f => f.RegistrationTemplateFeeId == uiFee.Key && f.RegistrationTemplateFeeItemId == uiFeeOption.RegistrationTemplateFeeItemId) .FirstOrDefault(); if (dbFee == null) { dbFee = new RegistrationRegistrantFee(); dbFee.RegistrationTemplateFeeId = uiFee.Key; var registrationTemplateFeeItem = uiFeeOption.RegistrationTemplateFeeItemId != null?registrationTemplateFeeItemService.GetNoTracking(uiFeeOption.RegistrationTemplateFeeItemId.Value) : null; if (registrationTemplateFeeItem != null) { dbFee.Option = registrationTemplateFeeItem.Name; } dbFee.RegistrationTemplateFeeItemId = uiFeeOption.RegistrationTemplateFeeItemId; registrant.Fees.Add(dbFee); } var templateFee = dbFee.RegistrationTemplateFee; if (templateFee == null) { templateFee = registrationTemplateFeeService.Get(uiFee.Key); } string feeName = templateFee != null ? templateFee.Name : "Fee"; if (!string.IsNullOrWhiteSpace(uiFeeOption.FeeLabel)) { feeName = string.Format("{0} ({1})", feeName, uiFeeOption.FeeLabel); } if (dbFee.Id <= 0) { registrantChanges.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Fee").SetNewValue(feeName); } History.EvaluateChange(registrantChanges, feeName + " Quantity", dbFee.Quantity, uiFeeOption.Quantity); dbFee.Quantity = uiFeeOption.Quantity; History.EvaluateChange(registrantChanges, feeName + " Cost", dbFee.Cost, uiFeeOption.Cost); dbFee.Cost = uiFeeOption.Cost; } } if (this.RegistrationTemplate.RequiredSignatureDocumentTemplate != null) { var person = new PersonService(rockContext).Get(personId.Value); var documentService = new SignatureDocumentService(rockContext); var binaryFileService = new BinaryFileService(rockContext); SignatureDocument document = null; int?signatureDocumentId = hfSignedDocumentId.Value.AsIntegerOrNull(); int?binaryFileId = fuSignedDocument.BinaryFileId; if (signatureDocumentId.HasValue) { document = documentService.Get(signatureDocumentId.Value); } if (document == null && binaryFileId.HasValue) { var instance = new RegistrationInstanceService(rockContext).Get(RegistrationInstanceId); document = new SignatureDocument(); document.SignatureDocumentTemplateId = this.RegistrationTemplate.RequiredSignatureDocumentTemplate.Id; document.AppliesToPersonAliasId = registrant.PersonAliasId.Value; document.AssignedToPersonAliasId = registrant.PersonAliasId.Value; document.Name = string.Format( "{0}_{1}", instance != null ? instance.Name : this.RegistrationTemplate.Name, person != null ? person.FullName.RemoveSpecialCharacters() : string.Empty); document.Status = SignatureDocumentStatus.Signed; document.LastStatusDate = RockDateTime.Now; documentService.Add(document); } if (document != null) { int?origBinaryFileId = document.BinaryFileId; document.BinaryFileId = binaryFileId; if (origBinaryFileId.HasValue && origBinaryFileId.Value != document.BinaryFileId) { // if a new the binaryFile was uploaded, mark the old one as Temporary so that it gets cleaned up var oldBinaryFile = binaryFileService.Get(origBinaryFileId.Value); if (oldBinaryFile != null && !oldBinaryFile.IsTemporary) { oldBinaryFile.IsTemporary = true; } } // ensure the IsTemporary is set to false on binaryFile associated with this document if (document.BinaryFileId.HasValue) { var binaryFile = binaryFileService.Get(document.BinaryFileId.Value); if (binaryFile != null && binaryFile.IsTemporary) { binaryFile.IsTemporary = false; } } } } if (!registrant.IsValid) { // Controls will render the error messages return; } // use WrapTransaction since SaveAttributeValues does it's own RockContext.SaveChanges() rockContext.WrapTransaction(() => { rockContext.SaveChanges(); registrant.LoadAttributes(); // NOTE: We will only have Registration Attributes displayed and editable on Registrant Detail. // To Edit Person or GroupMember Attributes, they will have to go the PersonDetail or GroupMemberDetail blocks foreach (var field in this.RegistrationTemplate.Forms .SelectMany(f => f.Fields .Where(t => t.FieldSource == RegistrationFieldSource.RegistrantAttribute && t.AttributeId.HasValue))) { var attribute = AttributeCache.Get(field.AttributeId.Value); if (attribute != null) { string originalValue = registrant.GetAttributeValue(attribute.Key); var fieldValue = RegistrantState.FieldValues .Where(f => f.Key == field.Id) .Select(f => f.Value.FieldValue) .FirstOrDefault(); string newValue = fieldValue != null ? fieldValue.ToString() : string.Empty; if ((originalValue ?? string.Empty).Trim() != (newValue ?? string.Empty).Trim()) { string formattedOriginalValue = string.Empty; if (!string.IsNullOrWhiteSpace(originalValue)) { formattedOriginalValue = attribute.FieldType.Field.FormatValue(null, originalValue, attribute.QualifierValues, false); } string formattedNewValue = string.Empty; if (!string.IsNullOrWhiteSpace(newValue)) { formattedNewValue = attribute.FieldType.Field.FormatValue(null, newValue, attribute.QualifierValues, false); } History.EvaluateChange(registrantChanges, attribute.Name, formattedOriginalValue, formattedNewValue); } if (fieldValue != null) { registrant.SetAttributeValue(attribute.Key, fieldValue.ToString()); } } } registrant.SaveAttributeValues(rockContext); }); if (newRegistrant && this.RegistrationTemplate.GroupTypeId.HasValue && ppPerson.PersonId.HasValue) { using (var newRockContext = new RockContext()) { var reloadedRegistrant = new RegistrationRegistrantService(newRockContext).Get(registrant.Id); if (reloadedRegistrant != null && reloadedRegistrant.Registration != null && reloadedRegistrant.Registration.Group != null && reloadedRegistrant.Registration.Group.GroupTypeId == this.RegistrationTemplate.GroupTypeId.Value) { int?groupRoleId = this.RegistrationTemplate.GroupMemberRoleId.HasValue ? this.RegistrationTemplate.GroupMemberRoleId.Value : reloadedRegistrant.Registration.Group.GroupType.DefaultGroupRoleId; if (groupRoleId.HasValue) { var groupMemberService = new GroupMemberService(newRockContext); var groupMember = groupMemberService .Queryable().AsNoTracking() .Where(m => m.GroupId == reloadedRegistrant.Registration.Group.Id && m.PersonId == reloadedRegistrant.PersonId && m.GroupRoleId == groupRoleId.Value) .FirstOrDefault(); if (groupMember == null) { groupMember = new GroupMember(); groupMember.GroupId = reloadedRegistrant.Registration.Group.Id; groupMember.PersonId = ppPerson.PersonId.Value; groupMember.GroupRoleId = groupRoleId.Value; groupMember.GroupMemberStatus = this.RegistrationTemplate.GroupMemberStatus; groupMemberService.Add(groupMember); newRockContext.SaveChanges(); registrantChanges.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, string.Format("Registrant to {0} group", reloadedRegistrant.Registration.Group.Name)); } else { registrantChanges.AddChange(History.HistoryVerb.Modify, History.HistoryChangeType.Record, string.Format("Registrant to existing person in {0} group", reloadedRegistrant.Registration.Group.Name)); } if (reloadedRegistrant.GroupMemberId.HasValue && reloadedRegistrant.GroupMemberId.Value != groupMember.Id) { groupMemberService.Delete(reloadedRegistrant.GroupMember); newRockContext.SaveChanges(); registrantChanges.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, string.Format("Registrant to previous person in {0} group", reloadedRegistrant.Registration.Group.Name)); } // Record this to the Person's and Registrants Notes and History... reloadedRegistrant.GroupMemberId = groupMember.Id; } } if (reloadedRegistrant.Registration.FirstName.IsNotNullOrWhiteSpace() && reloadedRegistrant.Registration.LastName.IsNotNullOrWhiteSpace()) { reloadedRegistrant.Registration.SavePersonNotesAndHistory(reloadedRegistrant.Registration.FirstName, reloadedRegistrant.Registration.LastName, this.CurrentPersonAliasId, previousRegistrantPersonIds); } newRockContext.SaveChanges(); } } HistoryService.SaveChanges( rockContext, typeof(Registration), Rock.SystemGuid.Category.HISTORY_EVENT_REGISTRATION.AsGuid(), registrant.RegistrationId, registrantChanges, "Registrant: " + registrantName, null, null); } NavigateToRegistration(); }
/// <summary> /// This method is called in the /// <see cref="M:Rock.Data.Model`1.PreSaveChanges(Rock.Data.DbContext,System.Data.Entity.Infrastructure.DbEntityEntry,System.Data.Entity.EntityState)" /> /// method. Use it to populate <see cref="P:Rock.Data.Model`1.HistoryItems" /> if needed. /// These history items are queued to be written into the database post save (so that they /// are only written if the save actually occurs). /// </summary> /// <param name="dbContext">The database context.</param> /// <param name="entry">The entry.</param> /// <param name="state">The state.</param> protected override void BuildHistoryItems(Data.DbContext dbContext, DbEntityEntry entry, EntityState state) { /* * 12/18/2019 BJW * * We want to log the history of attribute values within a person matrix. Most of this logging occurs from * the attribute value model. However, when a matrix item (row in the table) is deleted, the pre-save event * of the attribute values is not called. Therefore, the delete event needs to be logged here. Additionally, * when the matrix item is added, the history is much cleaner when added here so that all the values of the * row are consolidated to one history item. Modified state is not possible to log here because the * matrix item is not actually modified when its attributes change. * * Task: https://app.asana.com/0/1120115219297347/1136643182208595/f */ if (state != EntityState.Deleted && state != EntityState.Added) { return; } var rockContext = new RockContext(); var matrixId = AttributeMatrixId != default ? AttributeMatrixId : entry.OriginalValues["AttributeMatrixId"].ToStringSafe().AsIntegerOrNull(); var matrix = AttributeMatrix; if (matrix == null && matrixId.HasValue) { var matrixService = new AttributeMatrixService(rockContext); matrix = matrixService.Queryable().AsNoTracking().FirstOrDefault(am => am.Id == matrixId); } if (matrix == null) { return; } // The root attribute matrix attribute value is linked to the matrix by the guid as the attribute value var matrixGuidString = matrix.Guid.ToString(); var personEntityTypeId = EntityTypeCache.Get(typeof(Person)).Id; var attributeValueService = new AttributeValueService(rockContext); var rootAttributeValue = attributeValueService.Queryable().AsNoTracking().FirstOrDefault(av => av.Value.Equals(matrixGuidString, System.StringComparison.OrdinalIgnoreCase) && av.Attribute.EntityTypeId == personEntityTypeId ); if (rootAttributeValue?.EntityId == null) { return; } var rootAttributeCache = AttributeCache.Get(rootAttributeValue.AttributeId); if (rootAttributeCache == null) { return; } // Evaluate the history changes var historyChangeList = new History.HistoryChangeList(); if (AttributeValues == null || !AttributeValues.Any()) { this.LoadAttributes(); } var isDelete = state == EntityState.Deleted; foreach (var attributeValue in AttributeValues.Values) { var attributeCache = AttributeCache.Get(attributeValue.AttributeId); var formattedOldValue = isDelete ? GetHistoryFormattedValue(attributeValue.Value, attributeCache) : string.Empty; var formattedNewValue = isDelete ? string.Empty : GetHistoryFormattedValue(attributeValue.Value, attributeCache); History.EvaluateChange(historyChangeList, attributeCache.Name, formattedOldValue, formattedNewValue, attributeCache.FieldType.Field.IsSensitive()); } if (!historyChangeList.Any()) { historyChangeList.AddChange( isDelete ? History.HistoryVerb.Delete : History.HistoryVerb.Add, History.HistoryChangeType.Record, $"{rootAttributeCache.Name} Item"); } HistoryItems = HistoryService.GetChanges( typeof(Person), SystemGuid.Category.HISTORY_PERSON_DEMOGRAPHIC_CHANGES.AsGuid(), rootAttributeValue.EntityId.Value, historyChangeList, rootAttributeCache.Name, typeof(Attribute), rootAttributeCache.Id, dbContext.GetCurrentPersonAlias()?.Id, dbContext.SourceOfChange); }
/// <summary> /// Sends the specified communication. /// </summary>Medi /// <param name="communication">The communication.</param> /// <param name="mediumEntityTypeId">The medium entity type identifier.</param> /// <param name="mediumAttributes">The medium attributes.</param> public override void Send(Rock.Model.Communication communication, int mediumEntityTypeId, Dictionary <string, string> mediumAttributes) { using (var communicationRockContext = new RockContext()) { // Requery the Communication communication = new CommunicationService(communicationRockContext) .Queryable() .Include(a => a.CreatedByPersonAlias.Person) .Include(a => a.CommunicationTemplate) .FirstOrDefault(c => c.Id == communication.Id); bool hasPendingRecipients; if (communication != null && communication.Status == Model.CommunicationStatus.Approved && (!communication.FutureSendDateTime.HasValue || communication.FutureSendDateTime.Value.CompareTo(RockDateTime.Now) <= 0)) { var qryRecipients = new CommunicationRecipientService(communicationRockContext).Queryable(); hasPendingRecipients = qryRecipients .Where(r => r.CommunicationId == communication.Id && r.Status == Model.CommunicationRecipientStatus.Pending && r.MediumEntityTypeId.HasValue && r.MediumEntityTypeId.Value == mediumEntityTypeId) .Any(); } else { hasPendingRecipients = false; } if (!hasPendingRecipients) { return; } var currentPerson = communication.CreatedByPersonAlias?.Person; var globalAttributes = GlobalAttributesCache.Get(); string publicAppRoot = globalAttributes.GetValue("PublicApplicationRoot").EnsureTrailingForwardslash(); var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null, currentPerson); var cssInliningEnabled = communication.CommunicationTemplate?.CssInliningEnabled ?? false; string fromAddress = communication.FromEmail; string fromName = communication.FromName; // Resolve any possible merge fields in the from address fromAddress = fromAddress.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands); fromName = fromName.ResolveMergeFields(mergeFields, currentPerson, communication.EnabledLavaCommands); // From - if none is set, use the one in the Organization's GlobalAttributes. if (string.IsNullOrWhiteSpace(fromAddress)) { fromAddress = globalAttributes.GetValue("OrganizationEmail"); } if (string.IsNullOrWhiteSpace(fromName)) { fromName = globalAttributes.GetValue("OrganizationName"); } MailMessage message = new MailMessage(); // Reply To try { string replyTo = communication.ReplyToEmail; if (!string.IsNullOrWhiteSpace(replyTo)) { // Resolve any possible merge fields in the replyTo address message.ReplyToList.Add(new MailAddress(replyTo.ResolveMergeFields(mergeFields, currentPerson))); } } catch { } message.IsBodyHtml = true; message.Priority = MailPriority.Normal; using (var smtpClient = GetSmtpClient()) { var personEntityTypeId = EntityTypeCache.Get("Rock.Model.Person").Id; var communicationEntityTypeId = EntityTypeCache.Get("Rock.Model.Communication").Id; var communicationCategoryGuid = Rock.SystemGuid.Category.HISTORY_PERSON_COMMUNICATIONS.AsGuid(); bool recipientFound = true; while (recipientFound) { // make a new rockContext per recipient var recipientRockContext = new RockContext(); var recipient = Rock.Model.Communication.GetNextPending(communication.Id, mediumEntityTypeId, recipientRockContext); if (recipient != null) { if (ValidRecipient(recipient, communication.IsBulkCommunication)) { try { message.To.Clear(); message.CC.Clear(); message.Bcc.Clear(); message.Headers.Clear(); message.AlternateViews.Clear(); // Set From/To and check safe sender message.From = new MailAddress(fromAddress, fromName); message.To.Add(new MailAddress(recipient.PersonAlias.Person.Email, recipient.PersonAlias.Person.FullName)); CheckSafeSender(message, globalAttributes); // Create merge field dictionary var mergeObjects = recipient.CommunicationMergeValues(mergeFields); // CC string cc = communication.CCEmails; if (!string.IsNullOrWhiteSpace(cc)) { // Resolve any possible merge fields in the cc address cc = cc.ResolveMergeFields(mergeObjects, currentPerson); foreach (string ccRecipient in cc.SplitDelimitedValues()) { message.CC.Add(new MailAddress(ccRecipient)); } } // BCC string bcc = communication.BCCEmails; if (!string.IsNullOrWhiteSpace(bcc)) { bcc = bcc.ResolveMergeFields(mergeObjects, currentPerson); foreach (string bccRecipient in bcc.SplitDelimitedValues()) { // Resolve any possible merge fields in the bcc address message.Bcc.Add(new MailAddress(bccRecipient)); } } // Subject message.Subject = ResolveText(communication.Subject, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); // Plain text if (mediumAttributes.ContainsKey("DefaultPlainText")) { string plainText = ResolveText(mediumAttributes["DefaultPlainText"], currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); if (!string.IsNullOrWhiteSpace(plainText)) { AlternateView plainTextView = AlternateView.CreateAlternateViewFromString(plainText, new System.Net.Mime.ContentType(MediaTypeNames.Text.Plain)); message.AlternateViews.Add(plainTextView); } } // Add Html view // Get the unsubscribe content and add a merge field for it string htmlBody = communication.Message; if (communication.IsBulkCommunication && mediumAttributes.ContainsKey("UnsubscribeHTML")) { string unsubscribeHtml = ResolveText(mediumAttributes["UnsubscribeHTML"], currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); mergeObjects.AddOrReplace("UnsubscribeOption", unsubscribeHtml); htmlBody = ResolveText(htmlBody, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); // Resolve special syntax needed if option was included in global attribute if (Regex.IsMatch(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]")) { htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", unsubscribeHtml); } // Add the unsubscribe option at end if it wasn't included in content if (!htmlBody.Contains(unsubscribeHtml)) { htmlBody += unsubscribeHtml; } } else { htmlBody = ResolveText(htmlBody, currentPerson, communication.EnabledLavaCommands, mergeObjects, publicAppRoot); htmlBody = Regex.Replace(htmlBody, @"\[\[\s*UnsubscribeOption\s*\]\]", string.Empty); } if (!string.IsNullOrWhiteSpace(htmlBody)) { if (cssInliningEnabled) { // move styles inline to help it be compatible with more email clients htmlBody = htmlBody.ConvertHtmlStylesToInlineAttributes(); } // add the main Html content to the email AlternateView htmlView = AlternateView.CreateAlternateViewFromString(htmlBody, new System.Net.Mime.ContentType(MediaTypeNames.Text.Html)); message.AlternateViews.Add(htmlView); } // Add any additional headers that specific SMTP provider needs var metaData = new Dictionary <string, string>(); metaData.Add("communication_recipient_guid", recipient.Guid.ToString()); AddAdditionalHeaders(message, metaData); // Recreate the attachments message.Attachments.Clear(); foreach (var binaryFile in communication.GetAttachments(CommunicationType.Email).Select(a => a.BinaryFile)) { message.Attachments.Add(new Attachment(binaryFile.ContentStream, binaryFile.FileName)); } smtpClient.Send(message); recipient.Status = CommunicationRecipientStatus.Delivered; string statusNote = StatusNote; if (!string.IsNullOrWhiteSpace(statusNote)) { recipient.StatusNote = statusNote; } recipient.TransportEntityTypeName = this.GetType().FullName; try { var historyChangeList = new History.HistoryChangeList(); historyChangeList.AddChange( History.HistoryVerb.Sent, History.HistoryChangeType.Record, $"Communication") .SetRelatedData(message.From.DisplayName, communicationEntityTypeId, communication.Id) .SetCaption(message.Subject); HistoryService.SaveChanges(recipientRockContext, typeof(Rock.Model.Person), communicationCategoryGuid, recipient.PersonAlias.PersonId, historyChangeList, false, communication.SenderPersonAliasId); } catch (Exception ex) { ExceptionLogService.LogException(ex, null); } } catch (Exception ex) { ExceptionLogService.LogException(ex); recipient.Status = CommunicationRecipientStatus.Failed; recipient.StatusNote = "Exception: " + ex.Messages().AsDelimited(" => "); } } recipientRockContext.SaveChanges(); } else { recipientFound = false; } } } } }
/// <summary> /// Handles the Swipe event of the csPayWithCard control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="SwipeEventArgs"/> instance containing the event data.</param> protected void csPayWithCard_Swipe(object sender, SwipeEventArgs e) { using (var rockContext = new RockContext()) { try { var swipeInfo = e.PaymentInfo; var person = Customer; if (person == null) { person = new PersonAliasService(rockContext).GetPerson(GetAttributeValue("GuestCustomer").AsGuid()); if (person == null) { nbSwipeErrors.Text = "No guest customer configured. Transaction not processed."; return; } } // // Get the gateway to use. // FinancialGateway financialGateway = null; GatewayComponent gateway = null; Guid? gatewayGuid = GetAttributeValue("CreditCardGateway").AsGuidOrNull(); if (gatewayGuid.HasValue) { financialGateway = new FinancialGatewayService(rockContext).Get(gatewayGuid.Value); if (financialGateway != null) { financialGateway.LoadAttributes(rockContext); } gateway = financialGateway.GetGatewayComponent(); } if (gateway == null) { nbSwipeErrors.Text = "Invalid gateway provided. Please provide a gateway. Transaction not processed."; return; } swipeInfo.Amount = Cart.Total; // // Process the transaction. // string errorMessage = string.Empty; var transaction = gateway.Charge(financialGateway, swipeInfo, out errorMessage); if (transaction == null) { nbSwipeErrors.Text = String.Format("An error occurred while process this transaction. Message: {0}", errorMessage); return; } // // Set some common information about the transaction. // transaction.AuthorizedPersonAliasId = person.PrimaryAliasId; transaction.TransactionDateTime = RockDateTime.Now; transaction.FinancialGatewayId = financialGateway.Id; transaction.TransactionTypeValueId = DefinedValueCache.Get(GetAttributeValue("TransactionType")).Id; transaction.SourceTypeValueId = DefinedValueCache.Get(GetAttributeValue("Source")).Id; transaction.Summary = swipeInfo.Comment1; // // Ensure we have payment details. // if (transaction.FinancialPaymentDetail == null) { transaction.FinancialPaymentDetail = new FinancialPaymentDetail(); } transaction.FinancialPaymentDetail.SetFromPaymentInfo(swipeInfo, gateway, rockContext); // // Setup the transaction details to credit the correct account. // GetTransactionDetails(rockContext).ForEach(d => transaction.TransactionDetails.Add(d)); var batchService = new FinancialBatchService(rockContext); // // Get the batch // var batch = batchService.Get( GetAttributeValue("BatchNamePrefix"), swipeInfo.CurrencyTypeValue, swipeInfo.CreditCardTypeValue, transaction.TransactionDateTime.Value, financialGateway.GetBatchTimeOffset()); var batchChanges = new History.HistoryChangeList(); if (batch.Id == 0) { batchChanges.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Batch"); History.EvaluateChange(batchChanges, "Batch Name", string.Empty, batch.Name); History.EvaluateChange(batchChanges, "Status", null, batch.Status); History.EvaluateChange(batchChanges, "Start Date/Time", null, batch.BatchStartDateTime); History.EvaluateChange(batchChanges, "End Date/Time", null, batch.BatchEndDateTime); } // // Update the control amount. // decimal newControlAmount = batch.ControlAmount + transaction.TotalAmount; History.EvaluateChange(batchChanges, "Control Amount", batch.ControlAmount.FormatAsCurrency(), newControlAmount.FormatAsCurrency()); batch.ControlAmount = newControlAmount; // // Add the transaction to the batch. // transaction.BatchId = batch.Id; batch.Transactions.Add(transaction); // // Generate the receipt. // int receiptId; using (var rockContext2 = new RockContext()) { var receipt = GenerateReceipt(rockContext2); receiptId = receipt.Id; } // // Update each transaction detail to reference the receipt. // foreach (var transactionDetail in transaction.TransactionDetails) { transactionDetail.EntityTypeId = EntityTypeCache.Get(typeof(InteractionComponent)).Id; transactionDetail.EntityId = receiptId; } rockContext.WrapTransaction(() => { rockContext.SaveChanges(); HistoryService.SaveChanges( rockContext, typeof(FinancialBatch), Rock.SystemGuid.Category.HISTORY_FINANCIAL_BATCH.AsGuid(), batch.Id, batchChanges ); }); ShowReceiptPanel(); } catch (Exception ex) { nbSwipeErrors.Text = String.Format("An error occurred while process this transaction. Message: {0}", ex.Message); } } }
/// <summary> /// Executes the specified workflow. /// </summary> /// <param name="rockContext">The rock context.</param> /// <param name="action">The action.</param> /// <param name="entity">The entity.</param> /// <param name="errorMessages">The error messages.</param> /// <returns></returns> public override bool Execute(RockContext rockContext, WorkflowAction action, Object entity, out List <string> errorMessages) { errorMessages = new List <string>(); // get person Person person = null; string personAttributeValue = GetAttributeValue(action, "Person"); Guid? guidPersonAttribute = personAttributeValue.AsGuidOrNull(); if (guidPersonAttribute.HasValue) { var attributePerson = AttributeCache.Get(guidPersonAttribute.Value, rockContext); if (attributePerson != null || attributePerson.FieldType.Class != "Rock.Field.Types.PersonFieldType") { string attributePersonValue = action.GetWorklowAttributeValue(guidPersonAttribute.Value); if (!string.IsNullOrWhiteSpace(attributePersonValue)) { Guid personAliasGuid = attributePersonValue.AsGuid(); if (!personAliasGuid.IsEmpty()) { person = new PersonAliasService(rockContext).Queryable() .Where(a => a.Guid.Equals(personAliasGuid)) .Select(a => a.Person) .FirstOrDefault(); if (person == null) { errorMessages.Add(string.Format("Person could not be found for selected value ('{0}')!", guidPersonAttribute.ToString())); return(false); } } } } } if (person == null) { errorMessages.Add("The attribute used to provide the person was invalid, or not of type 'Person'."); return(false); } // determine the location type to edit DefinedValueCache locationType = null; var locationTypeAttributeValue = action.GetWorklowAttributeValue(GetAttributeValue(action, "LocationTypeAttribute").AsGuid()); if (locationTypeAttributeValue != null) { locationType = DefinedValueCache.Get(locationTypeAttributeValue.AsGuid()); } if (locationType == null) { locationType = DefinedValueCache.Get(GetAttributeValue(action, "LocationType").AsGuid()); } if (locationType == null) { errorMessages.Add("The location type to be updated was not selected."); return(false); } // get the new phone number value Location location = null; string locationValue = GetAttributeValue(action, "Location"); Guid? locationGuid = locationValue.AsGuidOrNull(); if (!locationGuid.HasValue || locationGuid.Value.IsEmpty()) { string locationAttributeValue = GetAttributeValue(action, "LocationAttribute"); Guid? locationAttributeValueGuid = locationAttributeValue.AsGuidOrNull(); if (locationAttributeValueGuid.HasValue) { locationGuid = action.GetWorklowAttributeValue(locationAttributeValueGuid.Value).AsGuidOrNull(); } } if (locationGuid.HasValue) { location = new LocationService(rockContext).Get(locationGuid.Value); } if (location == null) { errorMessages.Add("The location value could not be determined."); return(false); } // gets value indicating if location is a mailing location string mailingValue = GetAttributeValue(action, "IsMailing"); Guid? mailingValueGuid = mailingValue.AsGuidOrNull(); if (mailingValueGuid.HasValue) { mailingValue = action.GetWorklowAttributeValue(mailingValueGuid.Value); } else { mailingValue = mailingValue.ResolveMergeFields(GetMergeFields(action)); } bool?mailing = mailingValue.AsBooleanOrNull(); // gets value indicating if location is a mapped location string mappedValue = GetAttributeValue(action, "IsMapped"); Guid? mappedValueGuid = mappedValue.AsGuidOrNull(); if (mappedValueGuid.HasValue) { mappedValue = action.GetWorklowAttributeValue(mappedValueGuid.Value); } else { mappedValue = mappedValue.ResolveMergeFields(GetMergeFields(action)); } bool?mapped = mappedValue.AsBooleanOrNull(); var savePreviousAddress = GetAttributeValue(action, "SavePreviousAddress").AsBoolean(); var locationService = new LocationService(rockContext); locationService.Verify(location, false); var groupLocationService = new GroupLocationService(rockContext); foreach (var family in person.GetFamilies(rockContext).ToList()) { bool locationUpdated = false; if (savePreviousAddress) { // Get all existing addresses of the specified type var groupLocations = family.GroupLocations.Where(l => l.GroupLocationTypeValueId == locationType.Id).ToList(); // Create a new address of the specified type, saving all existing addresses of that type as Previous Addresses // Use the specified Is Mailing and Is Mapped values from the action's parameters if they are set, // otherwise set them to true if any of the existing addresses of that type have those values set to true GroupService.AddNewGroupAddress(rockContext, family, locationType.Guid.ToString(), location.Id, true, $"the {action.ActionTypeCache.ActivityType.WorkflowType.Name} workflow", mailing ?? groupLocations.Any(x => x.IsMailingLocation), mapped ?? groupLocations.Any(x => x.IsMappedLocation)); } else { var groupLocation = family.GroupLocations.FirstOrDefault(l => l.GroupLocationTypeValueId == locationType.Id); string oldValue = string.Empty; if (groupLocation == null) { groupLocation = new GroupLocation(); groupLocation.GroupId = family.Id; groupLocation.GroupLocationTypeValueId = locationType.Id; groupLocationService.Add(groupLocation); } else { oldValue = groupLocation.Location.ToString(); } locationUpdated = oldValue != location.ToString(); groupLocation.Location = location; if (mailing.HasValue) { if (((oldValue == string.Empty) ? null : groupLocation.IsMailingLocation.ToString()) != mailing.Value.ToString()) { locationUpdated = true; } groupLocation.IsMailingLocation = mailing.Value; } if (mapped.HasValue) { if (((oldValue == string.Empty) ? null : groupLocation.IsMappedLocation.ToString()) != mapped.Value.ToString()) { locationUpdated = true; } groupLocation.IsMappedLocation = mapped.Value; } } if (locationUpdated) { var groupChanges = new History.HistoryChangeList(); groupChanges.AddChange(History.HistoryVerb.Modify, History.HistoryChangeType.Record, "Location").SourceOfChange = $"{action.ActionTypeCache.ActivityType.WorkflowType.Name} workflow"; foreach (var fm in family.Members) { HistoryService.SaveChanges( rockContext, typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON_FAMILY_CHANGES.AsGuid(), fm.PersonId, groupChanges, family.Name, typeof(Group), family.Id, false, null, rockContext.SourceOfChange); } } rockContext.SaveChanges(); action.AddLogEntry(string.Format("Updated the {0} location for {1} (family: {2}) to {3}", locationType.Value, person.FullName, family.Name, location.ToString())); } return(true); }
/// <summary> /// Updates the last login and writes to the person's history log /// </summary> /// <param name="userName">Name of the user.</param> public static void UpdateLastLogin(string userName) { if (!string.IsNullOrWhiteSpace(userName)) { using (var rockContext = new RockContext()) { int? personId = null; bool impersonated = userName.StartsWith("rckipid="); if (!impersonated) { var userLogin = new UserLoginService(rockContext).GetByUserName(userName); if (userLogin != null) { userLogin.LastLoginDateTime = RockDateTime.Now; personId = userLogin.PersonId; } } else { var impersonationToken = userName.Substring(8); personId = new PersonService(rockContext).GetByImpersonationToken(impersonationToken, false, null)?.Id; } if (personId.HasValue) { var relatedDataBuilder = new System.Text.StringBuilder(); int?relatedEntityTypeId = null; int?relatedEntityId = null; if (impersonated) { var impersonatedByUser = HttpContext.Current?.Session["ImpersonatedByUser"] as UserLogin; relatedEntityTypeId = EntityTypeCache.GetId <Rock.Model.Person>(); relatedEntityId = impersonatedByUser?.PersonId; if (impersonatedByUser != null) { relatedDataBuilder.Append($" impersonated by { impersonatedByUser.Person.FullName }"); } } if (HttpContext.Current != null && HttpContext.Current.Request != null) { string cleanUrl = PersonToken.ObfuscateRockMagicToken(HttpContext.Current.Request.Url.AbsoluteUri); // obfuscate the url specified in the returnurl, just in case it contains any sensitive information (like a rckipid) Regex returnurlRegEx = new Regex(@"returnurl=([^&]*)"); cleanUrl = returnurlRegEx.Replace(cleanUrl, "returnurl=XXXXXXXXXXXXXXXXXXXXXXXXXXXX"); relatedDataBuilder.AppendFormat(" to <span class='field-value'>{0}</span>, from <span class='field-value'>{1}</span>", cleanUrl, HttpContext.Current.Request.UserHostAddress); } var historyChangeList = new History.HistoryChangeList(); var historyChange = historyChangeList.AddChange(History.HistoryVerb.Login, History.HistoryChangeType.Record, userName); if (relatedDataBuilder.Length > 0) { historyChange.SetRelatedData(relatedDataBuilder.ToString(), null, null); } HistoryService.SaveChanges(rockContext, typeof(Rock.Model.Person), Rock.SystemGuid.Category.HISTORY_PERSON_ACTIVITY.AsGuid(), personId.Value, historyChangeList, true); } } } }
/// <summary> /// Pres the save. /// </summary> /// <param name="dbContext">The database context.</param> /// <param name="entry"></param> public override void PreSaveChanges(Rock.Data.DbContext dbContext, DbEntityEntry entry) { var rockContext = (RockContext)dbContext; HistoryChangeList = new History.HistoryChangeList(); switch (entry.State) { case EntityState.Added: { HistoryChangeList.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Transaction"); string person = History.GetValue <PersonAlias>(AuthorizedPersonAlias, AuthorizedPersonAliasId, rockContext); History.EvaluateChange(HistoryChangeList, "Authorized Person", string.Empty, person); History.EvaluateChange(HistoryChangeList, "Gateway", string.Empty, History.GetValue <FinancialGateway>(FinancialGateway, FinancialGatewayId, rockContext)); History.EvaluateChange(HistoryChangeList, "Gateway Schedule Id", string.Empty, GatewayScheduleId); History.EvaluateChange(HistoryChangeList, "Transaction Code", string.Empty, TransactionCode); History.EvaluateChange(HistoryChangeList, "Summary", string.Empty, Summary); History.EvaluateChange(HistoryChangeList, "Type", (int?)null, TransactionTypeValue, TransactionTypeValueId); History.EvaluateChange(HistoryChangeList, "Source", (int?)null, SourceTypeValue, SourceTypeValueId); History.EvaluateChange(HistoryChangeList, "Frequency", (int?)null, TransactionFrequencyValue, TransactionFrequencyValueId); History.EvaluateChange(HistoryChangeList, "Start Date", (DateTime?)null, StartDate); History.EvaluateChange(HistoryChangeList, "End Date", (DateTime?)null, EndDate); History.EvaluateChange(HistoryChangeList, "Number of Payments", (int?)null, NumberOfPayments); History.EvaluateChange(HistoryChangeList, "Is Active", (bool?)null, IsActive); History.EvaluateChange(HistoryChangeList, "Card Reminder Date", (DateTime?)null, CardReminderDate); History.EvaluateChange(HistoryChangeList, "Last Reminded Date", (DateTime?)null, LastRemindedDate); break; } case EntityState.Modified: { string origPerson = History.GetValue <PersonAlias>(null, entry.OriginalValues["AuthorizedPersonAliasId"].ToStringSafe().AsIntegerOrNull(), rockContext); string person = History.GetValue <PersonAlias>(AuthorizedPersonAlias, AuthorizedPersonAliasId, rockContext); History.EvaluateChange(HistoryChangeList, "Authorized Person", origPerson, person); int?origGatewayId = entry.OriginalValues["FinancialGatewayId"].ToStringSafe().AsIntegerOrNull(); if (!FinancialGatewayId.Equals(origGatewayId)) { History.EvaluateChange(HistoryChangeList, "Gateway", History.GetValue <FinancialGateway>(null, origGatewayId, rockContext), History.GetValue <FinancialGateway>(FinancialGateway, FinancialGatewayId, rockContext)); } History.EvaluateChange(HistoryChangeList, "Gateway Schedule Id", entry.OriginalValues["GatewayScheduleId"].ToStringSafe(), GatewayScheduleId); History.EvaluateChange(HistoryChangeList, "Transaction Code", entry.OriginalValues["TransactionCode"].ToStringSafe(), TransactionCode); History.EvaluateChange(HistoryChangeList, "Summary", entry.OriginalValues["Summary"].ToStringSafe(), Summary); History.EvaluateChange(HistoryChangeList, "Type", entry.OriginalValues["TransactionTypeValueId"].ToStringSafe().AsIntegerOrNull(), TransactionTypeValue, TransactionTypeValueId); History.EvaluateChange(HistoryChangeList, "Source", entry.OriginalValues["SourceTypeValueId"].ToStringSafe().AsIntegerOrNull(), SourceTypeValue, SourceTypeValueId); History.EvaluateChange(HistoryChangeList, "Frequency", entry.OriginalValues["TransactionFrequencyValueId"].ToStringSafe().AsIntegerOrNull(), TransactionFrequencyValue, TransactionFrequencyValueId); History.EvaluateChange(HistoryChangeList, "Start Date", entry.OriginalValues["StartDate"].ToStringSafe().AsDateTime(), StartDate); History.EvaluateChange(HistoryChangeList, "End Date", entry.OriginalValues["EndDate"].ToStringSafe().AsDateTime(), EndDate); History.EvaluateChange(HistoryChangeList, "Number of Payments", entry.OriginalValues["EndDate"].ToStringSafe().AsIntegerOrNull(), NumberOfPayments); History.EvaluateChange(HistoryChangeList, "Is Active", entry.OriginalValues["IsActive"].ToStringSafe().AsBooleanOrNull(), IsActive); History.EvaluateChange(HistoryChangeList, "Card Reminder Date", entry.OriginalValues["CardReminderDate"].ToStringSafe().AsDateTime(), CardReminderDate); History.EvaluateChange(HistoryChangeList, "Last Reminded Date", entry.OriginalValues["LastRemindedDate"].ToStringSafe().AsDateTime(), LastRemindedDate); break; } case EntityState.Deleted: { HistoryChangeList.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "Transaction"); break; } } base.PreSaveChanges(dbContext, entry); }
/// <summary> /// This method is called in the /// <see cref="M:Rock.Data.Model`1.PreSaveChanges(Rock.Data.DbContext,System.Data.Entity.Infrastructure.DbEntityEntry,System.Data.Entity.EntityState)" /> /// method. Use it to populate <see cref="P:Rock.Data.Model`1.HistoryItems" /> if needed. /// These history items are queued to be written into the database post save (so that they /// are only written if the save actually occurs). /// </summary> /// <param name="dbContext">The database context.</param> /// <param name="entry">The entry.</param> /// <param name="state">The state.</param> protected override void BuildHistoryItems(Data.DbContext dbContext, DbEntityEntry entry, EntityState state) { // Sometimes, especially if the model is being deleted, some properties might not be // populated, but we can query to try to get their original value. We need to use a new // rock context to get the actual value from the DB var rockContext = new RockContext(); var service = new PersonSearchKeyService(rockContext); var originalModel = service.Queryable("PersonAlias") .FirstOrDefault(fpsa => fpsa.Id == Id); // Use the original value for the person alias or the new value if that is not set var personId = (originalModel?.PersonAlias ?? PersonAlias)?.PersonId; if (!personId.HasValue) { // If this model is new, it won't have any virtual properties hydrated or an original // record in the database if (PersonAliasId.HasValue) { var personAliasService = new PersonAliasService(rockContext); var personAlias = personAliasService.Get(PersonAliasId.Value); personId = personAlias?.PersonId; } // We can't log history if we don't know who the saved account belongs to if (!personId.HasValue) { return; } } History.HistoryVerb verb; switch (state) { case EntityState.Added: verb = History.HistoryVerb.Add; break; case EntityState.Deleted: verb = History.HistoryVerb.Delete; break; case EntityState.Modified: verb = History.HistoryVerb.Modify; break; default: // As of now, there is no requirement to log other events return; } var caption = verb == History.HistoryVerb.Modify ? "Person Search Key" : GetCaptionForHistory(originalModel?.SearchValue ?? SearchValue, originalModel?.SearchTypeValueId ?? SearchTypeValueId); var historyChangeList = new History.HistoryChangeList(); if (verb != History.HistoryVerb.Modify) { historyChangeList.AddChange(verb, History.HistoryChangeType.Record, "Person Search Key"); } else { History.EvaluateChange(historyChangeList, $"SearchValue", entry.OriginalValues["SearchValue"].ToStringSafe(), SearchValue, false); var originalSearchType = DefinedValueCache.Get(entry.OriginalValues["SearchTypeValueId"].ToStringSafe().AsInteger()); var currentSearchType = DefinedValueCache.Get(SearchTypeValueId); History.EvaluateChange(historyChangeList, $"SearchType", originalSearchType?.Value, currentSearchType?.Value, false); } HistoryItems = HistoryService.GetChanges( typeof(Person), Rock.SystemGuid.Category.HISTORY_PERSON.AsGuid(), personId.Value, historyChangeList, caption, typeof(PersonSearchKey), Id, dbContext.GetCurrentPersonAlias()?.Id, dbContext.SourceOfChange); }
/// <summary> /// Pres the save. /// </summary> /// <param name="dbContext">The database context.</param> /// <param name="entry"></param> public override void PreSaveChanges(Rock.Data.DbContext dbContext, System.Data.Entity.Infrastructure.DbEntityEntry entry) { var rockContext = (RockContext)dbContext; HistoryChangeList = new History.HistoryChangeList(); BatchHistoryChangeList = new Dictionary <int, History.HistoryChangeList> (); switch (entry.State) { case System.Data.Entity.EntityState.Added: { HistoryChangeList.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Transaction"); string person = History.GetValue <PersonAlias>(AuthorizedPersonAlias, AuthorizedPersonAliasId, rockContext); History.EvaluateChange(HistoryChangeList, "Authorized Person", string.Empty, person); History.EvaluateChange(HistoryChangeList, "Batch", string.Empty, History.GetValue <FinancialBatch>(Batch, BatchId, rockContext)); History.EvaluateChange(HistoryChangeList, "Gateway", string.Empty, History.GetValue <FinancialGateway>(FinancialGateway, FinancialGatewayId, rockContext)); History.EvaluateChange(HistoryChangeList, "Transaction Date/Time", (DateTime?)null, TransactionDateTime); History.EvaluateChange(HistoryChangeList, "Transaction Code", string.Empty, TransactionCode); History.EvaluateChange(HistoryChangeList, "Summary", string.Empty, Summary); History.EvaluateChange(HistoryChangeList, "Type", (int?)null, TransactionTypeValue, TransactionTypeValueId); History.EvaluateChange(HistoryChangeList, "Source", (int?)null, SourceTypeValue, SourceTypeValueId); History.EvaluateChange(HistoryChangeList, "Scheduled Transaction Id", (int?)null, ScheduledTransactionId); History.EvaluateChange(HistoryChangeList, "Processed By", string.Empty, History.GetValue <PersonAlias>(ProcessedByPersonAlias, ProcessedByPersonAliasId, rockContext)); History.EvaluateChange(HistoryChangeList, "Processed Date/Time", (DateTime?)null, ProcessedDateTime); History.EvaluateChange(HistoryChangeList, "Status", string.Empty, Status); History.EvaluateChange(HistoryChangeList, "Status Message", string.Empty, StatusMessage); int?batchId = Batch != null ? Batch.Id : BatchId; if (batchId.HasValue) { var batchChanges = new History.HistoryChangeList(); batchChanges.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Transaction").SetNewValue($"{this.TotalAmount.FormatAsCurrency()} for {person}"); BatchHistoryChangeList.Add(batchId.Value, batchChanges); } break; } case System.Data.Entity.EntityState.Modified: { string origPerson = History.GetValue <PersonAlias>(null, entry.OriginalValues["AuthorizedPersonAliasId"].ToStringSafe().AsIntegerOrNull(), rockContext); string person = History.GetValue <PersonAlias>(AuthorizedPersonAlias, AuthorizedPersonAliasId, rockContext); History.EvaluateChange(HistoryChangeList, "Authorized Person", origPerson, person); int?origBatchId = entry.OriginalValues["BatchId"].ToStringSafe().AsIntegerOrNull(); int?batchId = Batch != null ? Batch.Id : BatchId; if (!batchId.Equals(origBatchId)) { string origBatch = History.GetValue <FinancialBatch>(null, origBatchId, rockContext); string batch = History.GetValue <FinancialBatch>(Batch, BatchId, rockContext); History.EvaluateChange(HistoryChangeList, "Batch", origBatch, batch); } int?origGatewayId = entry.OriginalValues["FinancialGatewayId"].ToStringSafe().AsIntegerOrNull(); if (!FinancialGatewayId.Equals(origGatewayId)) { History.EvaluateChange(HistoryChangeList, "Gateway", History.GetValue <FinancialGateway>(null, origGatewayId, rockContext), History.GetValue <FinancialGateway>(FinancialGateway, FinancialGatewayId, rockContext)); } History.EvaluateChange(HistoryChangeList, "Transaction Date/Time", entry.OriginalValues["TransactionDateTime"].ToStringSafe().AsDateTime(), TransactionDateTime); History.EvaluateChange(HistoryChangeList, "Transaction Code", entry.OriginalValues["TransactionCode"].ToStringSafe(), TransactionCode); History.EvaluateChange(HistoryChangeList, "Summary", entry.OriginalValues["Summary"].ToStringSafe(), Summary); History.EvaluateChange(HistoryChangeList, "Type", entry.OriginalValues["TransactionTypeValueId"].ToStringSafe().AsIntegerOrNull(), TransactionTypeValue, TransactionTypeValueId); History.EvaluateChange(HistoryChangeList, "Source", entry.OriginalValues["SourceTypeValueId"].ToStringSafe().AsIntegerOrNull(), SourceTypeValue, SourceTypeValueId); History.EvaluateChange(HistoryChangeList, "Scheduled Transaction Id", entry.OriginalValues["ScheduledTransactionId"].ToStringSafe().AsIntegerOrNull(), ScheduledTransactionId); History.EvaluateChange(HistoryChangeList, "Processed By", entry.OriginalValues["ProcessedByPersonAliasId"].ToStringSafe().AsIntegerOrNull(), ProcessedByPersonAlias, ProcessedByPersonAliasId, rockContext); History.EvaluateChange(HistoryChangeList, "Processed Date/Time", entry.OriginalValues["ProcessedDateTime"].ToStringSafe().AsDateTime(), ProcessedDateTime); History.EvaluateChange(HistoryChangeList, "Status", entry.OriginalValues["Status"].ToStringSafe(), Status); History.EvaluateChange(HistoryChangeList, "Status Message", entry.OriginalValues["StatusMessage"].ToStringSafe(), StatusMessage); if (!batchId.Equals(origBatchId)) { var batchChanges = new History.HistoryChangeList(); if (origBatchId.HasValue) { batchChanges.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "Transaction").SetOldValue($"{this.TotalAmount.FormatAsCurrency()} for {person}"); } if (batchId.HasValue) { batchChanges.AddChange(History.HistoryVerb.Add, History.HistoryChangeType.Record, "Transaction").SetNewValue($"{this.TotalAmount.FormatAsCurrency()} for {person}"); } BatchHistoryChangeList.Add(batchId.Value, batchChanges); } else { if (batchId.HasValue) { var batchChanges = new History.HistoryChangeList(); batchChanges.AddChange(History.HistoryVerb.Modify, History.HistoryChangeType.Record, $"Transaction Id:{Id}"); BatchHistoryChangeList.Add(batchId.Value, batchChanges); } } break; } case System.Data.Entity.EntityState.Deleted: { HistoryChangeList.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "Transaction"); int?batchId = Batch != null ? Batch.Id : BatchId; if (batchId.HasValue) { string batch = History.GetValue <FinancialBatch>(Batch, BatchId, rockContext); string person = History.GetValue <PersonAlias>(AuthorizedPersonAlias, AuthorizedPersonAliasId, rockContext); var batchChanges = new History.HistoryChangeList(); batchChanges.AddChange(History.HistoryVerb.Delete, History.HistoryChangeType.Record, "Transaction").SetOldValue($"{this.TotalAmount.FormatAsCurrency()} for {person}"); BatchHistoryChangeList.Add(batchId.Value, batchChanges); } // since images have a cascade delete relationship, make sure the PreSaveChanges gets called var childImages = new FinancialTransactionImageService(dbContext as RockContext).Queryable().Where(a => a.TransactionId == this.Id); foreach (var image in childImages) { image.PreSaveChanges(dbContext, entry.State); } break; } } base.PreSaveChanges(dbContext, entry); }
/// <summary> /// Updates the last login, writes to the person's history log, and saves changes to the database /// </summary> /// <param name="userName">Name of the user.</param> public static void UpdateLastLogin(string userName) { if (string.IsNullOrWhiteSpace(userName)) { return; } int? personId = null; bool impersonated = userName.StartsWith("rckipid="); using (var rockContext = new RockContext()) { if (!impersonated) { var userLogin = new UserLoginService(rockContext).Queryable().Where(a => a.UserName == userName).FirstOrDefault(); if (userLogin != null) { userLogin.LastLoginDateTime = RockDateTime.Now; personId = userLogin.PersonId; rockContext.SaveChanges(); } } else { var impersonationToken = userName.Substring(8); personId = new PersonService(rockContext).GetByImpersonationToken(impersonationToken, false, null)?.Id; } } if (personId == null) { return; } var relatedDataBuilder = new System.Text.StringBuilder(); int?relatedEntityTypeId = null; int?relatedEntityId = null; if (impersonated) { var impersonatedByUser = HttpContext.Current?.Session?["ImpersonatedByUser"] as UserLogin; relatedEntityTypeId = EntityTypeCache.GetId <Rock.Model.Person>(); relatedEntityId = impersonatedByUser?.PersonId; if (impersonatedByUser != null) { relatedDataBuilder.Append($" impersonated by { impersonatedByUser.Person.FullName }"); } } if (HttpContext.Current != null && HttpContext.Current.Request != null) { string cleanUrl = PersonToken.ObfuscateRockMagicToken(HttpContext.Current.Request.UrlProxySafe().AbsoluteUri); // obfuscate the URL specified in the returnurl, just in case it contains any sensitive information (like a rckipid) Regex returnurlRegEx = new Regex(@"returnurl=([^&]*)"); cleanUrl = returnurlRegEx.Replace(cleanUrl, "returnurl=XXXXXXXXXXXXXXXXXXXXXXXXXXXX"); string clientIPAddress; try { clientIPAddress = Rock.Web.UI.RockPage.GetClientIpAddress(); } catch { // if we get an exception getting the IP Address, just ignore it clientIPAddress = ""; } relatedDataBuilder.AppendFormat( " to <span class='field-value'>{0}</span>, from <span class='field-value'>{1}</span>", cleanUrl, clientIPAddress); } var historyChangeList = new History.HistoryChangeList(); var historyChange = historyChangeList.AddChange(History.HistoryVerb.Login, History.HistoryChangeType.Record, userName); if (relatedDataBuilder.Length > 0) { historyChange.SetRelatedData(relatedDataBuilder.ToString(), null, null); } var historyList = HistoryService.GetChanges(typeof(Rock.Model.Person), Rock.SystemGuid.Category.HISTORY_PERSON_ACTIVITY.AsGuid(), personId.Value, historyChangeList, null, null, null, null, null); if (historyList.Any()) { Task.Run(async() => { // Wait 1 second to allow all post save actions to complete await Task.Delay(1000); try { using (var rockContext = new RockContext()) { rockContext.BulkInsert(historyList); } } catch (SystemException ex) { ExceptionLogService.LogException(ex, null); } }); } }