FaC: Neues Scheduling-Modul hinzugefügt, aber noch lange nicht fertig.

ownChat: Neues TimeStamp-Objekt wird unterstützt und der Chat funktioniert wieder.
This commit is contained in:
2024-06-05 14:45:33 +02:00
parent d2a29934ae
commit 23b8757ff5
108 changed files with 12550 additions and 3564 deletions

View File

@@ -129,6 +129,7 @@
<Reference Include="DevExpress.Xpf.Office.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.Xpf.RichEdit.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.Xpf.Scheduler.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.Xpf.Scheduling.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.Xpf.Themes.LightGray.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.Xpf.Themes.Office2010Black.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
<Reference Include="DevExpress.Xpf.Themes.Office2013.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a, processorArchitecture=MSIL" />
@@ -212,6 +213,26 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Scheduling\View\AppointmentEditView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Scheduling\View\AppointmentRecurrenceEditView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Scheduling\View\OccurrenceParticipationConfirmationView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Scheduling\View\OpenAppointmentsView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Scheduling\View\SchedulingView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="SchulbegleitenderDienst\SchulbegleitenderDienstEmployeeView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -493,6 +514,10 @@
<Page Include="View\Master\DokumenteView.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>
</Page>
<Page Include="View\Master\SchedulingMasterView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="View\TwoFactorAuthMessageDialog.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
@@ -844,6 +869,47 @@
<Compile Include="Scheduler\Utils\AppointmentExtensions.cs" />
<Compile Include="Scheduler\Utils\Utils.cs" />
<Compile Include="Scheduler\ViewModel\CustomFieldStorage.cs" />
<Compile Include="Scheduling\Converter\AppointmentBorderThicknessConverter.cs" />
<Compile Include="Scheduling\Converter\CustomerAndResourceBackgroundConverter.cs" />
<Compile Include="Scheduling\Converter\DayViewDayCountVisibilityConverter.cs" />
<Compile Include="Scheduling\Converter\EmployeeBackgroundColorConverter.cs" />
<Compile Include="Scheduling\Converter\EmployeeListConfirmationToolTipConverter.cs" />
<Compile Include="Scheduling\Converter\InfoButtonVisibilityConverter.cs" />
<Compile Include="Scheduling\Converter\ParticipationRequestListViewConverter.cs" />
<Compile Include="Scheduling\Converter\RecurringAppointmentDurationConverter.cs" />
<Compile Include="Scheduling\Converter\RequestVisibilityConverter.cs" />
<Compile Include="Scheduling\Converter\SchedulingBackgroundConverter.cs" />
<Compile Include="Scheduling\Converter\SchedulingCheckBoxConverter.cs" />
<Compile Include="Scheduling\Converter\SchedulingInformationVisibilityConverter.cs" />
<Compile Include="Scheduling\Converter\SchedulingParticipationBrushConverter.cs" />
<Compile Include="Scheduling\Converter\SchedulingRemoveElementVisibilityConverter.cs" />
<Compile Include="Scheduling\Converter\SchedulingTextFromIDataContractConverter.cs" />
<Compile Include="Scheduling\Converter\WidthAdditionMultiConverter.cs" />
<Compile Include="Scheduling\SchedulingUtils\AppointmentColorHelper.cs" />
<Compile Include="Scheduling\SchedulingUtils\CategoryDependencyObject.cs" />
<Compile Include="Scheduling\SchedulingUtils\EmployeeDependencyObject.cs" />
<Compile Include="Scheduling\SchedulingUtils\ListItemHelper.cs" />
<Compile Include="Scheduling\SchedulingUtils\ResourceDependencyObject.cs" />
<Compile Include="Scheduling\SchedulingUtils\TreeViewItemHelper.cs" />
<Compile Include="Scheduling\SchedulingUtils\Utils.cs" />
<Compile Include="Scheduling\ViewModel\AppointmentWindowVM.cs" />
<Compile Include="Scheduling\ViewModel\SchedulingAppointmentListVM.cs" />
<Compile Include="Scheduling\ViewModel\SchedulingAppointmentVM.cs" />
<Compile Include="Scheduling\View\AppointmentEditView.xaml.cs">
<DependentUpon>AppointmentEditView.xaml</DependentUpon>
</Compile>
<Compile Include="Scheduling\View\AppointmentRecurrenceEditView.xaml.cs">
<DependentUpon>AppointmentRecurrenceEditView.xaml</DependentUpon>
</Compile>
<Compile Include="Scheduling\View\OccurrenceParticipationConfirmationView.xaml.cs">
<DependentUpon>OccurrenceParticipationConfirmationView.xaml</DependentUpon>
</Compile>
<Compile Include="Scheduling\View\OpenAppointmentsView.xaml.cs">
<DependentUpon>OpenAppointmentsView.xaml</DependentUpon>
</Compile>
<Compile Include="Scheduling\View\SchedulingView.xaml.cs">
<DependentUpon>SchedulingView.xaml</DependentUpon>
</Compile>
<Compile Include="SchulbegleitenderDienst\Converter\SubstitutionBrushConverter.cs" />
<Compile Include="SchulbegleitenderDienst\SchulbegleitenderDienstEmployeeView.xaml.cs">
<DependentUpon>SchulbegleitenderDienstEmployeeView.xaml</DependentUpon>
@@ -1225,6 +1291,9 @@
<Compile Include="View\Master\DokumenteView.xaml.cs">
<DependentUpon>DokumenteView.xaml</DependentUpon>
</Compile>
<Compile Include="View\Master\SchedulingMasterView.xaml.cs">
<DependentUpon>SchedulingMasterView.xaml</DependentUpon>
</Compile>
<Compile Include="View\Navigation\Filter\PersonNavigationFilter.cs" />
<Compile Include="View\TwoFactorAuthMessageDialog.xaml.cs">
<DependentUpon>TwoFactorAuthMessageDialog.xaml</DependentUpon>
@@ -3108,6 +3177,9 @@
<ItemGroup>
<Resource Include="Ressources\Icons\Copy24.png" />
</ItemGroup>
<ItemGroup>
<Resource Include="Ressources\Icons\CalendarDisabledUnderConstruction.png" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>

View File

@@ -60,6 +60,9 @@ using Control = System.Windows.Controls.Control;
using Utils = BS.Shared.Core.Utils;
using Brush = System.Windows.Media.Brush;
using BeWo.View.Detail.Zeiterfassung;
using DevExpress.Xpf.Scheduling;
using CommandBarStyle = DevExpress.Xpf.DocumentViewer.CommandBarStyle;
using ImageSource = System.Windows.Media.ImageSource;
namespace BeWo.Core
{
@@ -2097,6 +2100,37 @@ namespace BeWo.Core
newView.ShowDialog();
}
// Zeiterfassungseintrag aus dem neuen Kalendermodul erstellen
public static void CreateZeiterfassung(DateTime start, DateTime end, List<CompactCustomerDC> customer, List<CompactEmployeeDC> employees, String notice, AppointmentItem appointment, Action schedulerCallback)
{
ChatDokumentationsView newView;
if(customer.Count == 0)
{
// Normale Buchung
newView = new ChatDokumentationsView(notice, null, null, start, end, schedulerCallback, appointment);
}
else if(customer.Count == 1 && employees.Count < 2)
{
var compactKlient = ServiceFacade.DoCustomerServiceSync(s => s.GetCompactCustomerDC(customer[0].CustomerOid));
// Normale Buchung
newView = new ChatDokumentationsView(notice, compactKlient, employees.Count == 1 ? employees[0] : null, start, end, schedulerCallback, appointment);
}
else
{
if(employees.Count == 0)
{
employees.Add(BeWoApp.CompactLoggedOnEmployee);
}
// Gruppenbuchungen
newView = new ChatDokumentationsView(appointment, notice, start, end, customer, employees, schedulerCallback);
}
newView.ShowDialog();
}
public static void CreateZeiterfassung(DateTime start, DateTime end, List<CompactCustomerDC> customer, List<CompactEmployeeDC> employees, String notice)
{
ChatDokumentationsView newView;

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using BeWo.View.Navigation.Filter;
using BS.Shared;
using DevExpress.Xpf.Scheduling;
using DevExpress.XtraScheduler;
namespace BeWo.Core.Config
@@ -462,6 +463,20 @@ namespace BeWo.Core.Config
}
}
private ViewType _SchedulingViewType;
public ViewType SchedulingViewType
{
get => _SchedulingViewType;
set
{
if(_SchedulingViewType != value)
{
_SchedulingViewType = value;
IsDirty = true;
}
}
}
private int _SchedulerTimelineViewDayCount;
public int SchedulerTimelineViewDayCount
{

View File

@@ -590,5 +590,51 @@ namespace BeWo.Core.Service
});
});
}
// Für neuen SchedulingView hinzugefügt
private List<CompactCustomerDC> _FilteredCustomers;
public void GetAllActiveCustomersCompactForEmployee(long employeeOid, bool forceReload, Action<List<CompactCustomerDC>> callback)
{
if(_FilteredCustomers is null || forceReload)
{
ServiceFacade.DoEmployeeServiceAsync(s => s.GetActiveCompactCustomersForEmployee(employeeOid), customers =>
{
customers.Sort((x, y) => $"{x.LastName}, {x.FirstName}".CompareTo($"{y.LastName}, {y.FirstName}"));
_FilteredCustomers = customers;
callback(customers);
});
}
else
{
callback(_FilteredCustomers);
}
}
public void ClearFilteredCustomers()
{
_FilteredCustomers = null;
}
private List<CompactEmployeeDC> _FilteredEmployees;
public void GetAllActiveCompactEmployeesForEmployee(long employeeOid, bool forceReload, Action<List<CompactEmployeeDC>> callback)
{
if(_FilteredEmployees is null || forceReload)
{
ServiceFacade.DoEmployeeServiceAsync(s => s.GetActiveCompactEmployeesForEmployee(employeeOid), employees =>
{
employees.Sort((x, y) => $"{x.LastName}, {x.FirstName}".CompareTo($"{y.LastName}, {y.FirstName}"));
_FilteredEmployees = employees;
callback(employees);
});
}
else
{
callback(_FilteredEmployees);
}
}
public void ClearFilteredEmployees()
{
_FilteredEmployees = null;
}
}
}

View File

@@ -294,6 +294,43 @@
</BeWo:OutlinedTextBlock.Triggers>
</BeWo:OutlinedTextBlock>
</Grid>
<!-- ToDo: Neuer Kalender -->
<Grid>
<localView:ImageButton r:DemandUserRight.VisibleDemands="KalenderAnsehen"
ImageSource="Ressources\Icons\CalendarDisabledUnderConstruction.png"
x:Name="ButtonScheduling"
Click="Button_Scheduling_Click"
Style="{StaticResource NavBarButton}"
Content="{t:Translate KalenderMenuItem}"
Background="{StaticResource ResourceContentBrush}"
Visibility="Collapsed"
RenderTransformOrigin="0.5,0.5"
Width="90">
<Button.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1" />
<SkewTransform AngleX="0" AngleY="0" />
<RotateTransform Angle="0" />
<TranslateTransform X="0" Y="0" />
</TransformGroup>
</Button.RenderTransform>
</localView:ImageButton>
<BeWo:OutlinedTextBlock Visibility="Collapsed" x:Name="NewAppointmentsOutlinedTextBlock2" Margin="25,0,0,0" FontFamily="Verdana" FontSize="25" FontWeight="ExtraBold" TextWrapping="Wrap" StrokeThickness="1" Stroke="White" Fill="OrangeRed" SnapsToDevicePixels="True" Text="!" HorizontalAlignment="Left" VerticalAlignment="Top">
<BeWo:OutlinedTextBlock.Triggers>
<EventTrigger RoutedEvent="BeWo:OutlinedTextBlock.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="NewAppointmentsOutlinedTextBlock2"
Storyboard.TargetProperty="(BeWo:OutlinedTextBlock.FontSize)"
To="30.0" Duration="0:0:0.3"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</BeWo:OutlinedTextBlock.Triggers>
</BeWo:OutlinedTextBlock>
</Grid>
<!-- /ToDo: Neuer Kalender -->
<localView:ImageButton r:DemandUserRight.VisibleDemands="ViewAll, ResourceBookingView_View"
ImageSource="Ressources\Icons\CalendarDisabled.png" x:Name="button_ResourceBooking"
Click="button_ResourceBooking_Click" Style="{StaticResource NavBarButton}"

View File

@@ -49,7 +49,8 @@ namespace BeWo
Scheduler,
Wohnheim,
Vertretungen,
CustomerTeam
CustomerTeam,
Scheduling
}
public partial class MainControl
@@ -77,36 +78,49 @@ namespace BeWo
KeyDown += MainControl_KeyDown;
NavigateToHomeView();
// ToDo: Neuer Kalender nur im Debug-Modus!
#if DEBUG
ButtonScheduling.Visibility = Visibility.Visible;
#else
ButtonScheduling.Visibility = Visibility.Hidden;
#endif
//EditorLocalizer.Active = new CustomDXEditorLocalizer();
//SchedulerControlLocalizer.Active = new CustomSchedulerLocalizer();
//GridControlLocalizer.Active = new CustomGridLocalizer();
// ToDo: Testen!
// var bewoClientType = BeWoApp.Mandator.BeWoClientType;
// var bewoClientType = BeWoApp.Mandator.BeWoClientType;
//var hasKilometerauswertung = BeWoApp.AppSettings.ShowDistanceFields && (BeWoApp.LoggedOnUser.HasRight(UserRightType.Kilometerauswertung_View) || BeWoApp.LoggedOnUser.HasRight(UserRightType.KilometerauswertungEigene_View));
//var hideAuswertungen = !BeWoApp.LoggedOnUser.HasRight(UserRightType.Auswertungen_BerichteAnsehen) &&
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.Auswertungen_StundenuebersichtAnsehen) &&
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.Auswertungen_HilfeplanuebersichtAnsehen) &&
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.Analysis_ServiceOverview_View) &&
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.Analysis_Auslastung_View) &&
// (bewoClientType != 3 || !BeWoApp.LoggedOnUser.HasRight(UserRightType.Analysis_EmployeeOverviewAll_View)) &&
// (BeWoApp.Tenant == "3010479871" || (!BeWoApp.LoggedOnUser.HasRight(UserRightType.Mitarbeiterstundenkonto_ViewAll) && !BeWoApp.LoggedOnUser.HasRight(UserRightType.Mitarbeiterstundenkonto_ViewSelf) && !BeWoApp.LoggedOnUser.HasRight(UserRightType.Mitarbeiterstundenkonto_ViewTeams))) &&
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.Jahresbericht) &&
// !BeWoApp.Mandator.AllowSbd &&
// !(BeWoApp.AppSettings.ShowPivotGrid && BeWoApp.LoggedOnUser.HasRight(UserRightType.PivotTabelleAnsehen)) &&
// !(BeWoApp.AppSettings.ShowDienstplanung && BeWoApp.LoggedOnUser.HasRight(UserRightType.DienstplanungAnsehen)) &&
// !(BeWoApp.AppSettings.ShowUrlaubsplanung && BeWoApp.LoggedOnUser.HasRight(UserRightType.AbwesenheitsPlanungAnsehen)) &&
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.BewertungAuswertung_View) &&
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.Analysis_ServiceOverview_View) &&
// !hasKilometerauswertung;
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.Auswertungen_StundenuebersichtAnsehen) &&
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.Auswertungen_HilfeplanuebersichtAnsehen) &&
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.Analysis_ServiceOverview_View) &&
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.Analysis_Auslastung_View) &&
// (bewoClientType != 3 || !BeWoApp.LoggedOnUser.HasRight(UserRightType.Analysis_EmployeeOverviewAll_View)) &&
// (BeWoApp.Tenant == "3010479871" || (!BeWoApp.LoggedOnUser.HasRight(UserRightType.Mitarbeiterstundenkonto_ViewAll) && !BeWoApp.LoggedOnUser.HasRight(UserRightType.Mitarbeiterstundenkonto_ViewSelf) && !BeWoApp.LoggedOnUser.HasRight(UserRightType.Mitarbeiterstundenkonto_ViewTeams))) &&
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.Jahresbericht) &&
// !BeWoApp.Mandator.AllowSbd &&
// !(BeWoApp.AppSettings.ShowPivotGrid && BeWoApp.LoggedOnUser.HasRight(UserRightType.PivotTabelleAnsehen)) &&
// !(BeWoApp.AppSettings.ShowDienstplanung && BeWoApp.LoggedOnUser.HasRight(UserRightType.DienstplanungAnsehen)) &&
// !(BeWoApp.AppSettings.ShowUrlaubsplanung && BeWoApp.LoggedOnUser.HasRight(UserRightType.AbwesenheitsPlanungAnsehen)) &&
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.BewertungAuswertung_View) &&
// !BeWoApp.LoggedOnUser.HasRight(UserRightType.Analysis_ServiceOverview_View) &&
// !hasKilometerauswertung;
//if(hideAuswertungen)
// {
// button_Reports.Visibility = Visibility.Collapsed;
// }
// {
// button_Reports.Visibility = Visibility.Collapsed;
// }
OpenedModalViewWindows = new List<ModalViewWindow>();
@@ -201,7 +215,8 @@ namespace BeWo
}
}
} else if(ActiveView?.GetType() == typeof(HomeView))
}
else if(ActiveView?.GetType() == typeof(HomeView))
{
var homeDragPanelView = (HomeView) ActiveView;
homeDragPanelView.UpdateRequestsHyperLink();
@@ -268,6 +283,9 @@ namespace BeWo
case UIContext.CustomerTeam:
view = new CustomerTeamNavigationView();
break;
case UIContext.Scheduling:
view = new SchedulingMasterView();
break;
}
_Views[uiContext] = view;
}
@@ -1757,5 +1775,13 @@ namespace BeWo
NavigateTo(GetViewForUIContext(UIContext.Vertretungen));
}
}
private void Button_Scheduling_Click(object sender, RoutedEventArgs e)
{
if(DoSaveCheck())
{
NavigateTo(GetViewForUIContext(UIContext.Scheduling));
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View File

@@ -1,6 +1,6 @@
using System;
using System.Drawing;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.IO;
@@ -10,20 +10,19 @@ namespace BeWo.Scheduler.Converter
{
public class BitmapToBitmapSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//return null;
System.Drawing.Bitmap source = value as System.Drawing.Bitmap;
if (source == null || targetType != typeof(ImageSource))
if (!(value is Bitmap source) || targetType != typeof(ImageSource))
{
return null;
}
MemoryStream stream = new MemoryStream();
var stream = new MemoryStream();
source.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
stream.Position = 0;
BitmapImage result = new BitmapImage();
var result = new BitmapImage();
result.BeginInit();
result.StreamSource = stream;
result.EndInit();
@@ -31,14 +30,9 @@ namespace BeWo.Scheduler.Converter
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
}

View File

@@ -0,0 +1,28 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
namespace BeWo.Scheduling.Converter
{
public class AppointmentBorderThicknessConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var defaultThickness = new Thickness(0);
if(value is SolidColorBrush solidColorBrush)
{
return solidColorBrush.Color == Colors.Transparent ? defaultThickness : new Thickness(2);
}
return defaultThickness;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,148 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using BeWo.Scheduler.ViewModel;
using BS.Shared.DataContracts;
using DevExpress.XtraScheduler;
using ColorConverter = System.Windows.Media.ColorConverter;
namespace BeWo.Scheduling.Converter
{
public class CustomerAndResourceBackgroundConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var farbe = Color.FromRgb(192, 255, 208);
try
{
if(!(values[0] is List<IDataContract> selectedItems) || !selectedItems.Any())
{
return new LinearGradientBrush(new GradientStopCollection { new GradientStop(farbe, 1) }, new Point(.5, 0), new Point(.5, 1));
}
if(!(values[1] is CustomFieldCollection customViewInfo))
{
return new LinearGradientBrush(new GradientStopCollection { new GradientStop(farbe, 1) }, new Point(.5, 0), new Point(.5, 1));
}
var customFieldStorage = (CustomFieldStorage) customViewInfo[nameof(CustomFieldStorage)];
var isTask = customFieldStorage.IsTask;
if(isTask)
{
farbe = Color.FromRgb(153, 59, 59);
}
var aptCustomers = customFieldStorage.CustomerList;
var aptResources = customFieldStorage.ResourceList;
var gradientCollection = new GradientStopCollection();
var farbKollektion = new List<Color>();
if(selectedItems.Any(aptCustomers.Contains))
{
farbKollektion.Add(Color.FromRgb(59, 119, 153));
}
if(selectedItems.Any(aptResources.Contains))
{
farbKollektion.Add(Color.FromRgb(4, 180, 208));
}
switch(farbKollektion.Count)
{
case 1:
if(BeWoApp.AppSettings.ShowMultipleResourceColors)
{
AddResourceColors(gradientCollection, aptResources, false);
}
else
{
var first = aptResources.FirstOrDefault();
gradientCollection.Add(first != null ? new GradientStop((Color) (ColorConverter.ConvertFromString(first.Color) ?? Color.FromRgb(4, 180, 208)), 1) : new GradientStop(farbKollektion[0], 1));
}
break;
case 2:
// 1. Klientenfarbe
gradientCollection.Add(new GradientStop(farbKollektion[0], 0.5));
// 2. Resourcenfarben
if(BeWoApp.AppSettings.ShowMultipleResourceColors)
{
AddResourceColors(gradientCollection, aptResources, true);
}
else
{
var first2 = aptResources.FirstOrDefault();
if(first2 != null)
{
gradientCollection.Add(new GradientStop((Color) (ColorConverter.ConvertFromString(first2.Color) ?? Color.FromRgb(4, 180, 208)), 0.5));
}
}
break;
default:
gradientCollection.Add(new GradientStop(farbe, 1));
break;
}
return new LinearGradientBrush(gradientCollection, new Point(.5, 0), new Point(.5, 1));
}
catch(Exception)
{
return new LinearGradientBrush(new GradientStopCollection { new GradientStop(farbe, 1) }, new Point(.5, 0), new Point(.5, 1));
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
private static void AddResourceColors(GradientStopCollection gradientCollection, IReadOnlyList<ResourceDC> resourceList, bool hasCustomers)
{
var previousOffset = hasCustomers ? 0.5 : 0;
var numberOfResources = resourceList.Count;
if(numberOfResources == 0)
{
return;
}
if(numberOfResources > 4)
{
numberOfResources = 4;
}
var iterator = hasCustomers == false ? 1d / numberOfResources : previousOffset / numberOfResources;
for(var i = 0; i < numberOfResources; i++)
{
var resource = resourceList[i];
var currentOffset = previousOffset;
var nextOffset = currentOffset + iterator;
if(nextOffset > 1)
{
nextOffset = 1;
}
previousOffset = nextOffset;
gradientCollection.Add(new GradientStop((Color) (ColorConverter.ConvertFromString(resource.Color) ?? Color.FromRgb(4, 180, 208)), currentOffset));
gradientCollection.Add(new GradientStop((Color) (ColorConverter.ConvertFromString(resource.Color) ?? Color.FromRgb(4, 180, 208)), nextOffset));
}
}
}
}

View File

@@ -0,0 +1,29 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace BeWo.Scheduling.Converter
{
public class DayViewDayCountVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is DevExpress.Xpf.Scheduling.ViewType.DayView && parameter is string stringParameter && stringParameter == "DayCount")
{
return Visibility.Visible;
}
else if(value is DevExpress.Xpf.Scheduling.ViewType.TimelineView && parameter is string strParameter && strParameter == "IntervalCount")
{
return Visibility.Visible;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,25 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
namespace BeWo.Scheduling.Converter
{
public class EmployeeBackgroundColorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if(values.Length == 3 && values[0] is bool showEmployeeBackgroundColor && values[1] is LinearGradientBrush backgroundBrush && values[2] is SolidColorBrush defaultBackgroundColor)
{
return showEmployeeBackgroundColor ? new SolidColorBrush(backgroundBrush.GradientStops[0].Color) : defaultBackgroundColor;
}
return new SolidColorBrush(Color.FromRgb(192, 255, 208));
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,47 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
using BS.Shared;
using BS.Shared.DataContracts;
namespace BeWo.Scheduling.Converter
{
public class EmployeeListConfirmationToolTipConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is Employee2SchedulerAppointmentDC e2s)
{
if(parameter?.Equals("EmployeeName") ?? false)
{
return e2s.Employee?.DetailDescription;
}
var color = Color.FromRgb(255, 255, 255);
switch(e2s.ParticipationAnswer)
{
case ParticipationAnswer.Vorbehalt:
color = Color.FromRgb(185, 39, 217);
break;
case ParticipationAnswer.Zusage:
color = Color.FromRgb(72, 212, 78);
break;
case ParticipationAnswer.Absage:
color = Color.FromRgb(171, 0, 48);
break;
}
return new SolidColorBrush(color);
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,20 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace BeWo.Scheduling.Converter
{
public class InfoButtonVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return BeWoApp.AppSettings.ShowInfoButtonInCalender ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,49 @@
using System;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
using BeWo.Scheduling.ViewModel;
using BS.Shared;
namespace BeWo.Scheduling.Converter
{
public class ParticipationRequestListViewConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is SchedulingAppointmentVM appointment)
{
if(appointment.LabelKey is null)
{
return $"{appointment.Start.ToShortDateString()}; {appointment.Subject}";
}
var participationAnswer = string.Empty;
var correspondingRelation = appointment.EmployeeList.ToList().Find(e2a => e2a.Employee2SchedulerAppointmentOid == appointment.LabelKey);
switch(correspondingRelation.ParticipationAnswer)
{
case ParticipationAnswer.Zusage:
participationAnswer = "zugesagt";
break;
case ParticipationAnswer.Vorbehalt:
participationAnswer = "mit Vorbehalt zugesagt";
break;
case ParticipationAnswer.Absage:
participationAnswer = "abgesagt";
break;
}
return $"{appointment.Start.ToShortDateString()}: {correspondingRelation.Employee.FirstNameLastName} hat {participationAnswer}";
}
return string.Empty;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,208 @@
using System;
using System.Globalization;
using System.Windows.Data;
using BeWo.Scheduling.ViewModel;
using DevExpress.XtraScheduler;
namespace BeWo.Scheduling.Converter
{
public class RecurringAppointmentDurationConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is null)
{
return null;
}
var appointment = (SchedulingAppointmentVM) value;
if(appointment.RecurrenceInfo is null)
{
return string.Empty;
}
IRecurrenceInfo recurrenceInfo = new RecurrenceInfo();
recurrenceInfo.FromXml(appointment.RecurrenceInfo);
var rangeString = string.Empty;
var suffix = string.Empty;
var periodicity = recurrenceInfo.Periodicity;
var intervalPlural = string.Empty;
var weekDays = string.Empty;
string weekOfMonth;
switch(recurrenceInfo.Range)
{
case RecurrenceRange.EndByDate:
rangeString += $"bis zum {recurrenceInfo.End.ToShortDateString()} ";
break;
case RecurrenceRange.OccurrenceCount:
rangeString += $"{recurrenceInfo.OccurrenceCount} mal ";
break;
}
switch(recurrenceInfo.Type)
{
case RecurrenceType.Daily:
if(periodicity == 1)
{
suffix = recurrenceInfo.WeekDays.Equals(WeekDays.WorkDays) ? "jeden Arbeitstag " : "täglich ";
}
intervalPlural = " Tage ";
break;
case RecurrenceType.Weekly:
if(periodicity == 1)
{
suffix = "wöchentlich ";
}
intervalPlural = " Wochen ";
weekDays = TranslateWorkDays(recurrenceInfo.WeekDays.ToString(), true);
break;
case RecurrenceType.Yearly:
weekDays = TranslateWorkDays(recurrenceInfo.WeekDays.ToString(), false);
weekOfMonth = TranslateWeekOfMonth(recurrenceInfo.WeekOfMonth);
var tag = recurrenceInfo.DayNumber;
suffix = "jährlich ";
if(recurrenceInfo.WeekOfMonth != WeekOfMonth.None)
{
suffix += $"jeden {weekOfMonth}{weekDays}im {GetMonthByInt(recurrenceInfo.Month)}";
}
else
{
suffix += $"am {tag}. {GetMonthByInt(recurrenceInfo.Month)}";
}
weekDays = string.Empty;
break;
case RecurrenceType.Monthly:
string monatlichesInterval;
if(recurrenceInfo.WeekOfMonth != WeekOfMonth.None)
{
weekOfMonth = TranslateWeekOfMonth(recurrenceInfo.WeekOfMonth);
weekDays = TranslateWorkDays(recurrenceInfo.WeekDays.ToString(), false);
suffix = $"jeden {weekOfMonth}{weekDays}";
monatlichesInterval = periodicity == 1 ? "jedes Monats " : $"jedes {periodicity}. Monats ";
suffix += monatlichesInterval;
weekDays = "";
}
else
{
monatlichesInterval = periodicity == 1 ? "jedes Monats " : $"jedes {periodicity}. Monats ";
suffix = $"am {recurrenceInfo.DayNumber}. {monatlichesInterval}";
weekDays = string.Empty;
}
break;
}
if(periodicity > 1 && recurrenceInfo.Type != RecurrenceType.Monthly)
{
suffix = $"alle {periodicity}{intervalPlural}";
}
return $"Dieser Termin wird {rangeString}{suffix}{weekDays}wiederholt";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
private static string TranslateWorkDays(string weekDays, bool mitGenitivS)
{
weekDays = weekDays.Replace("Monday", mitGenitivS ? "Montags" : "Montag");
weekDays = weekDays.Replace("Tuesday", mitGenitivS ? "Dienstags" : "Dienstag");
weekDays = weekDays.Replace("Wednesday", mitGenitivS ? "Mittwochs" : "Mittwoch");
weekDays = weekDays.Replace("Thursday", mitGenitivS ? "Donnerstags" : "Donnerstag");
weekDays = weekDays.Replace("Friday", mitGenitivS ? "Freitags" : "Freitag");
weekDays = weekDays.Replace("Saturday", mitGenitivS ? "Samstags" : "Samstag");
weekDays = weekDays.Replace("Sunday", mitGenitivS ? "Sonntags" : "Sonntag");
weekDays = weekDays.Replace("EveryDay", "jeden Tag");
var lastComma = weekDays.LastIndexOf(',');
if(lastComma != -1)
{
weekDays = weekDays.Remove(lastComma, 1).Insert(lastComma, " und");
}
return weekDays + " ";
}
private static string TranslateWeekOfMonth(WeekOfMonth weekOfMonth)
{
var result = " ";
switch(weekOfMonth)
{
case WeekOfMonth.First:
result = "ersten ";
break;
case WeekOfMonth.Second:
result = "zweiten ";
break;
case WeekOfMonth.Third:
result = "dritten ";
break;
case WeekOfMonth.Fourth:
result = "vierten ";
break;
case WeekOfMonth.Last:
result = "letzten ";
break;
case WeekOfMonth.None:
return result;
default:
return result;
}
return result;
}
private static string GetMonthByInt(int month)
{
switch(month)
{
case 1:
return "Januar ";
case 2:
return "Februar ";
case 3:
return "März ";
case 4:
return "April ";
case 5:
return "Mai ";
case 6:
return "Juni ";
case 7:
return "Juli ";
case 8:
return "August ";
case 9:
return "September ";
case 10:
return "Oktober ";
case 11:
return "November ";
case 12:
return "Dezember ";
default:
return " ";
}
}
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using BeWo.Scheduling.ViewModel;
using DevExpress.XtraScheduler;
namespace BeWo.Scheduling.Converter
{
public class RequestVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is null)
{
return Visibility.Collapsed;
}
var appointment = (SchedulingAppointmentVM) value;
var hasNoEnd = false;
var liesInPast = appointment.Start < DateTime.Now && appointment.End < DateTime.Now;
if(!(appointment.RecurrenceInfo is null))
{
IRecurrenceInfo recurrenceInfo = new RecurrenceInfo();
recurrenceInfo.FromXml(appointment.RecurrenceInfo);
hasNoEnd = recurrenceInfo.Range == RecurrenceRange.NoEndDate;
liesInPast = recurrenceInfo.Start < DateTime.Now && recurrenceInfo.End < DateTime.Now;
}
if(parameter?.Equals("ZusagenStack") ?? false)
{
if(appointment.LabelKey.HasValue)
{
return Visibility.Collapsed;
}
var shouldBeVisible = !liesInPast;
if(!(appointment.RecurrenceInfo is null))
{
shouldBeVisible = !liesInPast || hasNoEnd;
}
return shouldBeVisible ? Visibility.Visible : Visibility.Collapsed;
}
if(parameter?.Equals("OKBtn") ?? false)
{
return (appointment.LabelKey.HasValue || liesInPast) && !hasNoEnd ? Visibility.Visible : Visibility.Collapsed;
}
if(parameter?.Equals("TerminVerstrichen") ?? false)
{
return liesInPast && !hasNoEnd ? Visibility.Visible : Visibility.Collapsed;
}
if(parameter?.Equals("SerienterminLabel") ?? false)
{
return !(appointment.RecurrenceInfo is null) ? Visibility.Visible : Visibility.Collapsed;
}
return appointment.LabelKey.HasValue || liesInPast ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,42 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Compact;
namespace BeWo.Scheduling.Converter
{
public class SchedulingBackgroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var employeeBrush = new SolidColorBrush(Color.FromArgb(255, 69, 153, 59));
var customerBrush = new SolidColorBrush(Color.FromArgb(255, 59, 119, 153));
var resourceBrush = new SolidColorBrush(Color.FromArgb(255, 4, 180, 208));
var supportConceptBrush = new SolidColorBrush(Color.FromArgb(255, 153, 59, 59));
if(value is CompactEmployeeDC || value is Employee2SchedulerAppointmentDC)
{
return employeeBrush;
}
if(value is CompactCustomerDC)
{
return customerBrush;
}
if(value is CompactSupportConceptDC)
{
return supportConceptBrush;
}
return resourceBrush;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
using BeWo.Scheduling.ViewModel;
namespace BeWo.Scheduling.Converter
{
public class SchedulingCheckBoxConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if(values.Length < 2 || parameter == null)
{
return false;
}
var oid = (long) values[0];
var viewModel = (SchedulingAppointmentListVM) values[1];
switch(parameter.ToString())
{
case "Klienten":
return viewModel.SelectedCustomers.Any(item => item.CustomerOid == oid);
default:
return false;
}
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using BS.Shared.DataContracts.Compact;
namespace BeWo.Scheduling.Converter
{
public class SchedulingInformationVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is CompactCustomerDC ? Visibility.Visible : (object) Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,54 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;
using BS.Shared;
using BS.Shared.DataContracts;
namespace BeWo.Scheduling.Converter
{
public class SchedulingParticipationBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var offen = new SolidColorBrush(Color.FromRgb(255, 255, 255));
var zusage = new SolidColorBrush(Color.FromRgb(72, 212, 78));
var absage = new SolidColorBrush(Color.FromRgb(171, 0, 48));
var mitVorbehalt = new SolidColorBrush(Color.FromRgb(185, 39, 217));
if((string) parameter == "Border")
if(value is Employee2SchedulerAppointmentDC)
{
return new SolidColorBrush(Colors.Black);
}
else
{
return new SolidColorBrush(Colors.Transparent);
}
if(value is Employee2SchedulerAppointmentDC wert)
{
switch(wert.ParticipationAnswer)
{
case ParticipationAnswer.Zusage:
return zusage;
case ParticipationAnswer.Absage:
return absage;
case ParticipationAnswer.Vorbehalt:
return mitVorbehalt;
}
}
else
{
return new SolidColorBrush(Colors.Transparent);
}
return offen;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace BeWo.Scheduling.Converter
{
public class SchedulingRemoveElementVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
//if(value == null)
//{
return Visibility.Visible;
//}
//var isNew = SchedulerAppointmentEditForm.IsNew;
//var isAllowedToChange = BeWoUtils.CheckSchedulerRights(SchedulerAppointmentEditForm.CurrentAppointment, isNew, SchedulerRightsCheckType.Edit);
//return isAllowedToChange ? Visibility.Visible : Visibility.Hidden;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,32 @@
using System;
using System.Globalization;
using System.Windows.Data;
using BS.Shared.DataContracts;
namespace BeWo.Scheduling.Converter
{
public class SchedulingTextFromIDataContractConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is ResourceDC resourceDC)
{
return resourceDC.Name;
}
if(value is Employee2SchedulerAppointmentDC dc)
{
return dc.Employee.SimpleDescription;
}
var filterableDC = value as IFilterableDC;
return filterableDC?.SimpleDescription;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,22 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace BeWo.Scheduling.Converter
{
public class WidthAdditionMultiConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var w1 = System.Convert.ToDouble(values[0]);
var w2 = System.Convert.ToDouble(values[1]);
return w1 + w2;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

View File

@@ -0,0 +1,117 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Media;
namespace BeWo.Scheduling.SchedulingUtils
{
public class AppointmentColorHelper
{
public LinearGradientBrush ResourceAndCustomerBackground { get; set; }
public LinearGradientBrush EmployeeBackground { get; set; }
public AppointmentColorHelper(Color employeeColor, List<Color> resourceColors, bool hasCustomers, bool isTask)
{
var defaultColor = isTask ? Color.FromRgb(153, 59, 59) : Color.FromRgb(192, 255, 208);
EmployeeBackground = new LinearGradientBrush(new GradientStopCollection { new GradientStop(employeeColor, 1) }, new Point(0, 0), new Point(0, 1));
if(resourceColors is null)
{
resourceColors = new List<Color>();
}
// Weder Ressourcen noch Klienten vorhanden
if(!resourceColors.Any() && !hasCustomers)
{
ResourceAndCustomerBackground = new LinearGradientBrush(new GradientStopCollection { new GradientStop(defaultColor, 1) }, new Point(.5, 0), new Point(.5, 1));
}
var colorList = new List<Color>();
var gradientStopCollection = new GradientStopCollection();
if(hasCustomers)
{
colorList.Add(Color.FromRgb(59, 119, 153));
}
if(resourceColors.Any())
{
colorList.Add(Color.FromRgb(4, 180, 208));
}
switch(colorList.Count)
{
case 1:
if(BeWoApp.AppSettings.ShowMultipleResourceColors)
{
AddResourceColors(gradientStopCollection, resourceColors, hasCustomers);
}
else
{
var color = resourceColors.Count >= 1 ? resourceColors[0] : Color.FromRgb(4, 180, 208);
var gradientStop = new GradientStop(color, 1);
gradientStopCollection.Add(gradientStop);
}
break;
case 2:
// 1. Klientenfarbe
gradientStopCollection.Add(new GradientStop(colorList[0], .5));
// 2. Ressourcenfarben
if(BeWoApp.AppSettings.ShowMultipleResourceColors)
{
AddResourceColors(gradientStopCollection, resourceColors, hasCustomers);
}
else
{
var color = resourceColors.Count >= 1 ? resourceColors[0] : Color.FromRgb(4, 180, 208);
gradientStopCollection.Add(new GradientStop(color, .5));
}
break;
default:
gradientStopCollection.Add(new GradientStop(defaultColor, 1));
break;
}
ResourceAndCustomerBackground = new LinearGradientBrush(gradientStopCollection, new Point(.5, 0), new Point(.5, 1));
}
private static void AddResourceColors(GradientStopCollection gradientStopCollection, List<Color> resourceColors, bool hasCustomers)
{
var previousOffset = hasCustomers ? .5 : 0;
var numberOfResources = resourceColors.Count;
if(numberOfResources == 0)
{
return;
}
if(numberOfResources > 4)
{
numberOfResources = 4;
}
var iterator = hasCustomers ? previousOffset / numberOfResources : 1d / numberOfResources;
for(var i = 0; i < numberOfResources; i++)
{
var currentOffset = previousOffset;
var nextOffset = currentOffset + iterator;
if(nextOffset > 1)
{
nextOffset = 1;
}
previousOffset = nextOffset;
gradientStopCollection.Add(new GradientStop(resourceColors[i], currentOffset));
gradientStopCollection.Add(new GradientStop(resourceColors[i], nextOffset));
}
}
}
}

View File

@@ -0,0 +1,15 @@
using System.Windows;
using BS.Shared.DataContracts;
namespace BeWo.Scheduling.SchedulingUtils
{
public class CategoryDependencyObject : DependencyObject
{
public ValueListEntryDC ResourceCategory { get; }
public CategoryDependencyObject(ValueListEntryDC category)
{
ResourceCategory = category;
}
}
}

View File

@@ -0,0 +1,15 @@
using System.Windows;
using BS.Shared.DataContracts.Compact;
namespace BeWo.Scheduling.SchedulingUtils
{
public class EmployeeDependencyObject : DependencyObject
{
public CompactEmployeeDC Employee { get; }
public EmployeeDependencyObject(CompactEmployeeDC employee)
{
Employee = employee;
}
}
}

View File

@@ -0,0 +1,19 @@
using System.Windows;
namespace BeWo.Scheduling.SchedulingUtils
{
public class ListItemHelper : DependencyObject
{
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.RegisterAttached("IsChecked", typeof(bool?), typeof(ListItemHelper), new PropertyMetadata(false, null));
public static void SetIsChecked(DependencyObject element, bool? isChecked)
{
element.SetValue(IsCheckedProperty, isChecked);
}
public static bool? GetIsChecked(DependencyObject element)
{
return (bool?) element.GetValue(IsCheckedProperty);
}
}
}

View File

@@ -0,0 +1,15 @@
using System.Windows;
using BS.Shared.DataContracts;
namespace BeWo.Scheduling.SchedulingUtils
{
public class ResourceDependencyObject : DependencyObject
{
public ResourceDC DataContract { get; }
public ResourceDependencyObject(ResourceDC resource)
{
DataContract = resource;
}
}
}

View File

@@ -0,0 +1,31 @@
using System.Windows;
namespace BeWo.Scheduling.SchedulingUtils
{
public class TreeViewItemHelper : DependencyObject
{
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.RegisterAttached("IsChecked", typeof(bool?), typeof(TreeViewItemHelper), new PropertyMetadata(false, null));
public static void SetIsChecked(DependencyObject element, bool? isChecked)
{
element.SetValue(IsCheckedProperty, isChecked);
}
public static bool? GetIsChecked(DependencyObject element)
{
return (bool?) element.GetValue(IsCheckedProperty);
}
public static readonly DependencyProperty ParentProperty = DependencyProperty.RegisterAttached("Parent", typeof(object), typeof(TreeViewItemHelper));
public static void SetParent(DependencyObject element, object Parent)
{
element.SetValue(ParentProperty, Parent);
}
public static object GetParent(DependencyObject element)
{
return element.GetValue(ParentProperty);
}
}
}

View File

@@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using BeWo.Scheduling.ViewModel;
using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Compact;
using BS.Shared.Extensions;
using DevExpress.Xpf.Scheduling;
using DevExpress.XtraScheduler;
namespace BeWo.Scheduling.SchedulingUtils
{
public static class Utils
{
private static readonly Regex HexColorRegex = new Regex("^#([a-fA-F0-9]{8}|[a-fA-F0-9]{6}|[a-fA-F0-9]{3})$");
public static bool Categories2ResourcesEquals(ObservableDictionary<CategoryDependencyObject, List<ResourceDependencyObject>> dictionary1, ObservableDictionary<CategoryDependencyObject, List<ResourceDependencyObject>> dictionary2)
{
if(dictionary1 is null && dictionary2 != null || dictionary2 is null && dictionary1 != null)
{
return false;
}
return dictionary1 is null && dictionary2 is null || dictionary1 != null && dictionary2 != null && dictionary1.Count == dictionary2.Count && dictionary1.Except(dictionary2).Any();
}
public static List<SchedulingAppointmentVM> ConvertAbsenceTimesToAppointments(List<AbsenceTimeDC> absenceTimes, DateTime end, List<CompactEmployeeDC> allEmployees)
{
var result = new List<SchedulingAppointmentVM>();
foreach(var absenceTime in absenceTimes)
{
if(absenceTime.AbsenceTimeOid == null || absenceTime.Start == null)
{
continue;
}
var subject = absenceTime.Reason.Description;
var employee = absenceTime.EmployeeOid != null ? allEmployees.FirstOrDefault(f => f.EmployeeOid == absenceTime.EmployeeOid.Value) : null;
if(employee != null)
{
subject += $" ({employee.SimpleDescription})";
}
var absenceTimeEnd = absenceTime.End?.AddTicks(1);
result.AddIfNotIn(new SchedulingAppointmentVM(true, subject, absenceTime.Start.Value, absenceTime.End ?? end, employee, absenceTime.Start, absenceTimeEnd));
}
return result;
}
public static string GetDeleteMessageForAppointment(AppointmentItem appointment)
{
if(appointment is null)
{
return "Möchten Sie den gewählten Termin wirklich löschen?";
}
var subject = appointment.Subject;
var interval = GetAppointmentTimeString(appointment);
return $"Möchten Sie den gewählten Termin \"{subject}\" vom {interval} wirklich löschen?";
}
public static string GetAppointmentTimeString(AppointmentItem appointment)
{
if(appointment is null)
{
return string.Empty;
}
var start = appointment.Start;
var end = appointment.End;
// 1. 17. August 2021 09:00 Uhr bis 10:00 Uhr
// 2. 17. August 2021
// 3. 17. August 2021 09:00 Uhr bis 19. August 2021 10 Uhr
// 4. 17. August 2021 bis 19. August 2021
return start.Date == end.Date ?
appointment.AllDay ? $"{start:dd. MMMM yyyy}" : $"{start:dd. MMMM yyyy HH:mm} Uhr bis {end:HH:mm} Uhr" :
appointment.AllDay ? $"{start:dd. MMMM yyyy} bis zum {end:dd. MMMM yyyy}" : $"{start: dd. MMMM yyyy HH:mm} Uhr bis zum {end:dd. MMMM yyyy HH:mm} Uhr";
}
public static string GetDeactivationMessageForAppointments(IReadOnlyList<AppointmentItem> appointments2Deactivate)
{
var message = string.Empty;
if(appointments2Deactivate.Count > 1)
{
message = "Möchten Sie folgende Termine wirklich löschen?\n\n";
foreach(var appointment2Deactivate in appointments2Deactivate.OrderBy(o => o.Start))
{
var interval = GetAppointmentTimeString(appointment2Deactivate);
var subject = appointment2Deactivate.Subject;
message += $"{interval} \"{subject}\"\n";
}
}
else
{
var first = appointments2Deactivate.FirstOrDefault();
if(first is null)
{
return message;
}
var interval = GetAppointmentTimeString(first);
var subject = first.Subject;
message = $"Möchten Sie den gewählten Termin \"{subject}\" vom {interval} wirklich löschen?";
}
return message;
}
public static AppointmentType GetAppointmentTypeFromViewModel(int eventType)
{
switch(eventType)
{
case 0:
return AppointmentType.Normal;
case 1:
return AppointmentType.Pattern;
case 2:
return AppointmentType.Occurrence;
case 3:
return AppointmentType.ChangedOccurrence;
case 4:
return AppointmentType.DeletedOccurrence;
default:
return AppointmentType.Normal;
}
}
public static bool IsValidColorHexString(string hexString)
{
return !(hexString is null) && HexColorRegex.IsMatch(hexString);
}
public static StatusUpdatesAndAppointments SeperateStatusUpdatesAndAppointments(List<SchedulerAppointmentDC> statusUpdatesAndAppointments)
{
var result = new StatusUpdatesAndAppointments();
foreach(var appointment in statusUpdatesAndAppointments)
{
if(!(appointment.Originator?.Equals(BeWoApp.CompactLoggedOnEmployee) ?? false) && (appointment.EmployeeList?.Any(e2a => e2a.Employee.Equals(BeWoApp.CompactLoggedOnEmployee) && e2a.ParticipationAnswer == ParticipationAnswer.Offen) ?? false))
{
result.Appointments.AddIfNotIn(new SchedulingAppointmentVM(appointment));
}
else if((appointment.Originator?.Equals(BeWoApp.CompactLoggedOnEmployee) ?? false) && (appointment.EmployeeList?.Any(e2a => e2a.IsPChanged && e2a.ParticipationAnswer != ParticipationAnswer.Offen && e2a.ParticipationAnswer != ParticipationAnswer.Verstrichen && !e2a.Employee.Equals(BeWoApp.CompactLoggedOnEmployee)) ?? false))
{
var vm = new SchedulingAppointmentVM(appointment);
foreach(var employee2Appointment in appointment.EmployeeList.Where(e2a => e2a.IsPChanged && e2a.ParticipationAnswer != ParticipationAnswer.Offen && e2a.ParticipationAnswer != ParticipationAnswer.Verstrichen && !e2a.Employee.Equals(BeWoApp.CompactLoggedOnEmployee)))
{
if(result.StatusUpdates.All(a => a.LabelKey != employee2Appointment.Employee2SchedulerAppointmentOid))
{
if(employee2Appointment.Employee2SchedulerAppointmentOid.HasValue)
{
vm.LabelKey = employee2Appointment.Employee2SchedulerAppointmentOid;
}
}
}
result.StatusUpdates.AddIfNotIn(vm);
}
}
return result;
}
}
public class StatusUpdatesAndAppointments
{
public List<SchedulingAppointmentVM> StatusUpdates { get; }
public List<SchedulingAppointmentVM> Appointments { get; }
public StatusUpdatesAndAppointments()
{
StatusUpdates = new List<SchedulingAppointmentVM>();
Appointments = new List<SchedulingAppointmentVM>();
}
}
}

View File

@@ -0,0 +1,534 @@
<dx:DXWindow x:Class="BeWo.Scheduling.View.AppointmentEditView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
xmlns:converter="clr-namespace:BeWo.Converter"
xmlns:local="clr-namespace:BeWo.Scheduling.View"
xmlns:schedulingConverter="clr-namespace:BeWo.Scheduling.Converter"
xmlns:search="clr-namespace:BeWo.View.Search"
mc:Ignorable="d"
Loaded="Window_Loaded"
ResizeMode="NoResize"
Margin="0" Padding="0"
Height="Auto" Width="550" SizeToContent="Height"
dx:ThemeManager.ThemeName="Office2010Black">
<Window.Resources>
<converter:BoolReverseConverter x:Key="BoolReverseConverter" />
<converter:BoolVisibilityConverter x:Key="BoolVisibilityConverter" />
<converter:StringBrushConverter x:Key="StringBrushConverter" />
<schedulingConverter:SchedulingBackgroundConverter x:Key="SchedulingBackgroundConverter" />
<schedulingConverter:SchedulingParticipationBrushConverter x:Key="SchedulingParticipationBrushConverter" />
<schedulingConverter:SchedulingTextFromIDataContractConverter x:Key="SchedulingTextFromIDataContractConverter" />
<schedulingConverter:SchedulingInformationVisibilityConverter x:Key="SchedulingInformationVisibilityConverter" />
<schedulingConverter:SchedulingRemoveElementVisibilityConverter x:Key="SchedulingRemoveElementVisibilityConverter" />
<Style x:Key="MultiSupportConceptSelectionControlStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="Margin" Value="2,2,2,0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border x:Name="ItemBorder" CornerRadius="5" MinHeight="25" Background="#FF000000">
<Border.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#19000000" Offset="0" />
<GradientStop Color="#26000000" Offset="1" />
</LinearGradientBrush>
</Border.OpacityMask>
</Border>
<Border x:Name="ItemContent" CornerRadius="5" MinHeight="25" Background="{StaticResource SupportConceptContentBrush}">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,3,5,3" OpacityMask="{x:Null}" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Name="txtDetail1" Grid.Column="0" Grid.Row="0" Text="{Binding Path=CustomerName}" FontSize="12" Foreground="#FFD2D2D2" FontFamily="Microsoft Sans Serif" />
<TextBlock x:Name="txtDetail2" Grid.Column="0" Grid.Row="1" ToolTip="{Binding Path=FirstCostBearerDetailString}" Text="{Binding Path=FirstCostBearerDetailString}" FontSize="10" Foreground="{Binding ForegroundBrush}" FontFamily="Microsoft Sans Serif" />
<Button x:Name="btnRemoveSupportConcept" Grid.Column="1" Grid.Row="0" Grid.RowSpan="2" Width="20" Height="20" ToolTip="Hilfeplan aus der Liste entfernen" Tag="{Binding}" Style="{DynamicResource CloseButtonStyle}" Click="RemoveSupportConceptButton_OnClick" Margin="3,0,0,0" />
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Path=IsArchived}" Value="True">
<Setter Property="Foreground" TargetName="txtDetail1" Value="#FF808080" />
<Setter Property="Foreground" TargetName="txtDetail2" Value="#FF808080" />
</DataTrigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#33000000" Offset="0" />
<GradientStop Color="#66000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ListBoxItem.IsSelected" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99000000" Offset="0" />
<GradientStop Color="#CC000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ListBoxItem.IsSelected" Value="True" />
<Condition Property="Selector.IsSelectionActive" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99000000" Offset="0" />
<GradientStop Color="#B2000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MultiElementSelectionControlStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="Margin" Value="3,1,3,1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border CornerRadius="5" MinHeight="20" Background="{Binding Converter={StaticResource SchedulingBackgroundConverter}}"></Border>
<Border x:Name="ItemBorder" CornerRadius="5" MinHeight="20" Background="#FF000000">
<Border.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#19000000" Offset="0" />
<GradientStop Color="#26000000" Offset="1" />
</LinearGradientBrush>
</Border.OpacityMask>
</Border>
<Border x:Name="ItemContent" CornerRadius="5" MinHeight="20">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,3,5,3" OpacityMask="{x:Null}" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" CornerRadius="2" Width="5" Height="15" Background="{Binding Converter={StaticResource SchedulingParticipationBrushConverter}}" BorderThickness="1" BorderBrush="{Binding Converter={StaticResource SchedulingParticipationBrushConverter}, ConverterParameter=Border}" />
<TextBlock VerticalAlignment="Center" Grid.Column="1" Text="{Binding Converter={StaticResource SchedulingTextFromIDataContractConverter}}" Margin="3,0,0,0" FontSize="12" Foreground="#FFD2D2D2" FontFamily="Microsoft Sans Serif" />
<Button x:Name="btnInformation" Grid.Column="2" Grid.RowSpan="2" Width="15" Height="15" ToolTip="Informationen zur Auslastung anzeigen" Tag="{Binding}" Visibility="{Binding Converter={StaticResource SchedulingInformationVisibilityConverter}}" Content="i" Click="InformationButton_OnClick" Margin="3,0,0,0" />
<Button x:Name="btnRemoveElement" Grid.Column="3" Grid.RowSpan="2" Width="15" Height="15" ToolTip="Element aus der Liste entfernen" Tag="{Binding}" Visibility="{Binding Converter={StaticResource SchedulingRemoveElementVisibilityConverter}}" Style="{DynamicResource CloseButtonStyleSmall}" Click="RemoveElementButton_OnClick" Margin="3,0,0,0" />
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#33000000" Offset="0" />
<GradientStop Color="#66000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ListBoxItem.IsSelected" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99000000" Offset="0" />
<GradientStop Color="#CC000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ListBoxItem.IsSelected" Value="True" />
<Condition Property="Selector.IsSelectionActive" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99000000" Offset="0" />
<GradientStop Color="#B2000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MultiResourceSelectionControlStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="Margin" Value="3,1,3,1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border CornerRadius="5" MinHeight="20" Background="{Binding Converter={StaticResource SchedulingBackgroundConverter}}"></Border>
<Border x:Name="ItemBorder" CornerRadius="5" MinHeight="20" Background="#FF000000">
<Border.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#19000000" Offset="0" />
<GradientStop Color="#26000000" Offset="1" />
</LinearGradientBrush>
</Border.OpacityMask>
</Border>
<Border x:Name="ItemContent" CornerRadius="5" MinHeight="20">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,3,5,3" OpacityMask="{x:Null}" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" CornerRadius="2" Width="5" Height="15" Background="{Binding Converter={StaticResource SchedulingParticipationBrushConverter}}" BorderThickness="1" BorderBrush="{Binding Converter={StaticResource SchedulingParticipationBrushConverter}, ConverterParameter=Border}" />
<Rectangle Grid.Column="1" Width="10" Height="10" Fill="{Binding Path=Color, Converter={StaticResource StringBrushConverter}}" Stroke="Black" StrokeThickness="1" VerticalAlignment="Center" />
<TextBlock VerticalAlignment="Center" Grid.Column="2" Text="{Binding Converter={StaticResource SchedulingTextFromIDataContractConverter}}" Margin="3,0,0,0" FontSize="12" Foreground="#FFD2D2D2" FontFamily="Microsoft Sans Serif" />
<Button x:Name="btnRemoveElement" Grid.Column="3" Grid.RowSpan="2" Width="15" Height="15" ToolTip="Element aus der Liste entfernen" Tag="{Binding}" Visibility="{Binding Converter={StaticResource SchedulingRemoveElementVisibilityConverter}}" Style="{DynamicResource CloseButtonStyleSmall}" Click="RemoveElementButton_OnClick" Margin="3,0,0,0" />
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#33000000" Offset="0" />
<GradientStop Color="#66000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ListBoxItem.IsSelected" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99000000" Offset="0" />
<GradientStop Color="#CC000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ListBoxItem.IsSelected" Value="True" />
<Condition Property="Selector.IsSelectionActive" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99000000" Offset="0" />
<GradientStop Color="#B2000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<!-- 0 -->
<RowDefinition Height="Auto" />
<!-- 1 -->
<RowDefinition Height="Auto" />
<!-- 2 -->
<RowDefinition Height="Auto" />
<!-- 3 -->
<RowDefinition Height="Auto" />
<!-- 4 -->
<RowDefinition Height="Auto" />
<!-- 5 -->
<RowDefinition Height="Auto" />
<!-- 6 -->
<RowDefinition Height="Auto" />
<!-- 7 -->
<RowDefinition Height="Auto" />
<!-- 8 -->
<RowDefinition Height="Auto" />
<!-- 9 -->
<RowDefinition Height="Auto" />
<!-- 10 -->
<RowDefinition Height="Auto" />
<!-- 11 -->
<RowDefinition Height="Auto" />
<!-- 12 -->
<RowDefinition Height="Auto" />
<!-- 13 -->
<RowDefinition Height="Auto" />
<!-- 14 -->
<RowDefinition Height="Auto" />
<!-- 15 -->
<RowDefinition Height="Auto" />
<!-- 16 -->
<RowDefinition Height="Auto" />
<!-- 17 -->
<RowDefinition Height="Auto" />
<!-- 18 -->
<RowDefinition Height="Auto" />
<!-- 19 -->
</Grid.RowDefinitions>
<!-- #region Betreff -->
<Label Content="Betreff" Grid.Column="0" Grid.Row="0" Margin="3" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}" />
<dxe:TextEdit Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="4" Margin="3" Height="23" EditValue="{Binding ActualViewModel.Subject}" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}" />
<!-- #endregion Betreff -->
<!-- #region Ort -->
<Label Content="Ort" Grid.Column="0" Grid.Row="1" Margin="3" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}" />
<dxe:TextEdit Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="4" Margin="3" Height="23" EditValue="{Binding ActualViewModel.Location}" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}" />
<!-- #endregion Ort -->
<!-- #region Start -->
<Label Content="Start" Grid.Column="0" Grid.Row="2" Margin="3" />
<dxe:DateEdit Grid.Column="1" Grid.Row="2" MinWidth="80" Margin="3" Height="23" MaskType="DateTimeAdvancingCaret" EditValue="{Binding ActualViewModel.Start}" Visibility="{Binding
ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}" />
<dxe:TextEdit Grid.Column="2" Grid.Row="2" Margin="3" IsEnabled="{Binding ActualViewModel.AllDay, Converter={StaticResource BoolReverseConverter}}" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}"
MaskType="DateTime" Mask="t" MaskUseAsDisplayFormat="True" EditValue="{Binding ActualViewModel.Start}" Height="23" />
<dxe:CheckEdit Grid.Column="3" Grid.ColumnSpan="2" Grid.Row="2" Content="Ganztägig" Margin="3" Height="23" EditValue="{Binding Appointment.AllDay}" HorizontalAlignment="Right" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}" />
<!-- #endregion Start -->
<!-- #region Ende -->
<Label Content="Ende" Grid.Column="0" Grid.Row="3" Margin="3" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}" />
<dxe:DateEdit Grid.Column="1" Grid.Row="3" MinWidth="80" Margin="3" Height="23" MaskType="DateTimeAdvancingCaret" EditValue="{Binding ActualViewModel.End}" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}" />
<dxe:TextEdit Grid.Column="2" Grid.Row="3" Margin="3" IsEnabled="{Binding ActualViewModel.AllDay, Converter={StaticResource BoolReverseConverter}}" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}"
MaskType="DateTime" Mask="t" MaskUseAsDisplayFormat="True" EditValue="{Binding ActualViewModel.End}" Height="23" />
<!-- #endregion Ende -->
<!-- #region Zu erledigen bis (Aufgabe) -->
<Label Content="Zu erledigen bis" Grid.Column="0" Grid.Row="4" Margin="3" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}}" />
<dxe:DateEdit Grid.Column="1" Grid.Row="4" MinWidth="80" Margin="3" Height="23" MaskType="DateTimeAdvancingCaret" EditValue="{Binding ActualViewModel.DueDate}" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}}" />
<dxe:TextEdit Grid.Column="2" Grid.Row="4" Margin="3" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}}"
MaskType="DateTime" Mask="t" MaskUseAsDisplayFormat="True" EditValue="{Binding ActualViewModel.DueDate}" Height="23" />
<!-- #endregion Zu erldedigen bis (Aufgabe) -->
<!-- #region Mitarbeiter -->
<Label Content="Mitarbeiter" Grid.Column="0" Grid.Row="5" Margin="3" Visibility="{Binding EmployeeSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
<Grid Grid.Column="1" Grid.Row="5" Height="23" Margin="3" Grid.ColumnSpan="3" Visibility="{Binding EmployeeSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border Background="White" BorderThickness="1" BorderBrush="Gray" Grid.Column="0" Grid.ColumnSpan="2" Margin="0" Visibility="{Binding EmployeeSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<TextBlock VerticalAlignment="Center" Margin="4,0,4,0" Foreground="Black">
<Run Text="{Binding SelectedEmployees.Count, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:AppointmentEditView}}}" />
<Run Text=" Mitarbeiter ausgewählt" />
</TextBlock>
</Border>
<ToggleButton x:Name="EmployeeToggleButton" Grid.Column="1" IsThreeState="False" Margin="0,0,2,0" Height="19" Width="19" ToolTip="Ausgewählte Mitarbeiter anzeigen" Style="{StaticResource ExpanderLookAlikeToggleBotton}" Visibility="{Binding EmployeeSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
</Grid>
<Popup Grid.Column="1" Grid.Row="5" Margin="10" Name="PopupEmployee" StaysOpen="False" Placement="MousePoint" Width="450" Height="0" >
<search:MultiEmployeeSearch x:Name="MultiEmployeeSearch" SelectionChanged="MultiEmployeeSearch_OnSelectionChanged" ResultListBackground="{StaticResource EmployeeListBrush}" SelectedEmployees="{Binding ActualViewModel.EmployeeList, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</Popup>
<Button x:Name="MitarbeiterPopUpOeffnenBtn" Grid.Column="4" Grid.Row="5" Width="20" Height="20" Margin="3" VerticalAlignment="Center" Click="EmployeePopupClick"
Visibility="{Binding EmployeeSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<Grid Width="18" HorizontalAlignment="Center" VerticalAlignment="Center">
<Line X1="4" X2="12" Y1="8" Y2="8" Fill="{x:Null}" Stroke="#FFFFFFFF" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="16" Height="16" />
<Line X1="8" X2="8" Y1="4" Y2="12" Fill="{x:Null}" Stroke="#FFFFFFFF" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="16" Height="16" />
</Grid>
</Button>
<ListBox Grid.Column="1" Grid.Row="6" Background="{StaticResource ObjectEditBackgroundBrush}" Margin="4,0,1,4" ItemsSource="{Binding Path=SelectedEmployees, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:AppointmentEditView}}}"
IsSynchronizedWithCurrentItem="True" BorderBrush="Gray" BorderThickness="1,0,1,1"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.ColumnSpan="3" x:Name="SelectedMitarbeiter"
ItemContainerStyle="{DynamicResource MultiElementSelectionControlStyle}" MaxHeight="70" Height="70"
Visibility="{Binding IsChecked, ElementName=EmployeeToggleButton, Converter={StaticResource BoolVisibilityConverter}}">
<ListBox.Template>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" SnapsToDevicePixels="True" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
<ScrollViewer Focusable="False" Padding="{TemplateBinding Padding}" HorizontalScrollBarVisibility="Disabled">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</ListBox.Template>
</ListBox>
<!-- #endregion Mitarbeiter -->
<!-- #region Klienten -->
<Label Content="Klienten" Grid.Column="0" Grid.Row="7" Margin="3" Visibility="{Binding CustomerSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
<Grid x:Name="CustomersGrid" Grid.Column="1" Grid.Row="7" Height="23" Margin="3" Grid.ColumnSpan="3"
Visibility="{Binding CustomerSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border Background="White" BorderThickness="1" BorderBrush="Gray" Grid.Column="0" Grid.ColumnSpan="2" Margin="0" Visibility="{Binding CustomerSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<TextBlock VerticalAlignment="Center" Margin="4,0,4,0" Foreground="Black">
<Run Text="{Binding SelectedCustomers.Count, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:AppointmentEditView}}}" />
<Run Text=" Klienten ausgewählt" />
</TextBlock>
</Border>
<ToggleButton Grid.Column="1" x:Name="KlientenToggleButton" IsThreeState="False" Margin="0,0,2,0" Height="19" Width="19" ToolTip="Ausgewählte Klienten anzeigen" Style="{StaticResource ExpanderLookAlikeToggleBotton}" Visibility="{Binding CustomerSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
</Grid>
<Button x:Name="KlientenPopUpOeffnenBtn" Grid.Column="4" Grid.Row="7" Width="20" Height="20" Margin="3" VerticalAlignment="Center" Click="CustomerPopUpEditClick"
Visibility="{Binding CustomerSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<Grid Width="18" HorizontalAlignment="Center" VerticalAlignment="Center">
<Line X1="4" X2="12" Y1="8" Y2="8" Fill="{x:Null}" Stroke="#FFFFFFFF" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="16" Height="16" />
<Line X1="8" X2="8" Y1="4" Y2="12" Fill="{x:Null}" Stroke="#FFFFFFFF" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="16" Height="16" />
</Grid>
</Button>
<Popup Grid.Column="1" Grid.Row="7" Margin="10" Name="PopupCustomer" StaysOpen="False" Placement="MousePoint" Width="450" Height="0" >
<search:MultiCustomerSearchView x:Name="MultiCustomerSearch" ResultListBackground="{StaticResource CustomerListBrush}" SelectionChanged="MultiCustomerSearch_OnSelectionChanged" SelectedCustomers="{Binding Appointment.CustomFields[VMForCustomFields].CustomerList, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
</Popup>
<ListBox Grid.Column="1" Grid.Row="8" Background="{StaticResource ObjectEditBackgroundBrush}" Margin="4,0,1,4" ItemsSource="{Binding Path=SelectedCustomers, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:AppointmentEditView}}}" IsSynchronizedWithCurrentItem="True"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.ColumnSpan="3"
ItemContainerStyle="{DynamicResource MultiElementSelectionControlStyle}" MaxHeight="70" Height="70" x:Name="SelectedCustomersListBox"
Visibility="{Binding IsChecked, ElementName=KlientenToggleButton, Converter={StaticResource BoolVisibilityConverter}}">
<ListBox.Template>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" SnapsToDevicePixels="True" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
<ScrollViewer Focusable="False" Padding="{TemplateBinding Padding}" HorizontalScrollBarVisibility="Disabled">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</ListBox.Template>
</ListBox>
<!-- #endregion -->
<!-- #region Ressourcen -->
<Label Content="Ressourcen" Grid.Column="0" Grid.Row="9" Margin="3" Visibility="{Binding ResourceSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
<Grid Grid.Column="1" Grid.Row="9" Height="23" Margin="3" Grid.ColumnSpan="3" x:Name="ResourceToggleButtonGrid"
Visibility="{Binding ResourceSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border Background="White" BorderThickness="1" BorderBrush="Gray" Grid.Column="0" Grid.ColumnSpan="2" Margin="0" Visibility="{Binding ResourceSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<TextBlock VerticalAlignment="Center" Margin="4,0,4,0" Foreground="Black">
<Run Text="{Binding SelectedResources.Count, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:AppointmentEditView}}}" />
<Run Text=" Ressourcen ausgewählt" />
</TextBlock>
</Border>
<ToggleButton Grid.Column="1" x:Name="RessourcenToggleButton" IsThreeState="False" Margin="0,0,2,0" Height="19" Width="19" ToolTip="Ausgewählte Ressourcen anzeigen" Style="{StaticResource ExpanderLookAlikeToggleBotton}"/>
</Grid>
<Button x:Name="RessourcenPopUpOeffnenBtn" Grid.Column="4" Grid.Row="9" Width="20" Height="20" Margin="3" VerticalAlignment="Center" Click="ResourcePopUpClick"
Visibility="{Binding ResourceSelectionVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}">
<Grid Width="18" HorizontalAlignment="Center" VerticalAlignment="Center">
<Line X1="4" X2="12" Y1="8" Y2="8" Fill="{x:Null}" Stroke="#FFFFFFFF" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="16" Height="16" />
<Line X1="8" X2="8" Y1="4" Y2="12" Fill="{x:Null}" Stroke="#FFFFFFFF" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="16" Height="16" />
</Grid>
</Button>
<Popup Grid.Column="1" Grid.Row="9" Margin="10" Name="PopupResource" StaysOpen="False" Placement="MousePoint" Width="450" Height="0">
<search:ResourcesTreeSearchView x:Name="ResourcesTreeSearchView" ResultListBackground="{StaticResource ResourceContentBrush}" SelectionChanged="ResourcesTreeSearchView_OnSelectionChanged" SelectedResources="{Binding Appointment.CustomFields[VMForCustomFields].ResourceList}" />
</Popup>
<ListBox x:Name="ResourceListBox" Grid.Column="1" Grid.Row="10" Background="{StaticResource ObjectEditBackgroundBrush}" Margin="4,0,1,4" ItemsSource="{Binding Path=SelectedResources, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:AppointmentEditView}}}" IsSynchronizedWithCurrentItem="True"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.ColumnSpan="3"
ItemContainerStyle="{StaticResource MultiResourceSelectionControlStyle}" MaxHeight="70" Height="70"
Visibility="{Binding IsChecked, ElementName=RessourcenToggleButton, Converter={StaticResource BoolVisibilityConverter}}">
<ListBox.Template>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" SnapsToDevicePixels="True" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
<ScrollViewer Focusable="False" Padding="{TemplateBinding Padding}" HorizontalScrollBarVisibility="Disabled">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</ListBox.Template>
</ListBox>
<!-- #endregion Ressourcen -->
<!-- #region Hilfeplan (Aufgabe) -->
<Label Content="Hilfeplan" Grid.Column="0" Grid.Row="11" Margin="3" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}}" />
<Button x:Name="SupportConceptsPopUpOeffnenBtn" Grid.Column="4" Grid.Row="11" Width="20" Height="20" Margin="3" VerticalAlignment="Center" Click="SupportConceptsPopUpClick" Visibility="Collapsed">
<Grid Width="18" HorizontalAlignment="Center" VerticalAlignment="Center">
<Line X1="4" X2="12" Y1="8" Y2="8" Fill="{x:Null}" Stroke="#FFFFFFFF" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="16" Height="16" />
<Line X1="8" X2="8" Y1="4" Y2="12" Fill="{x:Null}" Stroke="#FFFFFFFF" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeThickness="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="16" Height="16" />
</Grid>
</Button>
<Popup Grid.Column="1" Grid.Row="11" Margin="10" Name="PopupSupportConcepts" StaysOpen="False" Placement="MousePoint" Width="450" Height="0">
<search:SupportConceptSearchView x:Name="SupportConceptsTreeSearchView" ItemSelected="SupportConceptSelectionControl_ItemSelected" ShowFilterPanel="True" />
</Popup>
<ListBox Grid.Column="1" Grid.Row="11" Background="White" Margin="4,0,1,4" ItemsSource="{Binding Path=SelectedSupportConcepts, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:AppointmentEditView}}}" IsSynchronizedWithCurrentItem="True"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch" Grid.ColumnSpan="3" Name="SelectedSupportConceptsListBox"
ItemContainerStyle="{StaticResource MultiSupportConceptSelectionControlStyle}" MaxHeight="35" Height="35" Visibility="Collapsed">
<ListBox.Template>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" SnapsToDevicePixels="True" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
<ScrollViewer Focusable="False" Padding="{TemplateBinding Padding}" HorizontalScrollBarVisibility="Disabled">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</ListBox.Template>
</ListBox>
<!-- #endregion -->
<!-- #region Beschreibung (Aufgabe) -->
<Label Content="Beschreibung" Grid.Column="0" Grid.Row="13" Margin="3" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}}" />
<TextBox Grid.Column="1" Grid.Row="13" Grid.ColumnSpan="4" AcceptsReturn="True" VerticalScrollBarVisibility="Auto"
Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}}"
HorizontalScrollBarVisibility="Disabled" Height="45" Margin="3" TextWrapping="Wrap" x:Name="TaskDescription"
Text="{Binding Path=ActualViewModel.TaskDescription, UpdateSourceTrigger=PropertyChanged}" MaxLength="1024" />
<!-- #endregion -->
<!-- #region Erledigt am (Aufgabe) -->
<Label Content="Erledigt am" Grid.Column="0" Grid.Row="14" Margin="3" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}}" />
<dxe:DateEdit Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}}"
x:Name="CompletedDate" Grid.Column="1" Grid.ColumnSpan="4" Grid.Row="14"
MaskType="DateTimeAdvancingCaret" Background="White" Height="23" MinWidth="80" Margin="3" EditValue="{Binding ActualViewModel.CompletedDate, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
<!-- #endregion -->
<!-- #region Notiz -->
<Label Margin="3" Content="Notiz" Grid.Column="0" Grid.Row="15" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}" />
<TextBox Grid.Column="1" Grid.Row="15" Grid.ColumnSpan="4" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}"
HorizontalScrollBarVisibility="Disabled" Height="45" Margin="3" TextWrapping="Wrap"
Text="{Binding Path=ActualViewModel.Description, UpdateSourceTrigger=PropertyChanged}" MaxLength="1024" />
<!-- #endregion -->
<!-- #region Wiederholung nur wenn es keine Occurrence ist -->
<Label Grid.Column="0" Grid.Row="16" Content="Wiederholung" Visibility="{Binding RecurrenceButtonVisibility, Mode=OneWay}" />
<dxe:ComboBoxEdit Grid.Column="1" Grid.Row="16" Margin="3" Grid.ColumnSpan="3"
x:Name="RecurrenceTypeComboBoxEdit"
Visibility="{Binding RecurrenceButtonVisibility, Mode=OneWay}"
ItemsSource="{Binding AvailableAppointmentRecurrenceTypes, UpdateSourceTrigger=PropertyChanged}"
EditValueChanged="RecurrenceTypeComboBoxEdit_OnChanged">
</dxe:ComboBoxEdit>
<Button Grid.Column="4" Grid.Row="16" Content="Bearbeiten"
IsEnabled="{Binding Appointment.RecurrenceInfo, Converter={StaticResource BoolNullCheckConverter}}"
Visibility="{Binding RecurrenceButtonVisibility, Mode=OneWay}"
Click="EditRecurrenceButton_OnClick"
/>
<!-- #endregion -->
<CheckBox Grid.Column="0" Grid.Row="18" Margin="3" Content="Privater Termin" IsChecked="{Binding Path=ActualViewModel.IsPrivate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding ActualViewModel.IsTask, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}" />
<Grid Grid.Column="0" Grid.Row="19" Grid.ColumnSpan="5" VerticalAlignment="Bottom">
<StackPanel VerticalAlignment="Bottom" Height="40" Orientation="Horizontal" HorizontalAlignment="Right" Margin="5,0,5,0">
<Button Content="OK" Width="80" Height="25" Margin="3" Click="OkButton_Click" Visibility="{Binding Path=OkButtonVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
<Button Content="Abbrechen" Width="80" Height="25" Margin="3" Click="CloseButton_OnClick" />
<Button Content="Löschen" Width="80" Height="25" Margin="3" Click="DeleteButton_OnClick" Visibility="{Binding Path=DeleteButtonVisibility, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</StackPanel>
</Grid>
</Grid>
</dx:DXWindow>

View File

@@ -0,0 +1,580 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Threading;
using BeWo.Annotations;
using BeWo.Core;
using BeWo.Scheduling.SchedulingUtils;
using BeWo.Scheduling.ViewModel;
using BeWo.ServiceProxy;
using BeWo.View;
using BeWo.View.Detail;
using BeWo.View.Search;
using BS.Shared;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Compact;
using BS.Shared.Extensions;
using DevExpress.Xpf.Editors;
using DevExpress.XtraScheduler;
namespace BeWo.Scheduling.View
{
public partial class AppointmentEditView : INotifyPropertyChanged
{
private AppointmentWindowVM ViewModel => DataContext as AppointmentWindowVM;
private ObservableCollection<Employee2SchedulerAppointmentDC> _SelectedEmployees;
public ObservableCollection<Employee2SchedulerAppointmentDC> SelectedEmployees
{
get => _SelectedEmployees ?? (_SelectedEmployees = ViewModel.EmployeeList ?? new ObservableCollection<Employee2SchedulerAppointmentDC>());
set
{
if(!ICollectionExtensions.ListEquals(_SelectedEmployees, value))
{
_SelectedEmployees = value;
SelectedEmployees.CollectionChanged += SelectedEmployeesCollectionChanged;
ViewModel.EmployeeList = SelectedEmployees;
OnPropertyChanged();
}
}
}
private ObservableCollection<CompactCustomerDC> _SelectedCustomers;
public ObservableCollection<CompactCustomerDC> SelectedCustomers
{
get => _SelectedCustomers ?? (_SelectedCustomers = new ObservableCollection<CompactCustomerDC>(ViewModel?.CustomerList ?? new List<CompactCustomerDC>()));
set
{
if(!ICollectionExtensions.ListEquals(_SelectedCustomers, value))
{
_SelectedCustomers = value;
SelectedCustomers.CollectionChanged += SelectedCustomersCollectionChanged;
ViewModel.CustomerList = SelectedCustomers.ToList();
OnPropertyChanged();
}
}
}
private ObservableCollection<CompactSupportConceptDC> _SelectedSupportConcepts;
public ObservableCollection<CompactSupportConceptDC> SelectedSupportConcepts
{
get => _SelectedSupportConcepts ?? (_SelectedSupportConcepts = new ObservableCollection<CompactSupportConceptDC>(ViewModel?.SupportConceptList ?? new ObservableCollection<CompactSupportConceptDC>()));
set
{
if(!ICollectionExtensions.ListEquals(_SelectedSupportConcepts, value))
{
_SelectedSupportConcepts = value;
SelectedSupportConcepts.CollectionChanged += SelectedSupportConceptsCollectionChanged;
ViewModel.SupportConceptList = value;
OnPropertyChanged();
}
}
}
private ObservableCollection<ResourceDC> _SelectedResources;
public ObservableCollection<ResourceDC> SelectedResources
{
get => _SelectedResources ?? (_SelectedResources = new ObservableCollection<ResourceDC>(ViewModel?.ResourceList ?? new List<ResourceDC>()));
set
{
_SelectedResources = value;
SelectedResources.CollectionChanged += SelectedResourcesCollectionChanged;
ViewModel.ResourceList = value.ToList();
OnPropertyChanged();
}
}
#region Ausgewählte Mitarbeiter, Klienten, Ressourcen
private void SelectedEmployeesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
ViewModel.ActualViewModel.EmployeeList = SelectedEmployees;
MultiEmployeeSearch.AusgewaehlteMitarbeiter = SelectedEmployees.Select(e2s => e2s.Employee).ToList();
}
private void SelectedCustomersCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
ViewModel.ActualViewModel.CustomerList = SelectedCustomers.ToList();
MultiCustomerSearch.AusgewaehlteKlienten = SelectedCustomers.ToList();
}
private void SelectedSupportConceptsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
ViewModel.ActualViewModel.SupportConceptList = SelectedSupportConcepts;
}
private void SelectedResourcesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
ViewModel.ActualViewModel.ResourceList = SelectedResources.ToList();
ResourcesTreeSearchView.AusgewaehlteRessourcen = SelectedResources.ToList();
}
#endregion
#region Visibilities
private Visibility _EmployeeSelectionVisibility;
public Visibility EmployeeSelectionVisibility
{
get => _EmployeeSelectionVisibility;
set
{
_EmployeeSelectionVisibility = value;
OnPropertyChanged();
}
}
private Visibility _CustomerSelectionVisibility;
public Visibility CustomerSelectionVisibility
{
get => _CustomerSelectionVisibility;
set
{
_CustomerSelectionVisibility = value;
OnPropertyChanged();
}
}
private Visibility _ResourceSelectionVisibility;
public Visibility ResourceSelectionVisibility
{
get => _ResourceSelectionVisibility;
set
{
_ResourceSelectionVisibility = value;
OnPropertyChanged();
}
}
private Visibility _SupportConceptVisibility;
public Visibility SupportConceptVisibility
{
get => _SupportConceptVisibility;
set
{
if(_SupportConceptVisibility != value)
{
_SupportConceptVisibility = value;
OnPropertyChanged();
}
}
}
public Visibility DeleteButtonVisibility => ViewModel.ActualViewModel.IsNew ? Visibility.Collapsed : ViewModel.IsReadyOnly ? Visibility.Collapsed : Visibility.Visible;
public Visibility OkButtonVisibility => ViewModel.IsReadyOnly ? Visibility.Collapsed : Visibility.Visible;
#endregion
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
public virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public InformationView InformationView { get; set; }
public CompactCustomerDC Customer { get; set; }
public AppointmentEditView()
{
InitializeComponent();
}
private void InitRights()
{
var hasRightToSeeEmployees = !ViewModel.ActualViewModel.IsTask && (BeWoUtils.HasRight(UserRightType.Employee_AllowViewOwnTeam) || BeWoUtils.HasRight(UserRightType.EmployeeView_View)) && BeWoUtils.HasRight(UserRightType.KalenderMitarbeitertermineAnsehen);
var hasRightToSeeCustomers = !ViewModel.ActualViewModel.IsTask && BeWoUtils.HasRight(UserRightType.CustomerView_View) || BeWoUtils.HasRight(UserRightType.Customer_ViewMyTeams) || BeWoUtils.HasRight(UserRightType.Customer_ViewMyCustomers);
var hasRightToSeeResources = !ViewModel.ActualViewModel.IsTask && BeWoUtils.HasRight(UserRightType.KalenderRessourcentermineAnlegen) || BeWoUtils.HasRight(UserRightType.KalenderRessourcentermineAendern);
var hasRightToSeeSupportConcepts = ViewModel.ActualViewModel.IsTask && (BeWoUtils.HasRight(UserRightType.SupportConceptView_View) || BeWoUtils.HasRight(UserRightType.ViewAll) || BeWoUtils.HasRight(UserRightType.SupportConcept_ViewMyTeams) || BeWoUtils.HasRight(UserRightType.SupportConcept_ViewAllSupportConcepts));
EmployeeSelectionVisibility = hasRightToSeeEmployees ? Visibility.Visible : Visibility.Collapsed;
CustomerSelectionVisibility = hasRightToSeeCustomers ? Visibility.Visible : Visibility.Collapsed;
ResourceSelectionVisibility = hasRightToSeeResources ? Visibility.Visible : Visibility.Collapsed;
SupportConceptVisibility = hasRightToSeeSupportConcepts ? Visibility.Visible : Visibility.Collapsed;
}
private void RemoveSupportConceptButton_OnClick(object sender, RoutedEventArgs e)
{
if(((Button) sender).Tag is CompactSupportConceptDC dc)
{
SelectedSupportConcepts.Remove(dc);
}
}
// KGW?
private void InformationButton_OnClick(object sender, RoutedEventArgs e)
{
if(sender is Button button && button.Tag is CompactCustomerDC customer)
{
InformationView = new InformationView();
InformationView.SetXaml(ServiceFacade.DoOperationsServiceSync(s => s.GetXAMLInformationStringForScheduler(Customer.CustomerOid)));
var beWoWindow = new BeWoWindow();
InformationView.ButtonCloseClicked += () => beWoWindow.Close();
beWoWindow.Height = 200;
beWoWindow.Width = 600;
beWoWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
beWoWindow.GroupBoxContent = InformationView;
beWoWindow.Owner = BeWoApp.CurrentBeWo.MainWindow;
beWoWindow.ShowDialog();
}
}
private void RemoveElementButton_OnClick(object sender, RoutedEventArgs e)
{
if(!ViewModel.ActualViewModel.IsTask && sender is Button button)
{
var obj = button.Tag;
switch(obj)
{
case ResourceDC res:
SelectedResources.Remove(res);
break;
case CompactCustomerDC cus:
SelectedCustomers.Remove(cus);
break;
case CompactSupportConceptDC sup:
SelectedSupportConcepts.Remove(sup);
break;
}
if(obj is Employee2SchedulerAppointmentDC e2s)
{
SelectedEmployees.Remove(e2s);
}
}
}
private void MultiEmployeeSearch_OnSelectionChanged(object sender, RoutedEventArgs e)
{
if(e.Source is MultiEmployeeSearch multiEmployeeSearch)
{
foreach(var employee in multiEmployeeSearch.SelectedEmployees.Where(employee => !SelectedEmployees.Any(e2s => e2s.Employee.Equals(employee))))
{
SelectedEmployees.Add(new Employee2SchedulerAppointmentDC { Employee = employee, ParticipationAnswer = ParticipationAnswer.Offen });
}
}
}
#region Popups
private void EmployeePopupClick(object sender, RoutedEventArgs e)
{
PopupEmployee.IsOpen = true;
PopupEmployee.Height = 300;
}
private void CustomerPopUpEditClick(object sender, RoutedEventArgs e)
{
PopupCustomer.IsOpen = true;
PopupCustomer.Height = 300;
}
private void ResourcePopUpClick(object sender, RoutedEventArgs e)
{
PopupResource.IsOpen = true;
PopupResource.Height = 300;
}
private void SupportConceptPopupClick(object sender, RoutedEventArgs e)
{
PopupSupportConcepts.IsOpen = true;
PopupSupportConcepts.Height = 300;
}
#endregion
private void CloseButton_OnClick(object sender, RoutedEventArgs e)
{
if(ViewModel.ActualViewModel.IsDirty && !ViewModel.IsReadOnly)
{
var result = MessageBox.Show("Wollen Sie die Änderungen am Termin speichern?", ViewModel.ActualViewModel.Subject, MessageBoxButton.YesNo, MessageBoxImage.Exclamation);
if(result == MessageBoxResult.Yes)
{
var dc = ViewModel.ActualViewModel.CommitToDataContract();
var ri = dc.RecurrenceInfo;
if(ViewModel.ActualViewModel.IsNew)
{
ServiceFacade.DoResourceServiceAsync(s => s.InsertSchedulerAppointments(new List<SchedulerAppointmentDC> { dc }),
cb =>
{
this.Dispatch(Close);
}
);
}
else
{
ServiceFacade.DoResourceServiceAsync(s => s.UpdateSchedulerAppointments(new List<SchedulerAppointmentDC> { dc }),
cb =>
{
this.Dispatch(Close);
}
);
}
}
else
{
Close();
}
}
else
{
Close();
}
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
if(ViewModel is null)
{
return;
}
InitRights();
var selectedEmployees = new ObservableCollection<CompactEmployeeDC>();
foreach(var e2s in ViewModel.EmployeeList)
{
selectedEmployees.AddIfNotIn(e2s.Employee);
}
SelectedResources.CollectionChanged += SelectedResourcesCollectionChanged;
SelectedCustomers.CollectionChanged += SelectedCustomersCollectionChanged;
SelectedEmployees.CollectionChanged += SelectedEmployeesCollectionChanged;
SelectedSupportConcepts.CollectionChanged += SelectedSupportConceptsCollectionChanged;
MultiEmployeeSearch.Sauce = ViewModel.AllEmployees;
MultiEmployeeSearch.AusgewaehlteMitarbeiter = selectedEmployees.ToList();
MultiEmployeeSearch.CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, (s, es) => this.Dispatch(() => { PopupEmployee.IsOpen = false; })));
MultiCustomerSearch.Sauce = ViewModel.AllCustomers;
MultiCustomerSearch.AusgewaehlteKlienten = SelectedCustomers.ToList();
MultiCustomerSearch.CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, (s, es) => this.Dispatch(() => { PopupCustomer.IsOpen = false; })));
ResourcesTreeSearchView.Sauce = ViewModel.AllCategories2Resources.ToDictionary(k => k.Key.ResourceCategory, k => k.Value.Select(s => s.DataContract).ToList());
ResourcesTreeSearchView.AusgewaehlteRessourcen = SelectedResources.ToList();
ResourcesTreeSearchView.CommandBindings.Add(new CommandBinding(ApplicationCommands.Close, (s, es) => this.Dispatch(() => { PopupResource.IsOpen = false; })));
if(ViewModel.IsTask && !SelectedEmployees.Any(e2a => e2a.Employee.Equals(BeWoApp.CompactLoggedOnEmployee)))
{
SelectedEmployees.Add(new Employee2SchedulerAppointmentDC { Employee = BeWoApp.CompactLoggedOnEmployee });
EmployeeToggleButton.IsChecked = true;
}
if(ViewModel.RecurrenceInfo != null)
{
_IgnoreRecurrenceTypeChange = true;
}
RecurrenceTypeComboBoxEdit.SelectedItem = ViewModel.RecurrenceTypeName;
}
private bool _IgnoreRecurrenceTypeChange;
public void SetRecurrenceInfo(string originalRecurrenceInfo)
{
if(!(originalRecurrenceInfo is null))
{
ViewModel.Appointment.RecurrenceInfo?.FromXml(originalRecurrenceInfo);
ViewModel.ActualViewModel.RecurrenceInfo = originalRecurrenceInfo;
}
else
{
ViewModel.Appointment.RecurrenceInfo = null;
ViewModel.ActualViewModel.RecurrenceInfo = null;
}
RecurrenceTypeComboBoxEdit.SelectedItem = ViewModel.RecurrenceTypeName;
}
private void OkButton_Click(object sender, RoutedEventArgs e)
{
if(ViewModel.IsReadyOnly)
{
MessageBox.Show("Sie verfügen nicht über die benötigten Rechte, um diesen Termin zu speichern!", "Speichern nicht möglich", MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
var dataContract = ViewModel.ActualViewModel.CommitToDataContract();
var start = dataContract.StartDate.Value;
var end = dataContract.EndDate.Value;
var employeeOids = dataContract.EmployeeList.Select(s => s.Employee.EmployeeOid).ToList();
var customerOids = dataContract.CustomerList.Select(s => s.CustomerOid).ToList();
var resrouceOids = dataContract.ResourceList.Select(s => s.ResourceOid.Value).ToList();
var originatorOid = dataContract.Originator?.EmployeeOid ?? BeWoApp.LoggedOnEmployeeOid.Value;
var recurrenceId = dataContract.RecurrenceId;
var recurrenceIndex = dataContract.RecurrenceIndex;
ServiceFacade.DoResourceServiceAsync(s => s.OverlappingAppointmentsExist(start, end, employeeOids, customerOids, resrouceOids, originatorOid, dataContract.SchedulerAppointmentOid, recurrenceId, recurrenceIndex), isOverlapping =>
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action) (() =>
{
if(isOverlapping)
{
if(MessageBox.Show("Dieser Termin überschneidet sich mit einem anderen, bereits existierenden Termin.\r\n\r\nMöchten Sie trotzdem speichern?", "Überschneidung", MessageBoxButton.YesNo, MessageBoxImage.Warning) == MessageBoxResult.Yes)
{
SaveAppointment(dataContract);
}
}
else
{
SaveAppointment(dataContract);
}
}));
});
}
private void SaveAppointment(SchedulerAppointmentDC dataContract)
{
if(dataContract.SchedulerAppointmentOid is null)
{
ServiceFacade.DoResourceServiceAsync(s => s.InsertSchedulerAppointments(new List<SchedulerAppointmentDC> { dataContract }),
() => Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action) Close));
}
else
{
ServiceFacade.DoResourceServiceAsync(s => s.UpdateSchedulerAppointments(new List<SchedulerAppointmentDC> { dataContract }),
() => Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action) Close));
}
}
private void SupportConceptsPopUpClick(object sender, RoutedEventArgs e)
{
PopupSupportConcepts.IsOpen = true;
}
private void ResourcesTreeSearchView_OnSelectionChanged(object sender, RoutedEventArgs e)
{
if(!(e.Source is ResourcesTreeSearchView resourcesTreeSearchView))
{
return;
}
var resourcesCollection = resourcesTreeSearchView.SelectedResources.ToObservableCollection();
foreach(var resource in resourcesCollection)
{
SelectedResources.AddIfNotIn(resource);
}
SelectedResources = SelectedResources.Except(SelectedResources.Where(sr => !resourcesCollection.Contains(sr)).ToList()).ToObservableCollection();
}
private void MultiCustomerSearch_OnSelectionChanged(object sender, RoutedEventArgs e)
{
if(e.Source is MultiCustomerSearchView multiCustomerSearchView)
{
SelectedCustomers = multiCustomerSearchView.SelectedCustomers.ToObservableCollection();
}
}
private void SupportConceptSelectionControl_ItemSelected(object sender, BS.Shared.Core.EventArgs<CompactSupportConceptDC> e)
{
PopupSupportConcepts.IsOpen = false;
SelectedSupportConcepts.Clear();
SelectedSupportConcepts.Add(e.Data);
OnPropertyChanged(nameof(SelectedSupportConcepts));
}
private void RecurrenceTypeComboBoxEdit_OnChanged(object sender, EditValueChangedEventArgs e)
{
if(_IgnoreRecurrenceTypeChange)
{
_IgnoreRecurrenceTypeChange = false;
return;
}
if(e.NewValue is string newValue)
{
RecurrenceType? type;
switch(newValue)
{
case "(keine)":
type = null;
break;
case "täglich":
type = RecurrenceType.Daily;
break;
case "wöchentlich":
type = RecurrenceType.Weekly;
break;
case "monatlich":
type = RecurrenceType.Monthly;
break;
case "jährlich":
type = RecurrenceType.Yearly;
break;
default:
type = null;
break;
}
if(type is null)
{
// TODO: Typ bestimmen bzw. beim Loaded-Event merken! Zum zurücksetzen (nötig?)
return;
}
ViewModel.Appointment.Type = AppointmentType.Pattern;
ViewModel.Appointment.RecurrenceInfo.Type = type.Value;
ViewModel.ActualViewModel.RecurrenceInfo = ViewModel.Appointment.RecurrenceInfo.ToXml();
ViewModel.Scheduler.ShowRecurrenceWindow(ViewModel.Appointment);
}
}
//private IRecurrenceInfo RecurrenceInfo;
private void DeleteButton_OnClick(object sender, RoutedEventArgs e)
{
if(!ViewModel.IsReadyOnly && ViewModel.Appointment.Id is long appointmentOid)
{
var message = Utils.GetDeleteMessageForAppointment(ViewModel.Appointment);
if(MessageBox.Show(message, "Termin löschen", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes)
{
var dc = ViewModel.ActualViewModel.CommitToDataContract();
ServiceFacade.DoResourceServiceAsync(s => s.DeleteSchedulerAppointments(new Dictionary<long, long> { { dc.SchedulerAppointmentOid.Value, dc.NewSchedulerAppointmentVersion.Value } }), () =>
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action) Close);
});
}
}
}
// TODO: Fertig machen
private void EditRecurrenceButton_OnClick(object sender, RoutedEventArgs e)
{
if(!(ViewModel.Appointment.RecurrenceInfo is null))
{
ViewModel.Scheduler.ShowRecurrenceWindow(ViewModel.Appointment);
}
}
}
}

View File

@@ -0,0 +1,100 @@
<dx:DXWindow x:Class="BeWo.Scheduling.View.AppointmentRecurrenceEditView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:dxsch="http://schemas.devexpress.com/winfx/2008/xaml/scheduling"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
mc:Ignorable="d"
Loaded="AppointmentRecurrenceEditView_OnLoaded"
Background="{StaticResource ObjectEditBackgroundBrush}"
ResizeMode="NoResize"
Closing="AppointmentRecurrenceEditView_OnClosing"
Title="AppointmentRecurrenceEditView" Height="Auto" Width="507" SizeToContent="Height">
<Window.Resources>
<Style x:Key="RecurrenceInfoControlStyle" TargetType="dxsch:RecurrenceInfoControlBase">
<Setter Property="RecurrenceInfo" Value="{Binding RecurrenceInfo}"/>
<Style.Triggers>
<Trigger Property="Visibility" Value="Collapsed">
<Setter Property="RecurrenceInfo" Value="{x:Null}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style x:Key="GroupBoxStyle" TargetType="{x:Type GroupBox}">
<Setter Property="BorderBrush" Value="#D5DFE5" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupBox}">
<Grid SnapsToDevicePixels="true">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="6" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="6" />
</Grid.RowDefinitions>
<Border BorderBrush="Transparent" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.ColumnSpan="4" Grid.Column="0" CornerRadius="4" Grid.Row="1" Grid.RowSpan="3"/>
<Border SnapsToDevicePixels="True" x:Name="Header" Grid.Column="1" Padding="3,1,3,0" Grid.Row="0" Grid.RowSpan="2">
<ContentPresenter ContentSource="Header" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<ContentPresenter Grid.ColumnSpan="2" Grid.Column="1" Margin="{TemplateBinding Padding}" Grid.Row="2" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
<Border SnapsToDevicePixels="True" Grid.Column="0" BorderBrush="Gray" BorderThickness="{TemplateBinding BorderThickness}" Grid.ColumnSpan="4" CornerRadius="4" Grid.Row="1" Grid.RowSpan="3">
<Border.OpacityMask>
<MultiBinding ConverterParameter="7" Converter="{StaticResource BorderGapMaskConverter}">
<Binding ElementName="Header" Path="ActualWidth"/>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}"/>
<Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</Border.OpacityMask>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<GroupBox Grid.Row="0" Header="Serienmuster" Style="{StaticResource GroupBoxStyle}" Margin="5">
<DockPanel>
<dxsch:RecurrenceTypeControl DockPanel.Dock="Left" RecurrenceTypes="{Binding AvailableRecurrenceTypes}" RecurrenceType="{Binding RecurrenceInfo.Type, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<StackPanel Orientation="Horizontal">
<Separator />
</StackPanel>
<StackPanel MinHeight="90">
<dxsch:DailyRecurrenceControl Style="{StaticResource RecurrenceInfoControlStyle}" Visibility="{Binding RecurrenceInfo.Type, Converter={dxsch:RecurrenceTypeToVisibilityConverter VisibleValue=Daily}}"/>
<dxsch:WeeklyRecurrenceControl Style="{StaticResource RecurrenceInfoControlStyle}" Visibility="{Binding RecurrenceInfo.Type, Converter={dxsch:RecurrenceTypeToVisibilityConverter VisibleValue=Weekly}}" FirstDayOfWeek="{Binding FirstDayOfWeek}"/>
<dxsch:MonthlyRecurrenceControl Style="{StaticResource RecurrenceInfoControlStyle}" Visibility="{Binding RecurrenceInfo.Type, Converter={dxsch:RecurrenceTypeToVisibilityConverter VisibleValue=Monthly}}"/>
<dxsch:YearlyRecurrenceControl x:Name="YearlyRecurrence" Style="{StaticResource RecurrenceInfoControlStyle}" Visibility="{Binding RecurrenceInfo.Type, Converter={dxsch:RecurrenceTypeToVisibilityConverter VisibleValue=Yearly}}"/>
</StackPanel>
</DockPanel>
</GroupBox>
<GroupBox Grid.Row="1" Header="Serienende" Style="{StaticResource GroupBoxStyle}" Margin="5">
<dxsch:RecurrenceRangeControl RecurrenceInfo="{Binding RecurrenceInfo}"/>
</GroupBox>
<Grid Grid.Row="2" VerticalAlignment="Bottom" Margin="0">
<Border Height="40" Margin="0,10,0,0" VerticalAlignment="Bottom" Background="#FF000000">
<Border.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#19000000" Offset="0" />
<GradientStop Color="#33FFFFFF" Offset="1" />
</LinearGradientBrush>
</Border.OpacityMask>
</Border>
<StackPanel VerticalAlignment="Bottom" Height="40" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Content="OK" Width="80" Height="25" Margin="3" Click="OkButton_Click" />
<Button Content="Abbrechen" Width="80" Height="25" Margin="3" Click="CloseButton_OnClick" />
</StackPanel>
</Grid>
</Grid>
</dx:DXWindow>

View File

@@ -0,0 +1,53 @@
using System.ComponentModel;
using System.Windows;
using DevExpress.Xpf.Scheduling.VisualData;
namespace BeWo.Scheduling.View
{
public partial class AppointmentRecurrenceEditView
{
public RecurrenceWindowViewModel ViewModel => DataContext as RecurrenceWindowViewModel;
public bool IsCancelled
{
get;
private set;
}
private bool _IsCancelButtonClicked;
public AppointmentRecurrenceEditView()
{
InitializeComponent();
}
private void AppointmentRecurrenceEditView_OnLoaded(object sender, RoutedEventArgs e)
{
}
private void OkButton_Click(object sender, RoutedEventArgs e)
{
IsCancelled = false;
_IsCancelButtonClicked = false;
Close();
}
// ToDo: den Ursprungszustand wiederherstellen und schließen
private void CloseButton_OnClick(object sender, RoutedEventArgs e)
{
IsCancelled = true;
ViewModel.DeleteCommand.Execute(null);
_IsCancelButtonClicked = false;
Close();
}
private void AppointmentRecurrenceEditView_OnClosing(object sender, CancelEventArgs e)
{
if(_IsCancelButtonClicked)
{
IsCancelled = true;
}
}
}
}

View File

@@ -0,0 +1,23 @@
<dx:DXWindow x:Class="BeWo.Scheduling.View.OccurrenceParticipationConfirmationView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
mc:Ignorable="d"
Loaded="OccurrenceParticipationConfirmationView_OnLoaded"
WindowStartupLocation="CenterOwner" ResizeMode="NoResize"
dx:ThemeManager.ThemeName="Office2010Black"
Height="Auto" Width="500" SizeToContent="Height">
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding InfoText}" TextWrapping="Wrap" Margin="5" />
<CheckBox Content="Für alle Termine einer Serie übernehmen" IsThreeState="False" Margin="5" Visibility="{Binding CheckBoxVisibility}"
IsChecked="{Binding ApplyForAllOccurrences, UpdateSourceTrigger=PropertyChanged}" />
<StackPanel Orientation="Horizontal" Margin="0,5,0,0" HorizontalAlignment="Right">
<Button HorizontalAlignment="Right" Content="{Binding OkButtonText}" Margin="5" Click="YesButton_OnClick" />
<Button HorizontalAlignment="Right" Content="{Binding NoButtonText}" Margin="5" Click="NoButton_OnClick" />
</StackPanel>
</StackPanel>
</Grid>
</dx:DXWindow>

View File

@@ -0,0 +1,77 @@
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
using BeWo.Annotations;
using BS.Shared.Extensions;
namespace BeWo.Scheduling.View
{
public partial class OccurrenceParticipationConfirmationView : INotifyPropertyChanged
{
public bool? ShouldChangeSeries { get; private set; }
private readonly string _Subject;
private readonly string _ParticipationAnswerString;
public Visibility CheckBoxVisibility { get; }
public string OkButtonText => $"Ganzer Serie {_ParticipationAnswerString}";
public string NoButtonText => $"Nur diesem Termin {_ParticipationAnswerString}";
public string DateText { get; }
public string InfoText => $"Der Termin '{_Subject}' am {DateText} ist Teil einer Serie. Möchten Sie der ganzen Serie {_ParticipationAnswerString} oder nur dem ausgewählten Termin?";
private bool _ApplyForAllOccurrences;
public bool ApplyForAllOccurrences
{
get => _ApplyForAllOccurrences;
set
{
if(_ApplyForAllOccurrences != value)
{
_ApplyForAllOccurrences = value;
OnPropertyChanged();
}
}
}
// ToDo: Datum und evtl. Uhrzeit einbauen?
public OccurrenceParticipationConfirmationView(string subject, string participationAnswerString, bool isCheckBoxVisible, DateTime start, DateTime end)
{
InitializeComponent();
DateText = start.GetDateString(end);
_Subject = subject;
_ParticipationAnswerString = participationAnswerString;
CheckBoxVisibility = isCheckBoxVisible ? Visibility.Visible : Visibility.Collapsed;
DataContext = this;
}
private void YesButton_OnClick(object sender, RoutedEventArgs e)
{
ShouldChangeSeries = false;
}
private void NoButton_OnClick(object sender, RoutedEventArgs e)
{
ShouldChangeSeries = true;
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void OccurrenceParticipationConfirmationView_OnLoaded(object sender, RoutedEventArgs e)
{
ShouldChangeSeries = null;
}
}
}

View File

@@ -0,0 +1,172 @@
<dx:DXWindow x:Class="BeWo.Scheduling.View.OpenAppointmentsView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
xmlns:drawing="http://schemas.devexpress.com/winfx/2008/xaml/scheduler/internal"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:converter="clr-namespace:BeWo.Scheduling.Converter"
mc:Ignorable="d" Height="400" Width="650"
ShowIcon="False" MinHeight="300" MinWidth="500"
dx:ThemeManager.ThemeName="Office2010Black"
WindowStartupLocation="CenterScreen" Closing="OpenAppointmentsView_OnClosing">
<dx:DXWindow.Resources>
<drawing:TimeSpanToDateTimeConverter x:Key="TimeSpanToDateTimeConverter"/>
<converter:RecurringAppointmentDurationConverter x:Key="RecurringAppointmentDurationConverter" />
<converter:RequestVisibilityConverter x:Key="RequestVisibilityConverter" />
<converter:ParticipationRequestListViewConverter x:Key="ParticipationRequestListViewConverter" />
<LinearGradientBrush x:Key="NavigationContentBrush" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF04B4D0" Offset="0" />
<GradientStop Color="#FF038195" Offset="1" />
</LinearGradientBrush>
</dx:DXWindow.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ListView x:Name="OpenAppointmentsList" Grid.Column="0" MinWidth="120" SelectionMode="Single" Margin="3"
ItemsSource="{Binding OpenAppointments, UpdateSourceTrigger=PropertyChanged}" MaxWidth="300"
SelectedItem="{Binding SelectedAppointment, UpdateSourceTrigger=PropertyChanged}"
Background="{StaticResource NavigationContentBrush}" SelectedIndex="0">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="Margin" Value="0,2,1,0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border CornerRadius="5" MinHeight="20" Background="Transparent" />
<Border x:Name="ItemBorder" CornerRadius="5" MinHeight="20" Background="#FF000000">
<Border.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#19000000" Offset="0" />
<GradientStop Color="#26000000" Offset="1" />
</LinearGradientBrush>
</Border.OpacityMask>
</Border>
<Border x:Name="ItemContent" CornerRadius="5" MinHeight="20">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,3,5,3" OpacityMask="{x:Null}" SnapsToDevicePixels="True">
<TextBlock VerticalAlignment="Center" Text="{Binding Converter={StaticResource ParticipationRequestListViewConverter}, ConverterParameter=LabelId}" FontSize="12" Foreground="#FFD2D2D2" FontFamily="Microsoft Sans Serif" />
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#33000000" Offset="0" />
<GradientStop Color="#66000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ListBoxItem.IsSelected" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99000000" Offset="0" />
<GradientStop Color="#CC000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ListBoxItem.IsSelected" Value="True" />
<Condition Property="Selector.IsSelectionActive" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99000000" Offset="0" />
<GradientStop Color="#B2000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
<Grid Grid.Column="1" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.ColumnSpan="4" HorizontalAlignment="Center" Visibility="{Binding Path=SelectedAppointment, Converter={StaticResource RequestVisibilityConverter}, ConverterParameter=TerminVerstrichen}" Foreground="#9a0000">Dieser Termin liegt in der Vergangenheit</TextBlock>
<Label Grid.Column="0" Grid.Row="1" Content="Betreff" Margin="3" />
<TextBox Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="1" Height="23" Margin="3" Text="{Binding Path=SelectedAppointment.Subject, Mode=OneWay}" IsReadOnly="True" />
<Label Grid.Column="0" Grid.Row="2" Content="Ort" Margin="3" />
<TextBox Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="2" Height="23" Margin="3" Text="{Binding Path=SelectedAppointment.Location, Mode=OneWay}" IsReadOnly="True" />
<Label Grid.Column="0" Grid.Row="3" Content="Organisator" Margin="3" />
<TextBox Grid.Column="1" Grid.ColumnSpan="3" Grid.Row="3" Height="23" Margin="3" Text="{Binding Path=SelectedAppointment.Originator.FirstNameLastName, Mode=OneWay}" IsReadOnly="True" />
<Label Grid.Column="0" Grid.Row="4" VerticalAlignment="Center" Content="Start" Margin="3"/>
<dxe:DateEdit Grid.Column="1" Grid.Row="4" MaskType="DateTimeAdvancingCaret" Background="White" Height="23" MinWidth="80" Margin="3" IsEnabled="True" EditValue="{Binding SelectedAppointment.Start, Mode=OneWay}" IsReadOnly="True" PopupOpening="PopupBaseEdit_OnPopupOpening" />
<dxe:TextEdit IsEnabled="True" Grid.Column="2" Grid.Row="4" MaskType="DateTime" Mask="t" MaskUseAsDisplayFormat="True" Margin="3" Height="23" EditValue ="{Binding SelectedAppointment.StartTime, Converter={StaticResource TimeSpanToDateTimeConverter}, Mode=OneWay}" IsReadOnly="True"/>
<dxe:CheckEdit IsEnabled="False" Grid.Column="3" Grid.Row="4" Content="Ganztägig" EditValue ="{Binding SelectedAppointment.AllDay, Mode=OneWay}" HorizontalAlignment="Right" Margin="3" IsReadOnly="True" />
<Label Grid.Column="0" Grid.Row="5" VerticalAlignment="Center" Content="Ende" Margin="3"/>
<dxe:DateEdit IsEnabled="True" Grid.Column="1" Grid.Row="5" MaskType="DateTimeAdvancingCaret" Background="White" Height="23" MinWidth="80" Margin="3" EditValue="{Binding SelectedAppointment.End, Mode=OneWay}" IsReadOnly="True" PopupOpening="PopupBaseEdit_OnPopupOpening" />
<dxe:TextEdit IsEnabled="True" Grid.Column="2" Grid.Row="5" MaskType="DateTime" Mask="t" MaskUseAsDisplayFormat="True" Margin="3" Height="23" EditValue ="{Binding SelectedAppointment.EndTime, Converter={StaticResource TimeSpanToDateTimeConverter}, Mode=OneWay}" IsReadOnly="True"/>
<Label Grid.Column="0" Grid.Row="6" VerticalAlignment="Center" Content="Serientermin" Margin="3" Visibility="{Binding Path=SelectedAppointment, Converter={StaticResource RequestVisibilityConverter}, ConverterParameter=SerienterminLabel}" />
<TextBlock Grid.Column="1" Grid.Row="6" Grid.ColumnSpan="3" Margin="3" Padding="0" Foreground="Black" VerticalAlignment="Center"
Text="{Binding Path=SelectedAppointment, Converter={StaticResource RecurringAppointmentDurationConverter}}"
Visibility="{Binding Path=SelectedAppointment, Converter={StaticResource RequestVisibilityConverter}, ConverterParameter=SerienterminLabel}"
TextWrapping="WrapWithOverflow"/>
<Label Grid.Column="0" Grid.Row="7" Margin="3" Content="Notiz"/>
<TextBox Grid.Column="1" Grid.Row="7" Grid.ColumnSpan="3" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" VerticalAlignment="Stretch" HorizontalScrollBarVisibility="Disabled" Margin="3" TextWrapping="Wrap" Text="{Binding Path=SelectedAppointment.Description, Mode=OneWay}" IsReadOnly="True" />
<Grid Grid.Row="8" Grid.Column="0" Grid.ColumnSpan="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button x:Name="AlleBestaetigen" Grid.Column="0" Content="Alle bestätigen" Margin="3" Click="ConfirmAllButton_OnClick" Width="100" />
<StackPanel x:Name="ZusagenStack" Grid.Column="1" HorizontalAlignment="Right" Orientation="Horizontal" Visibility="{Binding Path=SelectedAppointment, Converter={StaticResource RequestVisibilityConverter}, ConverterParameter=ZusagenStack}">
<StackPanel HorizontalAlignment="Right" Orientation="Horizontal">
<Button Margin="3" Content="Zusagen" Click="ConfirmButton_OnClick" IsEnabled="{Binding SelectedAppointment, Converter={StaticResource ObjectBoolConverter}}" />
<Button Margin="3" Content="Mit Vorbehalt" Click="ConfirmWithReservationButton_OnClick" IsEnabled="{Binding SelectedAppointment, Converter={StaticResource ObjectBoolConverter}}" />
<Button Margin="3" Content="Absagen" Click="RejectButton_OnClick" IsEnabled="{Binding SelectedAppointment, Converter={StaticResource ObjectBoolConverter}}" />
</StackPanel>
</StackPanel>
</Grid>
<Button x:Name="OkButton" Grid.Row="8" Grid.Column="0" Grid.ColumnSpan="4" HorizontalAlignment="Right" Margin="3" Width="100" Content="OK" Click="OkButton_OnClick" Visibility="{Binding Path=SelectedAppointment, Converter={StaticResource RequestVisibilityConverter}, ConverterParameter=OKBtn}" />
</Grid>
</Grid>
<Button Grid.Row="1" x:Name="CloseBtn" Content="Schließen" HorizontalAlignment="Right" Margin="3" Width="100" Click="CloseButton_OnClick" />
</Grid>
</dx:DXWindow>

View File

@@ -0,0 +1,261 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using BeWo.Annotations;
using BeWo.Scheduling.ViewModel;
using BeWo.ServiceProxy;
using BS.Shared;
using BS.Shared.DataContracts;
using BS.Shared.Extensions;
using DevExpress.Xpf.Editors;
namespace BeWo.Scheduling.View
{
public partial class OpenAppointmentsView : INotifyPropertyChanged
{
private bool _RaiseChangeEvent = true;
public static readonly RoutedEvent ParticipationChangedEvent = EventManager.RegisterRoutedEvent(nameof(ParticipationChanged), RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(OpenAppointmentsView));
public event RoutedEventHandler ParticipationChanged
{
add => AddHandler(ParticipationChangedEvent, value);
remove => RemoveHandler(ParticipationChangedEvent, value);
}
private void RaiseParticipationChangedEventEvent()
{
var newEventArgs = new RoutedEventArgs(ParticipationChangedEvent);
RaiseEvent(newEventArgs);
}
private ObservableCollection<SchedulingAppointmentVM> _OpenAppointments;
public ObservableCollection<SchedulingAppointmentVM> OpenAppointments
{
get => _OpenAppointments ?? (_OpenAppointments = new ObservableCollection<SchedulingAppointmentVM>());
set
{
_OpenAppointments = value is null ?
new ObservableCollection<SchedulingAppointmentVM>() :
new ObservableCollection<SchedulingAppointmentVM>(value.OrderBy(o => o.Start));
OnPropertyChanged(nameof(OpenAppointments));
}
}
private SchedulingAppointmentVM _SelectedAppointment;
public SchedulingAppointmentVM SelectedAppointment
{
get => _SelectedAppointment;
set
{
_SelectedAppointment = value;
OnPropertyChanged(nameof(SelectedAppointment));
}
}
public OpenAppointmentsView(IEnumerable<SchedulingAppointmentVM> openAppointments, IEnumerable<SchedulingAppointmentVM> statusUpdates)
{
InitializeComponent();
OpenAppointments = new ObservableCollection<SchedulingAppointmentVM>(openAppointments.Union(statusUpdates));
DataContext = this;
if(OpenAppointments.Any())
{
OpenAppointmentsList.SelectedIndex = 0;
}
}
private void OpenAppointmentsView_OnClosing(object sender, CancelEventArgs e)
{
BeWoApp.MainControl.AufOffeneTerminePruefen();
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void UpdateView(List<SchedulerAppointmentDC> updatedAppointments)
{
ServiceFacade.DoResourceServiceAsync(s => s.GetAllOpenAppointmentsForEmployee(BeWoApp.CompactLoggedOnEmployee.EmployeeOid), openAppointments =>
{
this.Dispatch(() =>
{
var statusUpdatesAndAppointments = SchedulingUtils.Utils.SeperateStatusUpdatesAndAppointments(openAppointments);
OpenAppointments = new ObservableCollection<SchedulingAppointmentVM>(statusUpdatesAndAppointments.Appointments.Union(statusUpdatesAndAppointments.StatusUpdates));
RaiseParticipationChangedEventEvent();
ToggleControls();
if(_RaiseChangeEvent)
{
if(OpenAppointments.Count == 0)
{
Close();
}
else
{
OpenAppointmentsList.SelectedIndex = 0;
}
}
});
});
}
private void ToggleControls()
{
ZusagenStack.IsEnabled = !ZusagenStack.IsEnabled;
OkButton.IsEnabled = !OkButton.IsEnabled;
AlleBestaetigen.IsEnabled = !AlleBestaetigen.IsEnabled;
}
private void UpdateSelectedAppointment(ParticipationAnswer participationAnswer)
{
if(!(SelectedAppointment is null))
{
foreach(var employee2Appointment in SelectedAppointment.EmployeeList)
{
if(employee2Appointment.Employee.Equals(BeWoApp.CompactLoggedOnEmployee))
{
employee2Appointment.ParticipationAnswer = participationAnswer;
}
}
}
ToggleControls();
_RaiseChangeEvent = true;
ServiceFacade.DoResourceServiceAsync(s => s.UpdateSchedulerAppointments(new List<SchedulerAppointmentDC> { SelectedAppointment.CommitToDataContract() }), UpdateView);
}
private void CloseButton_OnClick(object sender, RoutedEventArgs e)
{
Close();
}
private void PopupBaseEdit_OnPopupOpening(object sender, OpenPopupEventArgs e)
{
// Es wird verhindert, dass das Popup angezeigt wird auch wenn das DateEdit readonly ist, damit man es nicht auf disabled setzen muss, da sonst die Schriftfarbe schwer lesbar ist.
e.Cancel = true;
}
private void ConfirmAllButton_OnClick(object sender, RoutedEventArgs e)
{
var appointments2Update = new List<SchedulerAppointmentDC>();
foreach(var appointment in OpenAppointments)
{
foreach(var employee2Appointment in appointment.EmployeeList)
{
employee2Appointment.IsPC_CheckedTs = DateTime.Now;
if(employee2Appointment.Employee.Equals(BeWoApp.CompactLoggedOnEmployee))
{
if(appointment.Start < DateTime.Now && appointment.End < DateTime.Now)
{
employee2Appointment.ParticipationAnswer = ParticipationAnswer.Verstrichen;
employee2Appointment.IsPC_CheckedTs = DateTime.Now;
employee2Appointment.IsPChanged = false;
}
else
{
employee2Appointment.IsPChanged = true;
employee2Appointment.ParticipationAnswer = ParticipationAnswer.Zusage;
}
}
else
{
employee2Appointment.IsPChanged = false;
}
}
}
ToggleControls();
_RaiseChangeEvent = false;
ServiceFacade.DoResourceServiceAsync(s => s.UpdateSchedulerAppointments(appointments2Update), updatedAppointments =>
{
UpdateView(updatedAppointments);
this.Dispatch(Close);
});
}
private void ConfirmButton_OnClick(object sender, RoutedEventArgs e)
{
UpdateSelectedAppointment(ParticipationAnswer.Zusage);
}
private void ConfirmWithReservationButton_OnClick(object sender, RoutedEventArgs e)
{
UpdateSelectedAppointment(ParticipationAnswer.Vorbehalt);
}
private void RejectButton_OnClick(object sender, RoutedEventArgs e)
{
UpdateSelectedAppointment(ParticipationAnswer.Absage);
}
private void OkButton_OnClick(object sender, RoutedEventArgs e)
{
if(SelectedAppointment?.LiesInPast ?? false)
{
var employee2Appointment = SelectedAppointment.EmployeeList.ToList().Find(e2a => e2a.Employee2SchedulerAppointmentOid == SelectedAppointment.LabelKey) ??
SelectedAppointment.EmployeeList.ToList().Find(e2a => e2a.Employee.Equals(BeWoApp.CompactLoggedOnEmployee));
if(!(employee2Appointment is null))
{
if(employee2Appointment.Employee.Equals(BeWoApp.CompactLoggedOnEmployee))
{
employee2Appointment.ParticipationAnswer = ParticipationAnswer.Verstrichen;
}
employee2Appointment.IsPC_CheckedTs = DateTime.Now;
employee2Appointment.IsPChanged = true;
ToggleControls();
_RaiseChangeEvent = true;
ServiceFacade.DoResourceServiceAsync(s => s.UpdateSchedulerAppointments(new List<SchedulerAppointmentDC> { SelectedAppointment.CommitToDataContract() }), UpdateView);
return;
}
}
if(SelectedAppointment?.LabelKey is null)
{
return;
}
var employee2Appointment2 = SelectedAppointment.EmployeeList.ToList().Find(e2a => e2a.Employee2SchedulerAppointmentOid == SelectedAppointment.LabelKey);
if(!(employee2Appointment2 is null))
{
employee2Appointment2.IsPC_CheckedTs = DateTime.Now;
employee2Appointment2.IsPChanged = false;
ToggleControls();
_RaiseChangeEvent = true;
ServiceFacade.DoResourceServiceAsync(s => s.UpdateSchedulerAppointments(new List<SchedulerAppointmentDC> { SelectedAppointment.CommitToDataContract() }), UpdateView);
}
}
}
}

View File

@@ -0,0 +1,994 @@
<localView:BeWoView x:Class="BeWo.Scheduling.View.SchedulingView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BeWo.Scheduling.View"
xmlns:localView="clr-namespace:BeWo.View"
xmlns:converter="clr-namespace:BeWo.Scheduling.Converter"
xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors"
xmlns:markup="clr-namespace:BeWo.MultiLanguage.Markup"
xmlns:view="clr-namespace:BeWo.Scheduler.View"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxsch="http://schemas.devexpress.com/winfx/2008/xaml/scheduling"
xmlns:converter1="clr-namespace:BeWo.Scheduler.Converter"
xmlns:viewModel="clr-namespace:BeWo.Scheduling.ViewModel"
xmlns:dxschv="http://schemas.devexpress.com/winfx/2008/xaml/scheduling/visual"
xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol"
xmlns:dxb="http://schemas.devexpress.com/winfx/2008/xaml/bars"
xmlns:schedulingUtils="clr-namespace:BeWo.Scheduling.SchedulingUtils"
mc:Ignorable="d"
Width="Auto" Height="Auto"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Focusable="true">
<localView:BeWoView.Resources>
<ResourceDictionary>
<converter:SchedulingCheckBoxConverter x:Key="CheckBoxConverter" />
<converter1:NewCalendarBackgroundConverter x:Key="NewCalendarBackgroundConverter" />
<view:TextFromIDataContractConverter x:Key="TextFromIDataContractConverter" />
<converter:WidthAdditionMultiConverter x:Key="WidthAdditionMultiConverter" />
<converter:EmployeeBackgroundColorConverter x:Key="EmployeeBackgroundColorConverter" />
<converter:DayViewDayCountVisibilityConverter x:Key="DayViewDayCountVisibilityConverter" />
<converter:EmployeeListConfirmationToolTipConverter x:Key="EmployeeListConfirmationToolTipConverter" />
<converter:InfoButtonVisibilityConverter x:Key="InfoButtonVisibilityConverter" />
<converter:AppointmentBorderThicknessConverter x:Key="AppointmentBorderThicknessConverter" />
<Style x:Key="MultiElementSelectionControlStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="Margin" Value="0,2,0,0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border CornerRadius="5" MinHeight="25" Background="{Binding Converter={StaticResource NewCalendarBackgroundConverter}}" />
<Border x:Name="ItemBorder" CornerRadius="5" MinHeight="25" Background="#FF000000">
<Border.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#19000000" Offset="0" />
<GradientStop Color="#26000000" Offset="1" />
</LinearGradientBrush>
</Border.OpacityMask>
</Border>
<Border x:Name="ItemContent" CornerRadius="5" MinHeight="25">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,3,5,3" OpacityMask="{x:Null}" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center" Grid.Column="0" Text="{Binding Converter={StaticResource TextFromIDataContractConverter}}" Margin="3,0,0,0" FontSize="14" Foreground="#FFD2D2D2" FontFamily="Microsoft Sans Serif" />
<Border Width="15" Height="15" Grid.Column="1" Background="{Binding Path=FilterableBrush}" CornerRadius="3" />
<Button x:Name="RemoveElementButton" Grid.Column="2" Grid.RowSpan="2" Width="20" Height="20" ToolTip="Element aus der Liste entfernen" Tag="{Binding}" Style="{DynamicResource CloseButtonStyle}" Click="RemoveElementButton_OnClick" Margin="3,0,0,0" />
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#33000000" Offset="0" />
<GradientStop Color="#66000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ListBoxItem.IsSelected" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99000000" Offset="0" />
<GradientStop Color="#CC000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ListBoxItem.IsSelected" Value="True" />
<Condition Property="Selector.IsSelectionActive" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99000000" Offset="0" />
<GradientStop Color="#B2000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MitarbeiterTabItemStyle" TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border" Margin="0">
<ContentPresenter x:Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="12,2,12,2" RecognizesAccessKey="True" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="{StaticResource EmployeeContentBrush}" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="{StaticResource EmployeeContentBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="KlientenTabItemStyle" TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border" Margin="0">
<ContentPresenter x:Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="12,2,12,2" RecognizesAccessKey="True" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="{StaticResource CustomerContentBrush}" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="{StaticResource CustomerContentBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="RessourcenTabItemStyle" TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border Name="Border" Margin="0">
<ContentPresenter x:Name="ContentSite" VerticalAlignment="Center" HorizontalAlignment="Center" ContentSource="Header" Margin="12,2,12,2" RecognizesAccessKey="True" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="{StaticResource ResourceContentBrush}" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="{StaticResource ResourceContentBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="dxschv:DayAppointmentControl">
<Setter Property="Padding" Value="0" />
</Style>
<Style TargetType="dxschv:MonthAppointmentControl">
<Setter Property="Padding" Value="0" />
</Style>
<Style TargetType="dxschv:AgendaAppointmentControl">
<Setter Property="Padding" Value="0" />
</Style>
<Style TargetType="dxschv:TimelineAppointmentControl">
<Setter Property="Padding" Value="0" />
</Style>
<Style TargetType="dxschv:AllDayAppointmentControl">
<Setter Property="Padding" Value="0" />
</Style>
<Style TargetType="dxschv:AppointmentHorizontalControl">
<Setter Property="Padding" Value="0" />
</Style>
<DataTemplate x:Key="VerticalAppointmentControl.ContentTemplate">
<Border BorderThickness="{Binding Appointment.CustomFields[VMForCustomField].AppointmentBorderBrush, Converter={StaticResource AppointmentBorderThicknessConverter}}" BorderBrush="{Binding Appointment.CustomFields[VMForCustomField].AppointmentBorderBrush}" CornerRadius="2">
<Grid Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="8" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8" />
</Grid.ColumnDefinitions>
<!-- Mitarbeiterfarbe -->
<Border Grid.Column="0">
<Border.Background>
<MultiBinding Mode="OneWay" Converter="{StaticResource EmployeeBackgroundColorConverter}">
<Binding Path="DataContext.IsEmployeeBrushVisible" Mode="OneWay" UpdateSourceTrigger="PropertyChanged" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type localView:BeWoView}}" />
<Binding Path="Appointment.CustomFields[VMForCustomField].AppointmentColors.EmployeeBackground" />
<Binding Path="Appointment.CustomFields[VMForCustomField].BackgroundColor" />
</MultiBinding>
</Border.Background>
</Border>
<!-- /Mitarbeiterfarbe -->
<!-- Hauptteil mit Betreff und (Ort) -->
<dxschv:AppointmentContentPanel Grid.Column="1" Background="{Binding Appointment.CustomFields[VMForCustomField].BackgroundColor}">
<dxschv:AppointmentContentPanel.IntervalSubject>
<TextBlock Foreground="{Binding Appointment.CustomFields[VMForCustomField].ForegroundColor}"
Text="{Binding Appointment.Subject}" Margin="3,3,0,0" FontWeight="Normal" />
</dxschv:AppointmentContentPanel.IntervalSubject>
<dxschv:AppointmentContentPanel.Location>
<TextBlock Foreground="{Binding Appointment.CustomFields[VMForCustomField].ForegroundColor}"
Visibility="{Binding Appointment.Location, Converter={StaticResource ObjectVisibilityConverter}}"
Margin="3,3,0,0" FontWeight="Normal" Text="{Binding Appointment.Location, StringFormat={}({0})}" />
</dxschv:AppointmentContentPanel.Location>
<dxschv:AppointmentContentPanel.Images>
<dxschv:AppointmentImagesPanel Margin="0,0,0,3" VerticalAlignment="Stretch" Background="{Binding Appointment.CustomFields[VMForCustomField].BackgroundColor}" />
</dxschv:AppointmentContentPanel.Images>
</dxschv:AppointmentContentPanel>
<!-- /Hauptteil mit Betreff und (Ort) -->
<!-- Klientenfarbe & Ressourcenfarbe -->
<Border Grid.Column="2" Background="{Binding Appointment.CustomFields[VMForCustomField].AppointmentColors.ResourceAndCustomerBackground}" />
<!-- /Klientenfarbe & Ressourcenfarbe -->
</Grid>
</Border>
</DataTemplate>
<DataTemplate x:Key="HorizontalAppointmentControl.ContentTemplate">
<Border Margin="-6,0,0,0" BorderThickness="{Binding Appointment.CustomFields[VMForCustomField].AppointmentBorderBrush, Converter={StaticResource AppointmentBorderThicknessConverter}}" BorderBrush="{Binding Appointment.CustomFields[VMForCustomField].AppointmentBorderBrush}" CornerRadius="2">
<Grid Background="{Binding Appointment.CustomFields[VMForCustomField].BackgroundColor}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="8" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="8" />
</Grid.ColumnDefinitions>
<!-- Mitarbeiterfarbe -->
<Border Grid.Column="0">
<Border.Background>
<MultiBinding Mode="OneWay" Converter="{StaticResource EmployeeBackgroundColorConverter}">
<Binding Path="DataContext.IsEmployeeBrushVisible" Mode="OneWay" UpdateSourceTrigger="PropertyChanged" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type localView:BeWoView}}" />
<Binding Path="Appointment.CustomFields[VMForCustomField].AppointmentColors.EmployeeBackground" />
<Binding Path="Appointment.CustomFields[VMForCustomField].BackgroundColor" />
</MultiBinding>
</Border.Background>
</Border>
<!-- /Mitarbeiterfarbe -->
<!-- Hauptteil mit Betreff und (Ort) -->
<dxschv:AppointmentContentPanel Grid.Column="1" Background="{Binding Appointment.CustomFields[VMForCustomField].BackgroundColor}" VerticalAlignment="Center">
<dxschv:AppointmentContentPanel.IntervalSubject>
<StackPanel Orientation="Horizontal">
<TextBlock Visibility="{Binding Appointment.AllDay, Converter={StaticResource BoolVisibilityConverter}, ConverterParameter=Reverse}" Foreground="{Binding Appointment.CustomFields[VMForCustomField].ForegroundColor}">
<Run Text="{Binding Appointment.Start, StringFormat={}{0:HH:mm}}" />
<Run Text="-" />
<Run Text="{Binding Appointment.End, StringFormat={}{0:HH:mm}}" />
</TextBlock>
<TextBlock Text="{Binding Appointment.Subject}" Margin="3,0,0,0" VerticalAlignment="Center" Foreground="{Binding Appointment.CustomFields[VMForCustomField].ForegroundColor}" />
</StackPanel>
</dxschv:AppointmentContentPanel.IntervalSubject>
<dxschv:AppointmentContentPanel.Images>
<dxschv:AppointmentImagesPanel Margin="0,3,3,0" Background="{Binding Appointment.CustomFields[VMForCustomField].BackgroundColor}" />
</dxschv:AppointmentContentPanel.Images>
</dxschv:AppointmentContentPanel>
<!-- /Hauptteil mit Betreff und (Ort) -->
<!-- Klientenfarbe & Ressourcenfarbe -->
<Border Grid.Column="2" Background="{Binding Appointment.CustomFields[VMForCustomField].AppointmentColors.ResourceAndCustomerBackground}"/>
<!-- /Klientenfarbe & Ressourcenfarbe -->
</Grid>
</Border>
</DataTemplate>
<DataTemplate x:Key="MyImageBox">
<Image Visibility="{Binding Path=Appointment.CustomFields[VMForCustomField].HasServiceRecordEntry, Converter={StaticResource BoolVisibilityConverter}}"
Source="/BeWoPlaner;component/Ressources/Icons/HistoryDisabled.png" SnapsToDevicePixels="True" Height="17" Width="17" />
</DataTemplate>
<Style x:Key="AppointmentStyle" TargetType="dxschv:AppointmentControl">
<Setter Property="ShowInterval" Value="True" />
<Setter Property="Margin" Value="0" />
<Setter Property="Padding" Value="0" />
<Setter Property="ImageBoxTemplate" Value="{StaticResource MyImageBox}" />
</Style>
<DataTemplate x:Key="TooltipTemplate">
<dxlc:LayoutControl IsHitTestVisible="False" Orientation="Vertical" Padding="0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="0" Margin="0,0,3,0" Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Orientation="Horizontal" Visibility="{Binding Path=Appointment.CustomFields[VMForCustomField].ToolTipTimeVisibility}">
<TextBlock Text="{Binding Path=Appointment.Start, StringFormat={}{0:HH:mm}}" />
<TextBlock Text=" - " />
<TextBlock Text="{Binding Path=Appointment.End, StringFormat={}{0:HH:mm}}" />
<TextBlock Text=" Uhr" Margin="0,0,4,0" />
</StackPanel>
<TextBlock Grid.Column="1" Text="{Binding Path=Appointment.CustomFields[VMForCustomField].ToolTip}" TextWrapping="Wrap" MaxWidth="{Binding ElementName=Scheduler, Path=ActualWidth}" />
</Grid>
<Separator Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Height="1" Background="DimGray" Visibility="{Binding Path=Appointment.CustomFields[VMForCustomField].ToolTipTrennstrichVisibility}" />
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,3,0" Text="Ressourcen:" Visibility="{Binding Path=Appointment.CustomFields[VMForCustomField].ToolTipResourcesVisibility}" />
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=Appointment.CustomFields[VMForCustomField].ResourcesToolTip}" Visibility="{Binding Path=Appointment.CustomFields[VMForCustomField].ToolTipResourcesVisibility}" />
<TextBlock Grid.Row="3" Grid.Column="0" Margin="0,0,3,0" Text="{markup:Translate Mitarbeiter:}" Visibility="{Binding Path=Appointment.CustomFields[VMForCustomField].ToolTipEmployeesVisibility}" />
<ListView Margin="-6,-3,0,0" Grid.Row="3" Background="Transparent" BorderThickness="0" ItemsSource="{Binding Path=Appointment.CustomFields[VMForCustomField].EmployeeList}" Grid.Column="1" Visibility="{Binding Path=Appointment.CustomFields[VMForCustomField].ToolTipEmployeesVisibility}" Name="ToolTipEmployeeList">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding (FrameworkElement.ActualWidth), RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"
ItemWidth="{Binding (ListView.View).ItemWidth, RelativeSource={RelativeSource AncestorType=ListView}}"
MinWidth="{Binding ItemWidth, RelativeSource={RelativeSource Self}}"
ItemHeight="{Binding (ListView.View).ItemHeight, RelativeSource={RelativeSource AncestorType=ListView}}" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="{Binding Converter={StaticResource EmployeeListConfirmationToolTipConverter}}" BorderThickness="1" BorderBrush="DimGray" Width="5" Margin="0,0,3,0" Visibility="{Binding Path=DataContext.Appointment.CustomFields[VMForCustomField].ToolTipZusageVisibility, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}" />
<TextBlock Grid.Column="1" Foreground="DimGray" Text="{Binding Converter={StaticResource EmployeeListConfirmationToolTipConverter}, ConverterParameter=EmployeeName}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBlock Margin="0,0,3,0" Grid.Row="4" Grid.Column="0" Text="{markup:Translate Klienten:}" Visibility="{Binding Path=Appointment.CustomFields[VMForCustomField].ToolTipCustomersVisibility}" />
<TextBlock Grid.Row="4" Grid.Column="1" Text="{Binding Path=Appointment.CustomFields[VMForCustomField].CustomersToolTip}"
Visibility="{Binding Path=Appointment.CustomFields[VMForCustomField].ToolTipCustomersVisibility}" />
<Separator Grid.Row="5" Grid.ColumnSpan="2" Grid.Column="0" Height="1" Background="DimGray" Visibility="{Binding Path=Appointment.CustomFields[VMForCustomField].CanBeEdited, Converter={StaticResource BoolVisibilityConverter}}" />
<TextBlock Margin="0,0,3,0" Grid.Row="6" Grid.Column="0" Text="Angelegt von:" Visibility="{Binding Path=Appointment.CustomFields[VMForCustomField].CanBeEdited, Converter={StaticResource BoolVisibilityConverter}}" />
<TextBlock Margin="0,0,3,0" Grid.Row="6" Grid.Column="1" Text="{Binding Path=Appointment.CustomFields[VMForCustomField].Originator}" Visibility="{Binding Path=Appointment.CustomFields[VMForCustomField].CanBeEdited, Converter={StaticResource BoolVisibilityConverter}}" />
</Grid>
</dxlc:LayoutControl>
</DataTemplate>
</ResourceDictionary>
</localView:BeWoView.Resources>
<Grid x:Name="RootGrid" Grid.IsSharedSizeScope="True" d:DataContext="{d:DesignInstance viewModel:SchedulingAppointmentListVM}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Column="0" x:Name="TopBarGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Orientation="Horizontal" Grid.Column="0" Grid.Row="0" VerticalAlignment="Bottom" MinWidth="239">
<StackPanel.Width>
<MultiBinding Converter="{StaticResource WidthAdditionMultiConverter}">
<Binding ElementName="AuswahlGrid" Path="ActualWidth" />
<Binding ElementName="LeftExpanderButton" Path="ActualWidth" />
</MultiBinding>
</StackPanel.Width>
<Button Margin="0,1,1,1" Height="24" Width="24" ToolTip="Tagesansicht" Click="DayViewButton_OnClick">
<Image Source="../../Ressources/Icons/Calendar1Day24.png"></Image>
</Button>
<Button Margin="0,1,1,1" Height="24" Width="24" ToolTip="Arbeitswoche anzeigen" Click="WorkWeekButton_OnClick">
<Image Source="../../Ressources/Icons/Calendar5Day24.png"></Image>
</Button>
<Button Margin="0,1,1,1" Height="24" Width="24" ToolTip="Volle Woche anzeigen" Click="WeekButton_OnClick">
<Image Source="../../Ressources/Icons/Calendar7Day24.png"></Image>
</Button>
<Button Margin="0,1,1,1" Height="24" Width="24" ToolTip="Monat anzeigen" Click="MonthButton_OnClick">
<Image Source="../../Ressources/Icons/Calendar31Day24.png"></Image>
</Button>
<Button Margin="0,1,1,1" Height="24" Width="24" ToolTip="Zeitleiste anzeigen" Click="TimelineButton_OnClick">
<Image Source="../../Ressources/Icons/History24.png"></Image>
</Button>
<Button Margin="0,1,1,1" Height="24" Width="24" ToolTip="Termine löschen"
x:Name="DeleteAppointmentsButton" Click="DeleteAppointmentsInIntervalButton_OnClick"
Visibility="{Binding DeleteInInvervalButtonVisibility, UpdateSourceTrigger=PropertyChanged}">
<Image Source="../../Ressources/Icons/Delete24.png"></Image>
</Button>
<StackPanel x:Name="DayViewOptions" Orientation="Horizontal"
Visibility="{Binding ElementName=SchedulerControl, Path=ActiveView.Type, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource DayViewDayCountVisibilityConverter}, ConverterParameter=DayCount}">
<Label VerticalAlignment="Center" Content="anz Tage:" />
<dxe:SpinEdit MinValue="1" MaxValue="100" VerticalAlignment="Center"
x:Name="SpinEditDayViewDayCount" AllowNullInput="False" Height="23" Width="50" IsFloatValue="False"
LostFocus="SpinEditDayViewDayCount_OnLostFocus" EditValueChanged="SpinEditDayViewDayCount_EditValueChanged" />
</StackPanel>
<StackPanel x:Name="TimelineViewOptions" Orientation="Horizontal"
Visibility="{Binding ElementName=SchedulerControl, Path=ActiveView.Type, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource DayViewDayCountVisibilityConverter}, ConverterParameter=IntervalCount}">
<Label VerticalAlignment="Center" Content="anz Tage:" />
<dxe:SpinEdit MinValue="1" MaxValue="100" VerticalAlignment="Center"
x:Name="SpinEditTimelineViewDayCount" AllowNullInput="False" Height="23" Width="50" IsFloatValue="False"
LostFocus="SpinEditTimelineViewDayCount_OnLostFocus" EditValueChanged="SpinEditTimelineViewDayCount_EditValueChanged" />
</StackPanel>
<Button Click="ReloadButton_OnClick" Margin="5,1,1,1" ToolTip="Kalender aktualisieren" Width="24" Height="24">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Image x:Name="imgDisabled" Source="..\..\Ressources\Icons\SymbolRefresh32Disabled.png" />
<Image x:Name="imgEnabled" Source="..\..\Ressources\Icons\SymbolRefresh32.png" Opacity="0" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Opacity" TargetName="imgEnabled" Value="1" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Button.Template>
</Button>
<Button Click="ExportButton_OnClick" Margin="5,1,1,1" ToolTip="Exportieren" Width="24" Height="24" Visibility="Collapsed"/>
</StackPanel>
<Grid Grid.Column="2" Grid.Row="0" Margin="6,0,0,0" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" Visibility="{Binding EmployeeControlsVisibility, UpdateSourceTrigger=PropertyChanged}" Content="{markup:Translate Mitarbeiterfarben}"
x:Name="MitarbeiterfarbenEinAusCheckBox"
IsChecked="{Binding Path=IsEmployeeBrushVisible}" />
<CheckBox Grid.Column="1" Content="Abwesenheiten" Margin="10,0,0,0" x:Name="AbwesenheitenEinAusCheckBox" Checked="AbwesenheitenEinAusCheckBox_OnChecked"
Unchecked="AbwesenheitenEinAusCheckBox_OnChecked"
IsChecked="{Binding Path=IsAbsenceTimeVisible, Mode=TwoWay}" />
<CheckBox Grid.Column="2" VerticalAlignment="Center" Margin="10,0,0,0" Content="Aufgaben" x:Name="ShowTasksCheckBox" IsChecked="{Binding Path=IsTasksVisible, Mode=TwoWay}" Click="ShowTasksCheckBox_OnClick" />
<TextBlock IsEnabled="{Binding Enabled, UpdateSourceTrigger=PropertyChanged}" Grid.Column="3" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="10,0,0,0">
<Hyperlink RequestNavigate="ShowAppointmentRequests" NavigateUri="#" IsEnabled="{Binding Enabled, UpdateSourceTrigger=PropertyChanged}">
<TextBlock Text="{Binding Requests, UpdateSourceTrigger=PropertyChanged}" />
</Hyperlink>
</TextBlock>
<CheckBox Grid.Column="4" IsChecked="{Binding OnlyPrivateAppointments, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Right" VerticalAlignment="Center" Content="Nur private Termine anzeigen" x:Name="ShowPrivateAppointmentsCheckBox" Click="ShowPrivateAppointmentsCheckBox_OnClick" />
</Grid>
<Border Grid.Row="0" Grid.Column="3" Width="{Binding ElementName=RightExpanderButton, Path=ActualWidth}" />
<Border Grid.Row="0" Grid.Column="4" Width="{Binding ElementName=DateNavigator, Path=ActualWidth}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
<Hyperlink NavigateUri="#" RequestNavigate="PrintCalendar">
<TextBlock>Drucken</TextBlock>
</Hyperlink>
</TextBlock>
</Border>
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" SharedSizeGroup="A" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" SharedSizeGroup="A" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" x:Name="ObjectSelectionGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- ToDo: Kann man weder Mitarbeiter, Klienten und Ressourcen sehen, "Nur meine Termine anzeigen", das AuswahlGrid, und den Togglebutton verschicken -->
<CheckBox x:Name="ZeigeNurMeineTermineCheckBox" Grid.Row="0" Grid.Column="0" Content="Nur meine Termine anzeigen" Margin="3, 3, 3, 3" IsChecked="{Binding Path=ZeigeNurMeineTermine, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Checked="NurMeineTermineEinAusCheckBox_OnChecked" Unchecked="NurMeineTermineEinAusCheckBox_OnChecked" />
<UniformGrid Grid.Column="0" x:Name="AuswahlGrid" Rows="2" Columns="1" Width="270" Grid.Row="1">
<TabControl SelectionChanged="Selector_OnSelectionChanged" SelectedIndex="{Binding SelectedTabItemIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" x:Name="TabControl" Visibility="{Binding SelectionControlVisibility, UpdateSourceTrigger=PropertyChanged}">
<!-- #region Mitarbeiterauswahl -->
<TabItem Visibility="{Binding EmployeeControlsVisibility, UpdateSourceTrigger=PropertyChanged}" Header="{markup:Translate Mitarbeiter}" Style="{StaticResource MitarbeiterTabItemStyle}" x:Name="MitarbeiterTabItem">
<Grid x:Name="MitarbeiterTabGrid" Visibility="{Binding EmployeeControlsVisibility, UpdateSourceTrigger=PropertyChanged}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<CheckBox Foreground="#FFD2D2D2" Grid.Column="0" Content="Alle auswählen" Margin="3" x:Name="AlleMitarbeiterCB" Click="AllEmployeesCheckBox_OnClick" />
<ToggleButton Margin="3" Grid.Row="0" Grid.Column="1" Height="17" Width="36" Style="{StaticResource LupenToggleButtonStyle}" x:Name="EmployeeSearchToggleButton" Checked="EmployeeSearchToggleButton_OnCheckedUnchecked" Unchecked="EmployeeSearchToggleButton_OnCheckedUnchecked" />
<Grid x:Name="MitarbeiterSuchGrid" Margin="0,1,0,3" Grid.Column="0" Grid.ColumnSpan="2" Background="Black" Grid.Row="1" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Content="Suche:" Grid.Column="0" Foreground="White" />
<TextBox x:Name="MitarbeiterSuchTextBox" Grid.Column="1" TextChanged="TextBoxEmployees_OnTextChanged" Margin="3" VerticalContentAlignment="Center" />
<Button Grid.Column="2" Style="{DynamicResource CloseButtonStyle}" Width="19" Height="19" Margin="0,3,3,3" ToolTip="Suchfeld leeren" Click="ClearEmployeeSearchButton_OnClick" />
</Grid>
<ListView Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2" Margin="0" ItemsSource="{Binding Path=FilteredEmployees, UpdateSourceTrigger=PropertyChanged}" Background="Transparent" BorderThickness="0">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="Margin" Value="0,2,2,0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border CornerRadius="5" MinHeight="25" Background="Transparent" />
<Border x:Name="ItemBorder" CornerRadius="5" MinHeight="25" Background="#FF000000">
<Border.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#19000000" Offset="0" />
<GradientStop Color="#26000000" Offset="1" />
</LinearGradientBrush>
</Border.OpacityMask>
</Border>
<Border x:Name="ItemContent" CornerRadius="5" MinHeight="25">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,3,5,3" OpacityMask="{x:Null}" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox Content="{Binding Path=Employee.DetailDescription}"
Click="ListItem_OnClick" Checked="EmployeeListViewCheckBox_OnChecked" Unchecked="EmployeeListViewCheckBox_OnChecked"
IsChecked="{Binding Path=(schedulingUtils:ListItemHelper.IsChecked), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Foreground" Value="#FFD2D2D2"/>
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(schedulingUtils:ListItemHelper.IsChecked)}" Value="False" />
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
<Border Width="15" Height="15" Grid.Column="1" Background="{Binding Path=Employee.FilterableBrush}" CornerRadius="3" />
<Button x:Name="btn_showEmployeeInformation" Width="15" Height="15" Grid.Column="2" Margin="5 0 5 0"
Click="EmployeeInformationButton_OnClick" FontFamily="Microsoft Sans Serif" Content="i"
Visibility="{Binding Converter={StaticResource InfoButtonVisibilityConverter}}" />
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#33000000" Offset="0" />
<GradientStop Color="#66000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ListBoxItem.IsSelected" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#70000000" Offset="0" />
<GradientStop Color="#BB000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ListBoxItem.IsSelected" Value="True" />
<Condition Property="Selector.IsSelectionActive" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#70000000" Offset="0" />
<GradientStop Color="#B2000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
</TabItem>
<!-- #endregion Mitarbeiterauswahl -->
<!-- #region Klientenauswahl -->
<TabItem Visibility="{Binding CustomerControlsVisibility, UpdateSourceTrigger=PropertyChanged}" Header="{markup:Translate Klienten}" Style="{StaticResource KlientenTabItemStyle}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<CheckBox Foreground="#FFD2D2D2" Grid.Row="0" Grid.Column="0" Content="Alle auswählen" Margin="3" x:Name="SelectAllCustomersCheckBox" Click="AllCustomersCheckBox_Checked" HorizontalAlignment="Left" HorizontalContentAlignment="Center" />
<CheckBox Foreground="#FFD2D2D2" Grid.Row="0" Grid.Column="1" Content="{markup:Translate Nur meine Klienten}" Click="OnlyMyCustomersCheckBox_Click" Margin="3" HorizontalAlignment="Right" IsThreeState="False" HorizontalContentAlignment="Center" />
<ToggleButton Margin="3" Grid.Row="0" Grid.Column="2" Height="17" Width="36" Style="{StaticResource LupenToggleButtonStyle}" x:Name="CustomerSearchToggleButton" Checked="CustomerSearchToggleButton_OnCheckedUnchecked" Unchecked="CustomerSearchToggleButton_OnCheckedUnchecked" />
<Grid x:Name="KlientenSuchGrid" Margin="0,1,0,3" Grid.Column="0" Grid.ColumnSpan="3" Background="Black" Grid.Row="1" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Content="Suche:" Grid.Column="0" Foreground="White" />
<TextBox Grid.Column="1" TextChanged="TextBoxCustomers_OnTextChanged" Margin="3" VerticalContentAlignment="Center" x:Name="KlientenSuchTextBox" />
<Button Grid.Column="2" Style="{DynamicResource CloseButtonStyle}" Width="19" Height="19" Margin="0,3,3,3" ToolTip="Suchfeld leeren" Click="ClearCustomerSearchButton_OnClick" />
</Grid>
</Grid>
<ListView Grid.Row="1" ItemsSource="{Binding Path=FilteredCustomers, UpdateSourceTrigger=PropertyChanged}" Margin="0" Background="Transparent" BorderThickness="0">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorLevel=1, AncestorType={x:Type ItemsControl}, Mode=FindAncestor}}" />
<Setter Property="Margin" Value="0,2,2,0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Border CornerRadius="5" MinHeight="25" Background="Transparent" />
<Border x:Name="ItemBorder" CornerRadius="5" MinHeight="25" Background="#FF000000">
<Border.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#19000000" Offset="0" />
<GradientStop Color="#26000000" Offset="1" />
</LinearGradientBrush>
</Border.OpacityMask>
</Border>
<Border x:Name="ItemContent" CornerRadius="5" MinHeight="25">
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5,3,5,3" OpacityMask="{x:Null}" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox Tag="{Binding}" Content="{Binding Path=DetailDescription}" Click="ListItem_OnClick" VerticalAlignment="Center" FontSize="12" Foreground="#FFD2D2D2" FontFamily="Microsoft Sans Serif">
<CheckBox.IsChecked>
<MultiBinding Mode="OneWay" Converter="{StaticResource CheckBoxConverter}" ConverterParameter="Klienten">
<Binding Path="CustomerOid" Mode="OneWay" />
<Binding Path="DataContext" Mode="OneWay" UpdateSourceTrigger="PropertyChanged" RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type localView:BeWoView}}" />
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
<Button x:Name="btn_showCustomerInformation" Width="15" Height="15" Grid.Column="1" Margin="5 0 5 0" Click="CustomerInformationButton_OnClick" Visibility="{Binding Converter={StaticResource InfoButtonVisibilityConverter}}" FontFamily="Microsoft Sans Serif" Content="i"/>
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#33000000" Offset="0" />
<GradientStop Color="#66000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="ListBoxItem.IsSelected" Value="True">
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99000000" Offset="0" />
<GradientStop Color="#CC000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ListBoxItem.IsSelected" Value="True" />
<Condition Property="Selector.IsSelectionActive" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="OpacityMask" TargetName="ItemBorder">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99000000" Offset="0" />
<GradientStop Color="#B2000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
</TabItem>
<!-- #endregion Klientenauswahl -->
<!-- #region Ressourcenauswahl -->
<TabItem Visibility="{Binding ResourceControlsVisibility, UpdateSourceTrigger=PropertyChanged}" x:Name="RessourcenTabItem" Header="Ressourcen" Style="{StaticResource RessourcenTabItemStyle}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<CheckBox Grid.Row="0" Content="Alle auswählen" Margin="3" x:Name="SelectAllResourcesCheckBox" Click="AllResourcesCheckBox_OnClick" />
<TreeView Grid.Row="1" BorderThickness="0" ItemsSource="{Binding Path=Categories2Resources, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Background="Transparent" ItemContainerStyle="{StaticResource ResourceTreeViewStyle}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Value}">
<Border BorderBrush="{x:Null}" Height="23">
<TextBlock FontWeight="Bold" Text="{Binding Path=Key.ResourceCategory}" VerticalAlignment="Center" />
</Border>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<Border BorderThickness="0 0 0 0" BorderBrush="{Binding DataContract.Color}"
Tag="{Binding}"
Margin="1" Height="23">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<CheckBox Click="ListItem_OnClick" Checked="ResourceTreeViewCheckBox_OnChecked" Unchecked="ResourceTreeViewCheckBox_OnChecked"
IsChecked="{Binding Path=(schedulingUtils:TreeViewItemHelper.IsChecked), Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Foreground" Value="Black"/>
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(schedulingUtils:TreeViewItemHelper.IsChecked)}" Value="False" />
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
<Rectangle VerticalAlignment="Center" Stroke="Black" StrokeThickness="1" Margin="1,0,1,0" Height="10" Width="10"
Fill="{Binding DataContract.Color, Converter={StaticResource StringBrushConverter}}" />
<TextBlock VerticalAlignment="Center" Text="{Binding Path=DataContract.Name}" />
</StackPanel>
</Border>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</TabItem>
<!-- #endregion Ressourcenauswahl -->
</TabControl>
<!--#region Liste aller ausgewählten Mitarbeiter, Klienten, und Ressourcen -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<GroupBox Header="Ausgewählte Elemente" Style="{StaticResource ObjectEditGroupBox}" Grid.Row="0" Margin="0,3,0,0">
<ListBox Background="Transparent" ItemsSource="{Binding Path=SelectedItems}" IsSynchronizedWithCurrentItem="True"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch"
ItemContainerStyle="{DynamicResource MultiElementSelectionControlStyle}">
<ListBox.Template>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" SnapsToDevicePixels="True" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
<ScrollViewer Focusable="False" Padding="{TemplateBinding Padding}" HorizontalScrollBarVisibility="Disabled">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</ListBox.Template>
</ListBox>
</GroupBox>
<Button Grid.Row="1" Content="Auswahl aufheben" Height="23" HorizontalAlignment="Stretch" Click="AuswahlAufhebenClick" Margin="30,0,5,0" />
</Grid>
<!--#endregion /Liste aller ausgewählten Mitarbeiter, Klienten, und Ressourcen -->
</UniformGrid>
</Grid>
<!--#region Filter oben links -->
<StackPanel x:Name="FilterCheckBoxenStackPanel" Orientation="Vertical" Grid.Column="1" HorizontalAlignment="Center">
<CheckBox x:Name="MitarbeiterEbenenCheckBox" Visibility="{Binding EmployeeControlsVisibility, UpdateSourceTrigger=PropertyChanged}" Content="{markup:Translate Nur Mitarbeiter}" SnapsToDevicePixels="True" Margin="0,3,0,3" Checked="ListItem_OnClick" Unchecked="ListItem_OnClick" IsThreeState="False">
<CheckBox.LayoutTransform>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="270" />
</CheckBox.LayoutTransform>
</CheckBox>
<CheckBox x:Name="KlientenEbenenCheckBox" Visibility="{Binding CustomerControlsVisibility, UpdateSourceTrigger=PropertyChanged}" Content="{markup:Translate Nur Klienten}" SnapsToDevicePixels="True" Margin="0,0,0,3" Checked="ListItem_OnClick" Unchecked="ListItem_OnClick" IsThreeState="False">
<CheckBox.LayoutTransform>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="270" />
</CheckBox.LayoutTransform>
</CheckBox>
<CheckBox x:Name="RessourcenEbenenCheckBox" Visibility="{Binding ResourceControlsVisibility, UpdateSourceTrigger=PropertyChanged}" Content="Nur Ressourcen" SnapsToDevicePixels="True" Margin="0,0,0,3" Checked="ListItem_OnClick" Unchecked="ListItem_OnClick" IsThreeState="False">
<CheckBox.LayoutTransform>
<RotateTransform CenterX="0.5" CenterY="0.5" Angle="270" />
</CheckBox.LayoutTransform>
</CheckBox>
</StackPanel>
<!--#endregion Filter oben links -->
<ToggleButton Grid.Column="1" Style="{StaticResource VerticalExpanderLookAlikeToggleBotton}" Width="23" Height="23" Margin="3" Click="LeftExpanderClick" x:Name="LeftExpanderButton" />
<!-- SchedulerControl -->
<dxsch:SchedulerControl x:Name="SchedulerControl"
Grid.Column="2"
FirstDayOfWeek="Monday"
dx:ThemeManager.ThemeName="Office2010Black"
ActiveViewType="WorkWeekView"
ToolTipMode="ToolTip"
SelectedAppointmentsSource="{Binding SelectedAppointments}"
SelectedInterval="{Binding Interval, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
EditOccurrenceWindowShowing="SchedulerControl_OnEditOccurrenceWindowShowing"
AppointmentWindowShowing="SchedulerControl_OnAppointmentWindowShowing"
CustomAllowAppointmentCreate="SchedulerControl_CustomAllowAppointmentCreate"
CustomAllowAppointmentEdit="SchedulerControl_CustomAllowAppointmentEdit"
CustomAllowAppointmentDrag="SchedulerControl_CustomAllowAppointmentEdit"
CustomAllowAppointmentResize="SchedulerControl_CustomAllowAppointmentEdit"
CustomAllowAppointmentDragBetweenResources="SchedulerControl_CustomAllowAppointmentEdit"
RecurrenceWindowShowing="SchedulerControl_OnRecurrenceWindowShowing"
DropAppointment="SchedulerControl_OnDropAppointment"
AppointmentRemoved="SchedulerControl_OnAppointmentRemoved"
CommitAppointmentResize="SchedulerControl_OnCommitAppointmentResize"
ToolTipContentTemplate="{StaticResource TooltipTemplate}"
PopupMenuShowing="SchedulerControl_OnPopupMenuShowing"
AppointmentAdded="SchedulerControl_OnAppointmentAdded"
PastingFromClipboard="SchedulerControl_OnPastingFromClipboard"
AppointmentRemoving="SchedulerControl_OnAppointmentRemoving"
>
<dxsch:SchedulerControl.OptionsContextMenu>
<dxsch:OptionsContextMenu>
<dxsch:OptionsContextMenu.CellContextMenuActions>
<!--
<dxb:RemoveAction ElementName="{x:Static Member=dxsch:DefaultBarItemNames.ContextMenu_Items_AppointmentDrop_Actions_CopyAppointmentsOnDrop}"/>
-->
<dxb:RemoveAction ElementName="{x:Static Member=dxsch:DefaultBarItemNames.ContextMenu_Items_Cell_Actions_NewRecurringEvent}" />
<dxb:RemoveAction ElementName="{x:Static Member=dxsch:DefaultBarItemNames.ContextMenu_Items_Cell_Actions_NewAllDayEvent}" />
<dxb:RemoveAction ElementName="{x:Static Member=dxsch:DefaultBarItemNames.ContextMenu_Items_Cell_Actions_Paste}" />
<dxb:RemoveAction ElementName="{x:Static Member=dxsch:DefaultBarItemNames.ContextMenu_Items_Cell_Actions_NewRecurringAppointment}" />
<dxb:InsertAction>
<dxb:BarButtonItem Content="Verfügbare Mitarbeiter anzeigen" ItemClick="EmployeeAvailabilityBarItem_OnItemClick" />
</dxb:InsertAction>
</dxsch:OptionsContextMenu.CellContextMenuActions>
<dxsch:OptionsContextMenu.AppointmentContextMenuActions>
<dxb:RemoveAction ElementName="{x:Static Member=dxsch:DefaultBarItemNames.ContextMenu_Items_Appointment_Options_ShowTimeAs}" />
<dxb:RemoveAction ElementName="{x:Static Member=dxsch:DefaultBarItemNames.ContextMenu_Items_Appointment_Options_LabelAs}" />
<dxb:RemoveAction ElementName="{x:Static Member=dxsch:DefaultBarItemNames.ContextMenu_Items_Appointment_Actions_Cut}" />
<dxb:RemoveAction ElementName="{x:Static Member=dxsch:DefaultBarItemNames.ContextMenu_Items_Appointment_Actions_Copy}" />
<dxb:RemoveAction ElementName="{x:Static Member=dxsch:DefaultBarItemNames.ContextMenu_Items_Appointment_Actions_Paste}" />
<dxb:InsertAction>
<dxb:BarItemSeparator Name="ZusagenStackSeperatorTop" />
</dxb:InsertAction>
<dxb:InsertAction>
<dxb:BarButtonItem Content="Zusagen" ItemClick="ConfirmParticipationBarButtonItem_OnClick" />
</dxb:InsertAction>
<dxb:InsertAction>
<dxb:BarButtonItem Content="Mit Vorbehalt zusagen" ItemClick="AcceptWithReservationParticipationBarButtonItem_OnClick" />
</dxb:InsertAction>
<dxb:InsertAction>
<dxb:BarButtonItem Content="Absagen" ItemClick="DeclineParticipationBarButtonItem_OnClick" />
</dxb:InsertAction>
<dxb:InsertAction>
<dxb:BarItemSeparator Name="ZusagenStackSeperatorBottom" />
</dxb:InsertAction>
<dxb:InsertAction>
<dxb:BarButtonItem Content="{markup:Translate In Zeiterfassung übertragen}" ItemClick="ZeiterfassungButtonItem_OnItemClick" />
</dxb:InsertAction>
<dxb:InsertAction>
<dxb:BarButtonItem Content="Verfügbare Mitarbeiter anzeigen" ItemClick="EmployeeAvailabilityBarItem_OnItemClick" />
</dxb:InsertAction>
</dxsch:OptionsContextMenu.AppointmentContextMenuActions>
</dxsch:OptionsContextMenu>
</dxsch:SchedulerControl.OptionsContextMenu>
<dxsch:SchedulerControl.OptionsWindows>
<dxsch:OptionsWindows AppointmentWindowType="{x:Type local:AppointmentEditView}"
RecurrenceWindowType="{x:Type local:AppointmentRecurrenceEditView}" />
</dxsch:SchedulerControl.OptionsWindows>
<dxsch:SchedulerControl.DataSource>
<dxsch:DataSource AppointmentsSource="{Binding VMList}">
<dxsch:DataSource.AppointmentMappings>
<dxsch:AppointmentMappings
Id="Id"
LabelId="LabelKey"
Start="Start"
End="End"
Subject="Subject"
Description="Description"
AllDay="AllDay"
RecurrenceInfo="RecurrenceInfo"
Location="Location"
Type="EventType"
>
<dxsch:CustomFieldMapping Mapping="VMForCustomField" Name="VMForCustomField" />
<dxsch:CustomFieldMapping Mapping="EmployeeList" Name="EmployeeList" />
<dxsch:CustomFieldMapping Mapping="CustomerList" Name="CustomerList" />
<dxsch:CustomFieldMapping Mapping="ResourceList" Name="ResourceList" />
<dxsch:CustomFieldMapping Mapping="Originator" Name="Originator" />
<dxsch:CustomFieldMapping Mapping="SupportConceptList" Name="SupportConceptList" />
<dxsch:CustomFieldMapping Mapping="IsPrivate" Name="IsPrivate" />
<dxsch:CustomFieldMapping Mapping="IsAbsenceTime" Name="IsAbsenceTime" />
<dxsch:CustomFieldMapping Mapping="IsTask" Name="IsTask" />
<dxsch:CustomFieldMapping Mapping="TaskDescription" Name="TaskDescription" />
<dxsch:CustomFieldMapping Mapping="CompletedNotice" Name="CompletedNotice" />
<dxsch:CustomFieldMapping Mapping="CompletedDate" Name="CompletedDate" />
<dxsch:CustomFieldMapping Mapping="DueDate" Name="DueDate" />
<dxsch:CustomFieldMapping Mapping="DueTime" Name="DueTime" />
<dxsch:CustomFieldMapping Mapping="AppointmentColors" Name="AppointmentColors" />
<dxsch:CustomFieldMapping Mapping="BackgroundColor" Name="BackgroundColor" />
<dxsch:CustomFieldMapping Mapping="ForegroundColor" Name="ForegroundColor" />
<dxsch:CustomFieldMapping Mapping="CanBeEdited" Name="CanBeEdited" />
<dxsch:CustomFieldMapping Mapping="ToolTip" Name="ToolTip" />
<dxsch:CustomFieldMapping Mapping="ToolTipTimeVisibility" Name="ToolTipTimeVisibility" />
<dxsch:CustomFieldMapping Mapping="ToolTipResourcesVisibility" Name="ToolTipResourcesVisibility" />
<dxsch:CustomFieldMapping Mapping="ToolTipEmployeesVisibility" Name="ToolTipEmployeesVisibility" />
<dxsch:CustomFieldMapping Mapping="ToolTipCustomersVisibility" Name="ToolTipCustomersVisibility" />
<dxsch:CustomFieldMapping Mapping="ToolTipTrennstrichVisibility" Name="ToolTipTrennstrichVisibility" />
<dxsch:CustomFieldMapping Mapping="ToolTipZusageVisibility" Name="ToolTipZusageVisibility" />
<dxsch:CustomFieldMapping Mapping="ResourcesToolTip" Name="ResourcesToolTip" />
<dxsch:CustomFieldMapping Mapping="EmployeesToolTip" Name="EmployeesToolTip" />
<dxsch:CustomFieldMapping Mapping="CustomersToolTip" Name="CustomersToolTip" />
</dxsch:AppointmentMappings>
</dxsch:DataSource.AppointmentMappings>
</dxsch:DataSource>
</dxsch:SchedulerControl.DataSource>
<dxsch:DayView ShowAppointmentStatus="False"
AppointmentStyle="{StaticResource AppointmentStyle}"
ShowAllDayArea="True"
ResourcesPerPage="0"
ShowAppointmentRecurrenceImage="True"
ShowAllDayAppointmentRecurrenceImage="True"
AppointmentContentTemplate="{StaticResource VerticalAppointmentControl.ContentTemplate}"
AllDayAppointmentContentTemplate="{StaticResource HorizontalAppointmentControl.ContentTemplate}" />
<dxsch:WeekView ShowAppointmentStatus="False"
AppointmentStyle="{StaticResource AppointmentStyle}"
ShowAllDayArea="True"
ResourcesPerPage="0"
ShowAppointmentRecurrenceImage="True"
ShowAllDayAppointmentRecurrenceImage="True"
AppointmentContentTemplate="{StaticResource VerticalAppointmentControl.ContentTemplate}"
AllDayAppointmentContentTemplate="{StaticResource HorizontalAppointmentControl.ContentTemplate}" />
<dxsch:WorkWeekView ShowAppointmentStatus="False"
AppointmentStyle="{StaticResource AppointmentStyle}"
ShowAllDayArea="True"
ResourcesPerPage="0"
ShowAppointmentRecurrenceImage="True"
ShowAllDayAppointmentRecurrenceImage="True"
AppointmentContentTemplate="{StaticResource VerticalAppointmentControl.ContentTemplate}"
AllDayAppointmentContentTemplate="{StaticResource HorizontalAppointmentControl.ContentTemplate}" />
<dxsch:MonthView ShowAppointmentStatus="False"
AppointmentStyle="{StaticResource AppointmentStyle}"
ResourcesPerPage="0"
ShowAppointmentRecurrenceImage="True"
AppointmentContentTemplate="{StaticResource HorizontalAppointmentControl.ContentTemplate}" />
<dxsch:AgendaView ShowAppointmentStatus="False"
AppointmentStyle="{StaticResource AppointmentStyle}"
ShowAppointmentRecurrenceImage="True"
AppointmentContentTemplate="{StaticResource HorizontalAppointmentControl.ContentTemplate}" />
<dxsch:TimelineView ShowAppointmentStatus="False"
AppointmentStyle="{StaticResource AppointmentStyle}"
ResourcesPerPage="0"
ViewMode="Legacy"
ShowAppointmentRecurrenceImage="True"
AppointmentContentTemplate="{StaticResource HorizontalAppointmentControl.ContentTemplate}" />
</dxsch:SchedulerControl>
<ToggleButton Grid.Column="3" Style="{StaticResource VerticalRightExpanderLookAlikeToggleBotton}" Width="23" Height="23" Margin="3" Click="RightExpanderClick" x:Name="RightExpanderButton" />
<dxe:DateNavigator x:Name="DateNavigator" Grid.Column="4" HighlightSpecialDates="True" VerticalAlignment="Stretch" dx:ThemeManager.ThemeName="Office2010Black" SelectedDatesChanged="DateNavigator_OnSelectedDatesChanged" FirstDayOfWeek="Monday" CalendarView="Month">
<dxe:DateNavigator.StyleSettings>
<dxsch:SchedulerDateNavigatorStyleSettings Scheduler="{Binding ElementName=SchedulerControl}" />
</dxe:DateNavigator.StyleSettings>
</dxe:DateNavigator>
</Grid>
<Border Grid.Row="0" Grid.RowSpan="2" x:Name="PopupContent" />
<Popup Grid.Row="0" StaysOpen="True" Placement="MousePoint" Width="290" Height="80" Closed="popup_Closed" Opened="popup_Opened" x:Name="DeleteAppointmentsPopup">
<Grid Background="{StaticResource ControlBackground}" Margin="2,2,2,2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Column="0" Grid.Row="0" Content="Termine löschen bis: " Height="24" Margin="0,0,0,0" />
<dxe:DateEdit Grid.Column="1" Grid.Row="0" MaskType="DateTimeAdvancingCaret" Width="150" Height="24" VerticalAlignment="Center" Margin="0,0,0,0" x:Name="DeleteForGoodIntervalEndDateEdit" />
<StackPanel Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,10,0">
<Button Content="OK" Click="DeleteAppointmentsForGood_Click" />
<Button Content="Abbrechen" Margin="3,0,0,0" Click="AbortDeletingAppointments_Click" />
</StackPanel>
</Grid>
</Popup>
</Grid>
</localView:BeWoView>

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,222 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using BeWo.Scheduling.SchedulingUtils;
using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Compact;
using BS.Shared.Extensions;
using DevExpress.Xpf.Scheduling;
using DevExpress.XtraScheduler;
using SchedulerControl = DevExpress.Xpf.Scheduling.SchedulerControl;
using Utils = BS.Shared.Core.Utils;
namespace BeWo.Scheduling.ViewModel
{
public class AppointmentWindowVM : AppointmentWindowViewModel
{
#region Verfügbage Mitarbeiter, Klienten und Ressourcen
private ObservableCollection<CompactEmployeeDC> _AllEmployees;
public ObservableCollection<CompactEmployeeDC> AllEmployees
{
get => _AllEmployees;
set
{
if(!ICollectionExtensions.ListEquals(_AllEmployees, value))
{
_AllEmployees = value;
RaisePropertyChanged(nameof(AllEmployees));
}
}
}
private ObservableCollection<CompactCustomerDC> _AllCustomers;
public ObservableCollection<CompactCustomerDC> AllCustomers
{
get => _AllCustomers;
set
{
if(!ICollectionExtensions.ListEquals(_AllCustomers, value))
{
_AllCustomers = value;
RaisePropertyChanged(nameof(AllCustomers));
}
}
}
private ObservableDictionary<CategoryDependencyObject, List<ResourceDependencyObject>> _AllCategories2Resources;
public ObservableDictionary<CategoryDependencyObject, List<ResourceDependencyObject>> AllCategories2Resources
{
get => _AllCategories2Resources;
set
{
if(!SchedulingUtils.Utils.Categories2ResourcesEquals(_AllCategories2Resources, value))
{
_AllCategories2Resources = value;
RaisePropertiesChanged(nameof(AllCategories2Resources));
}
}
}
#endregion
public string OriginalRecurrenceInfo { get; }
public SchedulingAppointmentVM ActualViewModel { get; }
public ObservableCollection<Employee2SchedulerAppointmentDC> EmployeeList
{
get => ActualViewModel.EmployeeList; //Appointment.CustomFields["EmployeeList"] as ObservableCollection<Employee2SchedulerAppointmentDC>;
set => ActualViewModel.EmployeeList = value; //Appointment.CustomFields["EmployeeList"] = value;
}
public List<CompactCustomerDC> CustomerList
{
get => ActualViewModel.CustomerList; //Appointment.CustomFields["CustomerList"] as List<CompactCustomerDC>;
set => ActualViewModel.CustomerList = value; //Appointment.CustomFields["CustomerList"] = value;
}
public List<ResourceDC> ResourceList
{
get => ActualViewModel.ResourceList; //Appointment.CustomFields["ResourceList"] as List<ResourceDC>;
set => ActualViewModel.ResourceList = value; //Appointment.CustomFields["ResourceList"] = value;
}
public ObservableCollection<CompactSupportConceptDC> SupportConceptList
{
get => ActualViewModel.SupportConceptList; //Appointment.CustomFields["SupportConceptList"] as List<CompactSupportConceptDC>;
set => ActualViewModel.SupportConceptList = value; //Appointment.CustomFields["SupportConceptList"] = value;
}
public bool IsTask
{
get => ActualViewModel.IsTask; //Appointment.CustomFields["IsTask"] is bool isTask && isTask;
set => ActualViewModel.IsTask = value; //Appointment.CustomFields["IsTask"] = value;
}
public bool IsPrivate
{
get => ActualViewModel.IsPrivate; //Appointment.CustomFields["IsPrivate"] is bool isPrivate && isPrivate;
set => ActualViewModel.IsPrivate = value; //Appointment.CustomFields["IsPrivate"] = value;
}
public bool IsReadyOnly { get; }
public bool IsNew => ActualViewModel?.IsNew ?? false;
public CompactEmployeeDC Originator
{
get => ActualViewModel.Originator; //Appointment.CustomFields["Originator"] as CompactEmployeeDC;
set => ActualViewModel.Originator = value; //Appointment.CustomFields["Originator"] = value;
}
public bool IsAbsenceTime => ActualViewModel.IsAbsenceTime; //Appointment.CustomFields["IsAbsenceTime"] is bool isAbsenceTime && isAbsenceTime;
public string TaskDescription
{
get => ActualViewModel.TaskDescription; //Appointment.CustomFields["TaskDescription"] as string;
set => ActualViewModel.TaskDescription = value; //Appointment.CustomFields["TaskDescription"] = value;
}
public string CompletedNotice
{
get => ActualViewModel.CompletedNotice; //Appointment.CustomFields["CompletedNotice"] as string;
set => ActualViewModel.CompletedNotice = value; //Appointment.CustomFields["CompletedNotice"] = value;
}
public DateTime? CompletedDate
{
get => ActualViewModel.CompletedDate; //Appointment.CustomFields["CompletedDate"] as DateTime?;
set => ActualViewModel.CompletedDate = value; //Appointment.CustomFields["CompletedDate"] = value;
}
public DateTime? DueDate
{
get => ActualViewModel.DueDate; //Appointment.CustomFields["DueDate"] as DateTime?;
set => ActualViewModel.DueDate = value; //Appointment.CustomFields["DueDate"] = value;
}
public DateTime? DueTime
{
get => ActualViewModel.DueTime; //Appointment.CustomFields["DueTime"] as DateTime?;
set => ActualViewModel.DueTime = value; //Appointment.CustomFields["DueTime"] = value;
}
public long? Oid => Appointment.Id as long?;
public string RecurrenceTypeName => TranslateRecurrenceInfoType();
public ObservableCollection<string> AvailableAppointmentRecurrenceTypes
{
get;
}
public Visibility RecurrenceButtonVisibility => (Appointment.Type == AppointmentType.Pattern || Appointment.Type == AppointmentType.Normal) && !IsTask ? Visibility.Visible : Visibility.Collapsed;
public AppointmentWindowVM(
AppointmentItem appointmentItem,
SchedulerControl scheduler,
ObservableCollection<CompactEmployeeDC> allEmployees,
ObservableCollection<CompactCustomerDC> allCustomers,
ObservableDictionary<CategoryDependencyObject, List<ResourceDependencyObject>> allCategories2Resources,
CompactEmployeeDC originator,
List<long> teamMemberCustomerOids,
SchedulingAppointmentVM viewModel)
: base(appointmentItem, scheduler)
{
ActualViewModel = viewModel;
OriginalRecurrenceInfo = viewModel.RecurrenceInfo;
AllEmployees = allEmployees;
AllCustomers = allCustomers;
AllCategories2Resources = allCategories2Resources;
ActualViewModel.Originator = originator;
ActualViewModel.SetDirty(false);
var userRightsCheckType = IsNew ? SchedulerRightsCheckType.Create : SchedulerRightsCheckType.Edit;
IsReadyOnly = !Utils.CheckSchedulerRights(CustomerList.ToList(), ResourceList.ToList(), EmployeeList.ToList(), Originator, IsNew, userRightsCheckType, BeWoApp.LoggedOnUser, teamMemberCustomerOids);
AvailableAppointmentRecurrenceTypes = new ObservableCollection<string>
{
"(keine)",
"täglich",
"wöchentlich",
"monatlich",
"jährlich"
};
}
private string TranslateRecurrenceInfoType()
{
if(RecurrenceInfo is null)
{
return "(keine)";
}
switch(RecurrenceInfo.Type)
{
case RecurrenceType.Daily:
return "täglich";
case RecurrenceType.Weekly:
return "wöchentlich";
case RecurrenceType.Monthly:
return "monatlich";
case RecurrenceType.Yearly:
return "jährlich";
default:
return "(keine)";
}
}
}
}

View File

@@ -0,0 +1,699 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using BeWo.Scheduling.SchedulingUtils;
using BeWo.ViewModel.ListViewModel;
using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Compact;
using BS.Shared.Extensions;
using DevExpress.Mvvm;
namespace BeWo.Scheduling.ViewModel
{
public class SchedulingAppointmentListVM : AbstractDCListMapperVM<SchedulerAppointmentDC, SchedulingAppointmentVM>
{
#region Filtereinstellungen
private bool _IsAbsenceTimeVisible;
public bool IsAbsenceTimeVisible
{
get => _IsAbsenceTimeVisible;
set
{
_IsAbsenceTimeVisible = value;
FirePropertyChanged(nameof(IsAbsenceTimeVisible));
}
}
private bool _IsTasksVisible;
public bool IsTasksVisible
{
get => _IsTasksVisible;
set
{
_IsTasksVisible = value;
FirePropertyChanged(nameof(IsTasksVisible));
}
}
private bool _OnlyPrivateAppointments;
public bool OnlyPrivateAppointments
{
get => _OnlyPrivateAppointments;
set
{
_OnlyPrivateAppointments = value;
FirePropertyChanged(nameof(OnlyPrivateAppointments));
}
}
public bool ZeigeNurMeineTermine
{
get => BeWoApp.AppSettings.ZeigeNurMeineTermine;
set
{
if(BeWoApp.AppSettings.ZeigeNurMeineTermine != value)
{
BeWoApp.AppSettings.ZeigeNurMeineTermine = value;
BeWoApp.SaveAppSettings();
FirePropertyChanged(nameof(ZeigeNurMeineTermine));
}
}
}
#endregion Filtereinstellungen
private int _SelectedTabItemIndex;
public int SelectedTabItemIndex
{
get => _SelectedTabItemIndex;
set
{
_SelectedTabItemIndex = value;
FirePropertyChanged(nameof(SelectedTabItemIndex));
}
}
public bool DisableUpdateRequestString = false;
private string _Requests;
public string Requests
{
get => _Requests ?? (_Requests = "keine Benachrichtigung");
set
{
if(AreDifferent(_Requests, value))
{
_Requests = value ?? string.Empty;
FirePropertyChanged(nameof(Requests));
}
}
}
private bool _IsEmployeeBrushVisible;
public bool IsEmployeeBrushVisible
{
get => _IsEmployeeBrushVisible;
set
{
_IsEmployeeBrushVisible = value;
FirePropertyChanged(nameof(IsEmployeeBrushVisible));
}
}
public bool IsInCustomerViewMode { get; set; }
public ObservableCollection<ResourceDC> AllResources
{
get
{
if(Categories2Resources?.Any() ?? false)
{
var result = new ObservableCollection<ResourceDC>();
foreach(var cat2Res in Categories2Resources)
{
foreach(var res in cat2Res.Value)
{
result.AddIfNotIn(res.DataContract);
}
}
return result;
}
return new ObservableCollection<ResourceDC>();
}
}
private ObservableSortCollection<EmployeeDependencyObject> _FilteredEmployees;
/// <summary>
/// Die nach Suchtext gefilterten Mitarbeiter
/// </summary>
public ObservableSortCollection<EmployeeDependencyObject> FilteredEmployees
{
get => _FilteredEmployees ?? (_FilteredEmployees = new ObservableSortCollection<EmployeeDependencyObject>(Employees));
set
{
if(!ICollectionExtensions.ListEquals(_FilteredEmployees, value))
{
_FilteredEmployees = value;
_FilteredEmployees.Sort((x, y) => string.Compare(x.Employee.LastName + ", " + x.Employee.FirstName, y.Employee.LastName + ", " + y.Employee.FirstName, StringComparison.Ordinal));
FirePropertyChanged(nameof(FilteredEmployees));
}
}
}
private ObservableSortCollection<CompactCustomerDC> _FilteredCustomers;
/// <summary>
/// Die nach Suchtext gefilterten Klienten
/// </summary>
public ObservableSortCollection<CompactCustomerDC> FilteredCustomers
{
get => _FilteredCustomers ?? (_FilteredCustomers = new ObservableSortCollection<CompactCustomerDC>(AllCustomers));
set
{
if(!ICollectionExtensions.ListEquals(_FilteredCustomers, value))
{
_FilteredCustomers = value;
_FilteredCustomers.Sort((x, y) => string.Compare(x.LastName + ", " + x.FirstName, y.LastName + ", " + y.FirstName, StringComparison.Ordinal));
FirePropertyChanged(nameof(FilteredCustomers));
}
}
}
private ObservableSortCollection<CompactCustomerDC> _CustomerList;
public ObservableSortCollection<CompactCustomerDC> CustomerList
{
get => _CustomerList ?? (_CustomerList = new ObservableSortCollection<CompactCustomerDC>());
set
{
if(!ICollectionExtensions.ListEquals(_CustomerList, value))
{
_CustomerList = value;
_CustomerList.Sort((x, y) => string.Compare(x.LastName + ", " + x.FirstName, y.LastName + ", " + y.FirstName, StringComparison.Ordinal));
FirePropertyChanged(nameof(CustomerList));
}
}
}
private List<CompactEmployeeDC> _SelectedEmployees = new List<CompactEmployeeDC>();
public List<CompactEmployeeDC> SelectedEmployees
{
get => _SelectedEmployees;
set
{
if(!ICollectionExtensions.ListEquals(_SelectedEmployees, value))
{
_SelectedEmployees = value;
_SelectedEmployees.Sort((x, y) => string.Compare(x.LastName + ", " + x.FirstName, y.LastName + ", " + y.FirstName, StringComparison.Ordinal));
AllEmployeesCheckBoxIsChecked = ICollectionExtensions.ListEquals(value, AllEmployees);
ZeigeNurMeineTermine = value.Count == 1 && value.Contains(BeWoApp.CompactLoggedOnEmployee);
UpdateSelectedItems();
}
}
}
private List<CompactCustomerDC> _SelectedCustomers = new List<CompactCustomerDC>();
public List<CompactCustomerDC> SelectedCustomers
{
get => _SelectedCustomers;
set
{
if(!ICollectionExtensions.ListEquals(_SelectedCustomers, value))
{
_SelectedCustomers = value;
_SelectedCustomers.Sort((x, y) => string.Compare(x.LastName + ", " + x.FirstName, y.LastName + ", " + y.FirstName, StringComparison.Ordinal));
if(OnlyMyCustomersCheckBoxIsChecked || ICollectionExtensions.ListEquals(AllCustomers, value))
{
AllCustomersCheckBoxIsChecked = true;
}
UpdateSelectedItems();
}
}
}
private List<ResourceDC> _SelectedResources = new List<ResourceDC>();
public List<ResourceDC> SelectedResources
{
get => _SelectedResources;
set
{
if(!ICollectionExtensions.ListEquals(_SelectedResources, value))
{
_SelectedResources = value;
AllResourcesCheckBoxChecked = ICollectionExtensions.ListEquals(value, AllResources);
UpdateSelectedItems();
}
}
}
private bool _AllEmployeesCheckBoxIsChecked;
public bool AllEmployeesCheckBoxIsChecked
{
get => _AllEmployeesCheckBoxIsChecked;
set
{
_AllEmployeesCheckBoxIsChecked = value;
FirePropertyChanged(nameof(AllEmployeesCheckBoxIsChecked));
UpdateSelectedItems();
}
}
private bool _OnlyMyCustomersCheckBoxIsChecked;
public bool OnlyMyCustomersCheckBoxIsChecked
{
get => _OnlyMyCustomersCheckBoxIsChecked;
set
{
if(AreDifferent(_OnlyMyCustomersCheckBoxIsChecked, value))
{
_OnlyMyCustomersCheckBoxIsChecked = value;
FilterCustomers();
SelectedCustomers.Clear();
SelectedCustomers = FilteredCustomers.ToList();
FirePropertyChanged(nameof(OnlyMyCustomersCheckBoxIsChecked));
UpdateSelectedItems();
}
}
}
private bool _AllCustomersCheckBoxIsChecked;
public bool AllCustomersCheckBoxIsChecked
{
get => _AllCustomersCheckBoxIsChecked;
set
{
_AllCustomersCheckBoxIsChecked = value;
FirePropertyChanged(nameof(AllCustomersCheckBoxIsChecked));
UpdateSelectedItems();
}
}
private bool _AllResourcesCheckBoxChecked;
public bool AllResourcesCheckBoxChecked
{
get => _AllResourcesCheckBoxChecked;
set
{
_AllResourcesCheckBoxChecked = value;
FirePropertyChanged(nameof(AllResourcesCheckBoxChecked));
UpdateSelectedItems();
}
}
public ObservableCollection<IDataContract> SelectedItems
{
get
{
var selectedItems = new ObservableCollection<IDataContract>();
selectedItems.AddRange(SelectedEmployees);
selectedItems.AddRange(SelectedCustomers);
selectedItems.AddRange(SelectedResources);
return selectedItems;
}
}
public IEnumerable<IDataContract> AllItems
{
get
{
var allItems = new List<IDataContract>();
allItems.AddRange(FilteredEmployees.Select(s => s.Employee));
allItems.AddRange((IEnumerable<IDataContract>)FilteredCustomers);
allItems.AddRange(AllResources);
return allItems;
}
}
public Visibility EmployeeControlsVisibility => BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderMitarbeitertermineAnsehen) ? Visibility.Visible : Visibility.Collapsed;
public Visibility ResourceControlsVisibility => BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderRessourcentermineAnsehen) ? Visibility.Visible : Visibility.Collapsed;
public Visibility CustomerControlsVisibility => BeWoApp.LoggedOnUser.HasRight(UserRightType.CustomerView_View) || BeWoApp.LoggedOnUser.HasRight(UserRightType.Customer_ViewMyTeams) || BeWoApp.LoggedOnUser.HasRight(UserRightType.Customer_ViewMyCustomers) || BeWoApp.LoggedOnUser.HasRight(UserRightType.ViewAll) ? Visibility.Visible : Visibility.Collapsed;
public Visibility SelectionControlVisibility => EmployeeControlsVisibility == Visibility.Visible || ResourceControlsVisibility == Visibility.Visible || CustomerControlsVisibility == Visibility.Visible ? Visibility.Visible : Visibility.Collapsed;
public Visibility DeleteInInvervalButtonVisibility => BeWoApp.LoggedOnUser.HasRight(UserRightType.Termine_IntervalDelete) ? Visibility.Visible : Visibility.Collapsed;
private DateTimeRange _Interval;
public DateTimeRange Interval
{
get => _Interval;
set
{
if(AreDifferent(_Interval, value))
{
_Interval = value;
FirePropertyChanged(nameof(Interval));
}
}
}
public void ReloadRights()
{
FirePropertyChanged(nameof(EmployeeControlsVisibility));
FirePropertyChanged(nameof(ResourceControlsVisibility));
FirePropertyChanged(nameof(CustomerControlsVisibility));
FirePropertyChanged(nameof(SelectionControlVisibility));
FirePropertyChanged(nameof(DeleteInInvervalButtonVisibility));
}
public bool ShouldLockOverlappingAppointmentCheck { get; set; }
private ObservableSortCollection<CompactCustomerDC> _AllCustomers;
public ObservableSortCollection<CompactCustomerDC> AllCustomers
{
get => _AllCustomers ?? (_AllCustomers = new ObservableSortCollection<CompactCustomerDC>());
set
{
if(AreDifferent(_AllCustomers, value))
{
_AllCustomers = value;
FilterCustomers();
FirePropertyChanged(nameof(AllCustomers));
}
}
}
private ObservableSortCollection<CompactEmployeeDC> _AllEmployees;
public ObservableSortCollection<CompactEmployeeDC> AllEmployees
{
get => _AllEmployees ?? (_AllEmployees = new ObservableSortCollection<CompactEmployeeDC>());
set
{
if(AreDifferent(_AllEmployees, value))
{
_AllEmployees = value;
FirePropertyChanged(nameof(AllEmployees));
}
}
}
public ObservableCollection<SchedulingAppointmentVM> SelectedAppointments { get; set; }
private ObservableDictionary<CategoryDependencyObject, List<ResourceDependencyObject>> _Categories2Resources;
public ObservableDictionary<CategoryDependencyObject, List<ResourceDependencyObject>> Categories2Resources
{
get => _Categories2Resources ?? (_Categories2Resources = new ObservableDictionary<CategoryDependencyObject, List<ResourceDependencyObject>>());
set
{
if(!SchedulingUtils.Utils.Categories2ResourcesEquals(_Categories2Resources, value))
{
_Categories2Resources = value;
FirePropertyChanged(nameof(Categories2Resources));
}
}
}
public List<CompactCustomerDC> OwnCustomers { get; }
public SchedulingAppointmentListVM()
{
Categories2Resources = new ObservableDictionary<CategoryDependencyObject, List<ResourceDependencyObject>>();
AllCustomers = new ObservableSortCollection<CompactCustomerDC>();
AllEmployees = new ObservableSortCollection<CompactEmployeeDC>();
SelectedAppointments = new ObservableCollection<SchedulingAppointmentVM>();
OwnCustomers = BeWoApp.LoggedOnEmployee.RelatedCustomers.Select(s => s.Customer).ToList();
UpdateSelectedItems();
InitViewModel();
}
public void AddAbsenceTimes(List<AbsenceTimeDC> absenceTimes, DateTime intervalEnd)
{
foreach(var absenceTime in absenceTimes.Where(w => w.Start != null))
{
var subject = absenceTime.Reason.Description;
var employee = absenceTime.EmployeeOid != null ? AllEmployees.FirstOrDefault(e => e.EmployeeOid == absenceTime.EmployeeOid.Value) : null;
if(employee != null)
{
subject += $" ({employee.SimpleDescription})";
}
var absenceTimeEnd = absenceTime.End?.AddTicks(1);
VMList.Add(new SchedulingAppointmentVM(true, subject, absenceTime.Start.Value, absenceTime.End ?? intervalEnd, employee, absenceTime.Start, absenceTimeEnd));
}
}
private bool _Enabled;
public bool Enabled
{
get => _Enabled;
set
{
_Enabled = value;
FirePropertyChanged(nameof(Enabled));
}
}
private void InitViewModel()
{
foreach(var item in VMList)
{
item.Id = item.DataContract.SchedulerAppointmentOid;
if(!item.IsPrivate || item.Originator.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid) || item.EmployeeList.Select(s => s.Employee).Contains(BeWoApp.CompactLoggedOnEmployee))
{
continue;
}
item.Description = "Privater Termin";
item.Subject = $"Privat ({item.Originator})";
}
}
private ObservableCollection<SchedulerAppointmentDC> _OpenAppointments;
public ObservableCollection<SchedulerAppointmentDC> OpenAppointments
{
get => _OpenAppointments;
set
{
if(AreDifferent(_OpenAppointments, value))
{
_OpenAppointments = value;
FirePropertyChanged(nameof(OpenAppointments));
}
}
}
public void FilterCustomers()
{
FilteredCustomers.Clear();
var customersToAdd = OnlyMyCustomersCheckBoxIsChecked ? AllCustomers.Where(customer => customer.IsRelatedToEmployee) : AllCustomers;
FilteredCustomers.AddRange(customersToAdd);
}
public void UpdateSelectedItems()
{
FirePropertyChanged(nameof(SelectedItems));
FirePropertyChanged(nameof(SelectedEmployees));
FirePropertyChanged(nameof(SelectedCustomers));
FirePropertyChanged(nameof(SelectedResources));
FirePropertyChanged(nameof(VMList));
FirePropertyChanged(nameof(Categories2Resources));
FirePropertyChanged(nameof(FilteredEmployees));
FirePropertyChanged(nameof(Employees));
FirePropertyChanged(nameof(AllEmployeesCheckBoxIsChecked));
}
public void UpdateEmployeeSelection()
{
AllEmployeesCheckBoxIsChecked = SelectedEmployees.Count == AllEmployees.Count;
}
public void UpdateEmployeeSelection2()
{
SelectedEmployees = GetSelectedEmployees();
FirePropertyChanged(nameof(Employees));
AllEmployeesCheckBoxIsChecked = SelectedEmployees.Count == AllEmployees.Count;
}
public void UpdateCustomerSelection()
{
AllCustomersCheckBoxIsChecked = SelectedCustomers.Count == AllCustomers.Count;
}
public void UpdateResourceSelection()
{
SelectedResources = new List<ResourceDC>(GetSelectedResources());
FirePropertyChanged(nameof(Categories2Resources));
AllResourcesCheckBoxChecked = SelectedResources.Count == AllResources.Count;
}
public void FilterEmployees(string searchText)
{
FilteredEmployees.Clear();
FilteredEmployees.AddRangeIfElementsNotIn(
Employees.Where(employeeDependencyObject => employeeDependencyObject.Employee.FirstName.ToLower().Contains(searchText.ToLower()) ||
employeeDependencyObject.Employee.LastName.ToLower().Contains(searchText.ToLower())
));
}
public void FilterCustomers(string searchText)
{
FilteredCustomers.Clear();
FilteredCustomers.AddRangeIfElementsNotIn(AllCustomers.Where(customer => customer.FirstName.ToLower().Contains(searchText.ToLower()) || customer.LastName.ToLower().Contains(searchText.ToLower())));
}
private IEnumerable<ResourceDC> GetSelectedResources()
{
var result = new List<ResourceDC>();
foreach(var cat2Res in Categories2Resources)
{
foreach(var resource in cat2Res.Value)
{
if(resource.GetValue(TreeViewItemHelper.IsCheckedProperty) is bool value && value)
{
result.AddIfNotIn(resource.DataContract);
}
}
}
return result;
}
public void DeselectResource(long oid)
{
foreach(var cat2Res in Categories2Resources)
{
foreach(var resource in cat2Res.Value)
{
if(resource.DataContract.ResourceOid.HasValue && resource.DataContract.ResourceOid.Value == oid)
{
resource.SetValue(TreeViewItemHelper.IsCheckedProperty, false);
}
}
}
}
public void DeselectAllResources()
{
foreach(var cat2Res in Categories2Resources)
{
foreach(var resource in cat2Res.Value)
{
resource.SetValue(TreeViewItemHelper.IsCheckedProperty, false);
}
}
SelectedResources.Clear();
}
public void SelectAllResources()
{
foreach(var cat2Res in Categories2Resources)
{
foreach(var resource in cat2Res.Value)
{
resource.SetValue(TreeViewItemHelper.IsCheckedProperty, true);
}
}
UpdateResourceSelection();
}
private ObservableSortCollection<EmployeeDependencyObject> _Employees;
public ObservableSortCollection<EmployeeDependencyObject> Employees
{
get => _Employees ?? (_Employees = new ObservableSortCollection<EmployeeDependencyObject>());
set
{
if(AreDifferent(_Employees, value))
{
_Employees = value;
FirePropertyChanged(nameof(Employees));
}
}
}
private List<CompactEmployeeDC> GetSelectedEmployees()
{
var result = new List<CompactEmployeeDC>();
foreach(var employee in Employees)
{
if(employee.GetValue(ListItemHelper.IsCheckedProperty) is bool isChecked && isChecked)
{
result.AddIfNotIn(employee.Employee);
}
}
return result;
}
public void DeselectEmployee(long oid)
{
foreach(var employeeDependencyObject in Employees)
{
if(employeeDependencyObject.Employee.EmployeeOid == oid)
{
employeeDependencyObject.SetValue(ListItemHelper.IsCheckedProperty, false);
}
}
}
public void DeselectAllEmployees()
{
foreach(var employeeDependencyObject in Employees)
{
employeeDependencyObject.SetValue(ListItemHelper.IsCheckedProperty, false);
}
SelectedEmployees.Clear();
}
public void SelectAllEmployees()
{
foreach(var employeeDependencyObject in Employees)
{
employeeDependencyObject.SetValue(ListItemHelper.IsCheckedProperty, true);
}
}
public void SelectEmployeesAfterReload()
{
foreach(var employeeDependencyObject in Employees)
{
var val = SelectedEmployees.Any(employee => employee.EmployeeOid == employeeDependencyObject.Employee.EmployeeOid);
employeeDependencyObject.SetValue(ListItemHelper.IsCheckedProperty, val);
}
}
}
}

View File

@@ -0,0 +1,875 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using BeWo.Scheduling.SchedulingUtils;
using BeWo.ViewModel;
using BS.Shared;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Compact;
using BS.Shared.Extensions;
using DevExpress.XtraScheduler;
using DevExpress.Xpf.Scheduling;
namespace BeWo.Scheduling.ViewModel
{
public class SchedulingAppointmentVM : AbstractDCMapperVM<SchedulerAppointmentDC>
{
public SchedulingAppointmentVM VMForCustomField => this;
private bool _AllDay;
private string _Description;
private DateTime _End;
private string _Location;
private string _RecurrenceInfo;
private DateTime _Start;
private int _Status;
private string _Subject;
private int _Type;
private bool _IsPrivate;
private ObservableCollection<Employee2SchedulerAppointmentDC> _EmployeeList;
private List<CompactCustomerDC> _CustomerList;
private List<ResourceDC> _ResourceList;
private ObservableCollection<CompactSupportConceptDC> _SupportConceptList;
private CompactEmployeeDC _Originator;
private bool _IsTask;
private string _TaskDescription;
private string _CompletedNotice;
private DateTime? _CompletedDate;
private DateTime? _DueDate;
private DateTime? _DueTime;
private bool _HasServiceRecordEntry;
private bool _IsArchived;
public bool HasServiceRecordEntry
{
get => _HasServiceRecordEntry;
set
{
if(AreDifferent(_HasServiceRecordEntry, value))
{
_HasServiceRecordEntry = value;
StoreDirtyInformation(AreDifferent(DataContract.HasServiceRecordEntry, value), nameof(HasServiceRecordEntry));
FirePropertyChanged(nameof(HasServiceRecordEntry));
}
}
}
public bool IsArchived
{
get => _IsArchived;
set
{
if(AreDifferent(_IsArchived, value))
{
_IsArchived = value;
StoreDirtyInformation((value && DataContract.ActivationType == ActivationTypeId.Active) || (!value && DataContract.ActivationType == ActivationTypeId.Archived), nameof(IsArchived));
FirePropertyChanged(nameof(IsArchived));
}
}
}
public DateTime? AbsenceTimeStart { get; set; }
public DateTime? AbsenceTimeEnd { get; set; }
public virtual string ReminderInfo { get; set; }
public virtual object Id { get; set; }
public virtual long? LabelKey { get; set; }
/// <summary>
/// Der AppointmentType des Termins als Integer; 0 = Pattern; 1 = Normal; 2 = Occurrence; 3 = ChangedOccurrence; 4 = DeletedOccurrence
/// </summary>
public virtual int EventType
{
get => _Type;
set
{
if(AreDifferent(_Type, value))
{
_Type = value;
StoreDirtyInformation(AreDifferent(DataContract.Type, value), nameof(Type));
FirePropertyChanged(nameof(Type));
}
}
}
public virtual DateTime End
{
get => _End;
set
{
if(AreDifferent(_End, value))
{
_End = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.EndDate, value), nameof(End));
FirePropertyChanged(nameof(End));
}
}
}
public virtual DateTime Start
{
get => _Start;
set
{
if(AreDifferent(_Start, value))
{
_Start = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.StartDate, value), nameof(Start));
FirePropertyChanged(nameof(Start));
}
}
}
public virtual bool AllDay
{
get => _AllDay;
set
{
if(AreDifferent(_AllDay, value))
{
_AllDay = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.AllDay, value), nameof(AllDay));
FirePropertyChanged(nameof(AllDay));
}
}
}
public virtual string Subject
{
get => _Subject;
set
{
if(AreDifferent(_Subject, value))
{
_Subject = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.Subject, value), nameof(Subject));
FirePropertyChanged(nameof(Subject));
}
}
}
public virtual string Location
{
get => _Location;
set
{
if(AreDifferent(_Location, value))
{
_Location = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.Location, value), nameof(Location));
FirePropertyChanged(nameof(Location));
}
}
}
public virtual int Status
{
get => _Status;
set
{
if(AreDifferent(_Status, value))
{
_Status = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.Status, value), nameof(Status));
FirePropertyChanged(nameof(Status));
}
}
}
public bool IsTeilnahmeBestaetigung { get; }
public virtual string RecurrenceInfo
{
get => _RecurrenceInfo;
set
{
if(AreDifferent(_RecurrenceInfo, value))
{
_RecurrenceInfo = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.RecurrenceInfo, value), nameof(RecurrenceInfo));
FirePropertyChanged(nameof(RecurrenceInfo));
}
}
}
public virtual string Description
{
get => _Description;
set
{
if(AreDifferent(_Description, value))
{
_Description = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.Description, value), nameof(Description));
FirePropertyChanged(nameof(Description));
}
}
}
public ObservableCollection<Employee2SchedulerAppointmentDC> EmployeeList
{
get => _EmployeeList ?? (_EmployeeList = new ObservableCollection<Employee2SchedulerAppointmentDC>());
set
{
if(AreDifferent(_EmployeeList, value))
{
_EmployeeList = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.EmployeeList, value), nameof(EmployeeList));
FirePropertyChanged(nameof(EmployeeList));
}
}
}
public List<CompactCustomerDC> CustomerList
{
get => _CustomerList ?? (_CustomerList = new List<CompactCustomerDC>());
set
{
if(AreDifferent(_CustomerList, value))
{
_CustomerList = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.CustomerList, value), nameof(CustomerList));
FirePropertyChanged(nameof(CustomerList));
}
}
}
public List<ResourceDC> ResourceList
{
get => _ResourceList ?? (ResourceList = new List<ResourceDC>());
set
{
if(AreDifferent(_ResourceList, value))
{
_ResourceList = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.ResourceList, value), nameof(ResourceList));
FirePropertyChanged(nameof(ResourceList));
}
}
}
public ObservableCollection<CompactSupportConceptDC> SupportConceptList
{
get => _SupportConceptList ?? (SupportConceptList = new ObservableCollection<CompactSupportConceptDC>());
set
{
if(AreDifferent(_SupportConceptList, value))
{
_SupportConceptList = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.SupportConceptList, value), nameof(SupportConceptList));
FirePropertyChanged(nameof(SupportConceptList));
}
}
}
public bool IsPrivate
{
get => _IsPrivate;
set
{
if(AreDifferent(_IsPrivate, value))
{
_IsPrivate = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.IsPrivate, value), nameof(IsPrivate));
FirePropertyChanged(nameof(IsPrivate));
}
}
}
public virtual CompactEmployeeDC Originator
{
get => _Originator;
set
{
if(AreDifferent(_Originator, value))
{
_Originator = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.Originator, value), nameof(Originator));
FirePropertyChanged(nameof(Originator));
}
}
}
public virtual TimeSpan EndTime => End.TimeOfDay;
public virtual TimeSpan StartTime => Start.TimeOfDay;
public virtual bool IsAbsenceTime { get; }
public bool IsTask
{
get => _IsTask;
set
{
if(AreDifferent(_IsTask, value))
{
_IsTask = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.IsTask, value), nameof(IsTask));
FirePropertyChanged(nameof(IsTask));
}
}
}
public string TaskDescription
{
get => _TaskDescription;
set
{
if(AreDifferent(_TaskDescription, value))
{
_TaskDescription = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.TaskDescription, value), nameof(TaskDescription));
FirePropertyChanged(nameof(TaskDescription));
}
}
}
public string CompletedNotice
{
get => _CompletedNotice;
set
{
if(AreDifferent(_CompletedNotice, value))
{
_CompletedNotice = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.CompletedNotice, value), nameof(CompletedNotice));
FirePropertyChanged(nameof(CompletedNotice));
}
}
}
public DateTime? CompletedDate
{
get => _CompletedDate;
set
{
if(AreDifferent(_CompletedDate, value))
{
_CompletedDate = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.CompletedDate, value), nameof(CompletedDate));
FirePropertyChanged(nameof(CompletedDate));
}
}
}
public DateTime? DueDate
{
get => _DueDate;
set
{
if(AreDifferent(_DueDate, value))
{
_DueDate = value;
if(IsAbsenceTime)
{
return;
}
StoreDirtyInformation(AreDifferent(DataContract.DueDate, value), nameof(DueDate));
FirePropertyChanged(nameof(DueDate));
}
}
}
public DateTime? DueTime
{
get => _DueTime;
set
{
if(AreDifferent(_DueTime, value))
{
_DueTime = value;
StoreDirtyInformation(AreDifferent(DataContract.DueDate, value), nameof(DueTime));
FirePropertyChanged(nameof(DueTime));
}
}
}
public Guid? RecurrenceId => BS.Shared.Core.Utils.GetRecurrenceIdFromRecurrenceInfo(RecurrenceInfo);
public int RecurrenceIndex => BS.Shared.Core.Utils.GetRecurrenceIndexFromRecurrenceInfo(RecurrenceInfo);
public bool CanBeEdited { get; set; } = true;
public AppointmentColorHelper AppointmentColors { get; set; }
public SolidColorBrush BackgroundColor { get; set; }
public SolidColorBrush ForegroundColor { get; set; }
public SolidColorBrush AppointmentBorderBrush
{
get
{
if(EmployeeList?.Any(e2a => e2a.Employee.Equals(BeWoApp.CompactLoggedOnEmployee) && e2a.ParticipationAnswer == ParticipationAnswer.Vorbehalt) ?? false)
{
return new SolidColorBrush(Color.FromRgb(185, 39, 217));
}
return new SolidColorBrush(Colors.Transparent);
}
}
public string ToolTip
{
get
{
var result = Subject;
if(IsTask)
{
result = result ?? "";
if(CompletedDate.HasValue)
{
result += $" erledigt am {CompletedDate.Value:dd.MM.yyyy}";
}
else if(DueDate.HasValue)
{
result += $" bis {DueDate.Value:dd.MM.yyyy HH:mm}";
}
}
if(IsAbsenceTime && AbsenceTimeStart.HasValue)
{
result += AbsenceTimeStart.Value.GetIntervalDescription(AbsenceTimeEnd);
}
return result;
}
}
public Visibility ToolTipTimeVisibility => IsTask || IsAbsenceTime || AllDay ? Visibility.Collapsed : Visibility.Visible;
public Visibility ToolTipResourcesVisibility => ResourceList?.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
public Visibility ToolTipEmployeesVisibility => EmployeeList?.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
public Visibility ToolTipCustomersVisibility => CustomerList?.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
public Visibility ToolTipTrennstrichVisibility => EmployeeList?.Count > 0 || CustomerList?.Count > 0 || ResourceList?.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
public Visibility ToolTipZusageVisibility => IsTask ? Visibility.Collapsed : Visibility.Visible;
public string ResourcesToolTip => GetIFiltereableInfo(ResourceList.Cast<IFilterableDC>().ToList());
public string EmployeesToolTip => GetIFiltereableInfo(EmployeeList.Select(s => s.Employee).Cast<IFilterableDC>().ToList());
public string CustomersToolTip => GetIFiltereableInfo(CustomerList.Cast<IFilterableDC>().ToList());
public bool LiesInPast => Start < DateTime.Now && End < DateTime.Now;
private static string GetIFiltereableInfo(List<IFilterableDC> list)
{
var tooltip = string.Empty;
foreach(var item in list)
{
var index = list.IndexOf(item);
if(index % 3 == 0 && index < list.Count - 1 && index > 0)
{
tooltip += "\n";
}
tooltip += item.ToString();
if(index < list.Count - 1)
{
tooltip += "; ";
}
}
return tooltip;
}
// Für DevExpress
public SchedulingAppointmentVM() : base(new SchedulerAppointmentDC(), true)
{
CanBeEdited = true;
}
public SchedulingAppointmentVM(SchedulerAppointmentDC dataContract) : base(dataContract, dataContract.SchedulerAppointmentOid == null)
{
IsTeilnahmeBestaetigung = dataContract.IsTeilnahmeBestaetigung;
CanBeEdited = dataContract.CanBeEdited;
InitAppointmentColors();
}
// Wird für Abwesenheiten genutzt
public SchedulingAppointmentVM(bool pAllDay, string pSubject, DateTime pStart, DateTime pEnd, CompactEmployeeDC pOriginator, DateTime? absenceTimeStart, DateTime? absenceTimeEnd)
{
_AllDay = pAllDay;
_Subject = pSubject;
_Start = pStart;
_End = pEnd;
_Originator = pOriginator;
AbsenceTimeStart = absenceTimeStart;
AbsenceTimeEnd = absenceTimeEnd;
IsAbsenceTime = true;
InitAppointmentColors();
}
// Zum Erstellen einer neuen Serienausnahme
/// <summary>
/// Zur Erstellung einer Serienausnahme (ChangedOccurrence) aus einem AppointmentItem.
/// </summary>
/// <param name="appointmentItem">AppointmentItem aus dem ein SchedulingAppointmentVM mit Typ 'ChangedOccurrence' erzeugt werden soll</param>
/// <param name="recurrenceInfoXml">Wiederholungsinfo für das SchedulerControl mit Id und Index</param>
public SchedulingAppointmentVM(AppointmentItem appointmentItem, string recurrenceInfoXml) : base(new SchedulerAppointmentDC(), true)
{
if(appointmentItem.Type == AppointmentType.Normal)
{
return;
}
_AllDay = appointmentItem.AllDay;
_Start = appointmentItem.Start;
_End = appointmentItem.End;
_Location = appointmentItem.Location;
_RecurrenceInfo = recurrenceInfoXml;
_Description = appointmentItem.Description;
_Subject = appointmentItem.Subject;
_Type = 3; // ChangedOccurrence, Occurrence ist nicht in der Datenbank gespeichert
_IsPrivate = appointmentItem.CustomFields["IsPrivate"] is bool b && b;
_EmployeeList = appointmentItem.CustomFields["EmployeeList"] as ObservableCollection<Employee2SchedulerAppointmentDC> ?? new ObservableCollection<Employee2SchedulerAppointmentDC>();
_CustomerList = appointmentItem.CustomFields["CustomerList"] as List<CompactCustomerDC> ?? new List<CompactCustomerDC>();
_ResourceList = appointmentItem.CustomFields["ResourceList"] as List<ResourceDC> ?? new List<ResourceDC>();
_Originator = appointmentItem.CustomFields["Originator"] as CompactEmployeeDC ?? BeWoApp.CompactLoggedOnEmployee;
}
/// <summary>
/// Wird für Strg + V und zur Rechteprüfung bei der Erstellung des Löschen-Buttons des Contextmenüs benutzt.
/// </summary>
/// <param name="appointmentItem">AppointmentItem aus dem ein SchedulingAppointmentVM erzeugt werden soll</param>
public SchedulingAppointmentVM(AppointmentItem appointmentItem) : base(new SchedulerAppointmentDC(), true)
{
_AllDay = appointmentItem.AllDay;
_Start = appointmentItem.Start;
_End = appointmentItem.End;
_Location = appointmentItem.Location;
_RecurrenceInfo = appointmentItem.RecurrenceInfo?.ToString();
_Description = appointmentItem.Description;
_Subject = appointmentItem.Subject;
_Type = (int) appointmentItem.Type;
_IsPrivate = appointmentItem.CustomFields["IsPrivate"] is bool b && b;
var tempEmployeeList = appointmentItem.CustomFields["EmployeeList"] as ObservableCollection<Employee2SchedulerAppointmentDC> ?? new ObservableCollection<Employee2SchedulerAppointmentDC>();
var tempCustomerList = appointmentItem.CustomFields["CustomerList"] as List<CompactCustomerDC> ?? new List<CompactCustomerDC>();
var tempResourceList = appointmentItem.CustomFields["ResourceList"] as List<ResourceDC> ?? new List<ResourceDC>();
var tempSupportConceptList = appointmentItem.CustomFields["SupportConceptList"] as List<CompactSupportConceptDC> ?? new List<CompactSupportConceptDC>();
_EmployeeList = new ObservableCollection<Employee2SchedulerAppointmentDC>();
_CustomerList = new List<CompactCustomerDC>();
_ResourceList = new List<ResourceDC>();
_SupportConceptList = new ObservableCollection<CompactSupportConceptDC>();
foreach(var e2a in tempEmployeeList)
{
_EmployeeList.AddIfNotIn(new Employee2SchedulerAppointmentDC { Employee = e2a.Employee });
}
foreach(var customer in tempCustomerList)
{
_CustomerList.AddIfNotIn(customer);
}
foreach(var resource in tempResourceList)
{
_ResourceList.AddIfNotIn(resource);
}
foreach(var supportConcept in tempSupportConceptList)
{
_SupportConceptList.AddIfNotIn(supportConcept);
}
_Originator = appointmentItem.CustomFields["Originator"] as CompactEmployeeDC ?? BeWoApp.CompactLoggedOnEmployee;
}
protected override void InitByDataContract(SchedulerAppointmentDC pDataContract)
{
_AllDay = pDataContract.AllDay;
_Description = pDataContract.Description;
_End = pDataContract.EndDate ?? DateTime.Now;
_Location = pDataContract.Location;
_RecurrenceInfo = pDataContract.RecurrenceInfo;
_Start = pDataContract.StartDate ?? DateTime.Now;
_Status = pDataContract.Status;
_Subject = pDataContract.Subject;
_Type = pDataContract.Type;
_IsPrivate = pDataContract.IsPrivate;
_Originator = pDataContract.Originator;
_CustomerList = pDataContract.CustomerList ?? new List<CompactCustomerDC>();
_EmployeeList = new ObservableCollection<Employee2SchedulerAppointmentDC>(pDataContract.EmployeeList ?? new List<Employee2SchedulerAppointmentDC>());
_ResourceList = pDataContract.ResourceList ?? new List<ResourceDC>();
_IsTask = pDataContract.IsTask;
_TaskDescription = pDataContract.TaskDescription;
_CompletedNotice = pDataContract.CompletedNotice;
_CompletedDate = pDataContract.CompletedDate;
_SupportConceptList = new ObservableCollection<CompactSupportConceptDC>(pDataContract.SupportConceptList ?? new List<CompactSupportConceptDC>());
_HasServiceRecordEntry = pDataContract.HasServiceRecordEntry;
_IsArchived = pDataContract.ActivationType == ActivationTypeId.Archived;
CanBeEdited = pDataContract.CanBeEdited;
Id = pDataContract.SchedulerAppointmentOid;
if(pDataContract.DueDate.HasValue)
{
_DueDate = pDataContract.DueDate;
_DueTime = pDataContract.DueDate;
}
InitAppointmentColors();
}
private void InitAppointmentColors()
{
var employeeColor = Color.FromRgb(192, 255, 208);
if(Utils.IsValidColorHexString(Originator?.EmployeeColor))
{
employeeColor = (Color) ColorConverter.ConvertFromString(Originator.EmployeeColor);
}
if(IsTask)
{
employeeColor = Color.FromRgb(153, 59, 59);
}
var resourceColors = new List<Color>();
foreach(var resource in ResourceList)
{
if(Utils.IsValidColorHexString(resource.Color))
{
resourceColors.AddIfNotIn((Color) ColorConverter.ConvertFromString(resource.Color));
}
}
AppointmentColors = new AppointmentColorHelper(employeeColor, resourceColors, CustomerList?.Any() ?? false, IsTask);
var colorHexValue = IsTask ? Color.FromRgb(153, 59, 59) : Color.FromRgb(192, 255, 208);
BackgroundColor = new SolidColorBrush(colorHexValue);
var foregroundColorHexValue = IsTask ? Color.FromRgb(224, 224, 224) : Color.FromRgb(0, 0, 0);
ForegroundColor = new SolidColorBrush(foregroundColorHexValue);
}
protected override SchedulerAppointmentDC MapToDataContract(SchedulerAppointmentDC pDataContract, bool doCommit)
{
pDataContract.AllDay = _AllDay;
pDataContract.Description = _Description;
pDataContract.EndDate = _End;
pDataContract.Location = _Location;
pDataContract.RecurrenceInfo = _RecurrenceInfo;
pDataContract.StartDate = _Start;
pDataContract.Status = _Status;
pDataContract.Subject = _Subject;
pDataContract.Type = _Type;
pDataContract.IsPrivate = _IsPrivate;
pDataContract.Originator = _Originator;
pDataContract.CustomerList = _CustomerList;
pDataContract.EmployeeList = _EmployeeList.ToList();
pDataContract.ResourceList = _ResourceList;
pDataContract.IsTask = _IsTask;
pDataContract.TaskDescription = _TaskDescription;
pDataContract.CompletedNotice = _CompletedNotice;
pDataContract.CompletedDate = _CompletedDate;
pDataContract.SupportConceptList = _SupportConceptList.ToList();
pDataContract.HasServiceRecordEntry = _HasServiceRecordEntry;
pDataContract.ActivationType = _IsArchived ? ActivationTypeId.Archived : ActivationTypeId.Active;
if(_DueDate.HasValue && _DueTime.HasValue)
{
pDataContract.DueDate = new DateTime(_DueDate.Value.Year, _DueDate.Value.Month, _DueDate.Value.Day, _DueTime.Value.Hour, _DueTime.Value.Minute, 0);
}
else
{
pDataContract.DueDate = _DueDate;
}
return pDataContract;
}
public override bool Equals(object pObj)
{
if(!(pObj is SchedulingAppointmentVM schedulingAppointmentVM))
{
return false;
}
var customFieldsAreEqual = true;
var areEqual =
Equals(Subject, schedulingAppointmentVM.Subject) &&
LabelKey == schedulingAppointmentVM.LabelKey &&
AllDay == schedulingAppointmentVM.AllDay &&
IsPrivate == schedulingAppointmentVM.IsPrivate &&
IsDirty == schedulingAppointmentVM.IsDirty &&
IsNew == schedulingAppointmentVM.IsNew &&
IsTask == schedulingAppointmentVM.IsTask &&
TaskDescription == schedulingAppointmentVM.TaskDescription &&
Equals(CompletedDate, schedulingAppointmentVM.CompletedDate) &&
Equals(DueDate, schedulingAppointmentVM.DueDate) &&
Equals(CompletedNotice, schedulingAppointmentVM.CompletedNotice) &&
customFieldsAreEqual &&
CustomerList.AreEqual(schedulingAppointmentVM.CustomerList) &&
Equals(Description, schedulingAppointmentVM.Description) &&
EmployeeList.AreEqual(schedulingAppointmentVM.EmployeeList) &&
Equals(End, schedulingAppointmentVM.End) &&
Equals(EndTime, schedulingAppointmentVM.EndTime) &&
Equals(Location, schedulingAppointmentVM.Location) &&
ResourceList.AreEqual(schedulingAppointmentVM.ResourceList) &&
Equals(RecurrenceInfo, schedulingAppointmentVM.RecurrenceInfo) &&
HasServiceRecordEntry == schedulingAppointmentVM.HasServiceRecordEntry
;
return areEqual;
}
public override int GetHashCode()
{
if(DataContract?.SchedulerAppointmentOid.HasValue ?? false)
{
return GetType().Name.GetHashCode() ^ DataContract.SchedulerAppointmentOid.Value.GetHashCode();
}
return base.GetHashCode();
}
public override bool IsDirty => !IsAbsenceTime && base.IsDirty;
public new bool IsNew
{
get => !IsAbsenceTime && base.IsNew;
set => base.IsNew = value;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -3509,7 +3509,91 @@
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MaximizeButtonStyle" TargetType="{x:Type ToggleButton}">
<Style x:Key="ResourceTreeViewStyle" TargetType="{x:Type TreeViewItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
<Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
<Setter Property="Padding" Value="1,0,0,0" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
<Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<ControlTemplate.Resources>
<Storyboard x:Key="Storyboard1" />
</ControlTemplate.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="19" Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<ToggleButton x:Name="Expander" Style="{StaticResource ExpandCollapseToggleStyle}" ClickMode="Press" IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" />
<Border x:Name="Bd" Margin="0 2" SnapsToDevicePixels="true" Grid.Row="0" Grid.Column="1" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}" CornerRadius="5,5,5,5" Background="#FF000000">
<Border.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#19000000" Offset="0" />
<GradientStop Color="#26000000" Offset="1" />
</LinearGradientBrush>
</Border.OpacityMask>
</Border>
<ContentPresenter Margin="3 1" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Grid.Row="0"
Grid.Column="1" x:Name="PART_Header" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" ContentSource="Header" />
<ItemsPresenter x:Name="ItemsHost" Grid.Column="1" Grid.Row="1" OpacityMask="#FFA0A0A0" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="true">
<Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed" />
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter Property="Visibility" TargetName="Expander" Value="Hidden" />
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="OpacityMask" TargetName="Bd">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#99000000" Offset="0" />
<GradientStop Color="#CC000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true" />
<Condition Property="IsSelectionActive" Value="false" />
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="False" />
<Condition Property="IsMouseOver" Value="True" SourceName="PART_Header" />
</MultiTrigger.Conditions>
<Setter Property="OpacityMask" TargetName="Bd">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#33000000" Offset="0" />
<GradientStop Color="#66000000" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="MaximizeButtonStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="MinWidth" Value="0" />
<Setter Property="MinHeight" Value="0" />
<Setter Property="Width" Value="Auto" />

View File

@@ -7,6 +7,7 @@
xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase"
xmlns:s="clr-namespace:System;assembly=mscorlib"
xmlns:core="clr-namespace:BS.Shared.Core;assembly=BS.Shared"
xmlns:xtraEditors="clr-namespace:DevExpress.XtraEditors;assembly=DevExpress.XtraEditors.v23.2"
Height="Auto" Width="Auto" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Focusable="True">
<GroupBox Name="root" Header="Aktuell definierte Abwesenheitskategorien" Style="{StaticResource ObjectEditGroupBox}">

View File

@@ -16,6 +16,7 @@ using BS.Shared.Extensions;
using DevExpress.Xpf.Editors.Settings;
using DevExpress.Xpf.Grid;
using DependencyObject = System.Windows.DependencyObject;
namespace BeWo.View.Detail
{

View File

@@ -9,6 +9,8 @@ using BeWo.ViewModel;
using BeWo.ViewModel.ListViewModel;
using BS.Shared.Extensions;
using DependencyObject = System.Windows.DependencyObject;
namespace BeWo.View.Detail
{
public partial class AbsenceTimesView

View File

@@ -25,6 +25,8 @@ using BS.Shared.Translation;
using Microsoft.Win32;
using BS.Shared.Extensions;
using DependencyObject = System.Windows.DependencyObject;
namespace BeWo.View.Detail
{
public partial class AccountingTransactionBookingView

View File

@@ -19,6 +19,8 @@ using DevExpress.Xpf.Editors.Settings;
using DevExpress.Xpf.Grid;
using Microsoft.Win32;
using DependencyObject = System.Windows.DependencyObject;
namespace BeWo.View.Detail
{
/// <summary>

View File

@@ -11,6 +11,8 @@ using BeWo.Validation;
using BeWo.ViewModel;
using BeWo.ViewModel.ListViewModel;
using DependencyObject = System.Windows.DependencyObject;
namespace BeWo.View.Detail
{
public partial class AdditionalServiceAddView : BeWoView

View File

@@ -13,6 +13,8 @@ using BeWo.ViewModel.ListViewModel;
using DevExpress.Xpf.Editors.Settings;
using DependencyObject = System.Windows.DependencyObject;
namespace BeWo.View.Detail
{
public partial class AdditionalServiceRegionView : BeWoView

View File

@@ -36,6 +36,8 @@ using DevExpress.Xpf.Grid;
using Microsoft.Win32;
using DependencyObject = System.Windows.DependencyObject;
namespace BeWo.View.Detail
{
public partial class AdditionalServiceView : INotifyPropertyChanged

View File

@@ -41,7 +41,7 @@ namespace BeWo.View.Detail
}
}
internal override DependencyObject ValidationOnSaveRootElement
internal override System.Windows.DependencyObject ValidationOnSaveRootElement
{
get
{

View File

@@ -43,7 +43,7 @@ namespace BeWo.View.Detail
}
}
internal override DependencyObject ValidationOnSaveRootElement
internal override System.Windows.DependencyObject ValidationOnSaveRootElement
{
get
{

View File

@@ -71,7 +71,7 @@ namespace BeWo.View.Detail
}
internal override DependencyObject ValidationOnSaveRootElement
internal override System.Windows.DependencyObject ValidationOnSaveRootElement
{
get { return this.borderTemp; }
}

View File

@@ -44,7 +44,7 @@ namespace BeWo.View.Detail
}
}
internal override DependencyObject ValidationOnSaveRootElement
internal override System.Windows.DependencyObject ValidationOnSaveRootElement
{
get { return button_addAuszahlungsart; }
}

View File

@@ -39,7 +39,7 @@ namespace BeWo.View.Detail
}
// TODO
internal override DependencyObject ValidationOnSaveRootElement
internal override System.Windows.DependencyObject ValidationOnSaveRootElement
{
get { return button_addBudget; }
}

View File

@@ -286,7 +286,7 @@ namespace BeWo.View.Detail
get { return Translator.Translate("Klienten"); }
}
internal override DependencyObject ValidationOnSaveRootElement
internal override System.Windows.DependencyObject ValidationOnSaveRootElement
{
get { return grid_details; }
}

View File

@@ -122,7 +122,7 @@ namespace BeWo.View.Detail
get { return "Klienten"; }
}
internal override DependencyObject ValidationOnSaveRootElement
internal override System.Windows.DependencyObject ValidationOnSaveRootElement
{
get
{

View File

@@ -53,7 +53,7 @@ namespace BeWo.View.Detail
}
}
internal override DependencyObject ValidationOnSaveRootElement
internal override System.Windows.DependencyObject ValidationOnSaveRootElement
{
get
{

View File

@@ -181,7 +181,7 @@ namespace BeWo.View.Detail
public override string Title => "Mitarbeiter";
internal override DependencyObject ValidationOnSaveRootElement => grid_details;
internal override System.Windows.DependencyObject ValidationOnSaveRootElement => grid_details;
public EmployeeVM ViewModel
{

View File

@@ -36,7 +36,7 @@ namespace BeWo.View.Detail
}
internal override DependencyObject ValidationOnSaveRootElement
internal override System.Windows.DependencyObject ValidationOnSaveRootElement
{
get
{

View File

@@ -136,7 +136,7 @@ namespace BeWo.View.Detail
}
}
internal override DependencyObject ValidationOnSaveRootElement
internal override System.Windows.DependencyObject ValidationOnSaveRootElement
{
get { return this.borderTemp; }
}

View File

@@ -47,7 +47,7 @@ namespace BeWo.View.Detail
VMFactory.CreateMedArtListVMAsync(r => this.Dispatch(delegate { ViewModel = r; }));
}
internal override DependencyObject ValidationOnSaveRootElement
internal override System.Windows.DependencyObject ValidationOnSaveRootElement
{
get { return button_addMedArt; }
}

View File

@@ -71,7 +71,7 @@ namespace BeWo.View.Detail
}
internal override DependencyObject ValidationOnSaveRootElement
internal override System.Windows.DependencyObject ValidationOnSaveRootElement
{
get { return this.borderTemp; }
}

View File

@@ -49,6 +49,7 @@ using Point = System.Windows.Point;
using Size = System.Windows.Size;
using SupportConceptService = BeWo.Core.Service.SupportConceptService;
using VerticalAlignment = System.Windows.VerticalAlignment;
using DependencyObject = System.Windows.DependencyObject;
namespace BeWo.View.Detail.Zeiterfassung
{

View File

@@ -314,7 +314,12 @@ namespace BeWo.View
(BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderAnsehen) ||
BeWoApp.LoggedOnUser.HasRight(UserRightType.ViewAll)) && sc2.StartDate.HasValue)
{
#if DEBUG
MainControl.NavigateTo(new SchedulingMasterView(sc2.StartDate.Value, sc2) { ParentView = this });
#else
MainControl.NavigateTo(new SchedulerMasterView(sc2.StartDate.Value, sc2) { ParentView = this });
#endif
}
}
}

View File

@@ -0,0 +1,58 @@
<view:BeWoView x:Class="BeWo.View.Master.SchedulingMasterView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:view="clr-namespace:BeWo.View"
xmlns:controls="clr-namespace:BeWo.Controls;assembly=BeWo.Controls"
mc:Ignorable="d"
Height="Auto" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Focusable="True">
<Grid Width="Auto" Height="Auto">
<controls:ShadowChrome>
<GroupBox Style="{StaticResource MainContentGroupBoxStyle}">
<GroupBox.Header>
<StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" Margin="0,11,0,0">
<Image Source="..\..\Ressources\Icons\CalendarDisabled.png" RenderTransformOrigin="0.5,0.5" Width="32">
<Image.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1.3" ScaleY="1.3" />
<SkewTransform AngleX="0" AngleY="0" />
<RotateTransform Angle="0" />
<TranslateTransform X="0" Y="-2" />
</TransformGroup>
</Image.RenderTransform>
</Image>
<TextBox Text="Kalender" Margin="10,0,0,0" Background="{x:Null}" Foreground="{DynamicResource MainGroupBoxForegroundBrush}" FontSize="22" BorderBrush="{x:Null}" VerticalAlignment="Stretch" Padding="0,0,0,0" BorderThickness="0,0,0,0" />
</StackPanel>
</GroupBox.Header>
<Grid Margin="0,3,0,0" Background="{StaticResource ObjectEditBackgroundBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Rectangle Fill="{DynamicResource ResourceContentBrush}" Height="6" />
<Grid x:Name="RootGrid" Grid.IsSharedSizeScope="True" Grid.Row="1" Margin="5,3,5,5" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
</Grid>
<Border Grid.Row="2" Grid.ColumnSpan="3" Height="35" Margin="0,0,0,0" VerticalAlignment="Stretch" Background="#FF000000">
<Border.OpacityMask>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#19000000" Offset="0" />
<GradientStop Color="#33FFFFFF" Offset="1" />
</LinearGradientBrush>
</Border.OpacityMask>
</Border>
<StackPanel Grid.ColumnSpan="3" Grid.Row="2" Orientation="Horizontal" VerticalAlignment="Center" Height="Auto" Margin="0,3,5,0" HorizontalAlignment="Right">
<Button Content="Schließen" Margin="0,0,0,0" Command="ApplicationCommands.Close" Height="25" />
</StackPanel>
</Grid>
</GroupBox>
</controls:ShadowChrome>
</Grid>
</view:BeWoView>

View File

@@ -0,0 +1,26 @@
using System;
using BeWo.Scheduling.View;
using BS.Shared.DataContracts;
namespace BeWo.View.Master
{
public partial class SchedulingMasterView
{
public SchedulingMasterView()
{
InitializeComponent();
var schedulingView = new SchedulingView();
RootGrid.Children.Add(schedulingView);
}
public SchedulingMasterView(DateTime pIntervalStartDate, SchedulerAppointmentDC pAppointment)
{
InitializeComponent();
var scheduler = new SchedulingView(pIntervalStartDate, pAppointment);
RootGrid.Children.Add(scheduler);
}
}
}

View File

@@ -14,6 +14,8 @@ using BS.Shared.Services;
using BS.Shared.DataContracts.Compact;
using BS.Shared;
using DispatcherObject = System.Windows.Threading.DispatcherObject;
namespace BeWo.ViewModel
{
public class AccountingBookingVM : AbstractBaseVM

View File

@@ -18,6 +18,8 @@ using BS.Shared.Extensions;
using BS.Shared.Services;
using Microsoft.VisualBasic;
using DispatcherObject = System.Windows.Threading.DispatcherObject;
namespace BeWo.ViewModel.ListViewModel
{
public class ServiceRecordListVM : AbstractDCListMapperVM<ServiceRecordDC, ServiceRecordVM>

View File

@@ -18,6 +18,7 @@ using DevExpress.XtraScheduler;
using BeWo.View.Detail.Zeiterfassung;
using BeWo.ServiceProxy;
using System.Linq;
using DevExpress.Xpf.Scheduling;
namespace BeWo.ownChat
{
@@ -220,7 +221,49 @@ namespace BeWo.ownChat
})));
}
// Konstruktor für neuen Kalender
public ChatDokumentationsView(string notice, CompactCustomerDC _compactCustomer, CompactEmployeeDC employee, DateTime firstTime, DateTime lastTime, Action schedulerCallback = null, AppointmentItem appointment = null)
{
InitializeComponent();
var customerCompact = _compactCustomer;
Cache.GetInstance().GetActiveSupportConceptCostbearer(scList =>
VMFactory.CreateServiceRecordVMAsync(
BeWoApp.LoggedOnUser.Employee.EmployeeOid,
vm => this.Dispatch(
delegate
{
var serviceRecordEditView = new ServiceRecordEditView();
vm.DispatcherObject = this;
var dc = SupportConceptService.ErstelleServiceRecordDC(firstTime, lastTime, customerCompact, scList);
if(employee != null)
{
dc.Employee = employee;
}
vm.PrototypeVM.UpdateServiceAccountings(null, vm.PrototypeVM.Category2Services, customerCompact != null);
if(vm.PrototypeVM.SortedCategories != null && vm.PrototypeVM.SortedCategories.Count > 0)
{
var cat1 = vm.PrototypeVM.SortedCategories[0];
dc.ServiceDescription = vm.PrototypeVM.Category2Services[cat1][0];
}
_ServiceRecord = new ServiceRecordVM(dc, vm.PrototypeVM.Category2Services, vm.PrototypeVM.AllGoalCategories, vm.PrototypeVM.AllGoals) { Notice = notice };
_ServiceRecord.SetInsertedOn(DateTime.Now);
var hideCustomerCombo = _ServiceRecord.SupportConcept == null;
serviceRecordEditView.InitView(vm, _ServiceRecord, hideCustomerCombo);
serviceRecordEditView.SetSearchText(customerCompact != null ? customerCompact.LastName : "");
CommandBindingsCloseSaveForSchedulingView(serviceRecordEditView, schedulerCallback);
Popup_Content(serviceRecordEditView);
})));
}
//GruppenBuchung Konstruktor für Kalender
public ChatDokumentationsView(string notice, DateTime startDate, DateTime endDate, List<CompactCustomerDC> _compactCustomer, List<CompactEmployeeDC> _compactEmployee, Action<List<ServiceRecordDC>> schedulerCallback = null, Appointment appointment = null)
@@ -363,6 +406,178 @@ namespace BeWo.ownChat
})));
}
// GruppenBuchung Konstruktor für neuen Kalender
public ChatDokumentationsView(AppointmentItem appointment, string notice, DateTime firstTime, DateTime lastTime, List<CompactCustomerDC> _compactCustomer, List<CompactEmployeeDC> _compactEmployee, Action schedulerCallback = null)
{
InitializeComponent();
Cache.GetInstance().GetActiveSupportConceptCostbearer(scList =>
VMFactory.CreateServiceRecordVMAsync(
BeWoApp.LoggedOnUser.Employee.EmployeeOid,
vm => this.Dispatch(
delegate
{
var newView = new ServiceRecordGroupEditView();
vm.DispatcherObject = this;
var serviceRecordGroup = new ServiceRecordGroupDC
{
StartDate = firstTime,
EndDate = lastTime,
CustomerCount = _compactCustomer.Count,
EmployeeCount = _compactEmployee.Count,
Notice = notice
};
var serviceRecordList = new List<ServiceRecordDC>();
foreach(var emp in _compactEmployee)
{
foreach(var cus in _compactCustomer)
{
var supportConcept = SupportConceptService.HoleHilfeplanAusListe(scList, cus, firstTime, lastTime);
if(supportConcept != null)
{
var serviceRecord = new ServiceRecordDC
{
Start = firstTime,
End = lastTime,
Employee = emp,
Customer = cus,
SupportConcept = SupportConceptService.HoleHilfeplanAusListe(scList, cus, firstTime, lastTime),
GroupEmployeeCount = _compactEmployee.Count,
GroupPersonCount = _compactCustomer.Count
};
if(BeWoApp.AppSettings.IsEndDateVisible)
{
serviceRecord.ServiceRecordFormat = ServiceRecordFormate.ZeiterfassungMitEndDatum;
}
else if(BeWoApp.AppSettings.IsOnlyYearMonthVisible)
{
serviceRecord.ServiceRecordFormat =
ServiceRecordFormate.ZeiterfassungMitMonatJahr;
}
else
{
serviceRecord.ServiceRecordFormat = ServiceRecordFormate.OriginaleZeiterfassung;
}
serviceRecord.DurationInStunden = ZeiterfassungsDauer.Minuten;
if(serviceRecord.SupportConcept.CostBearerList != null && serviceRecord.SupportConcept.CostBearerList.Count > 0)
{
serviceRecord.CostBearer = serviceRecord.SupportConcept.CostBearerList[0].Organisation;
}
serviceRecordList.Add(serviceRecord);
}
}
}
if(serviceRecordList.Count == 0)
{
MessageBox.Show(
"Es wurden keine laufenden Hilfepläne für die ausgewählten Klienten gefunden. Die Übernahme in die Zeiterfassung ist nicht möglich.",
"Übernahme nicht möglich", MessageBoxButton.OK, MessageBoxImage.Exclamation);
Close();
return;
}
serviceRecordGroup.ServiceRecordList = serviceRecordList;
if(vm.PrototypeVM.SortedCategories != null && vm.PrototypeVM.SortedCategories.Count > 0)
{
var cat1 = vm.PrototypeVM.SortedCategories[0];
serviceRecordList[0].ServiceDescription = vm.PrototypeVM.Category2Services[cat1][0];
}
_ServiceRecord = new ServiceRecordVM(serviceRecordList[0], vm.PrototypeVM.Category2Services, vm.PrototypeVM.AllGoalCategories, vm.PrototypeVM.AllGoals) { Notice = notice };
newView.InitView(vm, _ServiceRecord, serviceRecordGroup);
if(newView.CommandBindings.Count == 0)
{
newView.CommandBindings.Add(
new CommandBinding(
ApplicationCommands.Close,
(s, e) =>
{
if(!newView.DoSaveCheck())
{
return;
}
Close();
}));
newView.CommandBindings.Add(
new CommandBinding(
ApplicationCommands.Save,
(s, e) =>
{
var save = newView.IsValid();
if(!save)
{
return;
}
newView.SaveData();
schedulerCallback?.Invoke();
Close();
}));
}
popup_contentChat.Child = newView;
popup_contentChat.Visibility = Visibility.Visible;
})));
}
private void CommandBindingsCloseSaveForSchedulingView(ServiceRecordEditView newView, Action schedulerCallback)
{
if(newView.CommandBindings.Count == 0)
{
newView.CommandBindings.Add(
new CommandBinding(
ApplicationCommands.Close,
(s, e) =>
{
if(!newView.DoSaveCheck())
{
return;
}
Close();
}));
newView.CommandBindings.Add(
new CommandBinding(
ApplicationCommands.Save,
(s, e) =>
{
var isValid = newView.IsValid();
if(!isValid)
{
return;
}
// TODO: Callback einbauen, das den Termin verändert (vom Kalender übergeben)
if(newView.SaveData())
{
schedulerCallback?.Invoke();
}
Close();
}));
}
}
private void CommandBindingsCloseSave(ServiceRecordEditView newView, Action<List<ServiceRecordDC>> schedulerCallback)
{
if(newView.CommandBindings.Count != 0)

View File

@@ -600,6 +600,9 @@
<Content Include="Views\Main\OneTimeLinkCreationPartial.cshtml" />
<Content Include="Views\ExternalSignature\ExternalSignature.cshtml" />
<Content Include="Views\Shared\_ExternalSignatureLayout.cshtml" />
<Content Include="Views\Main\GroupBookingScCbRelList.cshtml" />
<Content Include="Views\Main\GroupBookingFormPartial.cshtml" />
<Content Include="Views\Main\Category2ServiceDescriptionPartial.cshtml" />
</ItemGroup>
<ItemGroup>
<Content Include="packages.config" />

View File

@@ -15,7 +15,7 @@
<Controller_SelectedScaffolderCategoryPath>root/Common/MVC/Controller</Controller_SelectedScaffolderCategoryPath>
<WebStackScaffolding_ControllerDialogWidth>600</WebStackScaffolding_ControllerDialogWidth>
<WebStackScaffolding_IsLayoutPageSelected>False</WebStackScaffolding_IsLayoutPageSelected>
<WebStackScaffolding_IsPartialViewSelected>False</WebStackScaffolding_IsPartialViewSelected>
<WebStackScaffolding_IsPartialViewSelected>True</WebStackScaffolding_IsPartialViewSelected>
<WebStackScaffolding_IsReferencingScriptLibrariesSelected>False</WebStackScaffolding_IsReferencingScriptLibrariesSelected>
<WebStackScaffolding_LayoutPageFile>
</WebStackScaffolding_LayoutPageFile>

View File

@@ -138,6 +138,7 @@ textarea {
--danger: #dc3545;
--light: #f8f9fa;
--dark: #343a40;
--bewo-custom-goal: #4682B4;
--service-record-marked: #c5e3ff;
--bewo-teams: #565999;
--bewo-goal-rating: #0000ff;
@@ -1822,6 +1823,26 @@ pre code {
background-color: #b9bbbe;
}
.table-bewo-custom-goal,
.table-bewo-custom-goal > th,
.table-bewo-custom-goal > td {
background-color: #cbdcea;
}
.table-bewo-custom-goal th,
.table-bewo-custom-goal td,
.table-bewo-custom-goal thead th,
.table-bewo-custom-goal tbody + tbody {
border-color: #9fbed8;
}
.table-hover .table-bewo-custom-goal:hover {
background-color: #b9d0e3;
}
.table-hover .table-bewo-custom-goal:hover > td,
.table-hover .table-bewo-custom-goal:hover > th {
background-color: #b9d0e3;
}
.table-service-record-marked,
.table-service-record-marked > th,
.table-service-record-marked > td {
@@ -2910,6 +2931,36 @@ fieldset:disabled a.btn {
box-shadow: 0 0 0 0.2rem rgba(82, 88, 93, 0.5);
}
.btn-bewo-custom-goal {
color: #fff;
background-color: #4682B4;
border-color: #4682B4;
}
.btn-bewo-custom-goal:hover {
color: #fff;
background-color: #3b6e98;
border-color: #38678f;
}
.btn-bewo-custom-goal:focus, .btn-bewo-custom-goal.focus {
color: #fff;
background-color: #3b6e98;
border-color: #38678f;
box-shadow: 0 0 0 0.2rem rgba(98, 149, 191, 0.5);
}
.btn-bewo-custom-goal.disabled, .btn-bewo-custom-goal:disabled {
color: #fff;
background-color: #4682B4;
border-color: #4682B4;
}
.btn-bewo-custom-goal:not(:disabled):not(.disabled):active, .btn-bewo-custom-goal:not(:disabled):not(.disabled).active, .show > .btn-bewo-custom-goal.dropdown-toggle {
color: #fff;
background-color: #38678f;
border-color: #346186;
}
.btn-bewo-custom-goal:not(:disabled):not(.disabled):active:focus, .btn-bewo-custom-goal:not(:disabled):not(.disabled).active:focus, .show > .btn-bewo-custom-goal.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(98, 149, 191, 0.5);
}
.btn-service-record-marked {
color: #212529;
background-color: #c5e3ff;
@@ -3560,6 +3611,31 @@ fieldset:disabled a.btn {
box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);
}
.btn-outline-bewo-custom-goal {
color: #4682B4;
border-color: #4682B4;
}
.btn-outline-bewo-custom-goal:hover {
color: #fff;
background-color: #4682B4;
border-color: #4682B4;
}
.btn-outline-bewo-custom-goal:focus, .btn-outline-bewo-custom-goal.focus {
box-shadow: 0 0 0 0.2rem rgba(70, 130, 180, 0.5);
}
.btn-outline-bewo-custom-goal.disabled, .btn-outline-bewo-custom-goal:disabled {
color: #4682B4;
background-color: transparent;
}
.btn-outline-bewo-custom-goal:not(:disabled):not(.disabled):active, .btn-outline-bewo-custom-goal:not(:disabled):not(.disabled).active, .show > .btn-outline-bewo-custom-goal.dropdown-toggle {
color: #fff;
background-color: #4682B4;
border-color: #4682B4;
}
.btn-outline-bewo-custom-goal:not(:disabled):not(.disabled):active:focus, .btn-outline-bewo-custom-goal:not(:disabled):not(.disabled).active:focus, .show > .btn-outline-bewo-custom-goal.dropdown-toggle:focus {
box-shadow: 0 0 0 0.2rem rgba(70, 130, 180, 0.5);
}
.btn-outline-service-record-marked {
color: #c5e3ff;
border-color: #c5e3ff;
@@ -5806,6 +5882,19 @@ a.badge-dark:focus, a.badge-dark.focus {
box-shadow: 0 0 0 0.2rem rgba(52, 58, 64, 0.5);
}
.badge-bewo-custom-goal {
color: #fff;
background-color: #4682B4;
}
a.badge-bewo-custom-goal:hover, a.badge-bewo-custom-goal:focus {
color: #fff;
background-color: #38678f;
}
a.badge-bewo-custom-goal:focus, a.badge-bewo-custom-goal.focus {
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(70, 130, 180, 0.5);
}
.badge-service-record-marked {
color: #212529;
background-color: #c5e3ff;
@@ -6142,6 +6231,18 @@ a.badge-bewo-report:focus, a.badge-bewo-report.focus {
color: #040505;
}
.alert-bewo-custom-goal {
color: #24445e;
background-color: #dae6f0;
border-color: #cbdcea;
}
.alert-bewo-custom-goal hr {
border-top-color: #b9d0e3;
}
.alert-bewo-custom-goal .alert-link {
color: #162939;
}
.alert-service-record-marked {
color: #667685;
background-color: #f3f9ff;
@@ -6679,6 +6780,20 @@ a.badge-bewo-report:focus, a.badge-bewo-report.focus {
border-color: #1b1e21;
}
.list-group-item-bewo-custom-goal {
color: #24445e;
background-color: #cbdcea;
}
.list-group-item-bewo-custom-goal.list-group-item-action:hover, .list-group-item-bewo-custom-goal.list-group-item-action:focus {
color: #24445e;
background-color: #b9d0e3;
}
.list-group-item-bewo-custom-goal.list-group-item-action.active {
color: #fff;
background-color: #24445e;
border-color: #24445e;
}
.list-group-item-service-record-marked {
color: #667685;
background-color: #eff7ff;
@@ -7718,6 +7833,16 @@ button.bg-dark:focus {
background-color: #1d2124 !important;
}
.bg-bewo-custom-goal {
background-color: #4682B4 !important;
}
a.bg-bewo-custom-goal:hover, a.bg-bewo-custom-goal:focus,
button.bg-bewo-custom-goal:hover,
button.bg-bewo-custom-goal:focus {
background-color: #38678f !important;
}
.bg-service-record-marked {
background-color: #c5e3ff !important;
}
@@ -7948,6 +8073,10 @@ button.bg-bewo-report:focus {
border-color: #343a40 !important;
}
.border-bewo-custom-goal {
border-color: #4682B4 !important;
}
.border-service-record-marked {
border-color: #c5e3ff !important;
}
@@ -11047,6 +11176,14 @@ a.text-dark:hover, a.text-dark:focus {
color: #121416 !important;
}
.text-bewo-custom-goal {
color: #4682B4 !important;
}
a.text-bewo-custom-goal:hover, a.text-bewo-custom-goal:focus {
color: #315a7d !important;
}
.text-service-record-marked {
color: #c5e3ff !important;
}

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
$theme-colors: ("service-record-marked": #c5e3ff, "bewo-teams": #565999, "bewo-goal-rating": #0000ff,"bewo-dev": #00cf7c, "primary": #FF5A00, "bewo-customers": #3b7799, "bewo-service-records": #c80000, "bewo-calendar": #04b4d0, "bewo-is-about-to-expire": #FF0000, "bewo-expires-in-three-months": #FF9400, "bewo-group-booking": #f9e79f, "bewo-customer-card-header": #AB4A07, "bewo-employee": #45993B, "bewo-resource": #04B4D0, "bewo-task-red": #993B3B, "bewo-report": #995E3B);
$theme-colors: ("bewo-custom-goal": #4682B4, "service-record-marked": #c5e3ff, "bewo-teams": #565999, "bewo-goal-rating": #0000ff,"bewo-dev": #00cf7c, "primary": #FF5A00, "bewo-customers": #3b7799, "bewo-service-records": #c80000, "bewo-calendar": #04b4d0, "bewo-is-about-to-expire": #FF0000, "bewo-expires-in-three-months": #FF9400, "bewo-group-booking": #f9e79f, "bewo-customer-card-header": #AB4A07, "bewo-employee": #45993B, "bewo-resource": #04B4D0, "bewo-task-red": #993B3B, "bewo-report": #995E3B);
textarea {
min-height: 150px !important;

View File

@@ -81,6 +81,8 @@ namespace BeWoPlanerMobil.Controllers
return mandator;
}
// ToDo: Am 03.06.2024: Überall prüfen, ob das Model null ist. Wenn ja, dann ausloggen!
[Authorize]
public ActionResult Main()
{
@@ -140,6 +142,8 @@ namespace BeWoPlanerMobil.Controllers
Model.IsShowingDurationInHours = true;
}
Model.FilterGroupServiceCategories = UserSettingsUtils.GetSettingValueAsBool(mandatorSettings, SettingsKeys.FilterGroupServiceCategories);
Model.SetStartTimeToEndTimeAfterSave = UserSettingsUtils.GetSettingValueAsBool(mandatorSettings, SettingsKeys.SetStartTimeToEndTimeAfterSave);
var user = GetUser();
@@ -249,7 +253,9 @@ namespace BeWoPlanerMobil.Controllers
Model.SelectedEmployee = MobileSessionFacade.LoggedInCompactEmployee;
}
Model.IsServiceRecordNoticeMandatory = UserSettingsUtils.GetSettingValueAsBool(mandatorSettings, SettingsKeys.IsServiceRecordNoticeMandatory);
var settingsValue = GetSettingValue(mandatorSettings, SettingsKeys.IsServiceRecordNoticeMandatory);
Model.IsServiceRecordNoticeMandatory = settingsValue is null || !settingsValue.Equals("0");
var isInList = !(Model.SelectedSupportConceptListObject is null) && Model.SupportConceptListObjects.Contains(Model.SelectedSupportConceptListObject);
@@ -453,36 +459,54 @@ namespace BeWoPlanerMobil.Controllers
[Authorize]
public void LoadGoals()
{
if((!Model.CostBearer2SupportConceptOid.HasValue || Model.CostBearer2SupportConceptOid.Value > 0) && Model.SelectedSupportConcept is null)
try
{
Logout();
}
var selectedGoals = new List<ValueListEntryDC>();
var supportConcept = Model.SupportConcepts.FirstOrDefault(sc => sc.CostBearerRelations.Any(sc2Cb => sc2Cb.CostBearer2SupportConceptOid.HasValue && sc2Cb.CostBearer2SupportConceptOid.Value.Equals(Model.CostBearer2SupportConceptOid.Value)));
if(supportConcept is null)
{
return;
}
Model.SelectedSupportConcept = supportConcept;
var selectedGoals = supportConcept.Goals;
var missingParents = selectedGoals.Where(w => w.ParentOid != null && false == selectedGoals.Any(a => a.ValueListEntryOid.Equals(w.ParentOid))).Select(s => s.ParentOid).ToList();
_ParentGoals = new Dictionary<long, ValueListEntryDC>();
foreach(var oid in missingParents)
{
if(oid.HasValue)
if(Model.IsInGroupBookingMode)
{
LoadMissingParents(oid.Value);
var supportConcepts = Model.GroupBookingSelectedSupportConcepts;
supportConcepts.DoForEach(sc => { selectedGoals.AddRangeIfElementsNotIn(sc.Goals); });
}
else
{
if(Model.CostBearer2SupportConceptOid is null)
{
return;
}
var supportConcept = Model.SupportConcepts.FirstOrDefault(sc => sc.CostBearerRelations.Any(sc2Cb => sc2Cb.CostBearer2SupportConceptOid.HasValue && sc2Cb.CostBearer2SupportConceptOid.Value.Equals(Model.CostBearer2SupportConceptOid.Value)));
if(supportConcept is null)
{
return;
}
Model.SelectedSupportConcept = supportConcept;
selectedGoals = supportConcept.Goals;
}
var missingParents = selectedGoals.Where(w => w.ParentOid != null && false == selectedGoals.Any(a => a.ValueListEntryOid.Equals(w.ParentOid))).Select(s => s.ParentOid).ToList();
_ParentGoals = new Dictionary<long, ValueListEntryDC>();
foreach(var oid in missingParents)
{
if(oid.HasValue)
{
LoadMissingParents(oid.Value);
}
}
var allGoals = selectedGoals.Union(_ParentGoals.Values).ToList();
Model.GoalTree = BuildGoalTree(allGoals);
}
catch(Exception exception)
{
Log.Error(exception);
}
var allGoals = selectedGoals.Union(_ParentGoals.Values).ToList();
Model.GoalTree = BuildGoalTree(allGoals);
}
private List<GoalTreeItem> BuildGoalTree(IReadOnlyCollection<ValueListEntryDC> goals)
@@ -496,14 +520,14 @@ namespace BeWoPlanerMobil.Controllers
foreach(var ziel in ziele.Where(z => z.ValueListEntryOid.HasValue))
{
var treeItem = new GoalTreeItem(true)
var treeItem = new GoalTreeItem(true, ziel.Type)
{
Children = new List<GoalTreeItem>(),
Header = ziel.DisplayName ?? string.Empty,
ParentOid = ziel.ParentOid,
ValueListEntryOid = ziel.ValueListEntryOid
};
goalTreeDic.Add(ziel.ValueListEntryOid.Value, treeItem);
if(ziel.ParentOid is null)
@@ -532,7 +556,7 @@ namespace BeWoPlanerMobil.Controllers
}
}
var kind = new GoalTreeItem(false)
var kind = new GoalTreeItem(false, ziel.Type)
{
Children = new List<GoalTreeItem>(),
Header = ziel.DisplayName ?? string.Empty,
@@ -1681,15 +1705,34 @@ namespace BeWoPlanerMobil.Controllers
private void LoadServiceCategoriesToModel(long? cb2ScOid)
{
if (cb2ScOid is null)
{
Log.Info("cb2ScOid is null !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
if (cb2ScOid is null && Model.IsInGroupBookingMode)
{
Model.ServiceCategories = CreateServiceCategoryModels(OperationsService.GetAllServiceDescriptions());
var selectedSupportConcepts = Model.GroupBookingSelectedSupportConcepts;
var nodes = OperationsService.GetSupportConceptTreeNodeDetailInfos(selectedSupportConcepts.Where(sc => sc.SupportConceptOid.HasValue).Select(sc => sc.SupportConceptOid.Value).ToList());
// Alle Categories und Services der ausgewählten Hilfepläne laden
if(Model.Categories2Descriptions is null)
{
Model.Categories2Descriptions = new Dictionary<ServiceCategoryDC, List<ServiceDescriptionDC>>();
}
Model.Categories2Descriptions.Clear();
Model.Categories2Descriptions = CreateServiceCategory2ServiceDescription(nodes, true);
// ToDo: Ist das hier noch notwendig?
var serviceDescriptionList = new List<List<ServiceDescriptionDC>>();
nodes.AsParallel().ForAll(node => serviceDescriptionList.Add(node.ServiceAccountings.Select(serviceAccounting => serviceAccounting.ServiceDescription).ToList()));
var serviceDescriptions = serviceDescriptionList.Any() ? serviceDescriptionList.AsParallel().Aggregate<IEnumerable<ServiceDescriptionDC>>((a, b) => a.Intersect(b)).ToList() : new List<ServiceDescriptionDC>();
Model.ServiceCategories = serviceDescriptions.Count == 0
? CreateServiceCategoryModels(OperationsService.GetAllServiceDescriptions())
: CreateServiceCategoryModels(serviceDescriptions);
return;
}
@@ -1706,42 +1749,63 @@ namespace BeWoPlanerMobil.Controllers
{
Model.SelectedSupportConceptListObject = Model.SupportConceptListObjects.First(f => long.Parse(f.CostBearer2SupportConceptOid) == cb2ScOid);
var details = OperationsService.GetSupportConceptTreeNodeDetailInfo(Model.SelectedSupportConcept.Customer.CustomerOid, Model.SelectedSupportConcept.SupportConceptOid, Model.CostBearer2SupportConceptOid);
var node = OperationsService.GetSupportConceptTreeNodeDetailInfo(Model.SelectedSupportConcept.Customer.CustomerOid, Model.SelectedSupportConcept.SupportConceptOid, Model.CostBearer2SupportConceptOid);
Model.ServiceCategories = details.ServiceAccountings.Count > 0
? CreateServiceCategoryModels(details.ServiceAccountings.Select(sa => sa.ServiceDescription).ToList())
Model.ServiceCategories = node.ServiceAccountings.Count > 0
? CreateServiceCategoryModels(node.ServiceAccountings.Select(sa => sa.ServiceDescription).ToList())
: CreateServiceCategoryModels(OperationsService.GetAllServiceDescriptions());
Model.ServiceCategories = Model.ServiceCategories.Where(c => !c.OhneHilfeplan.HasValue || c.OhneHilfeplan.Value == AccountingvisibilityType.Beides || c.OhneHilfeplan.Value == AccountingvisibilityType.NurKlientenbezogen).ToList();
Model.Categories2Descriptions = CreateServiceCategory2ServiceDescription(new List<SupportConceptTreeNodeDetailInfoDC> { node }, false);
}
else if(cb2ScOid == -2)
else if(cb2ScOid == -2) // Ohne Hilfeplan
{
var allServiceDescriptions = OperationsService.GetAllServiceDescriptions();
Model.SelectedSupportConceptListObject = Model.SupportConceptListObjects.First(f => f.CostBearer2SupportConceptOid.Equals(cb2ScOid.ToString()));
Model.ServiceCategories = CreateServiceCategoryModels(OperationsService.GetAllServiceDescriptions());
Model.ServiceCategories = Model.ServiceCategories.Where(c => !c.OhneHilfeplan.HasValue || c.OhneHilfeplan.Value == AccountingvisibilityType.Beides || c.OhneHilfeplan.Value == AccountingvisibilityType.NichtKlientenbezogen).ToList();
if(Model.Categories2Descriptions is null)
{
Model.Categories2Descriptions = new Dictionary<ServiceCategoryDC, List<ServiceDescriptionDC>>();
}
else
{
Model.Categories2Descriptions.Clear();
}
allServiceDescriptions.AsParallel().DoForEach(serviceDescription =>
{
if(serviceDescription.Category.OhneHilfeplan.HasValue && (serviceDescription.Category.OhneHilfeplan == AccountingvisibilityType.Beides || serviceDescription.Category.OhneHilfeplan == AccountingvisibilityType.NichtKlientenbezogen))
{
Model.Categories2Descriptions.AddOrUpdateValueInDictionary(serviceDescription.Category, serviceDescription);
}
});
}
else if(cb2ScOid == -1)
else if(cb2ScOid == -1) // Hilfeplan Auswählen
{
Model.SelectedSupportConceptListObject = Model.SupportConceptListObjects.First(f => f.CostBearer2SupportConceptOid.Equals(cb2ScOid.ToString()));
Model.ServiceCategories.Clear();
}
else
{
Log.Info("Model.SelectedSupportConcept is null !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
}
if (Model.SelectedSupportConceptListObject is null ||
Model.SelectedSupportConceptListObject.CostBearer2SupportConceptOid == "-1")
{
Log.Info($"LoadServiceCategoriesToModel() Model.SelectedSupportConceptListObject is null {Model.SelectedSupportConceptListObject is null}, Model.SelectedSupportConceptListObject.CostBearer2SupportConceptOid == {Model.SelectedSupportConceptListObject?.CostBearer2SupportConceptOid}");
if(Model.Categories2Descriptions is null)
{
Model.Categories2Descriptions = new Dictionary<ServiceCategoryDC, List<ServiceDescriptionDC>>();
}
else
{
Model.Categories2Descriptions.Clear();
}
}
// Kategorien werden nach Position sortiert
if (Model.ServiceCategories != null)
{
Model.ServiceCategories = Model.ServiceCategories.OrderBy(serviceCategory => serviceCategory.Position).ToList();
}
// Ist der Klient abwesend, wird dies wie im FaC angezeigt
if(Model.SelectedSupportConcept?.Customer?.AbsenceTimes?.Any() ?? false)
{
foreach(var absenceTime in Model.SelectedSupportConcept.Customer.AbsenceTimes)
@@ -1764,6 +1828,29 @@ namespace BeWoPlanerMobil.Controllers
}
}
private static Dictionary<ServiceCategoryDC, List<ServiceDescriptionDC>> CreateServiceCategory2ServiceDescription(List<SupportConceptTreeNodeDetailInfoDC> nodes, bool isGroupBooking)
{
var result = new Dictionary<ServiceCategoryDC, List<ServiceDescriptionDC>>();
foreach(var node in nodes)
{
node.ServiceAccountings.DoForEach(sa =>
{
var serviceDescription = sa.ServiceDescription;
var category = serviceDescription.Category;
var withSupportConceptCondition = !isGroupBooking && category.OhneHilfeplan.HasValue && (category.OhneHilfeplan == AccountingvisibilityType.Beides || category.OhneHilfeplan == AccountingvisibilityType.NurKlientenbezogen);
if(withSupportConceptCondition || isGroupBooking)
{
result.AddOrUpdateValueInDictionary(category, serviceDescription);
}
});
}
return result.OrderBy(kvp => kvp.Key.Position).ToDictionary(category2Descriptions => category2Descriptions.Key, category2Descriptions => category2Descriptions.Value);
}
[HttpPost]
[Authorize]
public ActionResult DeleteServiceRecord(FormCollection formCollection)
@@ -2944,45 +3031,62 @@ namespace BeWoPlanerMobil.Controllers
}
[Authorize]
public string AddSupportConceptCostBearerRelationsToGroupBooking(string pRelOids, string pGroupOids)
public ActionResult AddScCbRelsToGroupBooking(string[] relOids, string[] groupOids)
{
if(Model is null)
{
Logout();
return LeerzeichenFuerGetMethoden;
}
var rawRelOids = string.IsNullOrEmpty(pRelOids) ? new string[0] : pRelOids.Split(',');
var rawGroupOids = string.IsNullOrEmpty(pGroupOids) ? new string[0] : pGroupOids.Split(',');
var relOids = new List<long>();
var singleRels = new List<long>();
var groupRels = new List<long>();
var groups = new List<GroupOfPeopleDC>();
rawRelOids.DoForEach(s => relOids.AddIfNotIn(long.Parse(s)));
if(groupOids is null)
{
groupOids = Array.Empty<string>();
}
if(relOids is null)
{
relOids = Array.Empty<string>();
}
relOids.DoForEach(relOid =>
{
if(long.TryParse(relOid, out var singleRelOid))
{
singleRels.AddIfNotIn(singleRelOid);
}
});
groupOids.DoForEach(groupOid =>
{
if(long.TryParse(groupOid, out var g))
{
groupRels.AddIfNotIn(g);
}
});
Model.GroupBookingSelectedGroupOfPeopleOids.Clear();
rawGroupOids.DoForEach(s =>
groupRels.DoForEach(groupOid =>
{
var group = Model.GroupsOfPeople.FirstOrDefault(f => f.GroupOfPeopleOid.HasValue && f.GroupOfPeopleOid.Value.Equals(long.Parse(s)));
var group = Model.GroupsOfPeople.FirstOrDefault(f => f.GroupOfPeopleOid.HasValue && f.GroupOfPeopleOid.Value.Equals(groupOid));
if(group is null)
{
return;
}
groups.AddIfNotIn(group);
group.SupportConceptList.DoForEach(f => relOids.AddRangeIfElementsNotIn(f.CostBearerRelOids));
group.SupportConceptList.DoForEach(f => singleRels.AddRangeIfElementsNotIn(f.CostBearerRelOids));
});
Model.GroupBookingSelectedSupportConcepts.Clear();
Model.GroupBookingSelectedCostbearerRelOids.Clear();
Model.GroupBookingSelectedCostbearerRelOids.AddRangeIfElementsNotIn(relOids);
Model.GroupBookingSelectedCostbearerRelOids.AddRangeIfElementsNotIn(singleRels);
var selectedSupportConcepts = Model.SupportConcepts.Where(w => w != null && w.CostBearerRelations.Any(a => a.CostBearer2SupportConceptOid.HasValue && relOids.Contains(a.CostBearer2SupportConceptOid.Value))).ToList();
var selectedSupportConcepts = CustomerService.GetSupportConceptsByCostbearer2SupportConceptRelOids(singleRels);
var groupCostBearerRelations = CustomerService.GetSupportConceptCostBearerRelationsById(singleRels);
var groupCostBearerRelations = CustomerService.GetSupportConceptCostBearerRelationsById(relOids);
Model.SelectedConceptCostBearerRelations.Clear();
Model.SelectedConceptCostBearerRelations.AddRangeIfElementsNotIn(groupCostBearerRelations);
@@ -2993,14 +3097,14 @@ namespace BeWoPlanerMobil.Controllers
var groupRelOids = new List<long>();
gruppe.SupportConceptList.ForEach(f => groupRelOids.AddRange(f.CostBearerRelOids));
if (!gruppe.GroupOfPeopleOid.HasValue)
if(!gruppe.GroupOfPeopleOid.HasValue)
{
continue;
}
var groupOid = gruppe.GroupOfPeopleOid.Value;
if(relOids.ContainsItems(groupRelOids))
if(singleRels.ContainsItems(groupRelOids))
{
Model.GroupBookingSelectedGroupOfPeopleOids.AddIfNotIn(groupOid);
}
@@ -3010,9 +3114,40 @@ namespace BeWoPlanerMobil.Controllers
}
}
return SerializeObject(Model.GroupBookingSelectionObject);
return PartialView("GroupBookingScCbRelList", Model);
}
[Authorize]
public ActionResult RemoveSupportConceptCostbearerRel(string relOid)
{
if(!long.TryParse(relOid, out var supportConceptCostBearerRelationOid))
{
return PartialView("GroupBookingFormPartial", Model);
}
var supportConcept = Model.GroupBookingSelectedSupportConcepts.FirstOrDefault(f => f.CostBearerRelations.Any(a => a.CostBearer2SupportConceptOid == supportConceptCostBearerRelationOid));
var relation = Model.SelectedConceptCostBearerRelations.FirstOrDefault(f => f.CostBearer2SupportConceptOid == supportConceptCostBearerRelationOid);
Model.GroupBookingSelectedSupportConcepts.Remove(supportConcept);
Model.SelectedConceptCostBearerRelations.Remove(relation);
var selectedGroups = Model.GroupsOfPeople.Where(group => group.GroupOfPeopleOid.HasValue && Model.GroupBookingSelectedGroupOfPeopleOids.Contains(group.GroupOfPeopleOid.Value)).ToList();
var groups = selectedGroups.Where(group => group.SupportConceptList.All(a => Model.GroupBookingSelectedSupportConcepts.Where(w => w.SupportConceptOid.HasValue).Select(s => s.SupportConceptOid.Value).Contains(a.SupportConceptOid)));
Model.GroupBookingSelectedGroupOfPeopleOids = groups.Where(group => group.GroupOfPeopleOid.HasValue).Select(group => group.GroupOfPeopleOid.Value).ToList();
return PartialView("GroupBookingFormPartial", Model);
}
[Authorize]
public ActionResult ReloadGroupBookingForm()
{
return PartialView("GroupBookingFormPartial", Model);
}
// ToDo: Veraltet und durch RemoveSupportConceptCostbearerRel ersetzt!
[Authorize]
public string RemoveSupportConceptCostBearerRelationFromGroupBooking(string pRelOid)
{
@@ -4100,7 +4235,7 @@ namespace BeWoPlanerMobil.Controllers
recordsOhneDuplikate.Add(r);
}
Model.ServiceRecords = recordsOhneDuplikate.Where(serviceRecord => serviceRecord.Start.HasValue && serviceRecord.End.HasValue)
var serviceRecords = recordsOhneDuplikate.Where(serviceRecord => serviceRecord.Start.HasValue && serviceRecord.End.HasValue)
.OrderBy(serviceRecord => serviceRecord.Start.Value.Date)
.ThenBy(serviceRecord => serviceRecord.Start.Value.Hour)
.ThenBy(serviceRecord => serviceRecord.Start.Value.Minute)
@@ -4108,6 +4243,40 @@ namespace BeWoPlanerMobil.Controllers
.ThenBy(serviceRecord => serviceRecord.End.Value.Hour)
.ThenBy(serviceRecord => serviceRecord.End.Value.Minute)
.ThenByDescending(serviceRecord => serviceRecord.InsertedOn.Value).ToList();
var serviceRecordOids2GoalHeaders = new Dictionary<long, List<string>>();
var goalOids = new List<long>();
var measures = new List<ValueListEntryDC>();
serviceRecords.DoForEach(serviceRecord =>
{
measures.AddRangeIfElementsNotIn(serviceRecord.Goals);
goalOids.AddRangeIfElementsNotIn(serviceRecord.Goals.Where(goal => goal.ParentOid.HasValue).Select(goal => goal.ParentOid.Value));
});
var goalCategories = ValueListService.GetGoalCategoriesByOids(goalOids);
serviceRecords.DoForEach(serviceRecord =>
{
if(serviceRecord.ServiceRecordOid is null)
{
return;
}
serviceRecord.Goals.OrderBy(vle => $"{vle.Abbreviation}-{vle.TypeDescription}").DoForEach(goal =>
{
var goalCategory = goalCategories.FirstOrDefault(g => g.ValueListEntryOid.HasValue && goal.ValueListEntryOid.HasValue && g.ValueListEntryOid.Value.Equals(goal.ValueListEntryOid.Value) || (g.ValueListEntryOid.HasValue && goal.ParentOid.HasValue && g.ValueListEntryOid.Value.Equals(goal.ParentOid.Value)));
if(goalCategory != null)
{
serviceRecordOids2GoalHeaders.AddOrUpdateValueInDictionary(serviceRecord.ServiceRecordOid.Value, new List<string> { goalCategory.DisplayName });
}
});
});
Model.ServiceRecordOids2GoalHeader = serviceRecordOids2GoalHeaders;
Model.ServiceRecords = serviceRecords;
}
[Authorize]
@@ -4179,6 +4348,33 @@ namespace BeWoPlanerMobil.Controllers
}
throw new Exception("No network adapters with an IPv4 address in the system!");
}
[Authorize]
public ActionResult ReloadGoals()
{
LoadGoals();
return PartialView("GoalTreePartial", Model);
}
[Authorize]
public ActionResult UpdateServiceCategories()
{
LoadServiceCategoriesToModel(null);
return PartialView("Category2ServiceDescriptionPartial", Model);
}
[Authorize]
public ActionResult SetSelectedServiceCategory(string categoryOidStr)
{
if(long.TryParse(categoryOidStr, out var categoryOid))
{
Model.SelectedServiceCategory = Model.Categories2Descriptions.FirstOrDefault(f => f.Key?.ServiceCategoryOid != null && f.Key.ServiceCategoryOid.Value.Equals(categoryOid)).Key;
}
return PartialView("Category2ServiceDescriptionPartial", Model);
}
}
public class ServiceRecord2Monatsunterschrift

View File

@@ -30,11 +30,11 @@ namespace BeWoPlanerMobil
protected void Application_BeginRequest(object sender, EventArgs e)
{
Context.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
Context.Response.Cache.SetAllowResponseInBrowserHistory(false);
Context.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
Context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
Context.Response.Cache.SetNoStore();
//Context.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
// Context.Response.Cache.SetAllowResponseInBrowserHistory(false);
// Context.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
// Context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
// Context.Response.Cache.SetNoStore();
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
}

View File

@@ -766,6 +766,15 @@ namespace BeWoPlanerMobil.Models
public bool IsCustomerAbsence { get; set; }
public string CustomerAbsenceInfo { get; set; }
public Dictionary<long, List<string>> ServiceRecordOids2GoalHeader { get; set; }
public bool FilterGroupServiceCategories { get; set; }
public Dictionary<ServiceCategoryDC, List<ServiceDescriptionDC>> Categories2Descriptions { get; set; }
public ServiceCategoryDC SelectedServiceCategory { get; set; }
public ServiceDescriptionDC SelectedServiceDescription { get; set; }
}
public class CustomSelectListItem

View File

@@ -1,40 +1,4 @@
function addCostBearer2SupportConceptsToGroupBooking() {
var url = getAddSupportConceptsLink();
var selectedGroups = [];
var selectedSupportConcepts = [];
var scOidString = "";
var groupOidString = "";
$("#group-booking-supportconcepts input:checked").each(function () {
selectedSupportConcepts.push($(this).attr("value"));
});
$("#group-booking-groups input:checked").each(function () {
selectedGroups.push($(this).attr("value"));
});
for(var i = 0; i < selectedSupportConcepts.length; i++) {
scOidString += selectedSupportConcepts[i];
if(i < selectedSupportConcepts.length - 1) {
scOidString += ",";
}
}
for(var j = 0; j < selectedGroups.length; j++) {
groupOidString += selectedGroups[j];
if(j < selectedGroups.length - 1) {
groupOidString += ",";
}
}
$.get(url, {pRelOids: scOidString, pGroupOids: groupOidString}).done(updateGroupBookingCb2ScList);
}
function updateGroupBookingCb2ScList(result) {
function updateGroupBookingCb2ScList(result) {
try {
var list = $("#selected-cb2sc-list");

View File

@@ -1,27 +1,27 @@
class PasswordSecurity {
numbers = "0123456789";
lowercaseLetters = "abcdefghijklmnopqrstuvwxyz";
uppercaseLetters = "ABDEFGHIJKLMNOPQRSTUVWXYZ";
lowercaseUmlauts = "äöüß";
uppercaseUmlauts = "ÄÖÜ";
specialChars1 = "\\\"\'µ@€!";
specialChars2 = "&/()=?+*";
specialChars3 = ",.-;:_><|";
specialChars4 = "§$%'{[]}´";
specialChars5 = "`^°~²³";
class MoKPasswordSecurity {
_numbers = "0123456789";
_lowercaseLetters = "abcdefghijklmnopqrstuvwxyz";
_uppercaseLetters = "ABDEFGHIJKLMNOPQRSTUVWXYZ";
_lowercaseUmlauts = "äöüß";
_uppercaseUmlauts = "ÄÖÜ";
_specialChars1 = "\\\"\'µ@€!";
_specialChars2 = "&/()=?+*";
_specialChars3 = ",.-;:_><|";
_specialChars4 = "§$%'{[]}´";
_specialChars5 = "`^°~²³";
isPartial = false;
partialPassword = "";
passwordLengthDifference = 0;
score = 0;
previousValue = 0;
schalter = false;
previousValues = [];
_isPartial = false;
_partialPassword = "";
_passwordLengthDifference = 0;
_score = 0;
_previousValue = 0;
_schalter = false;
_previousValues = [];
passwordLabelId = "";
_passwordLabelId = "";
constructor(pwLabelId) {
this.passwordLabelId = pwLabelId;
this._passwordLabelId = pwLabelId;
}
validatePassword(password) {
@@ -32,13 +32,13 @@
for (var i = 0; i < password.length; i++) {
sx += password[i];
if (sx.length < this.partialPassword.length) {
this.isPartial = true;
this.passwordLengthDifference = this.partialPassword.length - sx.length;
if (sx.length < this._partialPassword.length) {
this._isPartial = true;
this._passwordLengthDifference = this._partialPassword.length - sx.length;
}
if (this.partialPassword !== sx) {
this.partialPassword = sx;
if (this._partialPassword !== sx) {
this._partialPassword = sx;
}
passwordStrength = this.calculatePasswordStrength(sx);
@@ -48,8 +48,8 @@
return;
}
this.score = 0;
this.previousValue = 0;
this._score = 0;
this._previousValue = 0;
this.displayPasswordStrength(-1);
}
@@ -65,54 +65,54 @@
}
getLastValue() {
if (this.previousValues === undefined || this.previousValues === null || this.previousValues.length === 0) {
if (this._previousValues === undefined || this._previousValues === null || this._previousValues.length === 0) {
return 0;
}
return this.previousValues[this.previousValues.length - 1];
return this._previousValues[this._previousValues.length - 1];
}
calculatePasswordStrength(passwordToValidate) {
var passwordStrength = 0;
this.previousValue = 0;
this._previousValue = 0;
if (this.isPartial === true) {
if (this.passwordLengthDifference === 1) {
this.score -= this.getLastValue();
this.previousValues.pop();
if (this._isPartial === true) {
if (this._passwordLengthDifference === 1) {
this._score -= this.getLastValue();
this._previousValues.pop();
} else {
for (var i = 0; i < this.passwordLengthDifference; i++) {
this.score -= this.getLastValue();
this.previousValues.pop();
for (var i = 0; i < this._passwordLengthDifference; i++) {
this._score -= this.getLastValue();
this._previousValues.pop();
}
}
this.isPartial = false;
this._isPartial = false;
} else {
var passwordLength = passwordToValidate.length;
if (passwordLength >= 6 && passwordLength < 9) {
this.score += 1;
this.previousValue = 1;
this.schalter = true;
this._score += 1;
this._previousValue = 1;
this._schalter = true;
}
if (passwordLength >= 9 && passwordLength < 12) {
this.score += 2;
this.previousValue = 2;
this.schalter = true;
this._score += 2;
this._previousValue = 2;
this._schalter = true;
}
if (passwordLength >= 12 && passwordLength < 18) {
this.score += 3;
this.previousValue = 3;
this.schalter = true;
this._score += 3;
this._previousValue = 3;
this._schalter = true;
}
if (passwordLength >= 18) {
this.score += 4;
this.previousValue = 4;
this.schalter = true;
this._score += 4;
this._previousValue = 4;
this._schalter = true;
}
var passwordAsArray = Array.from(passwordToValidate);
@@ -120,7 +120,7 @@
// Zahlen
var containsNumbers = false;
for (var i = 0; i < passwordAsArray.length; i++) {
if (this.numbers.includes(passwordAsArray[i])) {
if (this._numbers.includes(passwordAsArray[i])) {
containsNumbers = true;
break;
}
@@ -129,7 +129,7 @@
// Kleinbuchstaben
var containsLowercaseLetters = false;
for (var i = 0; i < passwordAsArray.length; i++) {
if (this.lowercaseLetters.includes(passwordAsArray[i])) {
if (this._lowercaseLetters.includes(passwordAsArray[i])) {
containsLowercaseLetters = true;
break;
}
@@ -138,7 +138,7 @@
// Großbuchstaben
var containsUppercaseLetters = false;
for (var i = 0; i < passwordAsArray.length; i++) {
if (this.uppercaseLetters.includes(passwordAsArray[i])) {
if (this._uppercaseLetters.includes(passwordAsArray[i])) {
containsUppercaseLetters = true;
break;
}
@@ -147,7 +147,7 @@
// Kleinumlaute
var containsLowercaseUmlauts = false;
for (var i = 0; i < passwordAsArray.length; i++) {
if (this.lowercaseUmlauts.includes(passwordAsArray[i])) {
if (this._lowercaseUmlauts.includes(passwordAsArray[i])) {
containsLowercaseUmlauts = true;
break;
}
@@ -156,7 +156,7 @@
// Großumlaute
var containsUppercaseUmlauts = false;
for (var i = 0; i < passwordAsArray.length; i++) {
if (this.uppercaseUmlauts.includes(passwordAsArray[i])) {
if (this._uppercaseUmlauts.includes(passwordAsArray[i])) {
containsUppercaseUmlauts = true;
break;
}
@@ -165,7 +165,7 @@
// Sonderzeichen 1
var containsSpecialCharacters1 = false;
for (var i = 0; i < passwordAsArray.length; i++) {
if (this.specialChars1.includes(passwordAsArray[i])) {
if (this._specialChars1.includes(passwordAsArray[i])) {
containsSpecialCharacters1 = true;
break;
}
@@ -173,7 +173,7 @@
var containsSpecialCharacters2 = false;
for (var i = 0; i < passwordAsArray.length; i++) {
if (this.specialChars2.includes(passwordAsArray[i])) {
if (this._specialChars2.includes(passwordAsArray[i])) {
containsSpecialCharacters2 = true;
break;
}
@@ -181,7 +181,7 @@
var containsSpecialCharacters3 = false;
for (var i = 0; i < passwordAsArray.length; i++) {
if (this.specialChars3.includes(passwordAsArray[i])) {
if (this._specialChars3.includes(passwordAsArray[i])) {
containsSpecialCharacters3 = true;
break;
}
@@ -189,7 +189,7 @@
var containsSpecialCharacters4 = false;
for (var i = 0; i < passwordAsArray.length; i++) {
if (this.specialChars4.includes(passwordAsArray[i])) {
if (this._specialChars4.includes(passwordAsArray[i])) {
containsSpecialCharacters4 = true;
break;
}
@@ -197,7 +197,7 @@
var containsSpecialCharacters5 = false;
for (var i = 0; i < passwordAsArray.length; i++) {
if (this.specialChars5.includes(passwordAsArray[i])) {
if (this._specialChars5.includes(passwordAsArray[i])) {
containsSpecialCharacters5 = true;
break;
}
@@ -243,26 +243,26 @@
this.addScoreValue(4);
}
this.previousValues.push(this.previousValue);
this._previousValues.push(this._previousValue);
}
if (this.score <= 15) {
if (this._score <= 15) {
passwordStrength = 0;
}
if (this.score > 15 && this.score <= 55) {
if (this._score > 15 && this._score <= 55) {
passwordStrength = 1;
}
if (this.score > 55 && this.score <= 115) {
if (this._score > 55 && this._score <= 115) {
passwordStrength = 2;
}
if (this.score > 115 && this.score <= 155) {
if (this._score > 115 && this._score <= 155) {
passwordStrength = 3;
}
if (this.score > 155) {
if (this._score > 155) {
passwordStrength = 4;
}
@@ -274,17 +274,17 @@
return;
}
this.score += defaultValue;
this._score += defaultValue;
if (this.schalter === true) {
this.previousValue += defaultValue;
if (this._schalter === true) {
this._previousValue += defaultValue;
} else {
this.previousValue = defaultValue;
this._previousValue = defaultValue;
}
}
displayPasswordStrength(passwordStrength) {
var passwordLabel = $("#" + this.passwordLabelId);
var passwordLabel = $("#" + this._passwordLabelId);
if (passwordStrength === undefined || !$.isNumeric(passwordStrength) || !passwordLabel.length) {
return;

View File

@@ -525,11 +525,11 @@ function getSignatureImage(serviceRecordOid, signatureOid) {
function setServiceDescription(id) {
try {
var url = getSetServiceDescriptionUrl();
var selectedServiceDescription = $("#" + id).find(":selected").val();
$.get(url, { pServiceDescriptionOid: selectedServiceDescription});
} catch (error) {
$.get(url, {pServiceDescriptionOid: selectedServiceDescription});
} catch(error) {
showErrorPopup(error);
}
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using BS.Shared;
namespace BeWoPlanerMobil.Util
{
@@ -20,9 +21,12 @@ namespace BeWoPlanerMobil.Util
public bool IsGoal { get; }
public GoalTreeItem(bool isGoal)
public ValueListEntryType ValueListEntryType { get; }
public GoalTreeItem(bool isGoal, ValueListEntryType valueListEntryType)
{
IsGoal = isGoal;
ValueListEntryType = valueListEntryType;
}
}
}

View File

@@ -0,0 +1,85 @@
@model BeWoPlanerMobil.Models.MainModel
<script type="text/javascript">
function setSelectedServiceDescription(serviceDescriptionOid) {
try {
$.get("@Url.Action("SetServiceDescription")", {pServiceDescriptionOid: serviceDescriptionOid});
} catch (error) {
showErrorPopup(error);
}
}
function setSelectedServiceCategory() {
try {
var selectedCategoryOid = $("#category-select").find(":selected").val();
$("#category-to-description-container").load("@Url.Action("SetSelectedServiceCategory")", {categoryOidStr: selectedCategoryOid}, function() {
$("#tree").load("@Url.Action("LoadUpToDateTextModules")");
});
} catch(error) {
showErrorPopup(error);
}
}
function loadServiceDescriptions(categoryOid) {
try {
// ToDo: Benötigt?
} catch(error) {
showErrorPopup(error);
}
}
</script>
<!-- Kategorie -->
<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>
<select id="category-select" class="custom-select" onchange="setSelectedServiceCategory()">
@foreach(var serviceCategory2ServiceDescriptions in Model.Categories2Descriptions)
{
var category = serviceCategory2ServiceDescriptions.Key;
var selected = Model.SelectedServiceCategory?.Equals(category) ?? false ? "selected" : string.Empty;
<option value="@category.ServiceCategoryOid" @selected>@category.Name</option>
}
</select>
</div>
</div>
</div>
</div>
<!-- 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')">
@{
var selectedCategory = Model.SelectedServiceCategory ?? Model.Categories2Descriptions.FirstOrDefault().Key;
}
@if(selectedCategory != null && Model.Categories2Descriptions.ContainsKey(selectedCategory))
{
foreach(var serviceDescription in Model.Categories2Descriptions[selectedCategory])
{
var selected = Model.SelectedServiceDescription?.Equals(serviceDescription) ?? false ? "selected" : string.Empty;
<option value="@serviceDescription.ServiceDescriptionOid" @selected>@serviceDescription.Name</option>
}
}
</select>
</div>
</div>
</div>
</div>

View File

@@ -1,5 +1,6 @@
@using BeWoPlanerMobil.Models
@using BeWoPlanerMobil.Util
@using BS.Shared
@using BS.Shared.DataContracts
@model MainModel
@@ -98,6 +99,11 @@
{
var isChecked = Model.SelectedGoals.Any(a => a.ValueListEntryOid.HasValue && a.ValueListEntryOid.Value == goalTreeItem.ValueListEntryOid);
var isCheckedValue = isChecked ? "checked" : string.Empty;
var textClass = goalTreeItem.ValueListEntryType == ValueListEntryType.SupportConceptIndividualGoalCategoryType ||
goalTreeItem.ValueListEntryType == ValueListEntryType.SupportConceptIndividualGoalType
? "text-bewo-custom-goal"
: string.Empty;
RatingTypeDC ratingType = null;
@@ -118,7 +124,7 @@
<div class="clearfix">
<div class="custom-control custom-checkbox goal-card-header float-left" onclick="stopToggle(event)" >
<input type="checkbox" class="custom-control-input" value="@goalTreeItem.ValueListEntryOid" @isCheckedValue id="@goalTreeItem.ValueListEntryOid" onchange="updateSelectedGoals()" />
<label class="custom-control-label goal-name-label" for="@goalTreeItem.ValueListEntryOid">@goalTreeItem.Header</label>
<label class="custom-control-label goal-name-label @textClass" for="@goalTreeItem.ValueListEntryOid">@goalTreeItem.Header</label>
@if(AbstractModel.HasRightToRateGoals)
{
<span id="goal-rating-@goalTreeItem.ValueListEntryOid" class="badge badge-bewo-goal-rating goal-rating-badge ml-1" onclick="showGoalRatingPopup(@goalTreeItem.ValueListEntryOid)">
@@ -147,7 +153,7 @@
<div class="custom-control custom-checkbox goal-text @marginBottom">
<input type="checkbox" class="custom-control-input" id="@goalTreeItem.ValueListEntryOid" @isCheckedValue onchange="updateSelectedGoals()">
<label for="@goalTreeItem.ValueListEntryOid" class="custom-control-label goal-name-label">@goalTreeItem.Header</label>
<label for="@goalTreeItem.ValueListEntryOid" class="custom-control-label goal-name-label @textClass">@goalTreeItem.Header</label>
@if(AbstractModel.HasRightToRateGoals)
{
<span id="goal-rating-@goalTreeItem.ValueListEntryOid" class="badge badge-bewo-goal-rating goal-rating-badge ml-1" onclick="showGoalRatingPopup(@goalTreeItem.ValueListEntryOid)">

View File

@@ -0,0 +1,414 @@
@using BeWoPlanerMobil.Models
@using BeWoPlanerMobil.Util
@using BS.Shared
@model BeWoPlanerMobil.Models.MainModel
<script type="text/javascript">
function removeSupportConceptCostBearerRel(relOid) {
try {
$(`#cb2sc-checkbox-${relOid}`).prop("checked", false);
$("#group-booking-form-container").load("@Url.Action("RemoveSupportConceptCostbearerRel")", {relOid: relOid}, function () {
$("#goals-tree").load("@Url.Action("ReloadGoals")", function() {
var checkedCheckboxes = $(".cb2sc-input:checkbox:checked");
$("#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, #marker-cb").prop("disabled", (checkedCheckboxes.length > 0 ? false : true));
$("#category-to-description-container").load("@Url.Action("UpdateServiceCategories")");
});
});
} catch (error) {
showErrorPopup(error);
}
}
</script>
@if(Model != null)
{
var submitButtonText = Model.IsInEditingMode ? "Speichern" : "Anlegen";
using(Html.BeginForm("CreateOrUpdateGroupBooking", "Main", FormMethod.Post, new { onreset = "serviceDescriptionSelectOnReset('category-select', 'leistung-select', 'textmodule-container', 'tree')", id = "groupBookingForm" }))
{
var startDate = Model.SelectedServiceRecord?.Start?.ToShortDateString() ?? DateTime.Today.ToShortDateString();
var endDate = Model.SelectedServiceRecord?.End?.ToShortDateString() ?? DateTime.Today.ToShortDateString();
var startTime = Model.SelectedServiceRecord?.Start?.ToShortTimeString() ?? string.Empty;
var endTime = Model.SelectedServiceRecord?.End?.ToShortTimeString() ?? string.Empty;
var duration = Model.SelectedServiceRecord?.GroupRoundedDuration?.ToString() ?? string.Empty;
var distance = Model.SelectedServiceRecord?.DistanceInMeter?.ToString() ?? string.Empty;
var notice0 = Model.SelectedServiceRecord?.Notice ?? string.Empty;
var noticeList = new[] { string.Empty, string.Empty, string.Empty, string.Empty, string.Empty };
if(Model.SelectedServiceRecord?.NoticeList != null)
{
var selectedNoticeList = Model.SelectedServiceRecord.NoticeList;
for(var i = 0; i < selectedNoticeList.Count; i++)
{
noticeList[i] = selectedNoticeList[i] ?? string.Empty;
}
}
<div class="mt-3">
<div class="form-row">
<div class="col-md">
<div class="alert alert-danger collapse" role="alert" id="form-alert">
</div>
</div>
</div>
<div class="form-row">
<div class="col-md">
<button type="button" class="btn btn-primary btn-block" data-toggle="modal" data-target="#group-booking-popup" id="support-concepts-and-groups-button">Hilfepläne und Gruppen hinzufügen</button>
</div>
</div>
<!-- Hilfeplanauswahl -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-1">
<div class="list-group" id="selected-cb2sc-list">
@foreach(var selectedCb2ScRelation in Model.GroupBookingSelectionObject.SelectedRelations)
{
<div class="list-group-item" id="relation-item-@selectedCb2ScRelation.Value">
<div class="row">
<div class="col">
<span>
@selectedCb2ScRelation.Text1
<br />
<span class="@selectedCb2ScRelation.TextColor">
@selectedCb2ScRelation.Text2
</span>
</span>
</div>
<div class="col-auto my-auto">
<button type="button" class="btn btn-primary" onclick="removeSupportConceptCostBearerRel(@selectedCb2ScRelation.Value)">
<span class="fas fa-times-circle"></span>
</button>
</div>
</div>
</div>
}
</div>
</div>
</div>
</div>
<!-- Mitarbeiter -->
<div class="form-row">
<div class="col-md">
<div class="form-group mb-1">
<button type="button" class="btn btn-primary btn-block" data-toggle="modal" data-target="#group-booking-employee-selection-popup" id="employees-button">
Mitarbeiter hinzufügen <span class="badge badge-light text-primary" id="selected-employees-count-badge">@Model.GroupBookingSelectedEmployees.Count</span>
</button>
</div>
</div>
</div>
<!-- Ziele -->
@if((Model.GroupBookingSelectedSupportConcepts?.Any() ?? false) && Model.GroupBookingSelectedSupportConcepts.Any(sc => sc.Goals.Any()))
{
<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>
}
<!-- Kategorie -->
<!--<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>-->
<!-- 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>-->
@* Kategorie und Leistungen *@
<div id="category-to-description-container">
@Html.Partial("Category2ServiceDescriptionPartial", Model)
</div>
<!-- Marker -->
@if(Model.ShowMarker)
{
var markerCheckedValue = Model.SelectedServiceRecord?.ServiceRecordType == ServiceRecordTypeId.Content ? "checked" : string.Empty;
<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" @markerCheckedValue />
<label class="custom-control-label" for="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">
<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="@startDate" />
<div class="input-group-append" data-target="#start-date-picker" data-toggle="datetimepicker">
<div class="input-group-text">
<i class="fas fa-calendar-alt"></i>
</div>
</div>
</div>
</div>
</div>
@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="@endDate" />
<div class="input-group-append" data-target="#end-date-picker" data-toggle="datetimepicker">
<div class="input-group-text">
<i class="fas fa-calendar-alt"></i>
</div>
</div>
</div>
</div>
</div>
}
</div>
<div class="form-row">
@{
var startTimeValue = Model.StartTimeToEdit;
var endTimeValue = Model.EndTimeToEdit;
var divisor = Model.SelectedDurationUnit == "Stunden" ? 60 : 1;
var durationValue = string.Empty;
if(!(Model.SelectedServiceRecord is null))
{
durationValue = (Model.SelectedServiceRecord?.RoundedDuration / divisor).ToString();
}
var afterValidationState = TempData[TempDataConstants.AfterValidationStateKey];
if(Model.SetStartTimeToEndTimeAfterSave && !Model.IsInEditingMode && afterValidationState is bool isAfterValidation && isAfterValidation == false)
{
startTimeValue = Model.NewStartTime;
endTimeValue = Model.NewEndTime;
if(Model.NewDuration.HasValue)
{
durationValue = (Model.NewDuration / divisor).ToString();
}
}
}
<!-- Von -->
<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">
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">
<i class="fas fa-clock"></i>
</div>
</div>
</div>
</div>
</div>
<!-- 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">
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">
<i class="fas fa-clock"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Dauer und Stunden/Minuten-Auswahl -->
<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>
@if(Model.ShowDistanceField)
{
<!-- Gefahrene Kilomter -->
<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 type="text" class="form-control" id="distance" name="Distanz" onchange="validateDistanceInput()" value="@distance">
</div>
</div>
</div>
</div>
}
@if(AbstractModel.HasRightToSeeTextModules)
{
<!-- 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">Textbausteine</button>
</div>
</div>
}
<!-- Dokumentation -->
<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">@notice0</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];
<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">@noticeList[i]</textarea>
</div>
}
</div>
}
</div>
</div>
</div>
}
<div class="d-flex bd-highlight mt-3">
<div class="mr-auto bd-highlight">
<!-- dient nur als Abstandshalter-->
</div>
<div class="ml-3 bd-highlight">
@if(TempData[TempDataConstants.IsInTransferModeKey] is bool isInTransferMode && isInTransferMode)
{
using(Html.BeginForm("ResetTransferMode", "Main", FormMethod.Post))
{
<button type="submit" class="btn btn-primary" onclick="showSpinner()">Abbrechen</button>
}
}
else
{
using(Html.BeginForm("ResetEditingMode", "Main", FormMethod.Post))
{
<button type="submit" class="btn btn-primary" onclick="showSpinner()">Abbrechen</button>
}
}
</div>
<div class="ml-3 bd-highlight">
<button type="button" class="btn btn-primary" id="create-button" onclick="submitGroupBookingForm()">@submitButtonText</button>
</div>
</div>
}

View File

@@ -1,7 +1,4 @@
@using BeWoPlanerMobil.Models
@using BeWoPlanerMobil.Util
@using BS.Shared
@model BeWoPlanerMobil.Models.MainModel
@model BeWoPlanerMobil.Models.MainModel
<script>
$(document).ready(function () {
@@ -44,371 +41,10 @@
}
<div class="row">
<div class="col col-12">
<div class="col col-12" id="group-booking-form-container">
@if(Model != null)
{
var submitButtonText = Model.IsInEditingMode ? "Speichern" : "Anlegen";
using(Html.BeginForm("CreateOrUpdateGroupBooking", "Main", FormMethod.Post, new { onreset = "serviceDescriptionSelectOnReset('category-select', 'leistung-select', 'textmodule-container', 'tree')", id = "groupBookingForm" }))
{
var startDate = Model.SelectedServiceRecord?.Start?.ToShortDateString() ?? DateTime.Today.ToShortDateString();
var endDate = Model.SelectedServiceRecord?.End?.ToShortDateString() ?? DateTime.Today.ToShortDateString();
var startTime = Model.SelectedServiceRecord?.Start?.ToShortTimeString() ?? string.Empty;
var endTime = Model.SelectedServiceRecord?.End?.ToShortTimeString() ?? string.Empty;
var duration = Model.SelectedServiceRecord?.GroupRoundedDuration?.ToString() ?? string.Empty;
var distance = Model.SelectedServiceRecord?.DistanceInMeter?.ToString() ?? string.Empty;
var notice0 = Model.SelectedServiceRecord?.Notice ?? string.Empty;
var noticeList = new[] { string.Empty, string.Empty, string.Empty, string.Empty, string.Empty };
if(Model.SelectedServiceRecord?.NoticeList != null)
{
var selectedNoticeList = Model.SelectedServiceRecord.NoticeList;
for(var i = 0; i < selectedNoticeList.Count; i++)
{
noticeList[i] = selectedNoticeList[i] ?? string.Empty;
}
}
<div class="mt-3">
<div class="form-row">
<div class="col-md">
<div class="alert alert-danger collapse" role="alert" id="form-alert">
</div>
</div>
</div>
<div class="form-row">
<div class="col-md">
<button type="button" class="btn btn-primary btn-block" data-toggle="modal" data-target="#group-booking-popup" id="support-concepts-and-groups-button">Hilfepläne und Gruppen hinzufügen</button>
</div>
</div>
<!-- Hilfeplanauswahl -->
<div class="form-row">
<div class="col-md">
<div class="form-group my-1">
<div class="list-group" id="selected-cb2sc-list">
@foreach(var selectedCb2ScRelation in Model.GroupBookingSelectionObject.SelectedRelations)
{
<div class="list-group-item" id="relation-item-@selectedCb2ScRelation.Value">
<div class="row">
<div class="col">
<span>
@selectedCb2ScRelation.Text1
<br />
<span class="@selectedCb2ScRelation.TextColor">
@selectedCb2ScRelation.Text2
</span>
</span>
</div>
<div class="col-auto my-auto">
<button type="button" class="btn btn-primary" onclick="removeCb2ScRelation(@selectedCb2ScRelation.Value)">
<span class="fas fa-times-circle"></span>
</button>
</div>
</div>
</div>
}
</div>
</div>
</div>
</div>
<!-- Mitarbeiter -->
<div class="form-row">
<div class="col-md">
<div class="form-group mb-1">
<button type="button" class="btn btn-primary btn-block" data-toggle="modal" data-target="#group-booking-employee-selection-popup" id="employees-button">
Mitarbeiter hinzufügen <span class="badge badge-light text-primary" id="selected-employees-count-badge">@Model.GroupBookingSelectedEmployees.Count</span>
</button>
</div>
</div>
</div>
<!-- Kategorie -->
<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>
<!-- 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)
{
var markerCheckedValue = Model.SelectedServiceRecord?.ServiceRecordType == ServiceRecordTypeId.Content ? "checked" : string.Empty;
<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" @markerCheckedValue />
<label class="custom-control-label" for="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">
<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="@startDate" />
<div class="input-group-append" data-target="#start-date-picker" data-toggle="datetimepicker">
<div class="input-group-text">
<i class="fas fa-calendar-alt"></i>
</div>
</div>
</div>
</div>
</div>
@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="@endDate" />
<div class="input-group-append" data-target="#end-date-picker" data-toggle="datetimepicker">
<div class="input-group-text">
<i class="fas fa-calendar-alt"></i>
</div>
</div>
</div>
</div>
</div>
}
</div>
<div class="form-row">
@{
var startTimeValue = Model.StartTimeToEdit;
var endTimeValue = Model.EndTimeToEdit;
var divisor = Model.SelectedDurationUnit == "Stunden" ? 60 : 1;
var durationValue = string.Empty;
if(!(Model.SelectedServiceRecord is null))
{
durationValue = (Model.SelectedServiceRecord?.RoundedDuration / divisor).ToString();
}
var afterValidationState = TempData[TempDataConstants.AfterValidationStateKey];
if(Model.SetStartTimeToEndTimeAfterSave && !Model.IsInEditingMode && afterValidationState is bool isAfterValidation && isAfterValidation == false)
{
startTimeValue = Model.NewStartTime;
endTimeValue = Model.NewEndTime;
if(Model.NewDuration.HasValue)
{
durationValue = (Model.NewDuration / divisor).ToString();
}
}
}
<!-- Von -->
<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">
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">
<i class="fas fa-clock"></i>
</div>
</div>
</div>
</div>
</div>
<!-- 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">
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">
<i class="fas fa-clock"></i>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Dauer und Stunden/Minuten-Auswahl -->
<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>
@if(Model.ShowDistanceField)
{
<!-- Gefahrene Kilomter -->
<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 type="text" class="form-control" id="distance" name="Distanz" onchange="validateDistanceInput()" value="@distance">
</div>
</div>
</div>
</div>
}
@if(AbstractModel.HasRightToSeeTextModules)
{
<!-- 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">Textbausteine</button>
</div>
</div>
}
<!-- Dokumentation -->
<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">@notice0</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];
<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">@noticeList[i]</textarea>
</div>
}
</div>
}
</div>
</div>
</div>
}
<div class="d-flex bd-highlight mt-3">
<div class="mr-auto bd-highlight">
<!-- dient nur als Abstandshalter-->
</div>
<div class="ml-3 bd-highlight">
@if(TempData[TempDataConstants.IsInTransferModeKey] is bool isInTransferMode && isInTransferMode)
{
using(Html.BeginForm("ResetTransferMode", "Main", FormMethod.Post))
{
<button type="submit" class="btn btn-primary" onclick="showSpinner()">Abbrechen</button>
}
}
else
{
using(Html.BeginForm("ResetEditingMode", "Main", FormMethod.Post))
{
<button type="submit" class="btn btn-primary" onclick="showSpinner()">Abbrechen</button>
}
}
</div>
<div class="ml-3 bd-highlight">
<button type="button" class="btn btn-primary" id="create-button" onclick="submitGroupBookingForm()">@submitButtonText</button>
</div>
</div>
@Html.Partial("GroupBookingFormPartial", Model);
}
</div>
</div>
@@ -428,61 +64,8 @@
<a class="nav-item nav-link active" href="#group-booking-supportconcepts" data-toggle="tab" role="tab">Hilfepläne</a>
<a class="nav-item nav-link" href="#group-booking-groups" data-toggle="tab" role="tab">Gruppen</a>
</nav>
<div class="tab-content">
<div class="tab-pane show active" role="tabpanel" id="group-booking-supportconcepts">
<ul class="list-group">
@foreach(var cb2Sc in Model.SupportConceptListObjectsForGroupBooking)
{
<li class="list-group-item">
@{
var timeSpanColorClass2 = cb2Sc.IsAboutToExpire ? "text-bewo-is-about-to-expire" : cb2Sc.ExpiresInThreeMonthsOrLess ? "text-bewo-expires-in-three-months" : "text-dark";
var wasSuccessful = long.TryParse(cb2Sc.CostBearer2SupportConceptOid, out var cb2ScOid);
var checkedValue = wasSuccessful ? Model.SelectedConceptCostBearerRelations.Any(a => a.CostBearer2SupportConceptOid.Equals(cb2ScOid)) : wasSuccessful;
}
<div class="custom-control custom-checkbox custom-control-inline">
<input type="checkbox"
@{ if(checkedValue) { @Html.Raw("checked=\"checked\"") ; } }
class="custom-control-input" id="cb2sc-checkbox-@cb2Sc.CostBearer2SupportConceptOid" onchange="addCostBearer2SupportConceptsToGroupBooking()" name="cb2sc-checkbox-@cb2Sc.CostBearer2SupportConceptOid" value="@cb2Sc.CostBearer2SupportConceptOid">
<label for="cb2sc-checkbox-@cb2Sc.CostBearer2SupportConceptOid" class="custom-control-label">
<span class="justify-content-between mb-1 text-dark text-left">
@cb2Sc.NameAndDateOfBirth
</span>
<br />
<span class="mb-1 text-left @timeSpanColorClass2">
@cb2Sc.SupportConceptTimeSpan
</span>
</label>
</div>
</li>
}
</ul>
</div>
<div class="tab-pane show" role="tabpanel" id="group-booking-groups">
<ul class="list-group">
@foreach(var group in Model.GroupOfPeopleListItems)
{
<li class="list-group-item">
@{
long groupOid;
var wasSuccessful = long.TryParse(group.Value, out groupOid);
var shouldBeChecked = wasSuccessful ? Model.GroupBookingSelectedGroupOfPeopleOids.Contains(groupOid) : wasSuccessful;
var attribute = shouldBeChecked ? "checked=\"checked\"" : string.Empty;
}
<div class="custom-control custom-checkbox custom-control-inline">
<input type="checkbox" @attribute class="custom-control-input" id="group-checkbox-@group.Value" value="@group.Value" onchange="addCostBearer2SupportConceptsToGroupBooking()" />
<label for="group-checkbox-@group.Value" class="custom-control-label">
@group.Text
</label>
</div>
</li>
}
</ul>
</div>
<div class="tab-content" id="group-booking-sc-cb-rel-tab-content">
@Html.Partial("GroupBookingScCbRelList", Model)
</div>
</div>
</div>

View File

@@ -0,0 +1,82 @@
@model BeWoPlanerMobil.Models.MainModel
<script type="text/javascript">
function addScCbRelsToGroupBooking() {
try {
var selectedGroups = [];
var selectedSupportConcepts = [];
$("#group-booking-supportconcepts input:checked").each(function () {
selectedSupportConcepts.push($(this).attr("value"));
});
$("#group-booking-groups input:checked").each(function () {
selectedGroups.push($(this).attr("value"));
});
$("#group-booking-sc-cb-rel-tab-content").load("@Url.Action("AddScCbRelsToGroupBooking")", {relOids: selectedSupportConcepts, groupOids: selectedGroups}, function() {
$("#group-booking-form-container").load("@Url.Action("ReloadGroupBookingForm")", function () {
$("#goals-tree").load("@Url.Action("ReloadGoals")", function() {
$("#category-to-description-container").load("@Url.Action("UpdateServiceCategories")");
});
});
});
} catch(error) {
showErrorPopup(error);
}
}
</script>
<div class="tab-pane show active" role="tabpanel" id="group-booking-supportconcepts">
<ul class="list-group">
@foreach(var cb2Sc in Model.SupportConceptListObjectsForGroupBooking)
{
<li class="list-group-item">
@{
var timeSpanColorClass2 = cb2Sc.IsAboutToExpire ? "text-bewo-is-about-to-expire" : cb2Sc.ExpiresInThreeMonthsOrLess ? "text-bewo-expires-in-three-months" : "text-dark";
var wasSuccessful = long.TryParse(cb2Sc.CostBearer2SupportConceptOid, out var cb2ScOid);
var checkedValue = wasSuccessful ? Model.SelectedConceptCostBearerRelations.Any(a => a.CostBearer2SupportConceptOid.Equals(cb2ScOid)) : wasSuccessful;
}
<div class="custom-control custom-checkbox custom-control-inline">
<input type="checkbox"
@{ if(checkedValue) { @Html.Raw("checked=\"checked\"") ; } }
class="custom-control-input cb2sc-input" id="cb2sc-checkbox-@cb2Sc.CostBearer2SupportConceptOid" onchange="addScCbRelsToGroupBooking()" name="cb2sc-checkbox-@cb2Sc.CostBearer2SupportConceptOid" value="@cb2Sc.CostBearer2SupportConceptOid">
<label for="cb2sc-checkbox-@cb2Sc.CostBearer2SupportConceptOid" class="custom-control-label">
<span class="justify-content-between mb-1 text-dark text-left">
@cb2Sc.NameAndDateOfBirth
</span>
<br />
<span class="mb-1 text-left @timeSpanColorClass2">
@cb2Sc.SupportConceptTimeSpan
</span>
</label>
</div>
</li>
}
</ul>
</div>
<div class="tab-pane show" role="tabpanel" id="group-booking-groups">
<ul class="list-group">
@foreach(var group in Model.GroupOfPeopleListItems)
{
<li class="list-group-item">
@{
var wasSuccessful = long.TryParse(group.Value, out var groupOid);
var shouldBeChecked = wasSuccessful ? Model.GroupBookingSelectedGroupOfPeopleOids.Contains(groupOid) : wasSuccessful;
var attribute = shouldBeChecked ? "checked=\"checked\"" : string.Empty;
}
<div class="custom-control custom-checkbox custom-control-inline">
<input type="checkbox" @attribute class="custom-control-input" id="group-checkbox-@group.Value" value="@group.Value" onchange="addScCbRelsToGroupBooking()" />
<label for="group-checkbox-@group.Value" class="custom-control-label">
@group.Text
</label>
</div>
</li>
}
</ul>
</div>

View File

@@ -16,11 +16,11 @@
}
<script>
var passwordSercurity = new PasswordSecurity("pw-strength-feedback");
//var passwortsicherheit = new MoKPasswordSecurity("pw-strength-feedback");
function validatePasswordStrength() {
try {
passwordSercurity.validatePassword($("#new-password").val());
(new MoKPasswordSecurity("pw-strength-feedback")).validatePassword($("#new-password").val());
} catch (error) {
showErrorPopup(error);
}
@@ -495,10 +495,6 @@
return "@Url.Action("LoadCompleteTextbausteinByOid")";
}
function getAddSupportConceptsLink() {
return "@Url.Action("AddSupportConceptCostBearerRelationsToGroupBooking")";
}
function getNumberOfDokutypes() {
return @Model.NumberOfDokuTypes;
}
@@ -644,7 +640,9 @@
<div class="container mb-3">
@if(Model.IsInGroupBookingMode && !Model.IsInMultiBookingMode)
{
@Html.Partial("GroupBookingPartial", Model)
<div id="group-booking-container">
@Html.Partial("GroupBookingPartial", Model)
</div>
}
</div>
@@ -973,4 +971,37 @@
<input type="hidden" name="@FormCollectionConstants.MarkerKey" id="srv-marker" />
<input type="hidden" name="@FormCollectionConstants.ServiceDescriptionKey" id="srv-service-description" />
<input type="hidden" name="@FormCollectionConstants.DurationKey" id="srv-duration" />
}
}
@*----- Ziele/Maßnahmen-Popup ----- *@
<div class="modal" tabindex="-1" role="dialog" id="goal-popup">
<div class="modal-dialog modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h6 class="modal-title">Ziele und Ma&szlig;nahmen</h6>
<button type="button" class="close" data-dismiss="modal" onclick="resetGoalTreeSearch()">
<span>&times;</span>
</button>
</div>
<div class="modal-body pb-0">
<div class="container-fluid px-0">
<div class="input-group mb-3">
<input class="form-control w-100" type="text" placeholder="Suchen..." oninput="goalTreeSearchOnChangeV2()" id="goal-search-input" />
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" onclick="resetGoalTreeSearch()">
<span class="fas fa-times-circle"></span>
</button>
</div>
</div>
</div>
<div id="goals-tree">
@Html.Partial("GoalTreePartial", Model)
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Schlie&szlig;en</button>
</div>
</div>
</div>
</div>

View File

@@ -148,50 +148,64 @@
</li>
</ul>
</nav>
}
}
foreach(var serviceRecord in Model.ServiceRecords)
{
if(serviceRecord.Start == null || serviceRecord.End == null)
{
continue;
}
foreach(var serviceRecord in Model.ServiceRecords)
{
if(serviceRecord.Start == null || serviceRecord.End == null)
{
continue;
}
var start = serviceRecord.Start.Value;
var end = serviceRecord.End.Value;
var hasSignatureStr = serviceRecord.SignatureOid.HasValue ? "JA" : "NEIN";
var start = serviceRecord.Start.Value;
var end = serviceRecord.End.Value;
var hasSignatureStr = serviceRecord.SignatureOid.HasValue ? "JA" : "NEIN";
var duration = (end - start).TotalMinutes;
var duration = (end - start).TotalMinutes;
var roundedDuration = MobileUtils.GetDecimalValueWithMaxDecimal(serviceRecord.RoundedDuration, 2);
var roundedDuration = MobileUtils.GetDecimalValueWithMaxDecimal(serviceRecord.RoundedDuration, 2);
if(serviceRecord.ServiceDescription.Category.Percentage > 0 && serviceRecord.ServiceDescription.Category.Percentage < 100)
{
roundedDuration = roundedDuration * serviceRecord.ServiceDescription.Category.Percentage / 100;
}
if(serviceRecord.ServiceDescription.Category.Percentage > 0 && serviceRecord.ServiceDescription.Category.Percentage < 100)
{
roundedDuration = roundedDuration * serviceRecord.ServiceDescription.Category.Percentage / 100;
}
var durationStr = serviceRecord.GroupOid.HasValue ? string.Format("{0:###0.#} ({0:###0.#})", roundedDuration) : $"{duration:###0.#} ({roundedDuration:###0.#})";
var durationStr = serviceRecord.GroupOid.HasValue ? string.Format("{0:###0.#} ({0:###0.#})", roundedDuration) : $"{duration:###0.#} ({roundedDuration:###0.#})";
// ToDo: Ziele UND Maßnahmen (goals & measures)
var goalsString = string.Empty;
var goalCategoriesString = string.Empty;
var goalsString = string.Empty;
if(serviceRecord.Goals != null && serviceRecord.Goals.Count > 0)
{
foreach(var goal in serviceRecord.Goals)
{
if(goal.Abbreviation != null)
{
goalsString += $"{goal.Abbreviation}: {goal.TypeDescription}";
}
else
{
goalsString += goal.TypeDescription;
}
if(serviceRecord.Goals != null && serviceRecord.Goals.Count > 0)
{
//var actualGoals = Model.GetGoalByOid()
if(serviceRecord.Goals.IndexOf(goal) < serviceRecord.Goals.Count - 1)
{
goalsString += ", ";
}
}
foreach(var goal in serviceRecord.Goals)
{
goalsString += goal.TypeDescription;
if(serviceRecord.ServiceRecordOid.HasValue && Model.ServiceRecordOids2GoalHeader.ContainsKey(serviceRecord.ServiceRecordOid.Value))
{
foreach(var goalHeader in Model.ServiceRecordOids2GoalHeader[serviceRecord.ServiceRecordOid.Value])
{
goalCategoriesString += $"{goalHeader}, ";
}
}
if(serviceRecord.Goals.IndexOf(goal) < serviceRecord.Goals.Count - 1)
{
goalsString += ", ";
}
}
}
goalCategoriesString = goalCategoriesString.TrimEnd(' ').TrimEnd(',');
}
var cardBackground = serviceRecord.ServiceRecordType == ServiceRecordTypeId.Content ? "bg-service-record-marked" : serviceRecord.GroupOid.HasValue ? "bg-bewo-group-booking" : string.Empty;
var cardBackground = serviceRecord.ServiceRecordType == ServiceRecordTypeId.Content ? "bg-service-record-marked" : serviceRecord.GroupOid.HasValue ? "bg-bewo-group-booking" : string.Empty;
<div class="row mb-3">
<div class="card w-100 @cardBackground">
@@ -291,6 +305,14 @@
<div class="col text-secondary">
Ziele:
</div>
<div class="col">
@goalCategoriesString
</div>
</div>
<div class="row">
<div class="col text-secondary">
Maßnahmen:
</div>
<div class="col">
@goalsString
</div>

View File

@@ -796,37 +796,7 @@
</div>
@*----- /Liste mit den Einträgen und dem Auswahl-Select ----- *@
@*----- Ziele/Maßnahmen-Popup ----- *@
<div class="modal" tabindex="-1" role="dialog" id="goal-popup">
<div class="modal-dialog modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h6 class="modal-title">Ziele und Ma&szlig;nahmen</h6>
<button type="button" class="close" data-dismiss="modal" onclick="resetGoalTreeSearch()">
<span>&times;</span>
</button>
</div>
<div class="modal-body pb-0">
<div class="container-fluid px-0">
<div class="input-group mb-3">
<input class="form-control w-100" type="text" placeholder="Suchen..." oninput="goalTreeSearchOnChangeV2()" id="goal-search-input" />
<div class="input-group-append">
<button class="btn btn-outline-secondary" type="button" onclick="resetGoalTreeSearch()">
<span class="fas fa-times-circle"></span>
</button>
</div>
</div>
</div>
<div id="goals-tree">
@Html.Partial("GoalTreePartial", Model)
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-primary" data-dismiss="modal">Schlie&szlig;en</button>
</div>
</div>
</div>
</div>
</div>
@using(Html.BeginForm("DeleteSignature", "Main", FormMethod.Post, new { id = "delete-signature-form"}))

View File

@@ -72,8 +72,10 @@
<script src="@Scripts.Url("~/Scripts/ownSoft-Scripts/utils/service-record-time-calc.js")" type="text/javascript"></script>
<script src="@Scripts.Url("~/Scripts/ownSoft-Scripts/utils/js-helper.js")" type="text/javascript"></script>
<script src="@Scripts.Url("~/Scripts/ownSoft-Scripts/utils/logging.js")" type="text/javascript"></script>
<script src="@Scripts.Url("~/Scripts/ownSoft-Scripts/utils/password-security.js")" type="text/javascript"></script>
<script type="text/javascript" src="@Scripts.Url("~/Scripts/devexpress-dependencies/devextreme/dx.all.js")"></script>
<link rel="stylesheet" href="@Url.Content("~/Content/dx.common.css")" />
<link rel="stylesheet" href="@Url.Content("~/Content/dx.light.css")" />
@@ -90,336 +92,6 @@
new Script { ExtensionType = ExtensionType.WebDocumentViewer }
)
<script type="text/javascript">
class PasswordSecurity {
numbers = "0123456789";
lowercaseLetters = "abcdefghijklmnopqrstuvwxyz";
uppercaseLetters = "ABDEFGHIJKLMNOPQRSTUVWXYZ";
lowercaseUmlauts = "äöüß";
uppercaseUmlauts = "ÄÖÜ";
specialChars1 = "\\\"\'µ@@€!";
specialChars2 = "&/()=?+*";
specialChars3 = ",.-;:_><|";
specialChars4 = "§$%'{[]}´";
specialChars5 = "`^°~²³";
isPartial = false;
partialPassword = "";
passwordLengthDifference = 0;
score = 0;
previousValue = 0;
schalter = false;
previousValues = [];
passwordLabelId = "";
constructor(pwLabelId) {
this.passwordLabelId = pwLabelId;
}
validatePassword(password) {
if(false === isUndefinedOrNull(password) && password.length > 0) {
var sx = "";
var passwordStrength = -1;
for(var i = 0; i < password.length; i++) {
sx += password[i];
if(sx.length < this.partialPassword.length) {
this.isPartial = true;
this.passwordLengthDifference = this.partialPassword.length - sx.length;
}
if(this.partialPassword !== sx) {
this.partialPassword = sx;
}
passwordStrength = this.calculatePasswordStrength(sx);
}
this.displayPasswordStrength(passwordStrength);
return;
}
this.score = 0;
this.previousValue = 0;
this.displayPasswordStrength(-1);
}
getIntegerFromArray(arr, index) {
if(arr === undefined || arr === null || arr.length < index) {
return 0;
}
var intValue = $.parseInt(arr[index], 10);
return $.isNumeric(intValue) ? intValue : 0;
}
getLastValue() {
if(this.previousValues === undefined || this.previousValues === null || this.previousValues.length === 0) {
return 0;
}
return this.previousValues[this.previousValues.length - 1];
}
calculatePasswordStrength(passwordToValidate) {
var passwordStrength = 0;
this.previousValue = 0;
if(this.isPartial === true) {
if(this.passwordLengthDifference === 1) {
this.score -= this.getLastValue();
this.previousValues.pop();
} else {
for(var i = 0; i < this.passwordLengthDifference; i++) {
this.score -= this.getLastValue();
this.previousValues.pop();
}
}
this.isPartial = false;
} else {
var passwordLength = passwordToValidate.length;
if(passwordLength >= 6 && passwordLength < 9) {
this.score += 1;
this.previousValue = 1;
this.schalter = true;
}
if(passwordLength >= 9 && passwordLength < 12) {
this.score += 2;
this.previousValue = 2;
this.schalter = true;
}
if(passwordLength >= 12 && passwordLength < 18) {
this.score += 3;
this.previousValue = 3;
this.schalter = true;
}
if(passwordLength >= 18) {
this.score += 4;
this.previousValue = 4;
this.schalter = true;
}
var passwordAsArray = Array.from(passwordToValidate);
// Zahlen
var containsNumbers = false;
for(var i = 0; i < passwordAsArray.length; i++) {
if(this.numbers.includes(passwordAsArray[i])) {
containsNumbers = true;
break;
}
}
// Kleinbuchstaben
var containsLowercaseLetters = false;
for(var i = 0; i < passwordAsArray.length; i++) {
if(this.lowercaseLetters.includes(passwordAsArray[i])) {
containsLowercaseLetters = true;
break;
}
}
// Großbuchstaben
var containsUppercaseLetters = false;
for(var i = 0; i < passwordAsArray.length; i++) {
if(this.uppercaseLetters.includes(passwordAsArray[i])) {
containsUppercaseLetters = true;
break;
}
}
// Kleinumlaute
var containsLowercaseUmlauts = false;
for(var i = 0; i < passwordAsArray.length; i++) {
if(this.lowercaseUmlauts.includes(passwordAsArray[i])) {
containsLowercaseUmlauts = true;
break;
}
}
// Großumlaute
var containsUppercaseUmlauts = false;
for(var i = 0; i < passwordAsArray.length; i++) {
if(this.uppercaseUmlauts.includes(passwordAsArray[i])) {
containsUppercaseUmlauts = true;
break;
}
}
// Sonderzeichen 1
var containsSpecialCharacters1 = false;
for(var i = 0; i < passwordAsArray.length; i++) {
if(this.specialChars1.includes(passwordAsArray[i])) {
containsSpecialCharacters1 = true;
break;
}
}
var containsSpecialCharacters2 = false;
for(var i = 0; i < passwordAsArray.length; i++) {
if(this.specialChars2.includes(passwordAsArray[i])) {
containsSpecialCharacters2 = true;
break;
}
}
var containsSpecialCharacters3 = false;
for(var i = 0; i < passwordAsArray.length; i++) {
if(this.specialChars3.includes(passwordAsArray[i])) {
containsSpecialCharacters3 = true;
break;
}
}
var containsSpecialCharacters4 = false;
for(var i = 0; i < passwordAsArray.length; i++) {
if(this.specialChars4.includes(passwordAsArray[i])) {
containsSpecialCharacters4 = true;
break;
}
}
var containsSpecialCharacters5 = false;
for(var i = 0; i < passwordAsArray.length; i++) {
if(this.specialChars5.includes(passwordAsArray[i])) {
containsSpecialCharacters5 = true;
break;
}
}
if(containsNumbers === true) {
this.addScoreValue(3);
}
if(containsLowercaseLetters === true) {
this.addScoreValue(2);
}
if(containsUppercaseLetters === true) {
this.addScoreValue(3);
}
if(containsLowercaseUmlauts === true) {
this.addScoreValue(2);
}
if(containsUppercaseUmlauts === true) {
this.addScoreValue(2);
}
if(containsSpecialCharacters1 === true) {
this.addScoreValue(4);
}
if(containsSpecialCharacters2 === true) {
this.addScoreValue(4);
}
if(containsSpecialCharacters3 === true) {
this.addScoreValue(4);
}
if(containsSpecialCharacters4 === true) {
this.addScoreValue(4);
}
if(containsSpecialCharacters5 === true) {
this.addScoreValue(4);
}
this.previousValues.push(this.previousValue);
}
if(this.score <= 15) {
passwordStrength = 0;
}
if(this.score > 15 && this.score <= 55) {
passwordStrength = 1;
}
if(this.score > 55 && this.score <= 115) {
passwordStrength = 2;
}
if(this.score > 115 && this.score <= 155) {
passwordStrength = 3;
}
if(this.score > 155) {
passwordStrength = 4;
}
return passwordStrength;
}
addScoreValue(defaultValue) {
if(defaultValue === undefined || defaultValue === null || false === $.isNumeric(defaultValue)) {
return;
}
this.score += defaultValue;
if(this.schalter === true) {
this.previousValue += defaultValue;
} else {
this.previousValue = defaultValue;
}
}
displayPasswordStrength(passwordStrength) {
var passwordLabel = $("#" + this.passwordLabelId);
if(passwordStrength === undefined || !$.isNumeric(passwordStrength) || !passwordLabel.length) {
return;
}
passwordLabel.removeClass("text-success text-danger text-warning");
switch(passwordStrength) {
case -1:
passwordLabel.addClass("d-none");
passwordLabel.html("");
break;
case 0:
passwordLabel.removeClass("d-none");
passwordLabel.html("Passwortstärke: Sehr schwach");
passwordLabel.addClass("text-danger");
break;
case 1:
passwordLabel.removeClass("d-none");
passwordLabel.html("Passwortstärke: Schwach");
passwordLabel.addClass("text-danger");
break;
case 2:
passwordLabel.removeClass("d-none");
passwordLabel.html("Passwortstärke: Mittel");
passwordLabel.addClass("text-warning");
break;
case 3:
passwordLabel.removeClass("d-none");
passwordLabel.html("Passwortstärke: Stark");
passwordLabel.addClass("text-success");
break;
case 4:
passwordLabel.removeClass("d-none");
passwordLabel.html("Passwortstärke: Sehr stark");
passwordLabel.addClass("text-success");
break;
}
}
}
</script>
<script type="text/javascript">
window.addEventListener("error", (event) => {
hideSpinner();
@@ -431,6 +103,18 @@
return;
}
if(event.message.includes("E0024 - DevExtreme bundle already included.")) {
logInfo("Fehler E0024. Kann ignoriert werden. Ist ein webKit-Bug.");
return;
}
if(event.message === "SyntaxError: Can't create duplicate variable: 'MoKPasswordSecurity'") {
logInfo("SyntaxError: Can't create duplicate variable: 'MoKPasswordSecurity'. Kann ignoriert werden. Ist ein webKit-Bug.");
return;
}
alert(`<<${event.message}>>`);
configureErrorPopup(textToShow);
});

View File

@@ -10,8 +10,8 @@
<section name="settings" type="DevExpress.Web.SettingsConfigurationSection, DevExpress.Web.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" requirePermission="false" />
<section name="resources" type="DevExpress.Web.ResourcesConfigurationSection, DevExpress.Web.v23.2, Version=23.2.4.0, Culture=neutral, PublicKeyToken=b88d1754d700e49a" requirePermission="false" />
</sectionGroup>
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
<!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<system.diagnostics>
<sources>
@@ -76,6 +76,9 @@
<requestLimits maxQueryString="32768" maxUrl="65535" />
</requestFiltering>
</security>
<staticContent>
<clientCache cacheControlMode="UseMaxAge" />
</staticContent>
</system.webServer>
<system.serviceModel>
<behaviors>
@@ -293,8 +296,6 @@
<errors callbackErrorRedirectUrl="" />
<settings rightToLeft="false" doctypeMode="Html5" ieCompatibilityVersion="edge" />
<resources>
<!--<add type="ThirdParty" />
<add type="DevExtreme" />-->
</resources>
</devExpress>
<system.codedom>

View File

@@ -5948,5 +5948,26 @@ namespace BeWo.Data.Access
return criteria.List<Bargeldtransaktionshistory>().ToList();
}
public List<ValueListEntry> GetGoalCategoriesByOids(List<long> oids)
{
var criteria = CreateCriteriaIsActive<ValueListEntry>()
.Add(
Restrictions.Or(
Restrictions.Eq(nameof(ValueListEntry.Type), ValueListEntryType.SupportConceptGoalCategoryType),
Restrictions.Eq(nameof(ValueListEntry.Type), ValueListEntryType.SupportConceptIndividualGoalCategoryType)))
.AddOrder(Order.Asc(nameof(ValueListEntry.Value)));
return criteria.List<ValueListEntry>().OrderBy(valueListEntry => $"{valueListEntry.Abbreviation}-{valueListEntry.Value}").ToList();
}
public List<SupportConcept> FindSupportConceptsByCostbearer2SupportConceptRelOids(List<long> costbearer2SupportConceptRelOids)
{
var criteria = CreateCriteria<SupportConcept>()
.CreateAlias(nameof(SupportConcept.CostBearer2SupportConceptList), "cb2Sc", JoinType.InnerJoin)
.Add(Restrictions.In($"cb2Sc.{nameof(BeWoEntityBase.Oid)}", costbearer2SupportConceptRelOids.ToArray()));
return criteria.List<SupportConcept>().ToList();
}
}
}

View File

@@ -109,7 +109,7 @@ namespace BeWo.Service.Plugins
//t = "8677523325"; // BeWo Richartz
//t = "1765854593"; // Mein Betreutes Wohnen
//t = "6802909544"; // Lebenshilfe Coburg
//t = "9417634361"; // Synprax
t = "9417634361"; // Synprax
//t = "5761861730"; // Lebenshilfe Warendorf
//t = "6712648331"; // BeWo Färber
//t = "4982295287"; // ASB Hamm

View File

@@ -752,5 +752,9 @@ namespace BeWo.Service.ServiceContracts
[FaultContract(typeof(BeWoFault))]
[OperationContract]
long? GetActiveMedListByTypeForCustomer(long customerOid, bool isBedarfsmedikation);
[FaultContract(typeof(BeWoFault))]
[OperationContract]
List<SupportConceptDC> GetSupportConceptsByCostbearer2SupportConceptRelOids(List<long> costbearer2SupportConceptRelOids);
}
}

View File

@@ -244,5 +244,29 @@ namespace BeWo.Service.ServiceContracts
[FaultContract(typeof(BeWoFault))]
[OperationContract]
Dictionary<string, List<string>> CheckResourceAvailabilityWithEmployeeInformation(DateTime start, DateTime end, List<long> resourceOids, long? selectedAppointmentOid, Guid? recurrenceId, int occurrenceIndex = 0, bool shouldSkipResourceAvailability = false);
[FaultContract(typeof(BeWoFault))]
[OperationContract]
bool CheckSchedulerRightsForAppointmentEditing(long appointmentOid, long loggedOnUserOid);
[FaultContract(typeof(BeWoFault))]
[OperationContract]
SchedulerAppointmentDC InsertSchedulerAppointment(SchedulerAppointmentDC appointment);
[FaultContract(typeof(BeWoFault))]
[OperationContract]
List<SchedulerAppointmentDC> CheckSchedulerRightsForAppointmentsToEdit(List<SchedulerAppointmentDC> appointments2Check, UserDC user);
[FaultContract(typeof(BeWoFault))]
[OperationContract]
List<SchedulerAppointmentDC> InsertOrUpdateSchedulerAppointments(List<SchedulerAppointmentDC> appointments2InsertOrUpdate);
[FaultContract(typeof(BeWoFault))]
[OperationContract]
void DeleteOrUpdateSchedulerAppointments(List<SchedulerAppointmentDC> appointments2DeleteOrUpdate);
[FaultContract(typeof(BeWoFault))]
[OperationContract]
Dictionary<SchedulerAppointmentDC, bool> OverlappingAppointmentsExistForMultiple(List<SchedulerAppointmentDC> appointments);
}
}

Some files were not shown because too many files have changed in this diff Show More