Ressourcen im Kalender des Mobilklienten verfügbar gemacht.

Verbesserungen im Mobilklienten.
This commit is contained in:
Lyndon Jetten
2020-06-29 19:24:24 +02:00
parent 8e953e9eb9
commit 645c755907
17 changed files with 500 additions and 79 deletions

View File

@@ -180,7 +180,8 @@
<Compile Include="Models\SchedulerModel.cs" />
<Compile Include="Util\AppointmentListItem.cs" />
<Compile Include="Util\BeWoLoginState.cs" />
<Compile Include="Util\GoalDisplayItem.cs" />
<Compile Include="Util\BootstrapTreeViewItem.cs" />
<Compile Include="Util\ConvertedDateTimes.cs" />
<Compile Include="Util\GoalTreeItem.cs" />
<Compile Include="Controllers\LoginController.cs" />
<Compile Include="Controllers\MainController.cs" />

View File

@@ -290,12 +290,12 @@ namespace BeWoPlanerMobil.Controllers
var parentItems = goals.Where(w => w.ValueListEntryOid.HasValue && goals.Any(a => a.ParentOid.HasValue && a.ParentOid.Equals(w.ValueListEntryOid))).ToList();
var goalTree = new List<GoalDisplayItem>();
var goalTreeDic = new Dictionary<long, GoalDisplayItem>();
var goalTree = new List<BootstrapTreeViewItem>();
var goalTreeDic = new Dictionary<long, BootstrapTreeViewItem>();
foreach (var ziel in ziele.Where(ziel => ziel.ValueListEntryOid.HasValue))
{
var treeItem = new GoalDisplayItem(ziel.TypeDescription, ziel.ParentOid, ziel.ValueListEntryOid.Value, parentItems.Contains(ziel));
var treeItem = new BootstrapTreeViewItem(ziel.TypeDescription, ziel.ParentOid, ziel.ValueListEntryOid.Value, parentItems.Contains(ziel));
goalTreeDic.Add(ziel.ValueListEntryOid.Value, treeItem);
@@ -307,17 +307,17 @@ namespace BeWoPlanerMobil.Controllers
foreach (var zielMitEltern in goalTreeDic.Values.Where(w => w.ParentOid != null))
{
goalTreeDic[zielMitEltern.ParentOid.Value].nodes.Add(zielMitEltern);
goalTreeDic[zielMitEltern.ParentOid.Value].Nodes.Add(zielMitEltern);
}
foreach (var ziel in massnahmen)
{
var node = new GoalDisplayItem(ziel.TypeDescription, ziel.ParentOid, ziel.ValueListEntryOid.Value, parentItems.Contains(ziel));
var node = new BootstrapTreeViewItem(ziel.TypeDescription, ziel.ParentOid, ziel.ValueListEntryOid.Value, parentItems.Contains(ziel));
if (ziel.ParentOid != null && goalTreeDic.ContainsKey(ziel.ParentOid.Value))
{
node.ParentOid = goalTreeDic[ziel.ParentOid.Value].ParentOid;
goalTreeDic[ziel.ParentOid.Value].nodes.Add(node);
goalTreeDic[ziel.ParentOid.Value].Nodes.Add(node);
}
}

View File

@@ -2,16 +2,20 @@
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.Helpers;
using System.Web.Mvc;
using BeWoPlanerMobil.Models;
using BeWoPlanerMobil.Service;
using BeWoPlanerMobil.Util;
using BS.Shared;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Compact;
using BS.Shared.Extensions;
using DevExpress.XtraScheduler;
using DevExpress.XtraScheduler.Compatibility;
using Newtonsoft.Json;
using static BeWoPlanerMobil.Util.MobileUtils;
namespace BeWoPlanerMobil.Controllers
@@ -54,6 +58,20 @@ namespace BeWoPlanerMobil.Controllers
return RedirectToActionPermanent("Index", "Login");
}
if(AbstractModel.HasRightToInsertRessourceAppointments)
{
var allResources = KalenderService.GetAllResources().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());
}
Model.ResourceCategories2Resources = categories2Resources;
}
LoadAppointmentsForDate();
return View(Model);
@@ -102,7 +120,7 @@ namespace BeWoPlanerMobil.Controllers
var changedOccurrences = holySweetFlyingFuck.Where(w => w.Type == 3).Select(s => GetOccurrenceId(s.RecurrenceInfo)).ToList();
holySweetFlyingFuck = holySweetFlyingFuck.Where(w => w.Type != 4).ToList();
var numberOfPatterns = appointments.Count(appointment => appointment.RecurrenceInfo != null && appointment.Type == 1);
foreach(var appointment in appointments)
{
if(appointment.RecurrenceInfo != null && appointment.Type == 1)
@@ -137,7 +155,7 @@ namespace BeWoPlanerMobil.Controllers
continue;
}
holySweetFlyingFuck.AddIfNotIn(new SchedulerAppointmentDC
var recurringAppointment = new SchedulerAppointmentDC
{
AllDay = appointment.AllDay,
CustomerList = appointment.CustomerList,
@@ -155,7 +173,11 @@ namespace BeWoPlanerMobil.Controllers
StartDate = termin.Start,
Subject = appointment.Subject ?? "",
Type = appointment.Type
});
};
Model.RecurringAppointments.AddIfNotIn(recurringAppointment);
holySweetFlyingFuck.AddIfNotIn(recurringAppointment);
}
}
}
@@ -163,7 +185,7 @@ namespace BeWoPlanerMobil.Controllers
holySweetFlyingFuck.AddRange(zuErledigen);
Model.Appointments = holySweetFlyingFuck;
Model.Appointments = holySweetFlyingFuck.OrderBy(appointment => appointment.StartDate).ToList();
}
[Authorize]
@@ -185,22 +207,27 @@ namespace BeWoPlanerMobil.Controllers
var location = formCollection["Location"];
var notice = formCollection["Notice"];
var isSuccessfulStartDate = DateTime.TryParseExact(rawStartDate, "dd.MM.yyyy", null, DateTimeStyles.None, out var startDate);
var isSuccessfulStartTime = DateTime.TryParseExact(rawStartTime, "HH:mm", null, DateTimeStyles.None, out var startTime);
var isSuccessfulEndDate = DateTime.TryParseExact(rawEndDate, "dd.MM.yyyy", null, DateTimeStyles.None, out var endDate);
var isSuccessfulEndTime = DateTime.TryParseExact(rawEndTime, "HH:mm", null, DateTimeStyles.None, out var endTime);
if (isSuccessfulStartDate && isSuccessfulStartTime && isSuccessfulEndDate && isSuccessfulEndTime)
var startAndEnd = ConvertStringDatesToDateTimes($"{rawStartDate} {rawStartTime}", $"{rawEndDate} {rawEndTime}");
var startDate = startAndEnd.StartDate;
var endDate = startAndEnd.EndDate;
if (isSuccessfulStartTime && isSuccessfulEndTime)
{
startDate = startDate.MergeDatesByDate(startTime);
endDate = endDate.MergeDatesByDate(endTime);
var appointmentToInsert = Model.SelectedAppointment ?? new SchedulerAppointmentDC();
appointmentToInsert.EmployeeList = new List<Employee2SchedulerAppointmentDC>();
appointmentToInsert.CustomerList = new List<CompactCustomerDC>();
appointmentToInsert.ResourceList = new List<ResourceDC>();
appointmentToInsert.SupportConceptList = new List<CompactSupportConceptDC>();
var isNew = !appointmentToInsert.SchedulerAppointmentOid.HasValue;
appointmentToInsert.EmployeeList = isNew ? new List<Employee2SchedulerAppointmentDC>() : appointmentToInsert.EmployeeList;
appointmentToInsert.CustomerList = isNew ? new List<CompactCustomerDC>() : appointmentToInsert.CustomerList;
appointmentToInsert.ResourceList = Model.SelectedResources ?? new List<ResourceDC>();
appointmentToInsert.SupportConceptList = isNew ? new List<CompactSupportConceptDC>() : appointmentToInsert.SupportConceptList;
appointmentToInsert.EndDate = endDate;
appointmentToInsert.StartDate = startDate;
appointmentToInsert.Subject = subject;
@@ -208,7 +235,7 @@ namespace BeWoPlanerMobil.Controllers
appointmentToInsert.Originator = MobileSessionFacade.LoggedInCompactEmployee;
appointmentToInsert.Location = location;
if (appointmentToInsert.SchedulerAppointmentOid.HasValue)
if (!isNew)
{
KalenderService.UpdateSchedulerAppointments(new List<SchedulerAppointmentDC> {appointmentToInsert});
}
@@ -227,6 +254,7 @@ namespace BeWoPlanerMobil.Controllers
if (Model != null)
{
Model.SelectedAppointment = null;
Model.SelectedResources?.Clear();
}
}
@@ -247,6 +275,7 @@ namespace BeWoPlanerMobil.Controllers
if(Model != null)
{
Model.SelectedAppointment = null;
Model.SelectedResources.Clear();
}
return RedirectToActionPermanent("Scheduler");
@@ -266,6 +295,7 @@ namespace BeWoPlanerMobil.Controllers
if(Model != null)
{
Model.SelectedAppointment = null;
Model.SelectedResources.Clear();
}
return RedirectToActionPermanent("Scheduler");
@@ -288,6 +318,7 @@ namespace BeWoPlanerMobil.Controllers
if(Model != null)
{
Model.SelectedAppointment = null;
Model.SelectedResources.Clear();
}
return RedirectToActionPermanent("Scheduler");
@@ -304,6 +335,7 @@ namespace BeWoPlanerMobil.Controllers
if (isSuccessful)
{
Model.SelectedAppointment = Model.Appointments.FirstOrDefault(app => app.SchedulerAppointmentOid.HasValue && app.SchedulerAppointmentOid.Value == appointmentOid);
Model.SelectedResources = Model.SelectedAppointment?.ResourceList ?? new List<ResourceDC>();
}
return RedirectToActionPermanent("Scheduler");
@@ -315,11 +347,13 @@ namespace BeWoPlanerMobil.Controllers
if (Model != null)
{
Model.SelectedAppointment = null;
Model.SelectedResources.Clear();
}
return Json(null, JsonRequestBehavior.AllowGet);
}
// TODO: Serientermine und Ressourcen berücksichtigen!
[Authorize]
public JsonResult CheckForOverlappingAppointments(string startDateRaw, string endDateRaw, string startTimeRaw, string endTimeRaw)
{
@@ -341,19 +375,58 @@ namespace BeWoPlanerMobil.Controllers
startDate = startDate.MergeDatesByDate(startTime);
endDate = endDate.MergeDatesByDate(endTime);
var customerList = Model.SelectedAppointment?.CustomerList?.Select(customer => customer.CustomerOid).ToList() ?? new List<long>();
var employeeList = Model.SelectedAppointment?.EmployeeList?.Select(employee2Appointment => employee2Appointment.Employee.EmployeeOid).ToList() ?? new List<long>();
var resourceList = Model.SelectedAppointment?.ResourceList?.Select(resource => resource.ResourceOid.Value).ToList() ?? new List<long>();
var customerOidList = Model.SelectedAppointment?.CustomerList?.Select(customer => customer.CustomerOid).ToList() ?? new List<long>();
var employeeOidList = Model.SelectedAppointment?.EmployeeList?.Select(employee2Appointment => employee2Appointment.Employee.EmployeeOid).ToList() ?? new List<long>();
var resourceOidList = Model.SelectedResources.Where(resource => resource.ResourceOid.HasValue).Select(resource => resource.ResourceOid.Value).ToList() ?? new List<long>();
var originator = Model.SelectedAppointment?.Originator ?? MobileSessionFacade.LoggedInCompactEmployee;
var recurrenceId = Model.SelectedAppointment?.RecurrenceId ?? string.Empty;
var recurrenceIndex = Model.SelectedAppointment?.RecurrenceIndex ?? 0;
isOverlapping = KalenderService.OverlappingAppointmentsExist(startDate, endDate, employeeList, customerList, resourceList, originator.EmployeeOid, oid, recurrenceId, recurrenceIndex);
isOverlapping = KalenderService.OverlappingAppointmentsExist(startDate, endDate, employeeOidList, customerOidList, resourceOidList, originator.EmployeeOid, oid, recurrenceId, recurrenceIndex);
}
return Json(isOverlapping, JsonRequestBehavior.AllowGet);
}
public string SelectResourcesForAppointment(string resourceOids)
{
if(Model == null)
{
return _LeerzeichenFuerGetMethoden;
}
var oidList = ConvertOidStringToList(resourceOids);
var list = new List<ResourceDC>();
Model.ResourceCategories2Resources.Values.DoForEach(l => l.DoForEach(s => list.AddIfNotIn(s)));
Model.SelectedResources = list.Where(resource => resource.ResourceOid.HasValue && oidList.Contains(resource.ResourceOid.Value)).ToList();
return JsonConvert.SerializeObject(Model.SelectedResources);
}
public string CheckResourcesAvailability(string start, string end, string resourceOids)
{
if(!AbstractModel.HasRightToInsertRessourceAppointments)
{
return _LeerzeichenFuerGetMethoden;
}
if(!string.IsNullOrWhiteSpace(start) && !string.IsNullOrWhiteSpace(end) && !string.IsNullOrWhiteSpace(resourceOids) && Model != null)
{
var oidList = ConvertOidStringToList(resourceOids);
var dateTimes = ConvertStringDatesToDateTimes(start, end);
var unavailableResources = KalenderService.CheckResourceAvailability(dateTimes.StartDate, dateTimes.EndDate, oidList, Model.SelectedAppointment?.SchedulerAppointmentOid);
return JsonConvert.SerializeObject(unavailableResources);
}
return _LeerzeichenFuerGetMethoden;
}
}
}

