Mitarbeiterstundenkonto: Rechte werden wie im FaC beachtet
Ressourcenverfügbarkeitsprüfung zeigt jetzt Intervalle, in denen die ausgewählten Ressourcen bereits gebucht sind an und von wem, sofern man diesen Mitarbeiter sehen darf.

FaC:
Ressourcenverfügbarkeitsprüfung zeigt jetzt Intervalle, in denen die ausgewählten Ressourcen bereits gebucht sind an und von wem, sofern man diesen Mitarbeiter sehen darf.
This commit is contained in:
2023-07-31 15:29:16 +02:00
parent febee3a2fc
commit 0f33a2b034
23 changed files with 713 additions and 609 deletions

View File

@@ -538,7 +538,7 @@ namespace BeWo
showBetrag = true;
showPivotGrid = true;
showArbeitszeiten = true;
showMarker = true;
//showMarker = true;
showUrlaubsplanung = true;
showDienstplanung = true;
showHilfeplanBezeichnung = true;

View File

@@ -696,7 +696,7 @@ namespace BeWo
public bool DoSaveCheck()
{
return _CurrentDetailView == null || _CurrentDetailView.DoSaveCheck();
return _CurrentDetailView is null || _CurrentDetailView.DoSaveCheck();
}
private void InitCommandBindings()
@@ -706,7 +706,7 @@ namespace BeWo
ApplicationCommands.Save,
(s, e) =>
{
if (_CurrentModalPopup == null)
if (_CurrentModalPopup is null)
{
_CurrentDetailView.SaveData();
}
@@ -717,13 +717,13 @@ namespace BeWo
},
(s, e) =>
{
if (_CurrentModalPopup == null)
if (_CurrentModalPopup is null)
{
e.CanExecute = _CurrentDetailView != null ? _CurrentDetailView.IsDirty : false;
e.CanExecute = _CurrentDetailView?.IsDirty ?? false;
}
else
{
e.CanExecute = _CurrentDetailView != null && (_CurrentModalPopup is BeWoView && ((BeWoView) _CurrentModalPopup).IsDirty);
e.CanExecute = _CurrentDetailView != null && (_CurrentModalPopup is BeWoView view && view.IsDirty);
}
}));

View File

@@ -141,7 +141,7 @@ namespace BeWo.View.Master
}
// Mitarbeiterstundenkonto
if (BeWoApp.Tenant == "3010479871" || (!BeWoApp.LoggedOnUser.HasRight(UserRightType.Mitarbeiterstundenkonto_ViewAll) && !BeWoApp.LoggedOnUser.HasRight(UserRightType.Mitarbeiterstundenkonto_ViewSelf) && !BeWoApp.LoggedOnUser.HasRight(UserRightType.Mitarbeiterstundenkonto_ViewTeams)))
if(BeWoApp.Tenant == "3010479871" || (!BeWoApp.LoggedOnUser.HasRight(UserRightType.Mitarbeiterstundenkonto_ViewAll) && !BeWoApp.LoggedOnUser.HasRight(UserRightType.Mitarbeiterstundenkonto_ViewSelf) && !BeWoApp.LoggedOnUser.HasRight(UserRightType.Mitarbeiterstundenkonto_ViewTeams)))
{
//Aachener Verein
tabitem_makonto.Visibility = Visibility.Collapsed;

View File

@@ -126,6 +126,8 @@ namespace BeWoPlanerMobil.Controllers
TempData["show_pw_change_popup"] = tempDataValue;
}
}
Model.ShowMarker = UserSettingsUtils.GetSettingValueAsBool(Model.Mandator.Settings, SettingsKeys.ShowMarker);
}
var mandatorSettings = Model.Mandator.Settings;
@@ -270,7 +272,6 @@ namespace BeWoPlanerMobil.Controllers
Log.Info($"Model.SupportConceptListObjects Oids = {sb}");
}
//Log.Info(String.Format("Main() Set CostBearer2SupportConceptOid = -1: Model.SelectedSupportConceptListObject is null {0}, isInList {1}", Model.SelectedSupportConceptListObject is null, isInList));
Model.SelectedSupportConceptListObject = Model.SupportConceptListObjects.FirstOrDefault(f => f.CostBearer2SupportConceptOid == "-1") ?? Model.SupportConceptListObjects.First();
Model.CostBearer2SupportConceptOid = -1;
@@ -926,6 +927,7 @@ namespace BeWoPlanerMobil.Controllers
appointmentListItemPrototype = appointmentListItem;
}
var marker = "on" == collection[FormCollectionConstants.MarkerKey];
string doku1;
if(Model.Dokutypes != null && Model.Dokutypes.Length > 0)
@@ -1035,7 +1037,10 @@ namespace BeWoPlanerMobil.Controllers
Model.NewServiceRecord.Goals = Model.SelectedGoals;
Model.NewServiceRecord.Start = zeitenFeld[0];
Model.NewServiceRecord.End = zeitenFeld[1];
if(marker)
{
Model.NewServiceRecord.ServiceRecordType = ServiceRecordTypeId.Content;
}
Model.NewServiceRecord.DistanceInMeterDecimal = distanceInMeters;
if(Model.Employee.EmployeeOid.HasValue)
@@ -2287,9 +2292,6 @@ namespace BeWoPlanerMobil.Controllers
var newResult = new ValidationResult();
var exitLoop = false;
// ToDo: Prüfen, ob eine Monatsunterschrift mit dem ServiceRecord verbunden ist und, ob die Zeiten geändert wurden.
// ToDo: Ist dem so, dann eine Warnung anzeigen, dass die damit verknpüpfte Unterschrift ungültig oder gelöscht wird, und so nicht mehr auf dem QB angezeigt wird.
if(Model.SelectedSupportConcept != null && Model.SelectedSupportConcept.Goals.Any() && Model.SelectedGoals.Count == 0)
{
newResult.Message += "Es wurden keine Ziele zugeordnet.<br/><br/>";
@@ -3037,6 +3039,8 @@ namespace BeWoPlanerMobil.Controllers
return View("Main", Model);
}
var marker = "on" == formCollection[FormCollectionConstants.MarkerKey];
var distanz = formCollection[FormCollectionConstants.DistanceKey];
decimal? distanceInMeters = null;
@@ -3126,6 +3130,11 @@ namespace BeWoPlanerMobil.Controllers
Model.NewServiceRecord.Start = zeitenFeld[0];
Model.NewServiceRecord.End = zeitenFeld[1];
if(marker)
{
Model.NewServiceRecord.ServiceRecordType = ServiceRecordTypeId.Content;
}
Model.NewServiceRecord.DistanceInMeterDecimal = distanceInMeters;
if(Model.Employee.EmployeeOid.HasValue)
@@ -3545,6 +3554,8 @@ namespace BeWoPlanerMobil.Controllers
return View("Main", Model);
}
var marker = "on" == formCollection[FormCollectionConstants.MarkerKey];
var distanz = formCollection[FormCollectionConstants.DistanceKey];
decimal? distanceInMeters = null;
@@ -3664,6 +3675,11 @@ namespace BeWoPlanerMobil.Controllers
ServiceDescription = OperationsService.GetServiceDescription(Model.SelectedServiceDescriptionOid.Value)
};
if(marker)
{
newServiceRecord.ServiceRecordType = ServiceRecordTypeId.Content;
}
if(Model.IsEndDateVisible)
{
newServiceRecord.ServiceRecordFormat = ServiceRecordFormate.ZeiterfassungMitEndDatum;

View File

@@ -56,23 +56,23 @@ namespace BeWoPlanerMobil.Controllers
if(AbstractModel.HasRightToInsertRessourceAppointments)
{
var allResources = KalenderService.GetAllResources().ToList();
var allResources = KalenderService.GetAllResources().OrderBy(r => r.Name).ToList();
var categories2Resources = new Dictionary<ValueListEntryDC, List<ResourceDC>>();
foreach(var category in allResources.Select(resource => resource.ResourceCategory))
{
categories2Resources.AddOrUpdateValueInDictionary(category, allResources.Where(resource => resource.ResourceCategory.Equals(category)).ToList());
categories2Resources.AddOrUpdateValueInDictionary(category, allResources.Where(resource => resource.ResourceCategory.Equals(category)).OrderBy(r => r.Name).ToList());
}
Model.ResourceCategories2Resources = categories2Resources;
Model.ResourceCategories2Resources = categories2Resources.OrderBy(kvp => kvp.Key.DisplayName).ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
}
if(Model?.Employee?.EmployeeOid.HasValue ?? false)
{
var compactEmployee = EmployeeService.GetActiveCompactEmployeeWithOid(Model.Employee.EmployeeOid.Value);
Model.MyTeamEmployees = EmployeeService.GetAllTeamMember(compactEmployee);
Model.MyTeamEmployees = EmployeeService.GetAllTeamMember(compactEmployee).OrderBy(employee => employee.LastName).ToList();
}
else if(!(Model is null))
{
@@ -81,7 +81,7 @@ namespace BeWoPlanerMobil.Controllers
if(AbstractModel.HasRightToViewTeams && (Model?.Employee?.EmployeeOid.HasValue ?? false))
{
Model.MyTeams = EmployeeService.GetAllActiveCompactTeamsForEmployee(Model.Employee.EmployeeOid.Value);
Model.MyTeams = EmployeeService.GetAllActiveCompactTeamsForEmployee(Model.Employee.EmployeeOid.Value).OrderBy(team => team.Name).ToList();
}
if(!(Model is null))
@@ -175,13 +175,13 @@ namespace BeWoPlanerMobil.Controllers
if(AbstractModel.HasRightToViewCustomerSelectionInScheduler)
{
//Model.AllCustomers = EmployeeService.GetActiveCompactCustomersForEmployee(Model.Employee.EmployeeOid).OrderBy(o => o.DetailDescription).ToList();
Model.AllCustomers = CustomerService.GetAllActiveCompactCustomers();
Model.AllCustomers = CustomerService.GetAllActiveCompactCustomers().OrderBy(customer => customer.LastName).ToList();
}
if(AbstractModel.HasRightToViewEmployeeAppointments)
{
//Model.AllEmployees = EmployeeService.GetActiveCompactEmployeesForEmployee(Model.Employee.EmployeeOid.Value).OrderBy(o => o.DetailDescription).ToList();
Model.AllEmployees = EmployeeService.GetAllActiveEmployeesCompact();
Model.AllEmployees = EmployeeService.GetAllActiveEmployeesCompact().OrderBy(employee => employee.LastName).ToList();
}
}
@@ -610,59 +610,61 @@ namespace BeWoPlanerMobil.Controllers
return LeerzeichenFuerGetMethoden;
}
var oidList = ConvertOidStringToList(resourceOids);
foreach(var oid in oidList)
{
if(!Model.ResourceCategories2Resources.Any(a => a.Value.All(b => b.ResourceOid != oid)))
{
return JsonConvert.SerializeObject(new List<ResourceDC>());
}
}
var dateTimes = ConvertStringDatesToDateTimes(start, end);
var unavailableResources = KalenderService.CheckResourceAvailability(dateTimes.StartDate, dateTimes.EndDate, oidList, Model.SelectedAppointment?.SchedulerAppointmentOid);
return JsonConvert.SerializeObject(unavailableResources);
// ToDo: Wieder einchecken
// ALT!
//var oidList = ConvertOidStringToList(resourceOids);
//foreach(var oid in oidList)
//{
// if(!Model.ResourceCategories2Resources.Any(a => a.Value.All(b => b.ResourceOid != oid)))
// {
// return LeerzeichenFuerGetMethoden;
// return JsonConvert.SerializeObject(new List<ResourceDC>());
// }
//}
//var dateTimes = ConvertStringDatesToDateTimes(start, end);
//if(allDay)
//{
// dateTimes.EndDate = dateTimes.EndDate.AddDays(1);
//}
//var unavailableResources = KalenderService.CheckResourceAvailability(dateTimes.StartDate, dateTimes.EndDate, oidList, Model.SelectedAppointment?.SchedulerAppointmentOid);
//var info = KalenderService.CheckResourceAvailabilityWithEmployeeInformation(dateTimes.StartDate, dateTimes.EndDate, oidList, Model.SelectedAppointment?.SchedulerAppointmentOid);
//return JsonConvert.SerializeObject(unavailableResources);
//var result = string.Empty;
//foreach(var kvp in info)
//{
// result += $"Die Ressource \"{kvp.Key}\" ist im ausgewählten Zeitraum {start} bis {end} bereits gebucht";
// if(!kvp.Value.All(string.IsNullOrWhiteSpace))
// {
// result += ":<br /><br />";
// }
var oidList = ConvertOidStringToList(resourceOids);
// foreach(var interval in kvp.Value)
// {
// result += $"{interval}<br />";
// }
//}
foreach(var oid in oidList)
{
if(!Model.ResourceCategories2Resources.Any(a => a.Value.All(b => b.ResourceOid != oid)))
{
return LeerzeichenFuerGetMethoden;
}
}
//return result;
var dateTimes = ConvertStringDatesToDateTimes(start, end);
if(allDay)
{
dateTimes.EndDate = dateTimes.EndDate.AddDays(1);
}
var recurrenceId = Model.SelectedAppointment.RecurrenceId;
var recurrenceIndex = Model.SelectedAppointment.RecurrenceIndex;
var info = KalenderService.CheckResourceAvailabilityWithEmployeeInformation(dateTimes.StartDate, dateTimes.EndDate, oidList, Model.SelectedAppointment?.SchedulerAppointmentOid, null);
var result = string.Empty;
foreach(var kvp in info)
{
result += $"Die Ressource \"{kvp.Key}\" ist im ausgewählten Zeitraum {start} bis {end} bereits gebucht";
if(!kvp.Value.All(string.IsNullOrWhiteSpace))
{
result += ":<br /><br />";
}
foreach(var interval in kvp.Value)
{
result += $"{interval}<br />";
}
}
return result;
}
[Authorize]

