diff --git a/BeWo/Scheduler/View/SchedulerAppointmentEditForm.xaml.cs b/BeWo/Scheduler/View/SchedulerAppointmentEditForm.xaml.cs index 664d8ea1a..4a8d228b5 100644 --- a/BeWo/Scheduler/View/SchedulerAppointmentEditForm.xaml.cs +++ b/BeWo/Scheduler/View/SchedulerAppointmentEditForm.xaml.cs @@ -458,22 +458,22 @@ namespace BeWo.Scheduler.View var item = (SchedulerAppointmentVM) Appointment.GetSourceObject(Control.GetCoreStorage()); - if(!IsInTaskViewMode){ - ServiceFacade.DoResourceServiceSync(definedBelow => overlaps = definedBelow.OverlappingAppointmentsExist(Appointment.Start, Appointment.End, employeeOids, customerOids, resources.Select(res => res.ResourceOid.Value).ToList(), ViewModel.NewVM.Originator.EmployeeOid, item?.CommitToDataContract().SchedulerAppointmentOid, string.Empty, Appointment.RecurrenceIndex)); + //if(!IsInTaskViewMode){ + // ServiceFacade.DoResourceServiceSync(definedBelow => overlaps = definedBelow.OverlappingAppointmentsExist(Appointment.Start, Appointment.End, employeeOids, customerOids, resources.Select(res => res.ResourceOid.Value).ToList(), ViewModel.NewVM.Originator.EmployeeOid, item?.CommitToDataContract().SchedulerAppointmentOid, string.Empty, Appointment.RecurrenceIndex)); - if (overlaps) - { - var erg = MessageBox.Show("Dieser Termin überschneidet sich mit einem anderen bereits existierenden Termin.\n Möchten Sie ihn wirklich speichern?", "Überschneidung", MessageBoxButton.YesNo, MessageBoxImage.Exclamation); + // if (overlaps) + // { + // var erg = MessageBox.Show("Dieser Termin überschneidet sich mit einem anderen bereits existierenden Termin.\n Möchten Sie ihn wirklich speichern?", "Überschneidung", MessageBoxButton.YesNo, MessageBoxImage.Exclamation); - if (erg.Equals(MessageBoxResult.No)) - { - Controller.Storage.EndUpdate(); - return; - } - } - } + // if (erg.Equals(MessageBoxResult.No)) + // { + // Controller.Storage.EndUpdate(); + // return; + // } + // } + //} - ViewModel.ShouldLockOverlappingAppointmentCheck = true; + ViewModel.ShouldLockOverlappingAppointmentCheck = Appointment.Type == AppointmentType.ChangedOccurrence; if (Appointment.RecurrenceInfo != null) { diff --git a/BeWoPlanerMobil/Controllers/MainController.cs b/BeWoPlanerMobil/Controllers/MainController.cs index 5b97de72d..608789846 100644 --- a/BeWoPlanerMobil/Controllers/MainController.cs +++ b/BeWoPlanerMobil/Controllers/MainController.cs @@ -175,7 +175,7 @@ namespace BeWoPlanerMobil.Controllers { var endDate = MainModel.GetEndDateOfSupportConcept(supportConcept); - return endDate == null || endDate.Value >= DateTime.Now; + return endDate == null || endDate.Value >= DateTime.Now.Date; }).ToList(); } @@ -992,7 +992,7 @@ namespace BeWoPlanerMobil.Controllers return ResetEditingMode(null); } - + // TODO: Eingeloggter Mitarbeiter wird beim Bearbeiten immer mit ausgewählt, obwohl er nicht unbedingt in der Mitarbeiterliste ist private ActionResult UpdateGroupBooking() { var dc = Model.SelectedServiceRecord; @@ -1570,7 +1570,10 @@ namespace BeWoPlanerMobil.Controllers Model.ServiceCategories = CreateServiceCategoryModels(OperationsService.GetAllServiceDescriptions()); var group = OperationsService.GetServiceRecordGroup(selectedServiceRecord.GroupOid.Value); - Model.SelectedEmployees.AddRangeIfElementsNotIn(group.ServiceRecordList.Select(serviceRecord => serviceRecord.Employee).ToList()); + + var employees = group.ServiceRecordList.Select(serviceRecord => serviceRecord.Employee).Distinct().ToList(); + + Model.SelectedEmployees = employees; var cb2ScOids = group.ServiceRecordList.Where(w => w.CostBearer2SupportConceptOid.HasValue).Select(s => s.CostBearer2SupportConceptOid.Value).ToList(); Model.SelectedConceptCostBearerRelations.AddRangeIfElementsNotIn(OperationsService.GetSupportConceptCostBearerRelDCsByOids(cb2ScOids)); @@ -1578,11 +1581,6 @@ namespace BeWoPlanerMobil.Controllers var selectedSupportConcepts = new List(); selectedSupportConcepts.AddRangeIfElementsNotIn(OperationsService.GetSupportConceptsById(group.ServiceRecordList.Select(s => s.SupportConcept.SupportConceptOid))); - // TODO: WARUM SIND DIE NICHT GLEICH? - var first = selectedSupportConcepts[0]; - var second = selectedSupportConcepts[1]; - var areEqual = first.Equals(second); - Model.SelectedSupportConcepts = selectedSupportConcepts; } diff --git a/BeWoPlanerMobil/Models/MainModel.cs b/BeWoPlanerMobil/Models/MainModel.cs index b10188620..d76bd64c1 100644 --- a/BeWoPlanerMobil/Models/MainModel.cs +++ b/BeWoPlanerMobil/Models/MainModel.cs @@ -168,7 +168,7 @@ namespace BeWoPlanerMobil.Models var allCostBearerRelations = new List {new SupportConceptListObject("Hilfeplan auswählen", "", "-1", false, false), new SupportConceptListObject("Ohne Hilfeplan", "", "-2", false, false) }; foreach(var sc in SupportConcepts.OrderBy(sc => sc.Customer.LastName)) { - allCostBearerRelations.AddRange(sc.CostBearerRelations.Where(w => ShowExpiredSupportConcepts || w.EndDate == null || w.EndDate.Value >= DateTime.Now).Select( + allCostBearerRelations.AddRange(sc.CostBearerRelations.Where(w => ShowExpiredSupportConcepts || w.EndDate == null || w.EndDate.Value >= DateTime.Now.Date).Select( cb => new SupportConceptListObject( $"{sc.Customer.LastNameFirstName} {(sc.Customer.DateOfBirth.HasValue ? "*" + sc.Customer.DateOfBirth.Value.ToString("dd.MM.yyyy") : string.Empty)}", $"{cb.StartDate?.ToShortDateString().Remove(6, 2) ?? string.Empty}-{cb.EndDate?.ToShortDateString().Remove(6, 2) ?? string.Empty} {cb.CostBearer.Name}", diff --git a/BeWoPlanerMobil/Scripts/group-booking.js b/BeWoPlanerMobil/Scripts/group-booking.js index fc21f4529..62ef24ed7 100644 --- a/BeWoPlanerMobil/Scripts/group-booking.js +++ b/BeWoPlanerMobil/Scripts/group-booking.js @@ -65,7 +65,7 @@ function removeCb2ScRelation(relOid) { $("#cb2sc-checkbox-" + relOid).prop("checked", false); } - if($("#selected-cb2sc-list").find(".list-group-item") === 0) { + if($("#selected-cb2sc-list").find(".list-group-item").length === 0) { deactivateGroupBookingForm(); $("#group-booking-supportconcepts input:checked").each(function() { @@ -73,19 +73,26 @@ function removeCb2ScRelation(relOid) { }); } - $.get(getRemoveCb2ScRelFromGroupBookingUrl(), { pRelOid: relOid }).done(updateGroupBookingGroupList); + $.get(getRemoveCb2ScRelFromGroupBookingUrl(), { pRelOid: relOid }).done(function(result) { + updateGroupBookingGroupList($.parseJSON(result)); + }); } function updateGroupBookingGroupList(groupBookingSelectionObject) { var groupOids = groupBookingSelectionObject.GroupOids === undefined ? [] : groupBookingSelectionObject.GroupOids; var relOids = []; + console.log(groupBookingSelectionObject); + if (groupBookingSelectionObject.SelectedRelations !== undefined){ - for (var i = 0; i < groupBookingSelectionObject.SelectedRelations.length; i++) { - relOids.push(parseInt(groupBookingSelectionObject.SelectedRelations[i].Value, 10)); + for(var i = 0; i < groupBookingSelectionObject.SelectedRelations.length; i++) { + var oidStringValue = groupBookingSelectionObject.SelectedRelations[i].Value; + var oidIntValue = parseInt(oidStringValue, 10); + + relOids.push(oidIntValue); } } - + $("#group-booking-supportconcepts input").each(function() { var value = $(this).val(); diff --git a/Data/Access/SearchDAO.cs b/Data/Access/SearchDAO.cs index d90222572..b05ac0c87 100644 --- a/Data/Access/SearchDAO.cs +++ b/Data/Access/SearchDAO.cs @@ -1301,10 +1301,24 @@ namespace BeWo.Data.Access return c.List().Count > 0; } - // TODO: Ändert man einen Serientermin, wird ZWEIMAL eine Warnung angezeigt, dass sich der Termin mit einem anderen Termin überschneidet! Dieser Termin ist die Serie selbst! public bool OverlappingAppointmentsExist(DateTime start, DateTime end, IEnumerable employees, IEnumerable customers, IEnumerable resources, long originator, long? appointmentOid, string recurrenceId = "", int occurrenceIndex = 0) { var isRecurrenceException = appointmentOid == null; + var isBeingUpdatedToNormalAppointment = false; + Guid? recurrenceIdToIgnore = null; + + if(appointmentOid != null) + { + // Das Patter wird geladen, bzw. mit der Ausnahme mit Index 0 verglichen + // Wird die Serie in einen Einzeltermin geändert und es existiert eine Ausnahme mit Index 0, sollte die Ausnahme behalten werden und nicht der Root-Termin + var original = DAOFactory.GenericDAO.LoadByID(appointmentOid.Value); + var ri = original.GetRecurrenceId(); + if(ri != null && IsNullOrWhiteSpace(recurrenceId)) + { + isBeingUpdatedToNormalAppointment = true; + recurrenceIdToIgnore = ri; + } + } Guid? recurrenceGuid = null; @@ -1349,6 +1363,39 @@ namespace BeWo.Data.Access var recurringAppointments = recurringAppointmentsCriteria.List().ToList(); + if(isBeingUpdatedToNormalAppointment) + { + recurringAppointments = recurringAppointments.Where(root => + { + var recId = root.GetRecurrenceId(); + + if(recId != null && recurrenceIdToIgnore != null) + { + if(recId.Equals(recurrenceIdToIgnore)) + { + return false; + } + } + + return true; + }).ToList(); + + schedulerAppointments = schedulerAppointments.Where(root => + { + var recId = root.GetRecurrenceId(); + + if(recId != null && recurrenceIdToIgnore != null) + { + if(recId.Equals(recurrenceIdToIgnore)) + { + return false; + } + } + + return true; + }).ToList(); + } + foreach(var appointment in recurringAppointments) { var recurrenceInfo = new RecurrenceInfo(); @@ -1367,6 +1414,8 @@ namespace BeWo.Data.Access // In diesem Fall die Start- und Enddaten des zu überprüfenden, neuen Termins var interval = new TimeInterval(start, end); + var subject = appointment.Subject; + // Die Serientermine werden berechnet (ausnahmslos, d.h. es werden auch bearbeitete und gelöschte Termine erstellt, die herausgefiltert werden müssen). var occurrences = occurenceCalculator.CalcOccurrences(interval, pattern); @@ -1387,7 +1436,10 @@ namespace BeWo.Data.Access // Der generierte Serientermin muss sich zeitlich mit dem neuen Termin überschneiden // und darf nicht in der Liste der geänderten Serientermine oder der Liste der gelöschten Serientermine sein. - if(!start.IsInInterval(end, occurrence.Start, occurrence.Start.AddMinutes(duration)) || + + var isInIntervalTest = start.IsInInterval(end, occurrence.Start, occurrence.Start.AddMinutes(duration)); + + if(!isInIntervalTest || changedOccurences.Any(changedOccurence => changedOccurence.PatternId.Equals(patternId) && changedOccurence.Index == index) || deletedOccurences.Any(deletedOccurence => deletedOccurence.PatternId.Equals(patternId) && deletedOccurence.Index == index) || index == occurrenceIndex && guidParsingSuccessful && recurrenceGuid.Equals(occurrenceGuid)) @@ -1413,8 +1465,16 @@ namespace BeWo.Data.Access }).ToList(); var hasToStop = false; + + // Prüfen, ob es sich bei dem Termin für den Überschneidungen gesucht werden, um zu unterscheiden, ob ein Serientermin in einen normalen geändert wird. + var root = FindRootAppointmentByRecurrenceId(recurrenceInfo.Id.ToString()); + if(root.Oid != null && appointmentOid != null && root.Oid == appointmentOid && root.RecurrenceInfo != null && IsNullOrWhiteSpace(recurrenceId)) + { + hasToStop = true; + } + // Indices und Ids der RecurrenceInfo vergleichen. Stimmen sie überein, dann wird das generiert Serienelement ignoriert. - if(occurrence.RecurrenceInfo?.Id != null) + if(occurrence.RecurrenceInfo?.Id != null && !hasToStop) { if(Guid.TryParse(occurrence.RecurrenceInfo.Id.ToString(), out var guid)) { @@ -3435,7 +3495,136 @@ namespace BeWo.Data.Access c.Add(criterion); - return c.List().ToList(); + var resources = c.List().ToList(); + + // TODO: Serien in dem Zeitraum erzeugen + var recurringAppointmentsCriteria = CreateRecurrenceCriteria(start, end).Add(Restrictions.Eq(nameof(SchedulerAppointment.Type), 1)); + + var recurringAppointments = recurringAppointmentsCriteria.List().ToList(); + recurringAppointments = recurringAppointments.Where(s => s.ResourceList.Any(r => r.Oid.HasValue && resourceOids.Contains(r.Oid.Value))).ToList(); + + var changedOccurrencesCriteria = CreateCriteriaIsActive().Add(Restrictions.Eq(nameof(SchedulerAppointment.Type), 3)); + var deletedOccurrencesCriteria = CreateCriteria().Add(Restrictions.Eq(nameof(SchedulerAppointment.Type), 4)); + + var inBetween = CreateBetweenDateTimesCriterion(start, end, nameof(SchedulerAppointment.StartDate), nameof(SchedulerAppointment.EndDate)); + + changedOccurrencesCriteria.Add(inBetween); + deletedOccurrencesCriteria.Add(inBetween); + + var appointments = new List(); + + if(selectedAppointmentOid.HasValue) + { + changedOccurrencesCriteria.Add(Restrictions.Not(Restrictions.Eq(nameof(BeWoEntityBase.Oid), selectedAppointmentOid.Value))); + deletedOccurrencesCriteria.Add(Restrictions.Not(Restrictions.Eq(nameof(BeWoEntityBase.Oid), selectedAppointmentOid.Value))); + } + + var changedOccurrences = changedOccurrencesCriteria.List().Where(a => a.ResourceList.Any(r => r.Oid.HasValue && resourceOids.Contains(r.Oid.Value))).ToList(); + var deletedOccurrences = deletedOccurrencesCriteria.List().Where(a => a.ResourceList.Any(r => r.Oid.HasValue && resourceOids.Contains(r.Oid.Value))).ToList(); + // TODO: funktioniert nicht richtig + // Sich wiederholende Termine erzeugen und dabei die Ausnahmen und gelöschten Ausnahmen ignorieren + var interval = new TimeInterval(start, end); + foreach(var recurringAppointment in recurringAppointments) + { + var recurrenceInfo = new RecurrenceInfo(); + recurrenceInfo.FromXml(recurringAppointment.RecurrenceInfo); + + var occurenceCalculator = OccurrenceCalculator.CreateInstance(recurrenceInfo); + + // Das Muster für die Terminserie wird berechnet + var pattern = StaticAppointmentFactory.CreateAppointment(AppointmentType.Pattern); + pattern.RecurrenceInfo.FromXml(recurringAppointment.RecurrenceInfo); + pattern.Start = pattern.RecurrenceInfo.Start; + pattern.End = pattern.RecurrenceInfo.End; + + var testResourceIds = recurringAppointment.ResourceList.Where(w => w.Oid.HasValue).Select(s => s.Oid.Value); + + //var patternId = pattern.RecurrenceInfo.Id.ToString(); + if(!Guid.TryParse(pattern.RecurrenceInfo.Id.ToString(), out var patternId)) + { + continue; + } + + // Die Serientermine werden berechnet (ausnahmslos, d.h. es werden auch bearbeitete und gelöschte Termine erstellt, die herausgefiltert werden müssen). + var occurrences = occurenceCalculator.CalcOccurrences(interval, pattern); + + foreach(var occurrence in occurrences.GetAppointments(interval)) + { + if(recurringAppointment.EndDate == null || recurringAppointment.StartDate == null) + { + continue; + } + + // Sicher machen + var index = occurrence.RecurrenceIndex; + + var isDeletedOrChanged = changedOccurrences.Any(a => + { + var guid = a.GetRecurrenceIdAndIndex(out var i); + + if(guid != null) + { + if(guid.Value.Equals(patternId) && index == i) + { + return true; + } + } + + return false; + }) || deletedOccurrences.Any(a => + { + var guid = a.GetRecurrenceIdAndIndex(out var i); + + if(guid != null) + { + if(guid.Value.Equals(patternId) && index == i) + { + return true; + } + } + + return false; + }); + + if(isDeletedOrChanged) + { + continue; + } + + var duration = (recurringAppointment.EndDate.Value - recurringAppointment.StartDate.Value).TotalMinutes; + var isInIntervalTest = start.IsInInterval(end, occurrence.Start, occurrence.Start.AddMinutes(duration)); + + if(!isInIntervalTest) + { + continue; + } + + var occurrenceAppointment = new SchedulerAppointment + { + AllDay = occurrence.AllDay, + CustomerList = recurringAppointment.CustomerList, + Notice = recurringAppointment.Notice, + EmployeeList = recurringAppointment.EmployeeList, + EndDate = occurrence.Start.AddMinutes(duration), + FormerBookingSequenceOid = recurringAppointment.FormerBookingSequenceOid, + IsPrivate = recurringAppointment.IsPrivate, + Location = recurringAppointment.Location, + Originator = recurringAppointment.Originator, + RecurrenceInfo = occurrence.RecurrenceInfo.ToXml(), + ReminderInfo = recurringAppointment.ReminderInfo, + ResourceList = recurringAppointment.ResourceList, + StartDate = occurrence.Start, + Subject = recurringAppointment.Subject ?? "", + Type = recurringAppointment.Type + }; + + appointments.AddIfNotIn(occurrenceAppointment); + } + } + + appointments.DoForEach(a => a.ResourceList.DoForEach(resources.AddIfNotIn)); + + return resources; } public IList FindCustomerServiceRecordsForKilometerauswertung(long customerOid, DateTimeSpan pSpan) @@ -3803,5 +3992,72 @@ namespace BeWo.Data.Access return criteria.List(); } + + //public SchedulerAppointment FindRootAppointmentByRecurrenceId(string recurrenceId) + //{ + // if(Guid.TryParse(recurrenceId, out var guid)) + // { + // var criteria = CreateCriteria() + // .Add(Restrictions.Like(nameof(SchedulerAppointment.RecurrenceInfo), recurrenceId, MatchMode.Anywhere)) + // .Add(Restrictions.Eq(nameof(Appointment.Type), 1)); + + // return criteria.List().FirstOrDefault(); + // } + + // return null; + //} + + public SchedulerAppointment FindIndexZeroChangedOccurrence(Guid? recurrenceId) + { + if(recurrenceId == null) + { + return null; + } + + var kek = recurrenceId.ToString(); + + var str = $""; + + var criteria = CreateCriteria() + .Add(Restrictions.Like(nameof(SchedulerAppointment.RecurrenceInfo), str, MatchMode.Exact)) + .Add(Restrictions.Not(Restrictions.Like(nameof(SchedulerAppointment.RecurrenceInfo), "Index=\"", MatchMode.Anywhere))) + .Add(Restrictions.Eq(nameof(Appointment.Type), 3)); + + return criteria.List().FirstOrDefault(); + } + + public string ValidateSchedulerAppointment(DateTime start, DateTime end, IEnumerable employees, IEnumerable customers, List resources, long originator, long? appointmentOid, string recurrenceId = "", int occurrenceIndex = 0) + { + + var isOverlapping = OverlappingAppointmentsExist(start, end, employees, customers, resources, originator, appointmentOid, recurrenceId, occurrenceIndex); + + var unavailableResources = CheckAvailabilityOfResources(resources.ToList(), start, end, appointmentOid); + + var stringBuilder = new StringBuilder(); + + + if(unavailableResources.Any()) + { + var names = string.Empty; + + unavailableResources.DoForEach(resource => names += resource.Name + ", "); + + names = names.TrimEnd(' ').TrimEnd(','); + + var resourceCount = resources.Count(); + + var suffix = (resourceCount > 1 ? "n" : string.Empty); + + var ressourceWarningMessage = resourceCount > 1 ? + $"Ein{(resourceCount > 1 ? "ige" : "e")} der ausgewählten Ressourcen ({names}) sind" : + $"{(resourceCount > 1 ? "Eine der" : "Die")} ausgewählte{suffix} Ressource{suffix} ({names}) ist"; + + ressourceWarningMessage += $" zum gewählten Zeitpunkt ({start.GetDateString(end)}) nicht verfügbar.\n\nMöchten Sie trotzdem speichern?"; + + stringBuilder.Append(ressourceWarningMessage); + } + + return stringBuilder.ToString(); + } } } diff --git a/Host/Multitenancy/debug.config b/Host/Multitenancy/debug.config index 90515ecf3..388d06869 100644 --- a/Host/Multitenancy/debug.config +++ b/Host/Multitenancy/debug.config @@ -9,7 +9,7 @@ NHibernate.Connection.DriverConnectionProvider NHibernate.Driver.SqlClientDriver - Password=test;Persist Security Info=True;User ID=BeWoUser;Initial Catalog=BeWo;Data Source=SERVER01 + Password=test;Persist Security Info=True;User ID=BeWoUser;Initial Catalog=BeWo;Data Source=1111111111 NHibernate.Dialect.MsSql2005Dialect diff --git a/Host/Multitenancy/demo.config b/Host/Multitenancy/demo.config index 380824c31..9bd275e8f 100644 --- a/Host/Multitenancy/demo.config +++ b/Host/Multitenancy/demo.config @@ -17,7 +17,7 @@ - Server=localhost;Password=root;User ID=root; Initial Catalog=lhfrankfurtoder + Server=localhost;Password=root;User ID=root; Initial Catalog=1111111111 diff --git a/Service/ServiceImplementations/ResourceServiceImp.cs b/Service/ServiceImplementations/ResourceServiceImp.cs index 45d47581d..d9cd75595 100644 --- a/Service/ServiceImplementations/ResourceServiceImp.cs +++ b/Service/ServiceImplementations/ResourceServiceImp.cs @@ -699,12 +699,40 @@ namespace BeWo.Service.ServiceImplementations var lOriginals = DAOFactory.GenericDAO.LoadByIDs(pSchedulerAppointments.Select(b => b.SchedulerAppointmentOid.Value)); var allegleich = true; - var test = pSchedulerAppointments.Where(w => w.SchedulerAppointmentOid.HasValue && lOriginals.Any(a => a.Oid.HasValue && - a.Oid.Value == w.SchedulerAppointmentOid.Value && a.RecurrenceInfo != null && - w.RecurrenceInfo == null)) - .ToList(); + // Termine mit Oid, die also nicht neu sind, und die in den Originalen mit RecurrenceInfo enthalten sind. Was, wenn die RecurrenceInfo auf null gesetzt wurde? + var test = pSchedulerAppointments.Where(w => w.SchedulerAppointmentOid.HasValue && + lOriginals.Any(a => + a.Oid.HasValue && + a.Oid.Value == w.SchedulerAppointmentOid.Value && + a.RecurrenceInfo != null && w.RecurrenceInfo == null)).ToList(); - if(test.Count > 0) + // Wenn das Objekt aus der Datenbank vom Typ 1 ist und der Termin, der geupdated werden soll, vom Typ 0 ist, dann wurde der Serientermin in einen normalen geändert. + // lOriginals und pSchedulerappointments haben dann nur einen Eintrag + var originalsCount = lOriginals.Count(); + var schedulerAppointmentsCount = pSchedulerAppointments.Count(); + + var shouldUpdateExceptions = true; + + SchedulerAppointment rootAppointmentToDelete = null; + + if(originalsCount == 1 && schedulerAppointmentsCount == 1) + { + var originalAppointment = lOriginals.First(); + var updatedAppointment = pSchedulerAppointments.First(); + + if(originalAppointment.RecurrenceInfo != null && updatedAppointment.RecurrenceInfo == null && originalAppointment.Type == 1 && updatedAppointment.Type == 0) + { + shouldUpdateExceptions = false; + + var guid = originalAppointment.GetRecurrenceId(); + if(guid != null && DAOFactory.SearchDAO.FindIndexZeroChangedOccurrence(guid) != null) + { + rootAppointmentToDelete = DAOFactory.SearchDAO.FindRootAppointmentByRecurrenceId(guid.ToString()); + } + } + } + + if(test.Count > 0 && shouldUpdateExceptions) { var originalAppointments = lOriginals.Where(w => w.Oid.HasValue && test.Select(s => s.SchedulerAppointmentOid.Value).Contains(w.Oid.Value)).ToList(); @@ -761,7 +789,16 @@ namespace BeWo.Service.ServiceImplementations MapperFactory.SchedulerAppointmentDCSchedulerAppointment.MergeWithEntitys(pSchedulerAppointments, lOriginals); DAOFactory.GenericDAO.Update(lOriginals); - return MapperFactory.SchedulerAppointmentDCSchedulerAppointment.MapToNewDCs(lOriginals); + + // Default-Root-Termin löschen, falls eine Ausnahme an der Stelle sein sollte. + if(rootAppointmentToDelete != null) + { + DAOFactory.GenericDAO.Delete(rootAppointmentToDelete); + } + + rootAppointmentToDelete = null; + + return MapperFactory.SchedulerAppointmentDCSchedulerAppointment.MapToNewDCs(lOriginals); } catch (Exception e) { diff --git a/Shared/Core/Utils.cs b/Shared/Core/Utils.cs index 2d90405c3..518a8cd8f 100644 --- a/Shared/Core/Utils.cs +++ b/Shared/Core/Utils.cs @@ -1018,7 +1018,7 @@ namespace BS.Shared.Core var obj1 = x[i]; var obj2 = y[i]; - if(!Equals(obj1, obj2)) + if(!(obj1?.Equals(obj2) ?? false)) { return false; } diff --git a/Shared/DataContracts/ServiceAccountingDC.cs b/Shared/DataContracts/ServiceAccountingDC.cs index 602ad4d93..08beeeb9b 100644 --- a/Shared/DataContracts/ServiceAccountingDC.cs +++ b/Shared/DataContracts/ServiceAccountingDC.cs @@ -23,5 +23,21 @@ namespace BS.Shared.DataContracts [DataMember] public bool IsDefault { get; set; } + public override bool Equals(object obj) + { + if(obj is ServiceAccountingDC s) + { + var a = Equals(ServiceAccountingOid, s.ServiceAccountingOid); + var b = Equals(ServiceAccountingVersion, s.ServiceAccountingVersion); + var c = Equals(BillableAmount, s.BillableAmount); + var d = AccountingInterval.Equals(s.AccountingInterval); + var e = Equals(ServiceDescription, s.ServiceDescription); + var f = IsDefault == s.IsDefault; + + return a && b && c && d && e && f; + } + + return false; + } } } \ No newline at end of file diff --git a/Shared/Extensions/DateTimeExtensions.cs b/Shared/Extensions/DateTimeExtensions.cs index edb2afed5..4a190f2e3 100644 --- a/Shared/Extensions/DateTimeExtensions.cs +++ b/Shared/Extensions/DateTimeExtensions.cs @@ -584,5 +584,12 @@ namespace BS.Shared.Extensions { return dateTime.GetFirstOfMonth().AddMonths(1).AddDays(-1); } + + public static string GetDateString(this DateTime start, DateTime end) + { + return start.Date != end.Date ? + $"{start.ToShortDateString()} {start.ToShortTimeString()} - {end.ToShortDateString()} {end.ToShortTimeString()}" : + $"{start.ToShortDateString()} {start.ToShortTimeString()} - {end.ToShortTimeString()}"; + } } } \ No newline at end of file