View File

@@ -1,6 +1,4 @@
using System.Linq;
using BeWoPlanerMobil.Service;
using BeWoPlanerMobil.Service;
using BS.Shared;
using BS.Shared.DataContracts;
@@ -9,17 +7,11 @@ namespace BeWoPlanerMobil.Models
{
public class AbstractModel
{
public static bool IsDeleteBtnVisible
{
get { return MobileSessionFacade.LoggedInUser.UserGroups.Any(a => a.Rights.Any(f => f.RightType.Equals(UserRightType.ServiceRecordView_Delete))); }
}
public static bool IsDeleteBtnVisible => MobileSessionFacade.CheckForUserRight(UserRightType.ServiceRecordView_Delete);
public static bool IsAllowedToSeeScheduler
{
get { return MobileSessionFacade.LoggedInUser != null && MobileSessionFacade.LoggedInUser.UserGroups.Any(a => a.Rights.Any(right => right.RightType.Equals(UserRightType.KalenderAnsehen))); }
}
public static bool IsAllowedToSeeScheduler => MobileSessionFacade.LoggedInUser != null && MobileSessionFacade.CheckForUserRight(UserRightType.KalenderAnsehen) || MobileSessionFacade.CheckForUserRight(UserRightType.ViewAll);
public static bool IsAllowedToSeeCustomers => MobileSessionFacade.CheckForUserRight(UserRightType.ViewAll) || (MobileSessionFacade.CheckForUserRight(UserRightType.CustomerView_View) || MobileSessionFacade.CheckForUserRight(UserRightType.Customer_ViewMyCustomers));
public static bool IsAllowedToSeeCustomers => MobileSessionFacade.CheckForUserRight(UserRightType.ViewAll) || MobileSessionFacade.CheckForUserRight(UserRightType.CustomerView_View) || MobileSessionFacade.CheckForUserRight(UserRightType.Customer_ViewMyCustomers);
public static bool IsEmployeeSelectionVisible => MobileSessionFacade.CheckForUserRight(UserRightType.ServiceRecord_AllowCreationForOtherEmployees) || MobileSessionFacade.CheckForUserRight(UserRightType.ServiceRecord_AllowCreationForOtherTeamMember);
@@ -40,5 +32,7 @@ namespace BeWoPlanerMobil.Models
public static bool HasRightToSeeServiceRecords => MobileSessionFacade.CheckForUserRight(UserRightType.ServiceRecordView_View) && MobileSessionFacade.CheckForUserRight(UserRightType.ServiceRecordView_Create);
public static string TimeOfLastAction { get; set; }
public static bool HasRightToInsertRessourceAppointments => MobileSessionFacade.CheckForUserRight(UserRightType.KalenderRessourcentermineAnlegen) || MobileSessionFacade.CheckForUserRight(UserRightType.CreateAll);
}
}