View File

@@ -155,7 +155,28 @@ namespace BeWoPlanerMobil.Models
public static bool HasRightMitarbeiterstundenkontoViewTeams => CheckRight(UserRightType.Mitarbeiterstundenkonto_ViewTeams);
public static bool HasRightMitarbeiterstundenkontoViewSelf => CheckRight(UserRightType.Mitarbeiterstundenkonto_ViewSelf);
public static bool HasRightToViewReports => CheckRight(UserRightType.QueryView_View);
public static bool HasRightToViewReports => CheckForAtLeastOneRight(new UserRightType[]
{
UserRightType.ViewAll,
UserRightType.QueryView_View,
UserRightType.Analysis_ServiceOverview_View,
UserRightType.Analysis_Auslastung_View,
UserRightType.Analysis_AuslastungAllEmployee_View,
UserRightType.Analysis_AuslastungTeam_View,
UserRightType.Kilometerauswertung_View,
UserRightType.KilometerauswertungEigene_View,
UserRightType.BewertungAuswertung_View,
UserRightType.PivotTabelleAnsehen,
UserRightType.DienstplanungAnsehen,
UserRightType.AbwesenheitsPlanungAnsehen,
UserRightType.Mitarbeiterstundenkonto_ViewAll,
UserRightType.Mitarbeiterstundenkonto_ViewSelf,
UserRightType.Mitarbeiterstundenkonto_ViewTeams,
UserRightType.Jahresbericht,
UserRightType.Auswertungen_BerichteAnsehen,
UserRightType.Auswertungen_StundenuebersichtAnsehen,
UserRightType.Auswertungen_HilfeplanuebersichtAnsehen
});
public static bool HasRightToViewMitarbeiterstundenkonto
{

View File

@@ -729,6 +729,8 @@ namespace BeWoPlanerMobil.Models
public MandatorDC Mandator { get; set; }
public bool IsPasswordSecurityEnabled { get; set; }
public bool ShowMarker { get; set; }
}
public class CustomSelectListItem

View File

@@ -85,7 +85,7 @@ namespace BeWoPlanerMobil.Models
allResources.AddRangeIfElementsNotIn(cat2res.Value);
}
return allResources;
return allResources.OrderBy(resource => resource.Name).ToList();
}
}

View File

