public void CreationThreeTimeEntriesOnEmptyDbTest() { XrmFakedContext context = new XrmFakedContext(); Guid resourseId = Guid.NewGuid(); DateTime startDate = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc); TimeSpan duration = TimeSpan.FromDays(2); var targetTimeEntry = EntityFactory.CreateTimeEntry(startDate, duration, resourseId); PreOperationAndThenCreate(context, targetTimeEntry); var entities = GetTimeEntries(new GetEntryTimeRangeRequest(startDate, startDate + duration, resourseId), context); var timeEntries = entities.Select(e => TimeEntryDtoConverter.ConvertToDto(e)).ToArray(); Assert.AreEqual(3, timeEntries.Length); var firstNewTimeEntry = timeEntries[0]; Assert.AreEqual(firstNewTimeEntry.BookableResource.Id, resourseId); Assert.AreEqual(firstNewTimeEntry.Start, startDate.AddDays(1)); Assert.AreEqual(firstNewTimeEntry.End, startDate.AddDays(1).EndOfTheDay()); var secondNewTimeEntry = timeEntries[1]; Assert.AreEqual(secondNewTimeEntry.BookableResource.Id, resourseId); Assert.AreEqual(secondNewTimeEntry.Start, startDate.AddDays(2)); Assert.AreEqual(secondNewTimeEntry.End, startDate.AddDays(2).EndOfTheDay()); // the "target" TimeEntry is created last var targetEntry = timeEntries[2]; Assert.AreEqual(targetEntry.BookableResource.Id, resourseId); Assert.AreEqual(targetEntry.Start, startDate); Assert.AreEqual(targetEntry.End, targetEntry.Start.EndOfTheDay()); }
public void CreationOnlyNonExistingTimeEntriesTest() { XrmFakedContext context = new XrmFakedContext(); Guid resourseId = Guid.NewGuid(); DateTime startDate = new DateTime(2000, 1, 1, 9, 0, 0, DateTimeKind.Utc); TimeSpan duration = TimeSpan.FromDays(2); var targetTimeEntry = EntityFactory.CreateTimeEntry(startDate, duration, resourseId); var existingEntryStart = startDate.AddDays(1); var existingEntryDuration = TimeSpan.FromHours(2); context.Initialize(new List <Entity> { EntityFactory.CreateTimeEntry(existingEntryStart, existingEntryDuration, resourseId), }); var request = new GetEntryTimeRangeRequest(startDate, startDate + duration, resourseId); var entitiesBeforeCreation = GetTimeEntries(request, context); Assert.AreEqual(1, entitiesBeforeCreation.Count); // One TimeEnrty exists, 1 should be added before existing one and 1 should be added after existing one PreOperationAndThenCreate(context, targetTimeEntry); var entitiesAfterCreation = GetTimeEntries(request, context); var timeEntries = entitiesAfterCreation.Select(e => TimeEntryDtoConverter.ConvertToDto(e)).ToArray(); Assert.AreEqual(3, timeEntries.Length); var existingTimeEntry = timeEntries[0]; Assert.AreEqual(existingTimeEntry.BookableResource.Id, resourseId); Assert.AreEqual(existingTimeEntry.Start, existingEntryStart); Assert.AreEqual(existingTimeEntry.End, existingEntryStart + existingEntryDuration); var firstNewTimeEntry = timeEntries[1]; Assert.AreEqual(firstNewTimeEntry.BookableResource.Id, resourseId); Assert.AreEqual(firstNewTimeEntry.Start, startDate.Date.AddDays(2)); Assert.AreEqual(firstNewTimeEntry.End, startDate.Date.AddDays(2).EndOfTheDay()); // a new time entry before the existing one is a changed "target" TimeEntry // the "target" TimeEntry is created last var secondNewTimeEntry = timeEntries[2]; Assert.AreEqual(secondNewTimeEntry.BookableResource.Id, resourseId); Assert.AreEqual(secondNewTimeEntry.Start, startDate); Assert.AreEqual(secondNewTimeEntry.End, startDate.EndOfTheDay()); }
public void Execute(IServiceProvider serviceProvider) { // https://docs.microsoft.com/ru-ru/powerapps/developer/data-platform/best-practices/business-logic/develop-iplugin-implementations-stateless#problematic-patterns // to avoid problematic pattern should create pluginExecutionFacade and pass it everywhere (instead of using a variable of class) var pluginExecutionFacade = new PluginExecutionFacade(serviceProvider); try { var context = pluginExecutionFacade.Context; // if another plugin creates TimeEntry then this check should be removed if (context.Depth > 1) { return; } var targetEntity = context.InputParameters.GetTargetEntity(); var targetTimeEntryDto = TimeEntryDtoConverter.ConvertToDto(targetEntity); if (targetTimeEntryDto.End.Date <= targetTimeEntryDto.Start.Date) { return; } // the main logic is located here for clarity var existingTimeEntrieDates = GetExistingTimeEntryDates(pluginExecutionFacade, targetTimeEntryDto); var date = targetTimeEntryDto.Start.Date; var maxDate = targetTimeEntryDto.End.Date; var datesToBeCreated = new List <DateTime>(); while (date <= maxDate) { if (!existingTimeEntrieDates.Contains(date)) { datesToBeCreated.Add(date); } date = date.AddDays(1); } if (!datesToBeCreated.Any()) { throw new InvalidPluginExecutionException("Duplicates creation is canceled"); } // target TimeEntry should be changed var firstDateToBeCreated = datesToBeCreated[0]; if (targetTimeEntryDto.Start.Date == firstDateToBeCreated) { var duration = targetTimeEntryDto.Start.EndOfTheDay() - targetTimeEntryDto.Start; targetEntity.SetDuration(duration); targetEntity.SetEnd(targetTimeEntryDto.Start + duration); } else { var duration = TimeSpan.FromDays(1) - TimeSpan.FromMinutes(1); targetEntity.SetStart(firstDateToBeCreated); targetEntity.SetDuration(duration); targetEntity.SetEnd(firstDateToBeCreated + duration); } // the first TimeEntry will be created later as the "target" TimeEntry datesToBeCreated.RemoveAt(0); foreach (var dateItem in datesToBeCreated) { var duration = (TimeSpan.FromDays(1) - TimeSpan.FromMinutes(1)); var newEntity = targetEntity.Clone(); newEntity.SetStart(dateItem); newEntity.SetDuration(duration); newEntity.SetEnd(dateItem + duration); pluginExecutionFacade.OrganizationService.Create(newEntity); } } catch (Exception ex) { pluginExecutionFacade.TracingService.Trace("{0}: {1}", nameof(TimeEntryUniqueDatePlugin), ex.ToString()); // just to debug throw new InvalidPluginExecutionException($"An error occurred in {nameof(TimeEntryUniqueDatePlugin)}.", ex); } }