View File

@@ -6,6 +6,7 @@ using BeWoPlanerMobil.Util;
using BS.Shared;
using BS.Shared.DataContracts;
using BS.Shared.Extensions;
using Newtonsoft.Json;
namespace BeWoPlanerMobil.Models
{
@@ -92,5 +93,13 @@ namespace BeWoPlanerMobil.Models
public string EndTimeToEdit => SelectedAppointment?.EndDate?.ToShortTimeString() ?? string.Empty;
public string LocationToEdit => SelectedAppointment?.Location ?? string.Empty;
public List<ResourceDC> AllResources { get; set; } = new List<ResourceDC>();
public List<ResourceDC> SelectedResources { get; set; } = new List<ResourceDC>();
public Dictionary<ValueListEntryDC, List<ResourceDC>> ResourceCategories2Resources { get; set; } = new Dictionary<ValueListEntryDC, List<ResourceDC>>();
public List<SchedulerAppointmentDC> RecurringAppointments { get; set; } = new List<SchedulerAppointmentDC>();
}
}

View File

@@ -103,8 +103,6 @@ function updateGroupBookingGroupList(groupBookingSelectionObject) {
} else {
activateGroupBookingForm();
}
console.log("updateGroupBookingGroupList called");
}
function addEmployeeToGroupBooking() {

View File

@@ -4,6 +4,12 @@
$("#scheduler-start-time, #scheduler-end-time, #subject, #location, #notice").val("");
$("#scheduler-start-date, #scheduler-end-date").val(moment().format("DD.MM.YYYY"));
$("#resources-popup input:checked").each(function() {
$(this).prop("checked", false);
});
$("#selected-resources-list").empty();
}
function submitInsertAppointmentForm() {
@@ -75,13 +81,80 @@ function validateAppointmentForm() {
return;
}
var selectedOids = [];
var oidString = "";
$("#resources-popup input:checked").each(function() {
var id = $(this).attr("id");
selectedOids.push(id.split("-")[0]);
});
for(var i = 0; i < selectedOids.length; i++) {
oidString += selectedOids[i] + ",";
}
$.get(getCheckResourcesAvailabilityUrl(), { start: startDate.format("DD.MM.YYYY HH:mm"), end: endDate.format("DD.MM.YYYY HH:mm"), resourceOids: oidString }).done(function(result) {
if(result === undefined || result === null || result.length === 0) {
return;
}
if (result.length > 1) {
try {
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();
$("#messagePopup .modal-body").html('<div class="alert alert-warning" role="alert">' + unavailableResourcesMessage + "<br/><br/>Möchten Sie trotzdem speichern?</div>");
showMessagePopup("Fehler");
showMessagePopupWithCallback("Überschneidung",
null,
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"));
});
return;
}
} catch(error) {
console.log("%c" + error.message, "color:red;");
hideSpinner();
return;
}
}
insertOrUpdateAppointment(startDate.format("DD.MM.YYYY"), endDate.format("DD.MM.YYYY"), startDate.format("HH:mm"), endDate.format("HH:mm"));
});
}
function insertOrUpdateAppointment(formattedStartDate, formattedEndDate, formattedStartTime, formattedEndTime) {
$.get(
getCheckForOverlappingAppointmentsUrl(),
{
startDateRaw: startDate.format("DD.MM.YYYY"),
endDateRaw: endDate.format("DD.MM.YYYY"),
startTimeRaw: startDate.format("HH:mm"),
endTimeRaw: endDate.format("HH:mm")
startDateRaw: formattedStartDate,
endDateRaw: formattedEndDate,
startTimeRaw: formattedStartTime,
endTimeRaw: formattedEndTime
}
).done(function(result) {
var isOverlapping = $.parseJSON(result);
@@ -126,4 +199,63 @@ function toggleAppointmentForm() {
} else {
showAppointmentForm();
}
}
function changeResourceSelection() {
var selectedOids = [];
var oidString = "";
$("#resources-popup input:checked").each(function() {
var id = $(this).attr("id");
selectedOids.push(id.split("-")[0]);
});
for (var i = 0; i < selectedOids.length; i++) {
oidString += selectedOids[i] + ",";
}
$.get(getSelectResourcesForAppointmentUrl(), { resourceOids: oidString }).done(test);
}
function test(jsonResult) {
var list = $("#selected-resources-list");
list.empty();
if (isEmptyOrSpaces(jsonResult)) {
return;
}
var resourceList = $.parseJSON(jsonResult);
$.each(resourceList, function(index, customListItem) {
var html =
"<div class='list-group-item' id='relation-item-" + customListItem.ResourceOid + "'>" +
"<div class='row'>" +
"<div class='col my-auto'>" +
"<i class='fas fa-cubes text-bewo-resource mr-2'></i>" + customListItem.Name +
"</div>" +
"<div class='col-auto my-auto'>" +
"<button type='button' class='btn btn-primary' onclick='removeSelectedResource(" + customListItem.ResourceOid + ")'>" +
"<span class='fas fa-times-circle'></span>" +
"</button>" +
"</div>" +
"</div>" +
"</div>";
list.append(html);
});
}
function removeSelectedResource(resourceOid) {
$("#relation-item-" + resourceOid).remove();
var checkbox = $("#" + resourceOid + "-checkbox");
if (checkbox.length) {
checkbox.prop("checked", false);
}
changeResourceSelection();
}

View File

@@ -0,0 +1,35 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace BeWoPlanerMobil.Util
{
public class BootstrapTreeViewItem
{
[JsonProperty("selectable")]
public bool Selectable { get; set; }
[JsonProperty("text")]
public string Text { get; set; }
[JsonProperty("tags")]
public List<string> Tags { get; set; }
[JsonProperty("nodes")]
public List<BootstrapTreeViewItem> Nodes { get; set; } = new List<BootstrapTreeViewItem>();
[JsonIgnore]
public long Oid { get; }
[JsonIgnore]
public long? ParentOid { get; set; }
public BootstrapTreeViewItem(string text, long? parentOid, long oid, bool isParent)
{
Text = text;
Tags = new List<string> { oid.ToString() };
ParentOid = parentOid;
Oid = oid;
Selectable = !isParent;
}
}
}

View File

@@ -0,0 +1,17 @@
using System;
namespace BeWoPlanerMobil.Util
{
public class ConvertedDateTimes
{
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public ConvertedDateTimes(DateTime startDate, DateTime endDate)
{
StartDate = startDate;
EndDate = endDate;
}
}
}

View File

@@ -1,28 +0,0 @@
using System.Collections.Generic;
using Newtonsoft.Json;
namespace BeWoPlanerMobil.Util
{
public class GoalDisplayItem
{
public bool selectable { get; set; }
public string text { get; set; }
public List<string> tags { get; set; }
public List<GoalDisplayItem> nodes { get; set; } = new List<GoalDisplayItem>();
[JsonIgnore]
public long Oid { get; }
[JsonIgnore]
public long? ParentOid { get; set; }
public GoalDisplayItem(string text, long? parentOid, long oid, bool isParent)
{
this.text = text;
tags = new List<string> {oid.ToString()};
ParentOid = parentOid;
Oid = oid;
selectable = !isParent;
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
@@ -411,5 +412,49 @@ namespace BeWoPlanerMobil.Util
return new BeWoLoginState(responseState, message.Replace("\\", "\\\\"));
}
public static List<long> ConvertOidStringToList(string oids, char token = ',')
{
var result = new List<long>();
if(IsNullOrWhiteSpace(oids))
{
return result;
}
var oidArray = oids.Trim(token).Split(token);
oidArray.DoForEach(oidString =>
{
var isSuccessful = long.TryParse(oidString, out var oid);
if(isSuccessful)
{
result.AddIfNotIn(oid);
}
});
return result;
}
public static ConvertedDateTimes ConvertStringDatesToDateTimes(string start, string end)
{
try
{
var isSuccessfulStartDate = DateTime.TryParseExact(start, "dd.MM.yyyy HH:mm", null, DateTimeStyles.None, out var startDate);
var isSuccessfulEndDate = DateTime.TryParseExact(end, "dd.MM.yyyy HH:mm", null, DateTimeStyles.None, out var endDate);
if(isSuccessfulStartDate && isSuccessfulEndDate)
{
return new ConvertedDateTimes(startDate, endDate);
}
throw new ArgumentException("Die Datumsstring dürfen nicht null sein und müssen das Format 'dd.MM.yyyy HH:mm' haben.");
}
catch(Exception exception)
{
throw exception;
}
}
}
}

View File

@@ -52,11 +52,6 @@
</div>
<script type="text/javascript">
$(document).ready(function() {
var test = "@HttpContext.Current.Request.RequestContext.RouteData.Values["blubb"]";
console.log("blubb:" + test);
});
$("body").keyup(
function(event) {
if (event.which === 13) {

View File

@@ -45,6 +45,14 @@
return "@Url.Action("CheckForOverlappingAppointments", "Scheduler")";
}
function getSelectResourcesForAppointmentUrl() {
return "@Url.Action("SelectResourcesForAppointment", "Scheduler")";
}
function getCheckResourcesAvailabilityUrl() {
return "@Url.Action("CheckResourcesAvailability", "Scheduler")";
}
$(document).ready(function() {
toggleFormVisibility();
@@ -59,7 +67,6 @@
$(window).resize(function() {
toggleFormVisibility();
});
</script>
<div class="container mt-3">
@@ -151,6 +158,41 @@
</div>
</div>
</div>
@if(AbstractModel.HasRightToInsertRessourceAppointments && Model.ResourceCategories2Resources.Any())
{
<div class="form-row">
<div class="col-md">
<div class="form-group my-1">
<button type="button" class="btn btn-primary w-100" data-toggle="modal" data-target="#resources-popup">Ressourcen hinzufügen</button>
</div>
</div>
</div>
<div class="form-row">
<div class="col-md">
<div class="form-group my-1">
<div class="list-group" id="selected-resources-list">
@foreach(var selectedResource in Model.SelectedResources)
{
<div class="list-group-item my-auto" id="relation-item-@selectedResource.ResourceOid">
<div class="row">
<div class="col my-auto">
<i class="fas fa-cubes text-bewo-resource mr-2"></i>
@selectedResource.Name
</div>
<div class="col-auto my-auto">
<button type="button" class="btn btn-primary" onclick="removeSelectedResource(@selectedResource.ResourceOid)">
<span class="fas fa-times-circle"></span>
</button>
</div>
</div>
</div>
}
</div>
</div>
</div>
</div>
}
<div class="form-row">
<div class="col-md">
<div class="form-group mb-1">
@@ -273,4 +315,46 @@
</div>
</div>
</div>
</div>
</div>
@if(AbstractModel.HasRightToInsertRessourceAppointments && Model.ResourceCategories2Resources.Any())
{
<div class="modal" tabindex="-1" role="dialog" id="resources-popup">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h6 class="modal-title">Ressourcen</h6>
<button type="button" class="close" data-dismiss="modal">
<span>&times;</span>
</button>
</div>
<div class="modal-body">
<div class="container-fluid">
@foreach(var category2Resources in Model.ResourceCategories2Resources)
{
<div class="card w-100 mb-3" id="resource-category-@category2Resources.Key.ValueListEntryOid">
<div class="card-header">
<h5>@category2Resources.Key.DisplayName</h5>
</div>
<div class="card-body">
@foreach(var resource in category2Resources.Value)
{
var checkedValue = Model.SelectedResources.Contains(resource) ? "checked" : string.Empty;
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" id="@resource.ResourceOid-checkbox" @checkedValue onchange="changeResourceSelection()" />
<label class="custom-control-label" for="@resource.ResourceOid-checkbox">@resource.Name</label>
</div>
}
</div>
</div>
}
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Übernehmen</button>
</div>
</div>
</div>
</div>
}

View File

@@ -1594,8 +1594,7 @@ namespace BeWo.Data.Access
CreateCriteria(Task.PropertyName_EmployeeList, JoinType.InnerJoin)
.Add(Restrictions.Eq(BeWoEntityBase.PropertyName_Oid, employeeOid)).List<Task>();
return c;
return c;
}
public Wohnheimbuchung GetWohnheimbuchungByWohnheimAndBuchungsdatum(long pWohnheimOid, DateTime pBuchungsdatum)
@@ -3142,5 +3141,61 @@ namespace BeWo.Data.Access
return c.List<CostBearer2SupportConcept>().ToList();
}
public bool IsResourceAvailable(DateTime start, DateTime end, long resourceOid)
{
var c = CreateCriteriaIsActive<Resource>();
var sql = $"SELECT COUNT(*) FROM resource WHERE oid = {resourceOid} AND isactive = 1 AND oid NOT IN (SELECT resourceoid FROM resource2newschapp r WHERE r.newschappoid NOT IN (SELECT oid FROM newschedulerappointment WHERE startdate > '{start:yyyy-MM-dd HH:mm:ss}' OR enddate < '{end:yyyy-MM-dd HH:mm:ss}'));";
var criterion = Expression.Sql(sql);
c.Add(criterion);
return c.List().Count > 0;
}
public List<Resource> GetAvailableResources(DateTime start, DateTime end)
{
var c = CreateCriteria<Resource>("r").Add(Restrictions.Eq(nameof(BeWoEntityBase.IsActive), ActivationTypeId.Active));
/*
* var detachedCriteria1 = DetachedCriteria.For<Employee2SchedulerAppointment>()
.Add(Restrictions.In(Employee2SchedulerAppointment.PropertyName_Employee + ".Oid", pSelectedEmployees))
.SetProjection(Projections.Property(Employee2SchedulerAppointment.PropertyName_SchedulerAppointment));
var employee2SchedCrit = Subqueries.PropertyIn(BeWoEntityBase.PropertyName_Oid, detachedCriteria1);
*/
var sql = $"Oid NOT IN (SELECT Oid FROM resource WHERE isactive = 1 AND Oid NOT IN (SELECT resourceoid FROM resource2newschapp r2n WHERE r2n.newschappoid NOT IN (SELECT oid FROM newschedulerappointment WHERE startdate > '{start:yyyy-MM-dd HH:mm:ss}' OR enddate < '{end:yyyy-MM-dd HH:mm:ss}')))";
var criterion = Expression.Sql(sql);
c.Add(criterion);
return c.List<Resource>().ToList();
}
/// <summary>
/// Prüft anhand der Oids von Ressourcen deren Verfügbarkeit in einem Zeitraum.
/// Gibt die nicht verfügbaren Ressourcen zurück für eine detaillierte Fehlermeldung.
/// </summary>
/// <param name="resourceOids">Die Oids der zu überprüfenden Ressourcen</param>
/// <returns>test</returns>
public List<Resource> CheckAvailabilityOfResources(List<long> resourceOids, DateTime start, DateTime end, long? selectedAppointmentOid)
{
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 {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);
return c.List<Resource>().ToList();
}
}
}

View File

@@ -15,9 +15,11 @@ namespace BeWo.Service.DCEntityMapper
pDataContract.Description = pEntity.Description;
pDataContract.Color = pEntity.Color;
pDataContract.ActivationType = pEntity.IsActive;
pDataContract.IsSystemEntry = pEntity.SystemEntryID != null;
ValueListEntry2Object lCategory = pEntity.ValueList.FindSingleByType(ValueListEntryType.ResourceCategory);
var lCategory = pEntity.ValueList.FindSingleByType(ValueListEntryType.ResourceCategory);
if (lCategory != null)
{

View File

@@ -200,5 +200,9 @@ namespace BeWo.Service.ServiceContracts
[FaultContract(typeof(BeWoFault))]
[OperationContract]
void DeleteTestAppointments();
[FaultContract(typeof(BeWoFault))]
[OperationContract]
List<ResourceDC> CheckResourceAvailability(DateTime start, DateTime end, List<long> resourceOids, long? selectedAppointmentOid);
}
}

View File

@@ -2243,5 +2243,10 @@ namespace BeWo.Service.ServiceImplementations
throw Utils.CreateBeWoFaultException(e);
}
}
public List<ResourceDC> CheckResourceAvailability(DateTime start, DateTime end, List<long> resourceOids, long? selectedAppointmentOid)
{
return MapperFactory.ResourceDC_Resource.MapToNewDCs(DAOFactory.SearchDAO.CheckAvailabilityOfResources(resourceOids, start, end, selectedAppointmentOid));
}
}
}