@@ -100,11 +100,11 @@ function submitGroupBookingForm() {
}
function deactivateGroupBookingForm() {
$("#employees-button, #category-select, #leistung-select, #start-date, #end-date, #start-time, #end-time, #duration, #distance, textarea, #reset-button, #create-button, #textbausteine-button, #hours-minutes-dropdown-btn").prop("disabled", true);
$("#employees-button, #category-select, #leistung-select, #start-date, #end-date, #start-time, #end-time, #duration, #distance, textarea, #reset-button, #create-button, #textbausteine-button, #hours-minutes-dropdown-btn, #gb-marker-cb").prop("disabled", true);
}
function activateGroupBookingForm() {
$("#employees-button, #category-select, #leistung-select, #start-date, #end-date, #start-time, #end-time, #duration, #distance, textarea, #reset-button, #create-button, #textbausteine-button, #hours-minutes-dropdown-btn").prop("disabled", false);
$("#employees-button, #category-select, #leistung-select, #start-date, #end-date, #start-time, #end-time, #duration, #distance, textarea, #reset-button, #create-button, #textbausteine-button, #hours-minutes-dropdown-btn, #gb-marker-cb").prop("disabled", false);
}
function deleteServiceRecord(serviceRecordOid) {

View File

@@ -121,57 +121,56 @@ function validateAppointmentForm() {
$.get(getCheckResourcesAvailabilityUrl(), { start: startDate.format("DD.MM.YYYY HH:mm"), end: endDate.format("DD.MM.YYYY HH:mm"), resourceOids: oidString, allDay: isAllDay }).done(function(result) {
if (result.length > 1) {
try {
// ToDo: Wieder einchecken! (24.07.2023)
//hideSpinner();
//if (result.includes("Fehler!")) {
// showErrorMessagePopup(result.substring(7));
// return;
//} else {
// showMessagePopupWithHtml("Überschneidung",
// result,
// function() {
// $("#messagePopup .modal-body").html();
// showSpinner();
// insertOrUpdateAppointment(startDate.format("DD.MM.YYYY"), endDate.format("DD.MM.YYYY"), startDate.format("HH:mm"), endDate.format("HH:mm"));
// },
// false);
//}
var unavailableResources = $.parseJSON(result);
var resourceCount = 0;
var names = "";
$.each(unavailableResources, function(index, resource) {
if (names.length > 1) {
names += ", ";
}
resourceCount++;
names += resource.Name;
});
var unavailableResourcesMessage;
if(resourceCount > 0) {
if(resourceCount > 1) {
unavailableResourcesMessage = "Einige der ausgewählten Ressourcen (" + names + ") sind zum gewählten Zeitpunkt nicht verfügbar.";
} else {
unavailableResourcesMessage = "Eine der ausgewählten Ressourcen (" + names + ") ist zum gewählten Zeitpunkt nicht verfügbar.";
}
hideSpinner();
showWarningMessageBox("Überschneidung", unavailableResourcesMessage, function() {
$("#messagePopup .modal-body").html();
showSpinner();
insertOrUpdateAppointment(startDate.format("DD.MM.YYYY"), endDate.format("DD.MM.YYYY"), startDate.format("HH:mm"), endDate.format("HH:mm"));
}, false);
hideSpinner();
if (result.includes("Fehler!")) {
showErrorMessagePopup(result.substring(7));
return;
} else {
showMessagePopupWithHtml("Überschneidung",
result,
function() {
$("#messagePopup .modal-body").html();
showSpinner();
insertOrUpdateAppointment(startDate.format("DD.MM.YYYY"), endDate.format("DD.MM.YYYY"), startDate.format("HH:mm"), endDate.format("HH:mm"));
},
false);
}
// ALT!
//var unavailableResources = $.parseJSON(result);
//var resourceCount = 0;
//var names = "";
//$.each(unavailableResources, function(index, resource) {
// if (names.length > 1) {
// names += ", ";
// }
// resourceCount++;
// names += resource.Name;
//});
//var unavailableResourcesMessage;
//if(resourceCount > 0) {
// if(resourceCount > 1) {
// unavailableResourcesMessage = "Einige der ausgewählten Ressourcen (" + names + ") sind zum gewählten Zeitpunkt nicht verfügbar.";
// } else {
// unavailableResourcesMessage = "Eine der ausgewählten Ressourcen (" + names + ") ist zum gewählten Zeitpunkt nicht verfügbar.";
// }
// hideSpinner();
// showWarningMessageBox("Überschneidung", unavailableResourcesMessage, function() {
// $("#messagePopup .modal-body").html();
// showSpinner();
// insertOrUpdateAppointment(startDate.format("DD.MM.YYYY"), endDate.format("DD.MM.YYYY"), startDate.format("HH:mm"), endDate.format("HH:mm"));
// }, false);
// return;
//}
} catch (error) {
showErrorPopup(error);
return;

View File

@@ -24,10 +24,9 @@
public static string RecordsKey => "Records";
public static string ServiceRecordOidHolder2Key => "service-record-oid-holder";
public static string IsInGroupBookingModeKey => "IsInGroupBookingMode";
public static string IsInMultiBookingModeKey => "IsInMultiBookingMode";
public static string DurationInMinutesKey => "DurationInMinutes";
public static string MarkerKey => "marker-cb";
// Kalender
public static string AppointmentStartDateKey => "StartDate";

View File

@@ -146,6 +146,25 @@
</div>
</div>
</div>
<!-- Marker -->
@if(Model.ShowMarker)
{
<div class="form-row">
<div class="col-md">
<div class="custom-control custom-checkbox custom-control-inline">
<input type="checkbox" class="custom-control-input" name="marker-cb" id="gb-marker-cb" />
<label class="custom-control-label" for="gb-marker-cb">Marker</label>
</div>
</div>
</div>
}
<div class="form-row">
<div class="col-md">
<hr/>
</div>
</div>
<!-- Start- und Enddatum -->
<div class="form-row">

View File

@@ -235,14 +235,14 @@
$("#employeesDropDown, #category-select, #leistung-select, " +
"#start-date, #end-date, #start-time, #end-time, #duration, " +
"#distance, #textbausteine-button, #goals-button, textarea, #reset-button, " +
"#create-button, #statistics-button, #timeFrameSelect, #hours-minutes-dropdown-btn").prop("disabled", (isSupportConceptSelected ? false : true));
"#create-button, #statistics-button, #timeFrameSelect, #hours-minutes-dropdown-btn, #marker-cb").prop("disabled", (isSupportConceptSelected ? false : true));
if("@Model.IsInGroupBookingMode".toLowerCase() === "true") {
var hasSelectedSupportConcepts = "@Model.SelectedConceptCostBearerRelations.Any()".toLowerCase() === "true";
$("#employees-button, #category-select, #leistung-select, " +
"#start-date, #end-date, #start-time, #end-time, #duration, " +
"#distance, textarea, #reset-button, #create-button, #textbausteine-button, #hours-minutes-dropdown-btn").prop("disabled", (hasSelectedSupportConcepts ? false : true));
"#distance, textarea, #reset-button, #create-button, #textbausteine-button, #hours-minutes-dropdown-btn, #gb-marker-cb").prop("disabled", (hasSelectedSupportConcepts ? false : true));
}
$("#fehlerdetail-textarea").prop("disabled", false);

View File

@@ -204,7 +204,7 @@
function deactivateMultiBookingForm() {
try {
$("#multi-booking-employees-button, #mb-category-select, #mb-leistung-select, #mb-start-date, #mb-end-date, #mb-start-time, #mb-end-time, #mb-duration, #mb-distance, textarea, #mb-reset-button, #mb-create-button, #mb-textbausteine-button, #mb-hours-minutes-dropdown-btn").prop("disabled", true);
$("#multi-booking-employees-button, #mb-category-select, #mb-leistung-select, #mb-start-date, #mb-end-date, #mb-start-time, #mb-end-time, #mb-duration, #mb-distance, textarea, #mb-reset-button, #mb-create-button, #mb-textbausteine-button, #mb-hours-minutes-dropdown-btn, #mb-marker-cb").prop("disabled", true);
} catch (error) {
showErrorPopup(error);
}
@@ -212,7 +212,7 @@
function activateMultiBookingForm() {
try {
$("#multi-booking-employees-button, #mb-category-select, #mb-leistung-select, #mb-start-date, #mb-end-date, #mb-start-time, #mb-end-time, #mb-duration, #mb-distance, textarea, #mb-reset-button, #mb-create-button, #mb-textbausteine-button, #mb-hours-minutes-dropdown-btn").prop("disabled", false);
$("#multi-booking-employees-button, #mb-category-select, #mb-leistung-select, #mb-start-date, #mb-end-date, #mb-start-time, #mb-end-time, #mb-duration, #mb-distance, textarea, #mb-reset-button, #mb-create-button, #mb-textbausteine-button, #mb-hours-minutes-dropdown-btn, #mb-marker-cb").prop("disabled", false);
} catch (error) {
showErrorPopup(error);
}
@@ -339,6 +339,25 @@
</div>
</div>
</div>
<!-- Marker -->
@if(Model.ShowMarker)
{
<div class="form-row">
<div class="col-md">
<div class="custom-control custom-checkbox custom-control-inline">
<input type="checkbox" class="custom-control-input" name="marker-cb" id="mb-marker-cb" />
<label class="custom-control-label" for="mb-marker-cb">Marker</label>
</div>
</div>
</div>
}
<div class="form-row">
<div class="col-md">
<hr/>
</div>
</div>
<!-- Start- und Enddatum -->
<div class="form-row">

View File

@@ -133,81 +133,121 @@
using(Html.BeginForm("CreateOrUpdateServiceRecord", "Main", FormMethod.Post, new { onreset = "serviceDescriptionSelectOnReset('category-select', 'leistung-select', 'textmodule-container', 'tree')", id = "singleBookingForm" }))
{
<div class="mt-3">
<!-- Einzelbuchung: Mitarbeiter -->
<div class="mt-3">
<!-- Einzelbuchung: Mitarbeiter -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text prepend-input-group-text">Mitarbeiter</div>
</div>
@Html.DropDownListFor(m => m.SelectedEmployeeOid, Model.EmployeeListItems, new { id = "employeesDropDown", @class = "custom-select", onchange = "setSelectedEmployee()" })
</div>
</div>
</div>
</div>
@if(Model.SelectedSupportConcept != null && Model.SelectedSupportConcept.Goals.Any())
{
<!-- Einzelbuchung: Ziele -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text prepend-input-group-text">Mitarbeiter</div>
<button type="button" class="btn btn-primary form-control my-3" data-toggle="modal" data-target="#goal-popup" id="goals-button">Ziele</button>
</div>
</div>
<div class="form-row">
<div class="col-md">
<div class="collapse w-100 mt-1 max-vw-50" id="goals-container"></div>
</div>
</div>
}
<!-- Einzelbuchung: Leistungskategorie -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text prepend-input-group-text">
Kategorie
</div>
</div>
@Html.DropDownListFor(m => m.SelectedServiceCategoryOid, Model.ServiceCategoryListItems, new { onchange = "loadServiceDescriptions('category-select', 'leistung-select', 'textmodule-container', 'tree')", @class = "custom-select", Id = "category-select" })
</div>
</div>
</div>
</div>
<!-- Einzelbuchung: Leistung -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text prepend-input-group-text">
Leistung
</div>
</div>
<select class="custom-select" id="leistung-select" name="ServiceDescription" onchange="setServiceDescription('leistung-select')">
</select>
</div>
</div>
</div>
</div>
<!-- Marker -->
@if(Model.ShowMarker)
{
<div class="form-row">
<div class="col-md">
<div class="custom-control custom-checkbox custom-control-inline">
<input type="checkbox" class="custom-control-input" name="marker-cb" id="marker-cb" />
<label class="custom-control-label" for="marker-cb">Marker</label>
</div>
</div>
</div>
}
<div class="form-row">
<div class="col-md">
<hr />
</div>
</div>
<!-- Einzelbuchung: Startdatum -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group date" id="start-date-picker" data-target-input="nearest">
<div class="input-group-prepend">
<div class="input-group-text prepend-input-group-text">
Startdatum
</div>
</div>
<input type="text" id="start-date" name="Datum" class="form-control datetimepicker-input" data-target="#start-date-picker" data-toggle="datetimepicker" value="@Model.StartDateToEdit" />
<div class="input-group-append" data-target="#start-date-picker" data-toggle="datetimepicker">
<div class="input-group-text px-2">
<i class="fas fa-calendar-alt"></i>
</div>
@Html.DropDownListFor(m => m.SelectedEmployeeOid, Model.EmployeeListItems, new { id = "employeesDropDown", @class = "custom-select", onchange = "setSelectedEmployee()" })
</div>
</div>
</div>
</div>
@if(Model.SelectedSupportConcept != null && Model.SelectedSupportConcept.Goals.Any())
<!-- Einzelbuchung: Enddatum -->
@if(Model.IsEndDateVisible)
{
<!-- Einzelbuchung: Ziele -->
<div class="form-row">
<div class="col-md">
<button type="button" class="btn btn-primary form-control my-3" data-toggle="modal" data-target="#goal-popup" id="goals-button">Ziele</button>
</div>
</div>
<div class="form-row">
<div class="col-md">
<div class="collapse w-100 mt-1 max-vw-50" id="goals-container"></div>
</div>
</div>
}
<!-- Einzelbuchung: Leistungskategorie -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group">
<div class="input-group date" id="end-date-picker" data-target-input="nearest">
<div class="input-group-prepend">
<div class="input-group-text prepend-input-group-text">
Kategorie
Enddatum
</div>
</div>
@Html.DropDownListFor(m => m.SelectedServiceCategoryOid, Model.ServiceCategoryListItems, new { onchange = "loadServiceDescriptions('category-select', 'leistung-select', 'textmodule-container', 'tree')", @class = "custom-select", Id = "category-select" })
</div>
</div>
</div>
</div>
<!-- Einzelbuchung: Leistung -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text prepend-input-group-text">
Leistung
</div>
</div>
<select class="custom-select" id="leistung-select" name="ServiceDescription" onchange="setServiceDescription('leistung-select')">
</select>
</div>
</div>
</div>
</div>
<!-- Einzelbuchung: Startdatum -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group date" id="start-date-picker" data-target-input="nearest">
<div class="input-group-prepend">
<div class="input-group-text prepend-input-group-text">
Startdatum
</div>
</div>
<input type="text" id="start-date" name="Datum" class="form-control datetimepicker-input" data-target="#start-date-picker" data-toggle="datetimepicker" value="@Model.StartDateToEdit" />
<div class="input-group-append" data-target="#start-date-picker" data-toggle="datetimepicker">
<input type="text" id="end-date" name="Enddatum" class="form-control datetimepicker-input" data-target="#end-date-picker" data-toggle="datetimepicker" value="@Model.EndDateToEdit" />
<div class="input-group-append" data-target="#end-date-picker" data-toggle="datetimepicker">
<div class="input-group-text px-2">
<i class="fas fa-calendar-alt"></i>
</div>
@@ -215,182 +255,162 @@
</div>
</div>
</div>
<!-- Einzelbuchung: Enddatum -->
@if(Model.IsEndDateVisible)
{
<div class="col-md">
<div class="form-group my-2">
<div class="input-group date" id="end-date-picker" data-target-input="nearest">
<div class="input-group-prepend">
<div class="input-group-text prepend-input-group-text">
Enddatum
</div>
</div>
<input type="text" id="end-date" name="Enddatum" class="form-control datetimepicker-input" data-target="#end-date-picker" data-toggle="datetimepicker" value="@Model.EndDateToEdit" />
<div class="input-group-append" data-target="#end-date-picker" data-toggle="datetimepicker">
<div class="input-group-text px-2">
<i class="fas fa-calendar-alt"></i>
</div>
</div>
</div>
</div>
</div>
}
</div>
<!-- Einzelbuchung: Von -->
<div class="form-row">
@{
var startTimeValue = Model.StartTimeToEdit;
var endTimeValue = Model.EndTimeToEdit;
var divisor = Model.SelectedDurationUnit == "Stunden" ? 60 : 1;
var durationValue = Model.DurationToEdit;
}
</div>
<!-- Einzelbuchung: Von -->
<div class="form-row">
@{
var startTimeValue = Model.StartTimeToEdit;
var endTimeValue = Model.EndTimeToEdit;
var divisor = Model.SelectedDurationUnit == "Stunden" ? 60 : 1;
var durationValue = Model.DurationToEdit;
if(Model.SetStartTimeToEndTimeAfterSave && !Model.IsInEditingMode)
if(Model.SetStartTimeToEndTimeAfterSave && !Model.IsInEditingMode)
{
startTimeValue = Model.NewStartTime;
endTimeValue = Model.NewEndTime;
durationValue = Model.NewDuration?.ToString();
if(Model.NewDuration.HasValue)
{
startTimeValue = Model.NewStartTime;
endTimeValue = Model.NewEndTime;
durationValue = Model.NewDuration?.ToString();
if(Model.NewDuration.HasValue)
{
durationValue = (Model.NewDuration / divisor).ToString();
}
durationValue = (Model.NewDuration / divisor).ToString();
}
}
<div class="col-md">
<div class="form-group my-2">
<div class="input-group date" id="start-time-picker" data-target-input="nearest">
<div class="input-group-prepend">
<div class="input-group-text sm-prepend-input-group-text px-2">
Von
</div>
</div>
<input type="text" id="start-time" name="Start" class="form-control datetimepicker-input" data-target="#start-time-picker" value="@startTimeValue" />
<div class="input-group-append" data-target="#start-time-picker" data-toggle="datetimepicker">
<div class="input-group-text px-2">
<i class="fas fa-clock"></i>
</div>
}
<div class="col-md">
<div class="form-group my-2">
<div class="input-group date" id="start-time-picker" data-target-input="nearest">
<div class="input-group-prepend">
<div class="input-group-text sm-prepend-input-group-text px-2">
Von
</div>
</div>
</div>
</div>
<!-- Einzelbuchung: Bis -->
<div class="col-md">
<div class="form-group my-2">
<div class="input-group date" id="end-time-picker" data-target-input="nearest">
<div class="input-group-prepend">
<div class="input-group-text sm-prepend-input-group-text px-2">
Bis
</div>
</div>
<input type="text" id="end-time" name="Ende" class="form-control datetimepicker-input" data-target="#end-time-picker" value="@endTimeValue" />
<div class="input-group-append" data-target="#end-time-picker" data-toggle="datetimepicker">
<div class="input-group-text px-2">
<i class="fas fa-clock"></i>
</div>
<input type="text" id="start-time" name="Start" class="form-control datetimepicker-input" data-target="#start-time-picker" value="@startTimeValue" />
<div class="input-group-append" data-target="#start-time-picker" data-toggle="datetimepicker">
<div class="input-group-text px-2">
<i class="fas fa-clock"></i>
</div>
</div>
</div>
</div>
</div>
<!-- Einzelbuchung: Dauer -->
<!-- Einzelbuchung: Bis -->
<div class="col-md">
<div class="form-group my-2">
<div class="input-group date" id="end-time-picker" data-target-input="nearest">
<div class="input-group-prepend">
<div class="input-group-text sm-prepend-input-group-text px-2">
Bis
</div>
</div>
<input type="text" id="end-time" name="Ende" class="form-control datetimepicker-input" data-target="#end-time-picker" value="@endTimeValue" />
<div class="input-group-append" data-target="#end-time-picker" data-toggle="datetimepicker">
<div class="input-group-text px-2">
<i class="fas fa-clock"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Einzelbuchung: Dauer -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group">
<div class="input-group-prepend">
@{
var labelText = Model.EinheitZeiterfassung == 1 ? "Dauer (h)" : "Dauer";
}
<div class="input-group-text prepend-input-group-text">
@labelText
</div>
</div>
<input type="text" class="form-control" id="duration" name="Dauer" onchange="onDurationChange('start-time', 'end-time', 'start-date', 'end-date', 'duration', 'hours-minutes-dropdown-btn', 'start-date-picker', 'end-date-picker')" value="@durationValue">
@if(Model.IsZeiterfassungInStdMin)
{
<div class="input-group-append">
<button id="hours-minutes-dropdown-btn" class="btn btn-outline-primary dropdown-toggle w-100" type="button" data-toggle="dropdown">
@Model.SelectedDurationUnit
</button>
<div class="dropdown-menu w-100">
<a class="dropdown-item hours-minutes-link" href="#">Minuten</a>
<a class="dropdown-item hours-minutes-link" href="#">Stunden</a>
</div>
</div>
}
</div>
</div>
</div>
</div>
<!-- Einzelbuchung: Distanz -->
@if(Model.ShowDistanceField)
{
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group">
<div class="input-group-prepend">
@{
var labelText = Model.EinheitZeiterfassung == 1 ? "Dauer (h)" : "Dauer";
}
<div class="input-group-text prepend-input-group-text">
@labelText
<div class="input-group-text">
Gefahrene Kilometer
</div>
</div>
<input type="text" class="form-control" id="duration" name="Dauer" onchange="onDurationChange('start-time', 'end-time', 'start-date', 'end-date', 'duration', 'hours-minutes-dropdown-btn', 'start-date-picker', 'end-date-picker')" value="@durationValue">
@if(Model.IsZeiterfassungInStdMin)
{
<div class="input-group-append">
<button id="hours-minutes-dropdown-btn" class="btn btn-outline-primary dropdown-toggle w-100" type="button" data-toggle="dropdown">
@Model.SelectedDurationUnit
</button>
<div class="dropdown-menu w-100">
<a class="dropdown-item hours-minutes-link" href="#">Minuten</a>
<a class="dropdown-item hours-minutes-link" href="#">Stunden</a>
</div>
</div>
}
<input class="form-control" id="distance" name="Distanz" onchange="validateDistanceInput()" value="@Model.DistanceToEdit">
</div>
</div>
</div>
</div>
<!-- Einzelbuchung: Distanz -->
@if(Model.ShowDistanceField)
{
<div class="form-row">
<div class="col-md">
<div class="form-group my-2">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text">
Gefahrene Kilometer
</div>
</div>
<input class="form-control" id="distance" name="Distanz" onchange="validateDistanceInput()" value="@Model.DistanceToEdit">
</div>
</div>
</div>
</div>
}
@if(AbstractModel.HasRightToSeeTextModules)
{
<script>
}
@if(AbstractModel.HasRightToSeeTextModules)
{
<script>
function textModuleButtonOnClick() {
$('#tree').load('@Url.Action("LoadUpToDateTextModules")');
}
</script>
<!-- Einzelbuchung: Textbausteine -->
<div class="form-row" id="textmodule-container">
<div class="col-md">
<button type="button" class="btn btn-primary form-control mt-3" data-toggle="modal" data-target="#textbausteine-popup" id="textbausteine-button" onclick="textModuleButtonOnClick()">Textbausteine</button>
</script>
<!-- Einzelbuchung: Textbausteine -->
<div class="form-row" id="textmodule-container">
<div class="col-md">
<button type="button" class="btn btn-primary form-control mt-3" data-toggle="modal" data-target="#textbausteine-popup" id="textbausteine-button" onclick="textModuleButtonOnClick()">Textbausteine</button>
</div>
</div>
}
<div class="form-row">
<div class="col-md mt-3">
@if(Model.NumberOfDokuTypes == 0)
{
<div class="form-group">
<label for="dokufeld">Dokumentation</label>
<textarea class="form-control" name="Dokumentation6" id="dokufeld">@Model.NoticeToEdit</textarea>
</div>
</div>
}
<div class="form-row">
<div class="col-md mt-3">
@if(Model.NumberOfDokuTypes == 0)
{
<div class="form-group">
<label for="dokufeld">Dokumentation</label>
<textarea class="form-control" name="Dokumentation6" id="dokufeld">@Model.NoticeToEdit</textarea>
</div>
}
else
{
<ul class="nav nav-tabs" role="tab-list">
@for(var i = 0; i < Model.Dokutypes.Length; i++)
{
var currentDokuType = Model.Dokutypes[i];
}
else
{
<ul class="nav nav-tabs" role="tab-list">
@for(var i = 0; i < Model.Dokutypes.Length; i++)
{
var currentDokuType = Model.Dokutypes[i];
<li class="nav-item">
<a href="#doku_@i" id="doku_@i-tab" data-toggle="tab" role="tab" aria-controls="doku_@i" class="nav-link@(i == 0 ? " active" : string.Empty)" aria-selected="true">
@currentDokuType.DisplayName
</a>
</li>
}
</ul>
<div class="tab-content" id="dokufelderTab">
@for(var i = 0; i < Model.Dokutypes.Length; i++)
{
var textareaName = i + 1 < 1 ? "Dokumentation" : "Dokumentation" + (i + 1);
<li class="nav-item">
<a href="#doku_@i" id="doku_@i-tab" data-toggle="tab" role="tab" aria-controls="doku_@i" class="nav-link@(i == 0 ? " active" : string.Empty)" aria-selected="true">
@currentDokuType.DisplayName
</a>
</li>
}
</ul>
<div class="tab-content" id="dokufelderTab">
@for(var i = 0; i < Model.Dokutypes.Length; i++)
{
var textareaName = i + 1 < 1 ? "Dokumentation" : "Dokumentation" + (i + 1);
<div class="tab-pane show@(i == 0 ? " active" : string.Empty)" id="doku_@i" role="tabpanel" aria-labelledby="doku_@i-tab">
<textarea class="form-control doku-form-control" id="doku-textarea-@i" name="@textareaName">@Model.NoticeListToEdit[i]</textarea>
</div>
}
</div>
}
</div>
</div>
<div class="tab-pane show@(i == 0 ? " active" : string.Empty)" id="doku_@i" role="tabpanel" aria-labelledby="doku_@i-tab">
<textarea class="form-control doku-form-control" id="doku-textarea-@i" name="@textareaName">@Model.NoticeListToEdit[i]</textarea>
</div>
}
</div>
}
</div>
</div>
</div>
}
<div class="d-flex bd-highlight mt-3">

View File

@@ -113,7 +113,7 @@
@if(Model.HasResourcesEmployeesOrCustomers)
{
<div class="form-row">
@if(AbstractModel.HasRightToViewEmployeeAppointments)
@if(AbstractModel.HasRightToViewEmployeeAppointments && AbstractModel.HasRightToInsertEmployeeAppointments)
{
<div class="col-md">
<div class="form-group my-1">
@@ -121,7 +121,7 @@
</div>
</div>
}
@if(AbstractModel.HasRightToViewCustomerSelectionInScheduler)
@if(AbstractModel.HasRightToViewCustomerSelectionInScheduler && AbstractModel.HasRightToInsertCustomerAppointments)
{
<div class="col-md">
<div class="form-group my-1">
@@ -129,7 +129,7 @@
</div>
</div>
}
@if(AbstractModel.HasRightToViewAllResourceAppointments && Model.ResourceCategories2Resources.Any())
@if(AbstractModel.HasRightToViewAllResourceAppointments && AbstractModel.HasRightToInsertRessourceAppointments && Model.ResourceCategories2Resources.Any())
{
<div class="col-md">
<div class="form-group my-1">
@@ -140,7 +140,7 @@
</div>
<div class="form-row">
@if(AbstractModel.HasRightToViewEmployeeAppointments)
@if(AbstractModel.HasRightToViewEmployeeAppointments && AbstractModel.HasRightToInsertEmployeeAppointments)
{
<div class="col-12">
<div class="form-group my-1">
@@ -169,7 +169,7 @@
</div>
</div>
}
@if(AbstractModel.HasRightToViewCustomerSelectionInScheduler)
@if(AbstractModel.HasRightToViewCustomerSelectionInScheduler && AbstractModel.HasRightToInsertCustomerAppointments)
{
<div class="col-12">
<div class="form-group my-1">
@@ -207,7 +207,7 @@
</div>
</div>
}
@if(AbstractModel.HasRightToViewAllResourceAppointments)
@if(AbstractModel.HasRightToViewAllResourceAppointments && AbstractModel.HasRightToInsertRessourceAppointments)
{
<div class="col-12">
<div class="form-group my-1">
@@ -293,7 +293,7 @@
</div>
</div>
@if(AbstractModel.HasRightToViewAllResourceAppointments && Model.ResourceCategories2Resources.Any())
@if(AbstractModel.HasRightToViewAllResourceAppointments && AbstractModel.HasRightToInsertRessourceAppointments && Model.ResourceCategories2Resources.Any())
{
<div class="modal" tabindex="-1" role="dialog" id="resources-popup">
<div class="modal-dialog modal-dialog-scrollable" role="document">
@@ -363,7 +363,7 @@
</div>
}
@if(AbstractModel.HasRightToViewEmployeeAppointments && Model.AllEmployees.Any())
@if(AbstractModel.HasRightToViewEmployeeAppointments && AbstractModel.HasRightToInsertEmployeeAppointments && Model.AllEmployees.Any())
{
<script type="text/javascript">
function resetEmployeeSearch() {
@@ -583,7 +583,7 @@
</div>
}
@if(AbstractModel.HasRightToViewCustomerSelectionInScheduler && Model.AllCustomers.Any())
@if(AbstractModel.HasRightToViewCustomerSelectionInScheduler && AbstractModel.HasRightToInsertCustomerAppointments && Model.AllCustomers.Any())
{
<div class="modal" tabindex="-1" role="dialog" id="customers-popup">
<div class="modal-dialog modal-dialog-scrollable" role="document">

View File

@@ -358,6 +358,7 @@
}
}
@if(AbstractModel.HasRightToViewQuittierungsbelege)
{
using(Html.BeginForm("RedirectToReportView", "Main", FormMethod.Post))
@@ -373,6 +374,7 @@
}
}
@*ToDo: Wie im FaC machen!*@
@if(AbstractModel.HasRightToViewReports && AbstractModel.HasRightToViewMitarbeiterstundenkonto)
{
using(Html.BeginForm("RedirectToReportViewer", "Main", FormMethod.Post))

View File

@@ -1359,22 +1359,22 @@ namespace BeWo.Data.Access
public bool OverlappingAppointmentsExist(DateTime start, DateTime end, IEnumerable<long> employees, IEnumerable<long> customers, IEnumerable<long> resources, long originator, long? appointmentOid, string recurrenceId = "", int occurrenceIndex = 0)
{
if(employees == null)
if(employees is null)
{
employees = new List<long>();
}
if(customers == null)
if(customers is null)
{
customers = new List<long>();
}
if(resources == null)
if(resources is null)
{
resources = new List<long>();
}
var isRecurrenceException = appointmentOid == null;
var isRecurrenceException = appointmentOid is null;
var isBeingUpdatedToNormalAppointment = false;
Guid? recurrenceIdToIgnore = null;
@@ -1414,7 +1414,7 @@ namespace BeWo.Data.Access
var appointments = appTmp.Where(a =>
{
if(a.RecurrenceInfo == null)
if(a.RecurrenceInfo is null)
{
return true;
}
@@ -1440,30 +1440,24 @@ namespace BeWo.Data.Access
{
var recId = root.GetRecurrenceId();
if(recId != null && recurrenceIdToIgnore != null)
if(recId is null || recurrenceIdToIgnore is null)
{
if(recId.Equals(recurrenceIdToIgnore))
{
return false;
}
return true;
}
return true;
return !recId.Equals(recurrenceIdToIgnore);
}).ToList();
schedulerAppointments = schedulerAppointments.Where(root =>
{
var recId = root.GetRecurrenceId();
if(recId != null && recurrenceIdToIgnore != null)
if(recId is null || recurrenceIdToIgnore is null)
{
if(recId.Equals(recurrenceIdToIgnore))
{
return false;
}
return true;
}
return true;
return !recId.Equals(recurrenceIdToIgnore);
}).ToList();
}
@@ -1477,7 +1471,7 @@ namespace BeWo.Data.Access
// Das Muster für die Terminserie wird berechnet
var pattern = StaticAppointmentFactory.CreateAppointment(AppointmentType.Pattern);
if(pattern == null)
if(pattern is null)
{
continue;
}
@@ -1496,7 +1490,7 @@ namespace BeWo.Data.Access
foreach(var occurrence in occurrences.GetAppointments(interval))
{
if(appointment.EndDate == null || appointment.StartDate == null)
if(appointment.EndDate is null || appointment.StartDate is null)
{
continue;
}
@@ -1576,21 +1570,21 @@ namespace BeWo.Data.Access
var recurringAppointment = new SchedulerAppointment
{
AllDay = occurrence.AllDay,
CustomerList = appointment.CustomerList,
Notice = appointment.Notice,
EmployeeList = appointment.EmployeeList,
EndDate = occurrence.Start.AddMinutes(duration),
AllDay = occurrence.AllDay,
CustomerList = appointment.CustomerList,
Notice = appointment.Notice,
EmployeeList = appointment.EmployeeList,
EndDate = occurrence.Start.AddMinutes(duration),
FormerBookingSequenceOid = appointment.FormerBookingSequenceOid,
IsPrivate = appointment.IsPrivate,
Location = appointment.Location,
Originator = appointment.Originator,
RecurrenceInfo = occurrence.RecurrenceInfo.ToXml(),
ReminderInfo = appointment.ReminderInfo,
ResourceList = appointment.ResourceList,
StartDate = occurrence.Start,
Subject = appointment.Subject ?? "",
Type = appointment.Type
IsPrivate = appointment.IsPrivate,
Location = appointment.Location,
Originator = appointment.Originator,
RecurrenceInfo = occurrence.RecurrenceInfo.ToXml(),
ReminderInfo = appointment.ReminderInfo,
ResourceList = appointment.ResourceList,
StartDate = occurrence.Start,
Subject = appointment.Subject ?? "",
Type = appointment.Type
};
schedulerAppointments.AddIfNotIn(recurringAppointment);
@@ -1608,7 +1602,7 @@ namespace BeWo.Data.Access
}
}
var oidList = new List<long>();
var employeeOidList = new List<long>();
schedulerAppointments = schedulerAppointments.Where(appointment => appointment.Type != 4).ToList();
@@ -1622,10 +1616,10 @@ namespace BeWo.Data.Access
}
}
oidList.AddRange(appointment.EmployeeList.Select(rel => rel.ParticipationAnswer != ParticipationAnswer.Absage && rel.Employee.Oid != null ? rel.Employee.Oid.Value : 0));
employeeOidList.AddRange(appointment.EmployeeList.Select(rel => rel.ParticipationAnswer != ParticipationAnswer.Absage && rel.Employee.Oid != null ? rel.Employee.Oid.Value : 0));
}
var hasOverlappingEmployeeAppointments = oidList.Intersect(employees).Any();
var hasOverlappingEmployeeAppointments = employeeOidList.Intersect(employees).Any();
var hasOverlappingCustomerAppointments = schedulerAppointments.Any(app => { return ShouldDoAppointmentOverlappingCheck(app, recurrenceGuid) && app.CustomerList.Select(c => c.Oid ?? 0).Intersect(customers).Any(); });
var hasOverlappingResourceAppointments = schedulerAppointments.Any(app => { return ShouldDoAppointmentOverlappingCheck(app, recurrenceGuid) && app.ResourceList.Select(r => r.Oid ?? 0).Intersect(resources).Any(); });
@@ -1644,23 +1638,22 @@ namespace BeWo.Data.Access
return hasOverlappingEmployeeAppointments || hasOverlappingCustomerAppointments || hasOverlappingResourceAppointments || hasOverlappingOriginatorAppointments;
}
private static bool ShouldDoAppointmentOverlappingCheck(SchedulerAppointment appointment, Guid? recurrenceId)
{
if(appointment.Oid.HasValue && recurrenceId.HasValue)
if(!appointment.Oid.HasValue || !recurrenceId.HasValue)
{
var recId = appointment.GetRecurrenceIdAndIndex(out var recIndex);
if(appointment.RecurrenceInfo != null && recId != null)
{
if(recId.Equals(recurrenceId))
{
return false;
}
}
return true;
}
return true;
var recId = appointment.GetRecurrenceIdAndIndex(out var recIndex);
if(appointment.RecurrenceInfo is null || recId is null)
{
return true;
}
return !recId.Equals(recurrenceId);
}
public IEnumerable<SchedulerAppointment> GetAllActiveAppointmentsForEmployeeInInterval(DateTime start, DateTime end, long pEmployeeOid)
@@ -4216,32 +4209,28 @@ namespace BeWo.Data.Access
{
var isOverlapping = OverlappingAppointmentsExist(start, end, employees, customers, resources, originator, appointmentOid, recurrenceId?.ToString() ?? "", occurrenceIndex);
var unavailableResources = shouldSkipResourceAvailability ? new List<Resource>() : CheckAvailabilityOfResources(resources.ToList(), start, end, appointmentOid, recurrenceId, occurrenceIndex);
// Die Ressourcen werden auf Verfügbarkeit im ausgewählten Zeitraum geprüft
var info = shouldSkipResourceAvailability ? new Dictionary<string, List<string>>() : CheckResourceAvailabilityWithEmployeeInformation(start, end, resources, appointmentOid, recurrenceId, occurrenceIndex);
var stringBuilder = new StringBuilder();
if(unavailableResources.Any())
foreach(var resourceName2Intervals in info)
{
var names = string.Empty;
stringBuilder.AppendLine($"Die Ressource \"{resourceName2Intervals.Key}\" ist im ausgewählten Zeitraum {start:dd.MM.yyyy HH:mm} bis {end:dd.MM.yyyy HH:mm} bereits gebucht:");
if(!resourceName2Intervals.Value.All(IsNullOrWhiteSpace))
{
stringBuilder.Append("\r\n\r\n");
}
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.";
stringBuilder.Append(ressourceWarningMessage);
foreach(var interval in resourceName2Intervals.Value)
{
stringBuilder.AppendLine($"{interval}");
}
}
if(isOverlapping)
{
if(unavailableResources.Any())
if(info.Any())
{
stringBuilder.Append("\n\n");
}
@@ -4249,7 +4238,7 @@ namespace BeWo.Data.Access
stringBuilder.Append("Dieser Termin überschneidet sich mit einem anderen bereits existierenden Termin.");
}
if(unavailableResources.Any() || isOverlapping)
if(info.Any() || isOverlapping)
{
stringBuilder.Append("\n\nMöchten Sie trotzdem speichern?");
}
@@ -4259,7 +4248,7 @@ namespace BeWo.Data.Access
public virtual IList FindFileattachmentOids(string text)
{
var q = Session.CreateSQLQuery(Format("SELECT Oid, bewofolderoid, objectoid, objecttid, path FROM FileAttachment WHERE Path like '%{0}%'", text));
var q = Session.CreateSQLQuery($"SELECT Oid, bewofolderoid, objectoid, objecttid, path FROM FileAttachment WHERE Path like '%{text}%'");
return q.List();
}
@@ -5183,8 +5172,6 @@ namespace BeWo.Data.Access
return signature.Count == 1;
}
// ToDo: FALSCHE METHODE! SUCHT NUR NACH SERIENTERMINEN, DIE SO NICHT IN DER DATENBANK SIND!
// ToDo: SQL BEARBEITEN, DAMIT DIE SCHEDULERAPPOINTMENT-OBJEKTE ZURÜCKGEGEBEN WERDEN UND NICHT DIE GEBUCHTEN RESSOURCEN!
/// <summary>
/// Prüft anhand der Oids von Ressourcen deren Verfügbarkeit in einem Zeitraum.
/// Gibt die nicht verfügbaren Ressourcen und Mitarbeiter, die sie gebucht aben zurück für eine detaillierte Fehlermeldung.
@@ -5198,24 +5185,12 @@ namespace BeWo.Data.Access
/// <returns>Die im angegebenen Zeitraum belegten Ressourcen mit den Mitarbeitern, die sie gebucht haben</returns>
public List<SchedulerAppointment> FindAppointmentsByResourcesInInterval(List<long> resourceOids, DateTime start, DateTime end, long? selectedAppointmentOid, Guid? recurrenceId = null, int? occurrenceIndex = null)
{
//var c = CreateCriteria<Resource>("r").Add(Restrictions.Eq(nameof(BeWoEntityBase.IsActive), ActivationTypeId.Active)).Add(Restrictions.In(nameof(BeWoEntityBase.Oid), resourceOids));
//var excludingSelectedAppointment = selectedAppointmentOid.HasValue ? $"Oid <> {selectedAppointmentOid} AND " : "";
//var sql = "Oid IN " +
// "(SELECT ResourceOid FROM resource2newschapp r2n WHERE r2n.NewSchAppOid IN " +
// $"(SELECT Oid FROM newschedulerappointment WHERE IsActive = 1 AND Type <> 4 AND {excludingSelectedAppointment}('{start:yyyy-MM-dd HH:mm:ss}' > StartDate OR '{end:yyyy-MM-dd HH:mm:ss}' > StartDate) AND ('{start:yyyy-MM-dd HH:mm:ss}' < EndDate OR '{end:yyyy-MM-dd HH:mm:ss}' < EndDate)))";
//var criterion = Expression.Sql(sql);
//c.Add(criterion);
//var resources = c.List<Resource>().ToList();
var betweenCriterion = CreateBetweenDateTimesCriterion(start, end, "StartDate", "EndDate");
var c2 = CreateCriteriaIsActive<SchedulerAppointment>()
.Add(Restrictions.Not(Restrictions.Eq(nameof(SchedulerAppointment.Type), 4)))
.Add(Expression.Sql($"'{start:yyyy-MM-dd HH:mm:ss}' BETWEEN StartDate AND EndDate OR '{end:yyyy-MM-dd HH:mm:ss}' BETWEEN StartDate AND EndDate OR StartDate BETWEEN '{start:yyyy-MM-dd HH:mm:ss}' AND '{end:yyyy-MM-dd HH:mm:ss}' OR EndDate BETWEEN '{start:yyyy-MM-dd HH:mm:ss}' AND '{end:yyyy-MM-dd HH:mm:ss}'"));
//.Add(Restrictions.Not(Restrictions.Eq(nameof(SchedulerAppointment.Type), 4)))
.Add(betweenCriterion);
if(!(selectedAppointmentOid is null))
{
@@ -5225,161 +5200,191 @@ namespace BeWo.Data.Access
c2.CreateAlias(nameof(SchedulerAppointment.ResourceList), "resources", JoinType.InnerJoin)
.Add(Restrictions.In($"resources.{nameof(BeWoEntityBase.Oid)}", resourceOids));
var appointments = c2.List<SchedulerAppointment>().ToList();
var tempAppointments = c2.List<SchedulerAppointment>().ToList();
var isBeingUpdatedToNormalAppointment = false;
Guid? recurrenceIdToIgnore = null;
if(selectedAppointmentOid.HasValue)
{
// Das Pattern 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<SchedulerAppointment>(selectedAppointmentOid.Value);
var originalRecurrenceId = original?.GetRecurrenceId();
if(!(originalRecurrenceId is null) && IsNullOrWhiteSpace(recurrenceId?.ToString()))
{
isBeingUpdatedToNormalAppointment = true;
recurrenceIdToIgnore = originalRecurrenceId;
}
}
var appointments = tempAppointments.Where(appointment =>
{
if(appointment.RecurrenceInfo is null)
{
return true;
}
var recId2 = appointment.GetRecurrenceIdAndIndex(out var index);
return !((recurrenceId?.Equals(recId2) ?? false) && occurrenceIndex == index);
}).ToList();
var deletedOccurrences = appointments.Where(app => app.Type == 4).Select(app => BS.Shared.Core.Utils.GetOccurrenceId(app.RecurrenceInfo)).ToList();
var changedOccurrences = appointments.Where(app => app.Type == 3).Select(app => BS.Shared.Core.Utils.GetOccurrenceId(app.RecurrenceInfo)).ToList();
var recurringAppointmentsCriteria = CreateRecurrenceCriteria(start, end).Add(Restrictions.Eq(nameof(SchedulerAppointment.Type), 1));
var recurringAppointments = recurringAppointmentsCriteria.List<SchedulerAppointment>().ToList();
if(isBeingUpdatedToNormalAppointment)
{
recurringAppointments = recurringAppointments.Where(root => FilterRootAppointment(root, recurrenceIdToIgnore)).ToList();
appointments = appointments.Where(root => FilterRootAppointment(root, recurrenceIdToIgnore)).ToList();
}
recurringAppointments = recurringAppointments.Where(s => s.ResourceList.Any(r => r.Oid.HasValue && resourceOids.Contains(r.Oid.Value))).ToList();
// ToDo: Wieso wird das gemacht?
if(recurringAppointments.Count == 0)
{
//return new List<SchedulerAppointment>();
}
var changedOccurrencesCriteria = CreateCriteriaIsActive<SchedulerAppointment>().Add(Restrictions.Eq(nameof(SchedulerAppointment.Type), 3));
var deletedOccurrencesCriteria = CreateCriteria<SchedulerAppointment>().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<SchedulerAppointment>();
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 = new List<SchedulerAppointment>();
var recurrenceIds = string.Empty;
recurringAppointments.DoForEach(appointment => recurrenceIds += $"'{appointment.GetRecurrenceId()}',");
recurrenceIds = recurrenceIds.Trim(',');
if(recurrenceIds.Any())
{
var changedCriteria = CreateCriteriaIsActive<SchedulerAppointment>()
.Add(Restrictions.Eq(nameof(SchedulerAppointment.Type), 3))
.Add(Expression.Sql($"RecurrenceInfo IS NOT NULL AND RecurrenceInfo LIKE '%Id%' AND SUBSTRING(RecurrenceInfo, LOCATE('Id', RecurrenceInfo) + 4, 36) IN ({recurrenceIds})"));
changedOccurrences = changedCriteria.List<SchedulerAppointment>().ToList();
}
//var changedOccurrences = changedOccurrencesCriteria.List<SchedulerAppointment>().Where(a => a.ResourceList.Any(r => r.Oid.HasValue && resourceOids.Contains(r.Oid.Value))).ToList();
var deletedOccurrences = deletedOccurrencesCriteria.List<SchedulerAppointment>().Where(a => a.ResourceList.Any(r => r.Oid.HasValue && resourceOids.Contains(r.Oid.Value))).ToList();
// Sich wiederholende Termine erzeugen und dabei die Ausnahmen und gelöschten Ausnahmen ignorieren
var interval = new TimeInterval(start, end);
foreach(var recurringAppointment in recurringAppointments)
foreach(var appointment in recurringAppointments)
{
var recurrenceInfo = new RecurrenceInfo();
recurrenceInfo.FromXml(recurringAppointment.RecurrenceInfo);
recurrenceInfo.FromXml(appointment.RecurrenceInfo);
var occurenceCalculator = OccurrenceCalculator.CreateInstance(recurrenceInfo);
var occurrenceCalculator = 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;
if(!Guid.TryParse(pattern.RecurrenceInfo.Id.ToString(), out var patternId))
if(pattern is null)
{
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);
pattern.RecurrenceInfo.FromXml(appointment.RecurrenceInfo);
pattern.Start = pattern.RecurrenceInfo.Start;
pattern.End = appointment.EndDate.Value;
var occurrenceAppointments = occurrences.GetAppointments(interval);
var patternId = pattern.RecurrenceInfo.Id.ToString();
foreach(var occurrence in occurrenceAppointments)
var interval = new TimeInterval(start, end);
var occurrences = occurrenceCalculator.CalcOccurrences(interval, pattern);
foreach(var occurrence in occurrences.GetAppointments(interval))
{
if(recurringAppointment.EndDate is null || recurringAppointment.StartDate is null)
if(appointment.EndDate is null || appointment.StartDate is null)
{
continue;
}
// Sicher machen
// Terminindex in der Serie
var index = occurrence.RecurrenceIndex;
var isDeletedOrChanged = changedOccurrences.Any(a =>
{
var guid = a.GetRecurrenceIdAndIndex(out var i);
// Das Ende ist offen, da die Terminserie kein Ende hat. Deshalb wird das Ende berechnet.
var duration = (appointment.EndDate.Value - appointment.StartDate.Value).TotalMinutes;
if(guid is null)
{
return false;
}
var guidParsingSuccessful = Guid.TryParse(occurrence.RecurrenceInfo?.Id?.ToString(), out var occurrenceGuid);
return guid.Value.Equals(patternId) && index == i;
}) || deletedOccurrences.Any(a =>
{
var guid = a.GetRecurrenceIdAndIndex(out var i);
if(guid is null)
{
return false;
}
return guid.Value.Equals(patternId) && index == i;
});
if(isDeletedOrChanged)
{
continue;
}
var duration = (recurringAppointment.EndDate.Value - recurringAppointment.StartDate.Value).TotalMinutes;
// 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.
var isInIntervalTest = start.IsInInterval(end, occurrence.Start, occurrence.Start.AddMinutes(duration));
if(!isInIntervalTest)
if(!isInIntervalTest ||
changedOccurrences.Any(changedOccurence => changedOccurence.PatternId.Equals(patternId) && changedOccurence.Index == index) ||
deletedOccurrences.Any(deletedOccurence => deletedOccurence.PatternId.Equals(patternId) && deletedOccurence.Index == index) ||
index == occurrenceIndex && guidParsingSuccessful && recurrenceId != null && recurrenceId.Equals(occurrenceGuid))
{
continue;
}
var occurrenceAppointment = new SchedulerAppointment
// Prüfen, ob es eine Ausnahme an dem Tag gibt, die zu dem Pattern gehört, um das Pattern auszuschließen
var relatedAppointments = FindAppointmentsByRecurrenceId(new List<string> { recurrenceInfo.Id.ToString() }, true);
var relatedAppointmentsInInterval = relatedAppointments.Where(a =>
{
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 ?? Empty,
Type = recurringAppointment.Type
};
if(!(recurrenceId is null) && occurrenceIndex.HasValue)
{
var recId = occurrenceAppointment.GetRecurrenceId();
if((recId?.Equals(recurrenceId.Value) ?? false) && index.Equals(occurrenceIndex.Value))
if(a.StartDate == null || a.EndDate == null)
{
continue;
return false;
}
var myStart = a.StartDate.Value.Date;
var myEnd = a.EndDate.Value.Date;
var isInInterval = start.Date.InBetween(myStart.GetShortDateTime(), myEnd, true);
return isInInterval && a.Type != 4;
}).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 && selectedAppointmentOid != null && root.Oid == selectedAppointmentOid && root.RecurrenceInfo != null && IsNullOrWhiteSpace(recurrenceId?.ToString()))
{
hasToStop = true;
}
// Indices und Ids der RecurrenceInfo vergleichen. Stimmen sie überein, dann wird das generiert Serienelement ignoriert.
if(occurrence.RecurrenceInfo?.Id != null && !hasToStop)
{
if(Guid.TryParse(occurrence.RecurrenceInfo.Id.ToString(), out var guid))
{
foreach(var relatedAppointment in relatedAppointmentsInInterval)
{
var relatedAppointmentRecurrenceId = relatedAppointment.GetRecurrenceIdAndIndex(out var relatedAppointmentRecurrenceIndex);
if(relatedAppointmentRecurrenceId != null)
{
if(guid.Equals(relatedAppointmentRecurrenceId) && relatedAppointmentRecurrenceIndex.Equals(occurrence.RecurrenceIndex))
{
hasToStop = true;
break;
}
}
}
}
}
appointments.AddIfNotIn(occurrenceAppointment);
if(hasToStop)
{
continue;
}
var recurringAppointment = new SchedulerAppointment
{
AllDay = occurrence.AllDay,
CustomerList = appointment.CustomerList,
Notice = appointment.Notice,
EmployeeList = appointment.EmployeeList,
EndDate = occurrence.Start.AddMinutes(duration),
FormerBookingSequenceOid = appointment.FormerBookingSequenceOid,
IsPrivate = appointment.IsPrivate,
Location = appointment.Location,
Originator = appointment.Originator,
RecurrenceInfo = occurrence.RecurrenceInfo.ToXml(),
ReminderInfo = appointment.ReminderInfo,
ResourceList = appointment.ResourceList,
StartDate = occurrence.Start,
Subject = appointment.Subject ?? "",
Type = appointment.Type
};
appointments.AddIfNotIn(recurringAppointment);
}
}
return appointments.ToList();
return appointments.Where(appointment => appointment.Type != 4).OrderBy(appointment => appointment.StartDate).ToList();
}
private static bool FilterRootAppointment(SchedulerAppointment root, Guid? recurrenceIdToIgnore)
{
var recId = root.GetRecurrenceId();
if(recId is null || recurrenceIdToIgnore is null)
{
return true;
}
return !recId.Equals(recurrenceIdToIgnore);
}
public List<ConfirmationReceiptSignature> LoadAllConfirmationReceiptSignaturesByServiceRecordOids(IList<long> serviceRecordOids)
@@ -5395,5 +5400,78 @@ namespace BeWo.Data.Access
return result;
}
public Dictionary<string, List<string>> CheckResourceAvailabilityWithEmployeeInformation(DateTime start, DateTime end, List<long> resourceOids, long? selectedAppointmentOid, Guid? recurrenceId = null, int occurrenceIndex = 0)
{
var appointments = FindAppointmentsByResourcesInInterval(resourceOids, start, end, selectedAppointmentOid, recurrenceId, occurrenceIndex);
var user = LoggedInUserOperationContextExt.Current?.User ?? SessionFacade.LoggedInUser;
var result = new Dictionary<string, List<string>>();
if(user is null)
{
return result;
}
var loggedInEmployee = user.Employee;
var hasRightToViewEmployeeAppointments = user.CheckForRight(UserRightType.KalenderMitarbeitertermineAnsehen);
var hasRightToViewResourceAppointments = user.CheckForRight(UserRightType.KalenderRessourcentermineAnsehen);
var dictionary = new Dictionary<Resource, List<SchedulerAppointment>>();
foreach(var appointment in appointments)
{
foreach(var resource in appointment.ResourceList)
{
dictionary.AddOrUpdateValueInDictionary(resource, appointment);
}
}
foreach(var resource2Appointments in dictionary)
{
foreach(var appointment in resource2Appointments.Value)
{
var originator = appointment.Originator;
var employee2Appointments = appointment.EmployeeList;
var isOwnAppointment = (originator?.Equals(loggedInEmployee) ?? false) || employee2Appointments.ToList().Any(e2a => e2a.Employee.Equals(loggedInEmployee));
// Wenn isOwnAppointment true ist, darf der Benutzer die Uhrzeiten und die Mitarbeiter sehen. Ansonsten müssen die Rechte geprüft werden.
if(isOwnAppointment || hasRightToViewEmployeeAppointments) // Es werden Zeit und Mitarbeiter angezeigt
{
result.AddOrUpdateValueInDictionary(resource2Appointments.Key.Name, $"{CreateDateTimeInfoFromAppointment(appointment.StartDate, appointment.EndDate, appointment.AllDay)} von {originator}");
}
else if(hasRightToViewResourceAppointments && !hasRightToViewEmployeeAppointments) // Nur die Uhrzeit anzeigen
{
result.AddOrUpdateValueInDictionary(resource2Appointments.Key.Name, $"{CreateDateTimeInfoFromAppointment(appointment.StartDate, appointment.EndDate, appointment.AllDay)}");
}
else if(!hasRightToViewEmployeeAppointments) // Es werden weder Zeit noch Mitarbeiter angezeigt
{
result.AddOrUpdateValueInDictionary(resource2Appointments.Key.Name, string.Empty);
}
}
}
return result;
}
private static string CreateDateTimeInfoFromAppointment(DateTime? start, DateTime? end, bool allDay)
{
if(start.HasValue && end.HasValue && allDay == false)
{
return start.Value.Date == end.Value.Date ?
$"{start.Value.ToShortTimeString()} - {end.Value.ToShortTimeString()} " :
$"{start.Value:dd.MM.yyyy HH:mm} - {end.Value:dd.MM.yyyy HH:mm} ";
}
if(allDay && start.HasValue && end.HasValue)
{
return start.Value.Date == end.Value.Date ? " " : $"{start.Value.ToShortDateString()} - {end.Value.ToShortDateString()} ";
}
return string.Empty;
}
}
}

View File

@@ -3,7 +3,7 @@
<PropertyGroup>
<NameOfLastUsedPublishProfile>BeWo2.0</NameOfLastUsedPublishProfile>
<UseIISExpress>true</UseIISExpress>
<LastActiveSolutionConfig>Release|Any CPU</LastActiveSolutionConfig>
<LastActiveSolutionConfig>Debug|Any CPU</LastActiveSolutionConfig>
<Use64BitIISExpress>false</Use64BitIISExpress>
<IISExpressSSLPort />
<IISExpressAnonymousAuthentication />

View File

@@ -117,7 +117,7 @@ namespace BeWo.Service.Plugins
//t = "4271389563"; // Komm Mit
//t = "5430005891"; // Marienhospital Eickel
//t = "3265049248"; // Gerdas Pflegedienst
t = "1549622397"; // Kontakt und Krisenhilfe
//t = "1549622397"; // Kontakt und Krisenhilfe
//t = "4782194565"; // Skm Rheydt
//t = "7535795843"; // Sozialwerk Dürener Christen
//t = "6388340414"; // Weitblick
@@ -195,7 +195,7 @@ namespace BeWo.Service.Plugins
//t = "9556218062"; // Diakonie Landshut
//t = "2279593936"; // Diakonie Mülheim
//t = "3623837005"; // Betreuwo Wesel
t = "8407321888"; // AWO Wesel
//t = "8407321888"; // AWO Wesel
//t = "8454426692"; // Mit-Menschen Wuppertal
//t = "0629004412"; // BeWo-Colonia Basaran (Projekt
//t = "7668701607"; // Wohnstätten Essen

View File

@@ -1,15 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BeWo.Data;
using BeWo.Data.Access;
using BeWo.Data.Entities;
using BeWo.Service.DCEntityMapper;
using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.Extensions;
using NHibernate.Util;
namespace BeWo.Service.Plugins
{
@@ -34,77 +29,9 @@ namespace BeWo.Service.Plugins
return list;
}
public virtual Dictionary<string, List<string>> CheckResourceAvailabilityWithBookingEmployees(DateTime start, DateTime end, List<long> resourceOids, long? selectedAppointmentOid)
public virtual Dictionary<string, List<string>> CheckResourceAvailabilityWithBookingEmployees(DateTime start, DateTime end, List<long> resourceOids, long? selectedAppointmentOid, Guid? recurrenceId, int occurrenceIndex = 0, bool shouldSkipResourceAvailability = false)
{
var appointments = DAOFactory.SearchDAO.FindAppointmentsByResourcesInInterval(resourceOids, start, end, selectedAppointmentOid);
var user = LoggedInUserOperationContextExt.Current?.User ?? SessionFacade.LoggedInUser;
var result = new Dictionary<string, List<string>>();
if(user is null)
{
return result;
}
var loggedInEmployee = user.Employee;
var hasRightToViewEmployeeAppointments = user.CheckForRight(UserRightType.KalenderMitarbeitertermineAnsehen);
var hasRightToViewResourceAppointments = user.CheckForRight(UserRightType.KalenderRessourcentermineAnsehen);
var dictionary = new Dictionary<Resource, List<SchedulerAppointment>>();
foreach(var appointment in appointments)
{
foreach(var resource in appointment.ResourceList)
{
dictionary.AddOrUpdateValueInDictionary(resource, appointment);
}
}
foreach(var resource2Appointments in dictionary)
{
foreach(var appointment in resource2Appointments.Value)
{
var originator = appointment.Originator;
var employee2Appointments = appointment.EmployeeList;
var isOwnAppointment = (originator?.Equals(loggedInEmployee) ?? false) || employee2Appointments.ToList().Any(e2a => e2a.Employee.Equals(loggedInEmployee));
// Wenn isOwnAppointment true ist, darf der Benutzer die Uhrzeiten und die Mitarbeiter sehen. Ansonsten müssen die Rechte geprüft werden.
if(isOwnAppointment || hasRightToViewEmployeeAppointments) // Es werden Zeit und Mitarbeiter angezeigt
{
result.AddOrUpdateValueInDictionary(resource2Appointments.Key.Name, $"{CreateDateTimeInfoFromAppointment(appointment.StartDate, appointment.EndDate, appointment.AllDay)} von {originator}");
}
else if(hasRightToViewResourceAppointments && !hasRightToViewEmployeeAppointments) // Nur die Uhrzeit anzeigen
{
result.AddOrUpdateValueInDictionary(resource2Appointments.Key.Name, $"{CreateDateTimeInfoFromAppointment(appointment.StartDate, appointment.EndDate, appointment.AllDay)}");
}
else if(!hasRightToViewEmployeeAppointments) // Es werden weder Zeit noch Mitarbeiter angezeigt
{
result.AddOrUpdateValueInDictionary(resource2Appointments.Key.Name, string.Empty);
}
}
}
return result;
}
private string CreateDateTimeInfoFromAppointment(DateTime? start, DateTime? end, bool allDay)
{
if(start.HasValue && end.HasValue)
{
return start.Value.Date == end.Value.Date ?
$"{start.Value.ToShortTimeString()} - {end.Value.ToShortTimeString()} " :
$"{start.Value:dd.MM.yyyy HH:mm} - {end.Value:dd.MM.yyyy HH:mm} ";
}
if(allDay && start.HasValue && end.HasValue)
{
return start.Value.Date == end.Value.Date ? " " : $"{start.Value.ToShortDateString()} - {end.Value.ToShortDateString()} ";
}
return string.Empty;
return DAOFactory.SearchDAO.CheckResourceAvailabilityWithEmployeeInformation(start, end, resourceOids, selectedAppointmentOid, recurrenceId, occurrenceIndex);
}
}
}

View File

@@ -243,6 +243,6 @@ namespace BeWo.Service.ServiceContracts
[FaultContract(typeof(BeWoFault))]
[OperationContract]
Dictionary<string, List<string>> CheckResourceAvailabilityWithEmployeeInformation(DateTime start, DateTime end, List<long> resourceOids, long? selectedAppointmentOid);
Dictionary<string, List<string>> CheckResourceAvailabilityWithEmployeeInformation(DateTime start, DateTime end, List<long> resourceOids, long? selectedAppointmentOid, Guid? recurrenceId, int occurrenceIndex = 0, bool shouldSkipResourceAvailability = false);
}
}

View File

@@ -2712,13 +2712,13 @@ namespace BeWo.Service.ServiceImplementations
}
}
public Dictionary<string, List<string>> CheckResourceAvailabilityWithEmployeeInformation(DateTime start, DateTime end, List<long> resourceOids, long? selectedAppointmentOid)
public Dictionary<string, List<string>> CheckResourceAvailabilityWithEmployeeInformation(DateTime start, DateTime end, List<long> resourceOids, long? selectedAppointmentOid, Guid? recurrenceId, int occurrenceIndex = 0, bool shouldSkipResourceAvailability = false)
{
try
{
var s = PluginLoader.FindClass<ResourceService>();
return s.CheckResourceAvailabilityWithBookingEmployees(start, end, resourceOids, selectedAppointmentOid);
return s.CheckResourceAvailabilityWithBookingEmployees(start, end, resourceOids, selectedAppointmentOid, recurrenceId, occurrenceIndex, shouldSkipResourceAvailability);
}
catch(Exception e)
{