From 8ef5fe78a6c3b7eed4456270b4c498cfdaa9d655 Mon Sep 17 00:00:00 2001 From: Lyndon Jetten Date: Mon, 24 Apr 2023 19:20:02 +0200 Subject: [PATCH 01/36] =?UTF-8?q?Bug=20beim=20Zusagen/Best=C3=A4tigen=20vo?= =?UTF-8?q?n=20Terminen=20behoben=20bei=20dem=20eine=20StaleObjectStateExc?= =?UTF-8?q?eption=20ausgel=C3=B6st=20wurde.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BeWo/Core/Service/Cache.cs | 39 +++++ BeWo/Scheduler/View/NewSchedulerView.xaml.cs | 155 +++++++++-------- BeWo/Scheduler/View/RequestAnswerView.xaml.cs | 157 +++++++----------- .../ViewModel/SchedulerAppointmentVM.cs | 3 + ...ignatureDC_ConfirmationReceiptSignature.cs | 4 + .../OperationsServiceImp.cs | 16 +- .../ConfirmationReceiptSignatureDC.cs | 6 +- 7 files changed, 207 insertions(+), 173 deletions(-) diff --git a/BeWo/Core/Service/Cache.cs b/BeWo/Core/Service/Cache.cs index 9fe1669e2..03b91b21b 100644 --- a/BeWo/Core/Service/Cache.cs +++ b/BeWo/Core/Service/Cache.cs @@ -551,5 +551,44 @@ namespace BeWo.Core.Service return mAllCompactCustomers; } + + public void GetSchedulerObjects(Action, List, Dictionary>> callback) + { + GetAllActiveEmployeesCompact(allEmployees => + { + GetAllActiveCustomersCompact(allCustomers => + { + GetCategories2ResourcesDictionary(resourceDictionary => + { + if(!BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderMitarbeitertermineAnsehen)) + { + allEmployees = new List { BeWoApp.CompactLoggedOnEmployee }; + } + + var darfKlientenAnsichtSehen = BeWoApp.LoggedOnUser.HasRight(UserRightType.Customer_ViewMyTeams) || BeWoApp.LoggedOnUser.HasRight(UserRightType.Customer_ViewMyCustomers) || BeWoApp.LoggedOnUser.HasRight(UserRightType.CustomerView_View); + var darfTermineAllerKlientenSehen = BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderKliententermineAlleAnsehen); + + if(darfKlientenAnsichtSehen) + { + if(!darfTermineAllerKlientenSehen || !BeWoApp.LoggedOnUser.HasRight(UserRightType.CustomerView_View)) + { + allCustomers = allCustomers.Where(w => w.IsRelatedToEmployee).ToList(); + } + } + else + { + allCustomers.Clear(); + } + + if(!BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderRessourcentermineAnsehen)) + { + resourceDictionary.Clear(); + } + + callback(allCustomers, allEmployees, resourceDictionary); + }); + }); + }); + } } } \ No newline at end of file diff --git a/BeWo/Scheduler/View/NewSchedulerView.xaml.cs b/BeWo/Scheduler/View/NewSchedulerView.xaml.cs index 96706d8f3..8eb0d05c0 100644 --- a/BeWo/Scheduler/View/NewSchedulerView.xaml.cs +++ b/BeWo/Scheduler/View/NewSchedulerView.xaml.cs @@ -432,52 +432,55 @@ namespace BeWo.Scheduler.View ConstructObject(); } - private void GetCacheObjects(Action, List, Dictionary>> callback) + // ToDo: In den Cache verschieben + private static void GetCacheObjects(Action, List, Dictionary>> callback) { - Cache.GetInstance().GetAllActiveEmployeesCompact(allEmployees => - { - this.Dispatch(() => - { - Cache.GetInstance().GetAllActiveCustomersCompact(allCustomers => - { - this.Dispatch(() => - { - Cache.GetInstance().GetCategories2ResourcesDictionary(resourceDictionary => - { - this.Dispatch(() => - { - if(!BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderMitarbeitertermineAnsehen)) - { - allEmployees = new List {BeWoApp.CompactLoggedOnEmployee}; - } + //Cache.GetInstance().GetAllActiveEmployeesCompact(allEmployees => + //{ + // this.Dispatch(() => + // { + // Cache.GetInstance().GetAllActiveCustomersCompact(allCustomers => + // { + // this.Dispatch(() => + // { + // Cache.GetInstance().GetCategories2ResourcesDictionary(resourceDictionary => + // { + // this.Dispatch(() => + // { + // if(!BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderMitarbeitertermineAnsehen)) + // { + // allEmployees = new List {BeWoApp.CompactLoggedOnEmployee}; + // } - var darfKlientenAnsichtSehen = BeWoApp.LoggedOnUser.HasRight(UserRightType.Customer_ViewMyTeams) || BeWoApp.LoggedOnUser.HasRight(UserRightType.Customer_ViewMyCustomers) || BeWoApp.LoggedOnUser.HasRight(UserRightType.CustomerView_View); - var darfTermineAllerKlientenSehen = BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderKliententermineAlleAnsehen); + // var darfKlientenAnsichtSehen = BeWoApp.LoggedOnUser.HasRight(UserRightType.Customer_ViewMyTeams) || BeWoApp.LoggedOnUser.HasRight(UserRightType.Customer_ViewMyCustomers) || BeWoApp.LoggedOnUser.HasRight(UserRightType.CustomerView_View); + // var darfTermineAllerKlientenSehen = BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderKliententermineAlleAnsehen); - if(darfKlientenAnsichtSehen) - { - if(!darfTermineAllerKlientenSehen || !BeWoApp.LoggedOnUser.HasRight(UserRightType.CustomerView_View)) - { - allCustomers = allCustomers.Where(w => w.IsRelatedToEmployee).ToList(); - } - } - else - { - allCustomers.Clear(); - } + // if(darfKlientenAnsichtSehen) + // { + // if(!darfTermineAllerKlientenSehen || !BeWoApp.LoggedOnUser.HasRight(UserRightType.CustomerView_View)) + // { + // allCustomers = allCustomers.Where(w => w.IsRelatedToEmployee).ToList(); + // } + // } + // else + // { + // allCustomers.Clear(); + // } - if(!BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderRessourcentermineAnsehen)) - { - resourceDictionary.Clear(); - } + // if(!BeWoApp.LoggedOnUser.HasRight(UserRightType.KalenderRessourcentermineAnsehen)) + // { + // resourceDictionary.Clear(); + // } - callback(allCustomers, allEmployees, resourceDictionary); - }); - }); - }); - }); - }); - }); + // callback(allCustomers, allEmployees, resourceDictionary); + // }); + // }); + // }); + // }); + // }); + //}); + + Cache.GetInstance().GetSchedulerObjects(callback); } private void ConstructObject() @@ -1659,38 +1662,9 @@ namespace BeWo.Scheduler.View { var neueListe = new SchedulerAppointmentListVM(_Liste, AllCustomers, AllEmployees, Category2ResourcesDictionary); - var vm = neueListe; + var zuBestaetigen = InitAppointmentsToAnswer(neueListe); - var zuBestaetigen = vm.Appointments.Where(app => - { - var customFieldStorage = (CustomFieldStorage) app.CustomFields[nameof(CustomFieldStorage)]; - - var originator = customFieldStorage.Originator; - - if(customFieldStorage.EmployeeList == null || originator.EmployeeOid == BeWoApp.LoggedOnEmployee.EmployeeOid.Value) - { - return false; - } - - var empList = customFieldStorage.EmployeeList; - - return empList.Any(a => a.Employee.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid) && a.ParticipationAnswer == ParticipationAnswer.Offen); - }).ToList(); - - var updates = vm.Appointments.Where(app => - { - var customFieldStorage = (CustomFieldStorage) app.CustomFields[nameof(CustomFieldStorage)]; - - if(customFieldStorage.Originator == null || customFieldStorage.EmployeeList == null) - { - return false; - } - - var empList = customFieldStorage.EmployeeList; - var or = customFieldStorage.Originator; - - return or.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid) && empList.Any(a => a.IsPChanged && a.ParticipationAnswer != ParticipationAnswer.Offen && a.ParticipationAnswer != ParticipationAnswer.Verstrichen && !a.Employee.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid)); - }).ToList(); + var updates = InitAppointmentStatusUpdates(neueListe); if(!zuBestaetigen.Any() && !updates.Any()) { @@ -1706,6 +1680,43 @@ namespace BeWo.Scheduler.View requestAnswerView.Show(); } + public static List InitAppointmentsToAnswer(SchedulerAppointmentListVM listVm) + { + return listVm.Appointments.Where(app => + { + var customFieldStorage = (CustomFieldStorage)app.CustomFields[nameof(CustomFieldStorage)]; + + var originator = customFieldStorage.Originator; + + if(customFieldStorage.EmployeeList is null || originator.EmployeeOid == BeWoApp.LoggedOnEmployee.EmployeeOid.Value) + { + return false; + } + + var empList = customFieldStorage.EmployeeList; + + return empList.Any(a => a.Employee.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid) && a.ParticipationAnswer == ParticipationAnswer.Offen); + }).ToList(); + } + + public static List InitAppointmentStatusUpdates(SchedulerAppointmentListVM listVm) + { + return listVm.Appointments.Where(app => + { + var customFieldStorage = (CustomFieldStorage)app.CustomFields[nameof(CustomFieldStorage)]; + + if(customFieldStorage.Originator is null || customFieldStorage.EmployeeList is null) + { + return false; + } + + var empList = customFieldStorage.EmployeeList; + var or = customFieldStorage.Originator; + + return or.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid) && empList.Any(a => a.IsPChanged && a.ParticipationAnswer != ParticipationAnswer.Offen && a.ParticipationAnswer != ParticipationAnswer.Verstrichen && !a.Employee.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid)); + }).ToList(); + } + private void RequestAnswerViewClosedEvent(object sender, EventArgs e) { ReloadVM(true); diff --git a/BeWo/Scheduler/View/RequestAnswerView.xaml.cs b/BeWo/Scheduler/View/RequestAnswerView.xaml.cs index c4962c046..fb1a686c9 100644 --- a/BeWo/Scheduler/View/RequestAnswerView.xaml.cs +++ b/BeWo/Scheduler/View/RequestAnswerView.xaml.cs @@ -9,6 +9,7 @@ using System.Windows.Controls; using System.Windows.Data; using BeWo.Annotations; +using BeWo.Core.Service; using BeWo.Scheduler.ViewModel; using BeWo.ServiceProxy; @@ -62,30 +63,38 @@ namespace BeWo.Scheduler.View public RequestAnswerView(IEnumerable appointments, IEnumerable statusUpdates) { - var statusUpdatesAsAppointments = new List(); - - foreach(var beWoAppointment in statusUpdates) - { - var item = (SchedulerAppointmentVM) beWoAppointment; - foreach(var relation in item.EmployeeList.Where(emp => emp.IsPChanged && emp.ParticipationAnswer != ParticipationAnswer.Offen && emp.ParticipationAnswer != ParticipationAnswer.Verstrichen && !emp.Employee.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid))) - { - if(statusUpdatesAsAppointments.All(a => a.LabelKey != relation.Employee2SchedulerAppointmentOid)) - { - if(relation.Employee2SchedulerAppointmentOid != null) - { - statusUpdatesAsAppointments.Add(BuildNewVMFromOldVM(item, relation.Employee2SchedulerAppointmentOid.Value)); - } - } - } - } - - OffeneTermine = appointments.ToObservableCollection(); - OffeneTermine.AddRange(new List(statusUpdatesAsAppointments)); + InitViewModel(appointments, statusUpdates); DataContext = this; InitializeComponent(); } - + + private void InitViewModel(IEnumerable appointments, IEnumerable statusUpdates) + { + var statusUpdatesAsAppointments = new List(); + + foreach(var beWoAppointment in statusUpdates) + { + var item = (SchedulerAppointmentVM) beWoAppointment; + foreach(var relation in item.EmployeeList.Where(emp => emp.IsPChanged && emp.ParticipationAnswer != ParticipationAnswer.Offen && emp.ParticipationAnswer != ParticipationAnswer.Verstrichen && !emp.Employee.EmployeeOid.Equals(BeWoApp.LoggedOnEmployee.EmployeeOid))) + { + if(statusUpdatesAsAppointments.Any(a => a.LabelKey == relation.Employee2SchedulerAppointmentOid)) + { + continue; + } + + if(relation.Employee2SchedulerAppointmentOid != null) + { + statusUpdatesAsAppointments.Add(BuildNewVMFromOldVM(item, relation.Employee2SchedulerAppointmentOid.Value)); + } + } + } + + OffeneTermine = appointments.ToObservableCollection(); + OffeneTermine.AddRange(new List(statusUpdatesAsAppointments)); + OnPropertyChanged(nameof(OffeneTermine)); + } + private static SchedulerAppointmentVM BuildNewVMFromOldVM(SchedulerAppointmentVM item, long emp2AppOid) { var customFieldStorage = (CustomFieldStorage) item.CustomFields[nameof(CustomFieldStorage)]; @@ -164,78 +173,45 @@ namespace BeWo.Scheduler.View private void UpdateView(List aktualisierteTermine) { - foreach (var dc in aktualisierteTermine) - { - foreach (var ivm in OffeneTermine) - { - var vm = ivm as SchedulerAppointmentVM; - if (vm == null || !vm.DataContract.Equals(dc)) - { - continue; - } + if(BeWoApp.LoggedOnEmployeeOid is null) + { + return; + } - var found = vm; - found.DataContract = dc; + ServiceFacade.DoResourceServiceAsync(s => s.GetAllOpenAppointmentsForEmployee(BeWoApp.LoggedOnEmployeeOid.Value), offeneTermine => + { + Cache.GetInstance().GetSchedulerObjects((customers, employees, categoriesToResources) => + { + this.Dispatch(() => + { + var listVm = new SchedulerAppointmentListVM(offeneTermine, customers, employees, categoriesToResources); - UpdateViewModel(dc, (SchedulerAppointmentVM) ivm); + var appointmentsToAnswer = NewSchedulerView.InitAppointmentsToAnswer(listVm); + var appointmentStatusUpdates = NewSchedulerView.InitAppointmentStatusUpdates(listVm); - vm.UpdateCustomFields(); - - if (vm.LabelKey is null) - { - this.Dispatch(() => - { - OffeneTermine = OffeneTermine.Where(w => !w.Equals(vm)).ToObservableCollection(); + InitViewModel(appointmentsToAnswer, appointmentStatusUpdates); - if (raiseChangeEvent) - { - OnPropertyChanged(nameof(OffeneTermine)); + RaiseParticipationChangedEventEvent(); - RaiseParticipationChangedEventEvent(); - } - }); - } - else - { - var test = (SchedulerAppointmentVM) OffeneTermine.FirstOrDefault(f => dc.EmployeeList.Any(a => a.Employee2SchedulerAppointmentOid.HasValue && a.Employee2SchedulerAppointmentOid.Value == f.LabelKey)); - this.Dispatch(() => + ToggleControls(); + + if(!raiseChangeEvent) { - OffeneTermine = OffeneTermine.Where(w => !w.Equals(test)).ToObservableCollection(); - if (raiseChangeEvent) - { - OnPropertyChanged(nameof(OffeneTermine)); + return; + } - RaiseParticipationChangedEventEvent(); - } - }); - } - } - } - - this.Dispatch(() => - { - RaiseParticipationChangedEventEvent(); - - ToggleControls(); - - if (!raiseChangeEvent) - { - //Close(); - } - else - { - if (OffeneTermine.Count == 0 && OTListView.Items.Count == 0) - { - Close(); - } - else - { - OTListView.SelectedIndex = 0; - } - } - - }); - } + if(OffeneTermine.Count == 0 && OTListView.Items.Count == 0) + { + Close(); + } + else + { + OTListView.SelectedIndex = 0; + } + }); + }); + }); + } private void OK_OnClick(object sender, RoutedEventArgs e) { @@ -280,16 +256,11 @@ namespace BeWo.Scheduler.View ServiceFacade.DoResourceServiceAsync(s => s.UpdateSchedulerAppointments(new List {((SchedulerAppointmentVM) SelektierterTermin).DataContract}), UpdateView); } - private static void UpdateViewModel(SchedulerAppointmentDC dc, SchedulerAppointmentVM vm) - { - vm.EmployeeList = new ObservableCollection(dc.EmployeeList); - } - private void ToggleControls() { - ZusagenStack.IsEnabled = !ZusagenStack.IsEnabled; - OkButton.IsEnabled = !OkButton.IsEnabled; - CloseBtn.IsEnabled = !CloseBtn.IsEnabled; + ZusagenStack.IsEnabled = !ZusagenStack.IsEnabled; + OkButton.IsEnabled = !OkButton.IsEnabled; + CloseBtn.IsEnabled = !CloseBtn.IsEnabled; AlleBestaetigen.IsEnabled = !AlleBestaetigen.IsEnabled; } diff --git a/BeWo/Scheduler/ViewModel/SchedulerAppointmentVM.cs b/BeWo/Scheduler/ViewModel/SchedulerAppointmentVM.cs index a9e3a59a3..9cb135def 100644 --- a/BeWo/Scheduler/ViewModel/SchedulerAppointmentVM.cs +++ b/BeWo/Scheduler/ViewModel/SchedulerAppointmentVM.cs @@ -813,6 +813,9 @@ namespace BeWo.Scheduler.ViewModel set => base.IsNew = value; } + /// + /// Wird im RequestAnswerView benutzt, um ein VM-Objekt pro Zusage/Absage/Vorbehalt zu erzeugen + /// public long? LabelKey { get; set; } public List ServiceRecordList diff --git a/Service/DCEntityMapper/ConfirmationReceiptSignatureDC_ConfirmationReceiptSignature.cs b/Service/DCEntityMapper/ConfirmationReceiptSignatureDC_ConfirmationReceiptSignature.cs index 103a944ae..efa4a9ac3 100644 --- a/Service/DCEntityMapper/ConfirmationReceiptSignatureDC_ConfirmationReceiptSignature.cs +++ b/Service/DCEntityMapper/ConfirmationReceiptSignatureDC_ConfirmationReceiptSignature.cs @@ -21,6 +21,8 @@ namespace BeWo.Service.DCEntityMapper pDataContract.ServiceRecords = MapperFactory.ServiceRecordDC_ServiceRecord.MapToNewDCs(pEntity.ServiceRecords); + pDataContract.InsTs = pEntity.InsTs; + if(pEntity.Employee != null) { pDataContract.Employee = MapperFactory.CompactEmployeeDC_Employee.MapToNewDC(pEntity.Employee); @@ -43,6 +45,8 @@ namespace BeWo.Service.DCEntityMapper pEntity.TimeSpanString = pDataContract.TimeSpanString; + pEntity.InsTs = pDataContract.InsTs; + if(pDataContract.ServiceRecords != null) { pEntity.ServiceRecords = DAOFactory.GenericDAO.LoadByIDs(pDataContract.ServiceRecords.Select(s => s.ServiceRecordOid.Value)); diff --git a/Service/ServiceImplementations/OperationsServiceImp.cs b/Service/ServiceImplementations/OperationsServiceImp.cs index bf000d225..9baf122c3 100644 --- a/Service/ServiceImplementations/OperationsServiceImp.cs +++ b/Service/ServiceImplementations/OperationsServiceImp.cs @@ -3214,17 +3214,19 @@ namespace BeWo.Service.ServiceImplementations { var lSignature = MapperFactory.SignatureDC_Signature.MapToNewEntity(s); DAOFactory.GenericDAO.Insert(lSignature); - SignatureDC updatedSignatureDC = MapperFactory.SignatureDC_Signature.MapToNewDC(lSignature); + var updatedSignatureDC = MapperFactory.SignatureDC_Signature.MapToNewDC(lSignature); - if (s.ServiceRecordOid.HasValue) + if(!s.ServiceRecordOid.HasValue) { - var sr = DAOFactory.GenericDAO.LoadByID(s.ServiceRecordOid.Value); - - sr.SignatureOid = lSignature.Oid; - - DAOFactory.GenericDAO.Update(sr); + return updatedSignatureDC; } + var sr = DAOFactory.GenericDAO.LoadByID(s.ServiceRecordOid.Value); + + sr.SignatureOid = lSignature.Oid; + + DAOFactory.GenericDAO.Update(sr); + return updatedSignatureDC; } catch (Exception e) diff --git a/Shared/DataContracts/ConfirmationReceiptSignatureDC.cs b/Shared/DataContracts/ConfirmationReceiptSignatureDC.cs index 9928006ff..4d4192205 100644 --- a/Shared/DataContracts/ConfirmationReceiptSignatureDC.cs +++ b/Shared/DataContracts/ConfirmationReceiptSignatureDC.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Runtime.Serialization; using BS.Shared.DataContracts.Compact; @@ -30,5 +31,8 @@ namespace BS.Shared.DataContracts [DataMember] public string TimeSpanString { get; set; } + + [DataMember] + public DateTime? InsTs { get; set; } } } From 25d64637fc215d4cf2a3aa1219f3d8b406e48f6d Mon Sep 17 00:00:00 2001 From: Lyndon Jetten Date: Mon, 24 Apr 2023 19:22:09 +0200 Subject: [PATCH 02/36] Neue Version des SignaturePads --- BeWoPlanerMobil/BeWoPlanerMobil.csproj | 5 +- BeWoPlanerMobil/BeWoPlanerMobil.csproj.user | 4 +- BeWoPlanerMobil/Controllers/MainController.cs | 6 +- .../Controllers/ReportController.cs | 91 ++- .../Controllers/SchedulerController.cs | 5 + BeWoPlanerMobil/Models/ReportModel.cs | 5 + BeWoPlanerMobil/Models/SchedulerModel.cs | 42 +- .../Scripts/signature_pad-3.2.min.js | 1 - .../Scripts/view-scripts/report.js | 71 +- BeWoPlanerMobil/Util/QuittierungsbelegItem.cs | 1 - .../Util/QuittierungsbelegResult.cs | 1 + .../Quittierungsbelegsunterschriftenobjekt.cs | 20 + BeWoPlanerMobil/Util/SignatureUtils.cs | 20 +- ...ConfirmationReceiptSignaturePartial.cshtml | 102 +++ .../QuittierungsbelegsResultPartial.cshtml | 74 +- BeWoPlanerMobil/Views/Report/Report.cshtml | 118 +-- .../Scheduler/OneDaySchedulerPartial.cshtml | 26 +- BeWoPlanerMobil/Views/Shared/_Layout.cshtml | 48 +- .../node_modules/.package-lock.json | 5 + .../node_modules/signature_pad/LICENSE | 21 + .../node_modules/signature_pad/README.md | 231 ++++++ .../signature_pad/dist/signature_pad.js | 559 +++++++++++++++ .../signature_pad/dist/signature_pad.js.map | 1 + .../signature_pad/dist/signature_pad.min.js | 6 + .../dist/signature_pad.min.js.map | 1 + .../signature_pad/dist/signature_pad.umd.js | 567 +++++++++++++++ .../dist/signature_pad.umd.js.map | 1 + .../dist/signature_pad.umd.min.js | 6 + .../dist/signature_pad.umd.min.js.map | 1 + .../signature_pad/dist/types/bezier.d.ts | 17 + .../signature_pad/dist/types/point.d.ts | 16 + .../dist/types/signature_event_target.d.ts | 7 + .../dist/types/signature_pad.d.ts | 100 +++ .../signature_pad/dist/types/throttle.d.ts | 1 + .../signature_pad/docs/.eslintrc.js | 5 + .../signature_pad/docs/css/ie9.css | 20 + .../signature_pad/docs/css/signature-pad.css | 135 ++++ .../signature_pad/docs/index.html | 61 ++ .../node_modules/signature_pad/docs/js/app.js | 156 ++++ .../docs/js/signature_pad.umd.js | 567 +++++++++++++++ .../node_modules/signature_pad/package.json | 103 +++ .../node_modules/signature_pad/src/bezier.ts | 109 +++ .../node_modules/signature_pad/src/point.ts | 45 ++ .../src/signature_event_target.ts | 35 + .../signature_pad/src/signature_pad.ts | 675 ++++++++++++++++++ .../signature_pad/src/throttle.ts | 51 ++ BeWoPlanerMobil/package-lock.json | 8 +- BeWoPlanerMobil/package.json | 3 +- 48 files changed, 3976 insertions(+), 177 deletions(-) delete mode 100644 BeWoPlanerMobil/Scripts/signature_pad-3.2.min.js create mode 100644 BeWoPlanerMobil/Util/ReportUtils/Quittierungsbelegsunterschriftenobjekt.cs create mode 100644 BeWoPlanerMobil/Views/Report/ConfirmationReceiptSignaturePartial.cshtml create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/LICENSE create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/README.md create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/dist/signature_pad.js create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/dist/signature_pad.js.map create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/dist/signature_pad.min.js create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/dist/signature_pad.min.js.map create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/dist/signature_pad.umd.js create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/dist/signature_pad.umd.js.map create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/dist/signature_pad.umd.min.js create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/dist/signature_pad.umd.min.js.map create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/dist/types/bezier.d.ts create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/dist/types/point.d.ts create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/dist/types/signature_event_target.d.ts create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/dist/types/signature_pad.d.ts create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/dist/types/throttle.d.ts create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/docs/.eslintrc.js create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/docs/css/ie9.css create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/docs/css/signature-pad.css create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/docs/index.html create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/docs/js/app.js create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/docs/js/signature_pad.umd.js create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/package.json create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/src/bezier.ts create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/src/point.ts create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/src/signature_event_target.ts create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/src/signature_pad.ts create mode 100644 BeWoPlanerMobil/node_modules/signature_pad/src/throttle.ts diff --git a/BeWoPlanerMobil/BeWoPlanerMobil.csproj b/BeWoPlanerMobil/BeWoPlanerMobil.csproj index 1434649d7..50ba28921 100644 --- a/BeWoPlanerMobil/BeWoPlanerMobil.csproj +++ b/BeWoPlanerMobil/BeWoPlanerMobil.csproj @@ -243,6 +243,7 @@ + @@ -24907,7 +24908,6 @@ - @@ -25471,6 +25471,7 @@ + @@ -25828,7 +25829,7 @@ - False + True False 8808 / diff --git a/BeWoPlanerMobil/BeWoPlanerMobil.csproj.user b/BeWoPlanerMobil/BeWoPlanerMobil.csproj.user index 29ada5c86..bcc1a01ff 100644 --- a/BeWoPlanerMobil/BeWoPlanerMobil.csproj.user +++ b/BeWoPlanerMobil/BeWoPlanerMobil.csproj.user @@ -8,7 +8,7 @@ - Release|Any CPU + Debug|Any CPU ShowAllFiles 600 MvcControllerEmptyScaffolder @@ -29,7 +29,7 @@ http://localhost/BeWoPlanerMobil - URL + CurrentPage True False False diff --git a/BeWoPlanerMobil/Controllers/MainController.cs b/BeWoPlanerMobil/Controllers/MainController.cs index e955d94ce..179c53604 100644 --- a/BeWoPlanerMobil/Controllers/MainController.cs +++ b/BeWoPlanerMobil/Controllers/MainController.cs @@ -696,13 +696,13 @@ namespace BeWoPlanerMobil.Controllers { try { - if (Model is null) + if(Model is null) { Logout(); return LeerzeichenFuerGetMethoden; } - using (var signatureBitmap = SignatureUtils.Base64StringToBitmap(blob.Split(',')[1])) + using(var signatureBitmap = SignatureUtils.Base64StringToBitmap(blob.Split(',')[1])) { var isValid = SignatureUtils.ValidateSignature(signatureBitmap); @@ -723,7 +723,7 @@ namespace BeWoPlanerMobil.Controllers return LeerzeichenFuerGetMethoden; } - catch (Exception e) + catch(Exception e) { Log.Error(e.Message, e); return SerializeObject("Fehler 540"); diff --git a/BeWoPlanerMobil/Controllers/ReportController.cs b/BeWoPlanerMobil/Controllers/ReportController.cs index 3f90e7d9c..5f9d1c33a 100644 --- a/BeWoPlanerMobil/Controllers/ReportController.cs +++ b/BeWoPlanerMobil/Controllers/ReportController.cs @@ -743,7 +743,7 @@ namespace BeWoPlanerMobil.Controllers { try { - if(Model == null) + if(Model is null) { Logout(); return LeerzeichenFuerGetMethoden; @@ -765,14 +765,7 @@ namespace BeWoPlanerMobil.Controllers var signatures = Model.GetConfirmationReceitSignaturesByOids(oids).Where(signature => signature.SignatureImage != null).ToList(); - var imageStrings = new List(); - - foreach(var signature in signatures) - { - imageStrings.AddIfNotIn(MainController.ApplyWatermark(signature.SignatureImage, Server.MapPath("../Content/images/bewoplaner_by_ownsoft_logo_mok.png"))); - } - - return MobileUtils.SerializeObject(imageStrings); + return MobileUtils.SerializeObject(ConvertSignatureDCsToSignatureObjects(signatures)); } return LeerzeichenFuerGetMethoden; @@ -783,6 +776,30 @@ namespace BeWoPlanerMobil.Controllers } } + private List ConvertSignatureDCsToSignatureObjects(List dataContracts) + { + var result = new List(); + + if(dataContracts is null) + { + return result; + } + + foreach(var signature in dataContracts) + { + var img = MainController.ApplyWatermark(signature.SignatureImage, Server.MapPath("../Content/images/bewoplaner_by_ownsoft_logo_mok.png")); + var date = signature.InsTs?.ToString("dd.MM.yyyy HH:mm") ?? "unbekannt"; + var personName = + signature.SignatureType == SignatureType.Customer ? + (Model.Customers.FirstOrDefault(f => f.CustomerOid.Equals(signature.CustomerOid))?.LastNameFirstName ?? "unbekannt") : + signature.Employee.SimpleDescription; + + result.AddIfNotIn(new ConfirmationReceiptSignatureObject(img, date, personName, signature.SignatureType == SignatureType.Employee, signature.ServiceRecords.Count)); + } + + return result; + } + /// /// Lädt die Übersicht über bereits geleistete oder fehlende Unterschriften für den ausgewählten Zeitraum /// @@ -1091,5 +1108,61 @@ namespace BeWoPlanerMobil.Controllers OperationsService.DeleteConfirmationReceiptSignatures(signatures.ToDictionary(s => s.ConfirmationReceiptSignatureOid.Value, s => s.ConfirmationReceiptSignatureVersion.Value)); } + + + [Authorize] + public ActionResult FetchConfirmationReceiptSignatures(string identifier, bool isEmployee) + { + if(Model is null) + { + return Logout(); + } + + if(!Guid.TryParse(identifier, out var resultIdentifier)) + { + return PartialView("ConfirmationReceiptSignaturePartial", Model); + } + + var obj = Model.ConfirmationReceiptObject.ConfirmationReceiptResultList.FirstOrDefault(f => f.Identifier.Equals(resultIdentifier)); + + if(obj is null) + { + return PartialView("ConfirmationReceiptSignaturePartial", Model); + } + + var oids = isEmployee ? obj.EmployeeSignatureOids : obj.CustomerSignatureOids; + + var signatures = Model.GetConfirmationReceitSignaturesByOids(oids); + + Model.SelectedConfirmationReceiptSignatures = ConvertSignatureDCsToSignatureObjects(signatures); + + var customerName = obj.CustomerName; + var employeeName = MobileSessionFacade.LoggedInCompactEmployee.SimpleDescription; + var serviceRecordCount = 0; + signatures.DoForEach(sig => serviceRecordCount += sig.ServiceRecords.Count); + var personName = isEmployee ? employeeName : customerName; + + Model.Quittierungsbelegsunterschriftenobjekt = new Quittierungsbelegsunterschriftenobjekt(isEmployee, personName, Model.ConfirmationReceiptObject.TimeSpanString, customerName, serviceRecordCount); + + return PartialView("ConfirmationReceiptSignaturePartial", Model); + } + } + + public class ConfirmationReceiptSignatureObject + { + public string ImageStr { get; } + public string InsTsStr { get; } + public string PersonName { get; } + public bool IsEmployeeSignature { get; } + public int NumberOfServiceRecords { get; } + + public ConfirmationReceiptSignatureObject(string imageStr, string insTsStr, string personName, bool isEmployeeSignature, int numberOfServiceRecords) + { + ImageStr = imageStr; + InsTsStr = insTsStr; + PersonName = personName; + IsEmployeeSignature = isEmployeeSignature; + NumberOfServiceRecords = numberOfServiceRecords; + } } } \ No newline at end of file diff --git a/BeWoPlanerMobil/Controllers/SchedulerController.cs b/BeWoPlanerMobil/Controllers/SchedulerController.cs index c0694ed73..604aa9e3c 100644 --- a/BeWoPlanerMobil/Controllers/SchedulerController.cs +++ b/BeWoPlanerMobil/Controllers/SchedulerController.cs @@ -84,6 +84,11 @@ namespace BeWoPlanerMobil.Controllers Model.MyTeams = EmployeeService.GetAllActiveCompactTeamsForEmployee(Model.Employee.EmployeeOid.Value); } + if(!(Model is null)) + { + Model.TeamMemberCustomerOids = EmployeeService.LoadTeamsRelatedCustomerOids(MobileSessionFacade.LoggedInCompactEmployee.EmployeeOid); + } + LoadAppointmentsForDate(); return View(Model); diff --git a/BeWoPlanerMobil/Models/ReportModel.cs b/BeWoPlanerMobil/Models/ReportModel.cs index 553e995e7..410c8a080 100644 --- a/BeWoPlanerMobil/Models/ReportModel.cs +++ b/BeWoPlanerMobil/Models/ReportModel.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Web.Mvc; +using BeWoPlanerMobil.Controllers; using BeWoPlanerMobil.Util.ReportUtils; using BS.Shared.Core; using BS.Shared.DataContracts; @@ -276,5 +277,9 @@ namespace BeWoPlanerMobil.Models public bool IsForSelectedEmployeesOnly { get; set; } public bool IsForSelectedCostbearersOnly { get; set; } public bool IsForSelectedCategoryOnly { get; set; } + + public List SelectedConfirmationReceiptSignatures { get; set; } + + public Quittierungsbelegsunterschriftenobjekt Quittierungsbelegsunterschriftenobjekt { get; set; } } } \ No newline at end of file diff --git a/BeWoPlanerMobil/Models/SchedulerModel.cs b/BeWoPlanerMobil/Models/SchedulerModel.cs index 57ed33f81..99a835ddf 100644 --- a/BeWoPlanerMobil/Models/SchedulerModel.cs +++ b/BeWoPlanerMobil/Models/SchedulerModel.cs @@ -15,6 +15,8 @@ namespace BeWoPlanerMobil.Models { public class SchedulerModel : AbstractModel { + public List TeamMemberCustomerOids { get; set; } + public DateTime SelectedDate { get; set; } = DateTime.Today; public SchedulerAppointmentDC SelectedAppointment { get; set; } @@ -55,45 +57,7 @@ namespace BeWoPlanerMobil.Models { var appointment = AppointmentListItems.FirstOrDefault(app => app.Identifier.Equals(identifier))?.SchedulerAppointment; //Appointments.FirstOrDefault(app => app.SchedulerAppointmentOid.HasValue && app.SchedulerAppointmentOid.Value == appointmentOid); - if(appointment == null) - { - return false; - } - - var hasCustomers = appointment.CustomerList.Any(); - var hasEmployees = appointment.EmployeeList.Any(); - var hasResources = appointment.ResourceList.Any(); - - var result = true; - - if(hasEmployees) - { - result = hasResources ? - MobileSessionFacade.CheckForUserRight(UserRightType.KalenderRessourcentermineAndererAendern) : - MobileSessionFacade.CheckForUserRight(UserRightType.KalenderMitarbeitertermineAendern); - - if (appointment.CustomerList.Any()) - { - result = MobileSessionFacade.CheckForUserRight(UserRightType.KalenderKliententermineAendern) && result; - } - } - else - { - if(hasCustomers && hasResources) - { - result = MobileSessionFacade.CheckForUserRight(UserRightType.KalenderKliententermineAendern) && MobileSessionFacade.CheckForUserRight(UserRightType.KalenderRessourcentermineAendern); - } - else if(hasCustomers) - { - result = MobileSessionFacade.CheckForUserRight(UserRightType.KalenderKliententermineAendern); - } - else if(hasResources) - { - result = MobileSessionFacade.CheckForUserRight(UserRightType.KalenderRessourcentermineAendern); - } - } - - return result; + return appointment != null && Utils.CheckSchedulerRights(appointment.CustomerList, appointment.ResourceList, appointment.EmployeeList, appointment.Originator, appointment.SchedulerAppointmentOid is null, SchedulerRightsCheckType.Edit, MobileSessionFacade.LoggedInUserDC, TeamMemberCustomerOids ?? new List()); } public string DescriptionToEdit => SelectedAppointment?.Description ?? string.Empty; diff --git a/BeWoPlanerMobil/Scripts/signature_pad-3.2.min.js b/BeWoPlanerMobil/Scripts/signature_pad-3.2.min.js deleted file mode 100644 index 4afa32bfd..000000000 --- a/BeWoPlanerMobil/Scripts/signature_pad-3.2.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(t, e) { "object" == typeof exports && "undefined" != typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define(e) : t.SignaturePad = e() }(this, function() { "use strict"; function t(t, e, i) { this.x = t, this.y = e, this.time = i || (new Date).getTime() } function e(t, e, i, o) { this.startPoint = t, this.control1 = e, this.control2 = i, this.endPoint = o } function i(t, e, i) { var o, n, s, r = null, h = 0; i || (i = {}); var a = function() { h = !1 === i.leading ? 0 : Date.now(), r = null, s = t.apply(o, n), r || (o = n = null) }; return function() { var c = Date.now(); h || !1 !== i.leading || (h = c); var d = e - (c - h); return o = this, n = arguments, d <= 0 || d > e ? (r && (clearTimeout(r), r = null), h = c, s = t.apply(o, n), r || (o = n = null)) : r || !1 === i.trailing || (r = setTimeout(a, d)), s } } function o(t, e) { var n = this, s = e || {}; this.velocityFilterWeight = s.velocityFilterWeight || .7, this.minWidth = s.minWidth || .5, this.maxWidth = s.maxWidth || 2.5, this.throttle = "throttle" in s ? s.throttle : 16, this.minDistance = "minDistance" in s ? s.minDistance : 5, this.throttle ? this._strokeMoveUpdate = i(o.prototype._strokeUpdate, this.throttle) : this._strokeMoveUpdate = o.prototype._strokeUpdate, this.dotSize = s.dotSize || function() { return (this.minWidth + this.maxWidth) / 2 }, this.penColor = s.penColor || "black", this.backgroundColor = s.backgroundColor || "rgba(0,0,0,0)", this.onBegin = s.onBegin, this.onEnd = s.onEnd, this._canvas = t, this._ctx = t.getContext("2d"), this.clear(), this._handleMouseDown = function(t) { 1 === t.which && (n._mouseButtonDown = !0, n._strokeBegin(t)) }, this._handleMouseMove = function(t) { n._mouseButtonDown && n._strokeMoveUpdate(t) }, this._handleMouseUp = function(t) { 1 === t.which && n._mouseButtonDown && (n._mouseButtonDown = !1, n._strokeEnd(t)) }, this._handleTouchStart = function(t) { if(1 === t.targetTouches.length) { var e = t.changedTouches[0]; n._strokeBegin(e) } }, this._handleTouchMove = function(t) { t.preventDefault(); var e = t.targetTouches[0]; n._strokeMoveUpdate(e) }, this._handleTouchEnd = function(t) { t.target === n._canvas && (t.preventDefault(), n._strokeEnd(t)) }, this.on() } return t.prototype.velocityFrom = function(t) { return this.time !== t.time ? this.distanceTo(t) / (this.time - t.time) : 1 }, t.prototype.distanceTo = function(t) { return Math.sqrt(Math.pow(this.x - t.x, 2) + Math.pow(this.y - t.y, 2)) }, t.prototype.equals = function(t) { return this.x === t.x && this.y === t.y && this.time === t.time }, e.prototype.length = function() { for(var t = 0, e = void 0, i = void 0, o = 0; o <= 10; o += 1) { var n = o / 10, s = this._point(n, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x), r = this._point(n, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y); if(o > 0) { var h = s - e, a = r - i; t += Math.sqrt(h * h + a * a) } e = s, i = r } return t }, e.prototype._point = function(t, e, i, o, n) { return e * (1 - t) * (1 - t) * (1 - t) + 3 * i * (1 - t) * (1 - t) * t + 3 * o * (1 - t) * t * t + n * t * t * t }, o.prototype.clear = function() { var t = this._ctx, e = this._canvas; t.fillStyle = this.backgroundColor, t.clearRect(0, 0, e.width, e.height), t.fillRect(0, 0, e.width, e.height), this._data = [], this._reset(), this._isEmpty = !0 }, o.prototype.fromDataURL = function(t) { var e = this, i = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : {}, o = new Image, n = i.ratio || window.devicePixelRatio || 1, s = i.width || this._canvas.width / n, r = i.height || this._canvas.height / n; this._reset(), o.src = t, o.onload = function() { e._ctx.drawImage(o, 0, 0, s, r) }, this._isEmpty = !1 }, o.prototype.toDataURL = function(t) { var e; switch(t) { case "image/svg+xml": return this._toSVG(); default: for(var i = arguments.length, o = Array(i > 1 ? i - 1 : 0), n = 1; n < i; n++)o[n - 1] = arguments[n]; return (e = this._canvas).toDataURL.apply(e, [t].concat(o)) } }, o.prototype.on = function() { this._handleMouseEvents(), this._handleTouchEvents() }, o.prototype.off = function() { this._canvas.removeEventListener("mousedown", this._handleMouseDown), this._canvas.removeEventListener("mousemove", this._handleMouseMove), document.removeEventListener("mouseup", this._handleMouseUp), this._canvas.removeEventListener("touchstart", this._handleTouchStart), this._canvas.removeEventListener("touchmove", this._handleTouchMove), this._canvas.removeEventListener("touchend", this._handleTouchEnd) }, o.prototype.isEmpty = function() { return this._isEmpty }, o.prototype._strokeBegin = function(t) { this._data.push([]), this._reset(), this._strokeUpdate(t), "function" == typeof this.onBegin && this.onBegin(t) }, o.prototype._strokeUpdate = function(t) { var e = t.clientX, i = t.clientY, o = this._createPoint(e, i), n = this._data[this._data.length - 1], s = n && n[n.length - 1], r = s && o.distanceTo(s) < this.minDistance; if(!s || !r) { var h = this._addPoint(o), a = h.curve, c = h.widths; a && c && this._drawCurve(a, c.start, c.end), this._data[this._data.length - 1].push({ x: o.x, y: o.y, time: o.time, color: this.penColor }) } }, o.prototype._strokeEnd = function(t) { var e = this.points.length > 2, i = this.points[0]; if(!e && i && this._drawDot(i), i) { var o = this._data[this._data.length - 1], n = o[o.length - 1]; i.equals(n) || o.push({ x: i.x, y: i.y, time: i.time, color: this.penColor }) } "function" == typeof this.onEnd && this.onEnd(t) }, o.prototype._handleMouseEvents = function() { this._mouseButtonDown = !1, this._canvas.addEventListener("mousedown", this._handleMouseDown), this._canvas.addEventListener("mousemove", this._handleMouseMove), document.addEventListener("mouseup", this._handleMouseUp) }, o.prototype._handleTouchEvents = function() { this._canvas.style.msTouchAction = "none", this._canvas.style.touchAction = "none", this._canvas.addEventListener("touchstart", this._handleTouchStart), this._canvas.addEventListener("touchmove", this._handleTouchMove), this._canvas.addEventListener("touchend", this._handleTouchEnd) }, o.prototype._reset = function() { this.points = [], this._lastVelocity = 0, this._lastWidth = (this.minWidth + this.maxWidth) / 2, this._ctx.fillStyle = this.penColor }, o.prototype._createPoint = function(e, i, o) { var n = this._canvas.getBoundingClientRect(); return new t(e - n.left, i - n.top, o || (new Date).getTime()) }, o.prototype._addPoint = function(t) { var i = this.points, o = void 0; if(i.push(t), i.length > 2) { 3 === i.length && i.unshift(i[0]), o = this._calculateCurveControlPoints(i[0], i[1], i[2]); var n = o.c2; o = this._calculateCurveControlPoints(i[1], i[2], i[3]); var s = o.c1, r = new e(i[1], n, s, i[2]), h = this._calculateCurveWidths(r); return i.shift(), { curve: r, widths: h } } return {} }, o.prototype._calculateCurveControlPoints = function(e, i, o) { var n = e.x - i.x, s = e.y - i.y, r = i.x - o.x, h = i.y - o.y, a = { x: (e.x + i.x) / 2, y: (e.y + i.y) / 2 }, c = { x: (i.x + o.x) / 2, y: (i.y + o.y) / 2 }, d = Math.sqrt(n * n + s * s), l = Math.sqrt(r * r + h * h), u = a.x - c.x, v = a.y - c.y, p = l / (d + l), _ = { x: c.x + u * p, y: c.y + v * p }, y = i.x - _.x, f = i.y - _.y; return { c1: new t(a.x + y, a.y + f), c2: new t(c.x + y, c.y + f) } }, o.prototype._calculateCurveWidths = function(t) { var e = t.startPoint, i = t.endPoint, o = { start: null, end: null }, n = this.velocityFilterWeight * i.velocityFrom(e) + (1 - this.velocityFilterWeight) * this._lastVelocity, s = this._strokeWidth(n); return o.start = this._lastWidth, o.end = s, this._lastVelocity = n, this._lastWidth = s, o }, o.prototype._strokeWidth = function(t) { return Math.max(this.maxWidth / (t + 1), this.minWidth) }, o.prototype._drawPoint = function(t, e, i) { var o = this._ctx; o.moveTo(t, e), o.arc(t, e, i, 0, 2 * Math.PI, !1), this._isEmpty = !1 }, o.prototype._drawCurve = function(t, e, i) { var o = this._ctx, n = i - e, s = Math.floor(t.length()); o.beginPath(); for(var r = 0; r < s; r += 1) { var h = r / s, a = h * h, c = a * h, d = 1 - h, l = d * d, u = l * d, v = u * t.startPoint.x; v += 3 * l * h * t.control1.x, v += 3 * d * a * t.control2.x, v += c * t.endPoint.x; var p = u * t.startPoint.y; p += 3 * l * h * t.control1.y, p += 3 * d * a * t.control2.y, p += c * t.endPoint.y; var _ = e + c * n; this._drawPoint(v, p, _) } o.closePath(), o.fill() }, o.prototype._drawDot = function(t) { var e = this._ctx, i = "function" == typeof this.dotSize ? this.dotSize() : this.dotSize; e.beginPath(), this._drawPoint(t.x, t.y, i), e.closePath(), e.fill() }, o.prototype._fromData = function(e, i, o) { for(var n = 0; n < e.length; n += 1) { var s = e[n]; if(s.length > 1) for(var r = 0; r < s.length; r += 1) { var h = s[r], a = new t(h.x, h.y, h.time), c = h.color; if(0 === r) this.penColor = c, this._reset(), this._addPoint(a); else if(r !== s.length - 1) { var d = this._addPoint(a), l = d.curve, u = d.widths; l && u && i(l, u, c) } } else { this._reset(); o(s[0]) } } }, o.prototype._toSVG = function() { var t = this, e = this._data, i = this._canvas, o = Math.max(window.devicePixelRatio || 1, 1), n = i.width / o, s = i.height / o, r = document.createElementNS("http://www.w3.org/2000/svg", "svg"); r.setAttributeNS(null, "width", i.width), r.setAttributeNS(null, "height", i.height), this._fromData(e, function(t, e, i) { var o = document.createElement("path"); if(!(isNaN(t.control1.x) || isNaN(t.control1.y) || isNaN(t.control2.x) || isNaN(t.control2.y))) { var n = "M " + t.startPoint.x.toFixed(3) + "," + t.startPoint.y.toFixed(3) + " C " + t.control1.x.toFixed(3) + "," + t.control1.y.toFixed(3) + " " + t.control2.x.toFixed(3) + "," + t.control2.y.toFixed(3) + " " + t.endPoint.x.toFixed(3) + "," + t.endPoint.y.toFixed(3); o.setAttribute("d", n), o.setAttribute("stroke-width", (2.25 * e.end).toFixed(3)), o.setAttribute("stroke", i), o.setAttribute("fill", "none"), o.setAttribute("stroke-linecap", "round"), r.appendChild(o) } }, function(e) { var i = document.createElement("circle"), o = "function" == typeof t.dotSize ? t.dotSize() : t.dotSize; i.setAttribute("r", o), i.setAttribute("cx", e.x), i.setAttribute("cy", e.y), i.setAttribute("fill", e.color), r.appendChild(i) }); var h = '', a = r.innerHTML; if(void 0 === a) { var c = document.createElement("dummy"), d = r.childNodes; c.innerHTML = ""; for(var l = 0; l < d.length; l += 1)c.appendChild(d[l].cloneNode(!0)); a = c.innerHTML } var u = h + a + ""; return "data:image/svg+xml;base64," + btoa(u) }, o.prototype.fromData = function(t) { var e = this; this.clear(), this._fromData(t, function(t, i) { return e._drawCurve(t, i.start, i.end) }, function(t) { return e._drawDot(t) }), this._data = t }, o.prototype.toData = function() { return this._data }, o }); diff --git a/BeWoPlanerMobil/Scripts/view-scripts/report.js b/BeWoPlanerMobil/Scripts/view-scripts/report.js index 2e3550b9e..a584b5095 100644 --- a/BeWoPlanerMobil/Scripts/view-scripts/report.js +++ b/BeWoPlanerMobil/Scripts/view-scripts/report.js @@ -138,6 +138,7 @@ function onCustomerSelectionChange() { // Lädt die bisher geleisteten Unterschriften function getSignatures(signatureOidStrings, containerId) { + logInfo3("Lade vorhandene Unterschriften für Container '" + containerId + "' mit veralteter Methode"); try { showSpinner(); @@ -148,16 +149,9 @@ function getSignatures(signatureOidStrings, containerId) { if(isUndefinedOrNull(json) || !checkJson(json)) { if(!checkJson(json)) { hideSpinner(); - logError("Ungültiges JSON in loadConfirmationReceiptSignatures. JSON: <" + json + ">"); - } - - if(isUndefinedOrNull(json)) { - logError("JSON ist undefined oder null in loadConfirmationReceiptSignatures"); } } - logDebug("Gültiges JSON in loadConfirmationReceiptSignatures"); - if(isEmptyOrSpaces(json)) { hideSpinner(); return; @@ -168,10 +162,12 @@ function getSignatures(signatureOidStrings, containerId) { var newHtml = ""; $.each(signatureList, function(index, signature) { - newHtml += '
' + - '
' + - '' + - "
" + + newHtml += + '
' + + '
' + + "
Unterschrift vom " + signature.InsTsStr + "
" + + '' + + "
" + "
"; }); @@ -183,20 +179,43 @@ function getSignatures(signatureOidStrings, containerId) { } } -function cancelSignature(canSign, signaturePad) { +function cancelSignature(canSign, signaturePad, canvasId, signatureContainer, overridingAlertId) { try { if (canSign === false) { - hideSignatureContainer(canSign, signaturePad); + hideSignatureContainer(signatureContainer, overridingAlertId); + signaturePad.clear(); + return; + } + + var canvas = document.getElementById(canvasId); + var twoDContext = canvas.getContext("2d"); + + var width = canvas.getBoundingClientRect().width; + var height = canvas.getBoundingClientRect().height; + + if (width === 0 || height === 0) { + hideSignatureContainer(signatureContainer, overridingAlertId); signaturePad.clear(); return; } + var isEmpty = signaturePad.isEmpty(); + + logInfo3("Canvas ist leer: " + isEmpty); + + if(isEmpty === true) { + hideSignatureContainer(signatureContainer, overridingAlertId); + signaturePad.clear(); + + return; + } + showMessagePopupWithCallback("Unterschrift", "Sind Sie sicher, dass Sie die Unterschrift nicht speichern möchten?", function() { - hideSignatureContainer(canSign, signaturePad); + hideSignatureContainer(signatureContainer, overridingAlertId); signaturePad.clear(); }, @@ -206,9 +225,8 @@ function cancelSignature(canSign, signaturePad) { } } -function hideSignatureContainer() { - $("#report-signature-container-div").removeClass("d-block"); - $("#overwriting-signature-alert").removeClass("d-block"); +function hideSignatureContainer(signatureContainer, overridingAlertId) { + $("#" + signatureContainer + ", #" + overridingAlertId).removeClass("d-block"); $("#report-form-container").show(); } @@ -251,11 +269,11 @@ function showSignaturePad(overwrite, signatureOidsString, canSign, cardBodyId, c var clearButton = document.getElementById("clear-report-canvas-button"); cancelButton.addEventListener("click", function() { - cancelSignature(canSign, signaturePad); + cancelSignature(canSign, signaturePad, "report-sketch-pad-canvas", "report-signature-container-div", "overwriting-signature-alert"); }); saveButton.addEventListener("click", function() { - saveSignature(customerOid, isEmployeeSignature, overwrite, signaturePad); + saveSignature(customerOid, isEmployeeSignature, overwrite, signaturePad, "report-sketch-pad-canvas"); }); clearButton.addEventListener("click", function() { @@ -266,16 +284,21 @@ function showSignaturePad(overwrite, signatureOidsString, canSign, cardBodyId, c } } -function saveSignature(customerOid, isEmployeeSignature, overwrite, signaturePad) { +function saveSignature(customerOid, isEmployeeSignature, overwrite, signaturePad, canvasId) { try { - var clonedCanvas = trimCanvas(cloneCanvas(document.getElementById("report-sketch-pad-canvas"))); + var canvas = document.getElementById(canvasId); + var clonedCanvas = cloneCanvas(canvas); + var trimmedCanvas = trimCanvas(clonedCanvas); - var context = clonedCanvas.getContext("2d"); + var context = trimmedCanvas.getContext("2d"); context.globalCompositeOperation = "destination-over"; context.fillStyle = "white"; - context.fillRect(0, 0, clonedCanvas.width, clonedCanvas.height); - var dataUrl = clonedCanvas.toDataURL("image/png"); + logInfo3(trimmedCanvas.width + " x " + trimmedCanvas.height); + + context.fillRect(0, 0, trimmedCanvas.width, trimmedCanvas.height); + + var dataUrl = trimmedCanvas.toDataURL("image/png"); showMessagePopupWithCallback( "Unterschrift speichern", diff --git a/BeWoPlanerMobil/Util/QuittierungsbelegItem.cs b/BeWoPlanerMobil/Util/QuittierungsbelegItem.cs index 89c8d95aa..6e30e14cf 100644 --- a/BeWoPlanerMobil/Util/QuittierungsbelegItem.cs +++ b/BeWoPlanerMobil/Util/QuittierungsbelegItem.cs @@ -1,6 +1,5 @@ using System; using BeWo.Report.ReportObjects; -using BS.Shared.DataContracts.Compact; namespace BeWoPlanerMobil.Util { diff --git a/BeWoPlanerMobil/Util/QuittierungsbelegResult.cs b/BeWoPlanerMobil/Util/QuittierungsbelegResult.cs index 85853e024..9cdbe912a 100644 --- a/BeWoPlanerMobil/Util/QuittierungsbelegResult.cs +++ b/BeWoPlanerMobil/Util/QuittierungsbelegResult.cs @@ -10,6 +10,7 @@ namespace BeWoPlanerMobil.Util public string CustomerName { get; } + // Die Liste mit den Zeiterfassungseinträgen public List Items { get; } public long CustomerOid { get; } diff --git a/BeWoPlanerMobil/Util/ReportUtils/Quittierungsbelegsunterschriftenobjekt.cs b/BeWoPlanerMobil/Util/ReportUtils/Quittierungsbelegsunterschriftenobjekt.cs new file mode 100644 index 000000000..b32485df6 --- /dev/null +++ b/BeWoPlanerMobil/Util/ReportUtils/Quittierungsbelegsunterschriftenobjekt.cs @@ -0,0 +1,20 @@ +namespace BeWoPlanerMobil.Util.ReportUtils +{ + public class Quittierungsbelegsunterschriftenobjekt + { + public bool IsEmployeeSignature { get; } + public string PersonName { get; } + public string TimeSpanInfo { get; } + public string CustomerName { get; } + public int ServiceRecordCount { get; } + + public Quittierungsbelegsunterschriftenobjekt(bool isEmployeeSignature, string personName, string timeSpanInfo, string customerName, int serviceRecordCount) + { + IsEmployeeSignature = isEmployeeSignature; + PersonName = personName; + TimeSpanInfo = timeSpanInfo; + CustomerName = customerName; + ServiceRecordCount = serviceRecordCount; + } + } +} \ No newline at end of file diff --git a/BeWoPlanerMobil/Util/SignatureUtils.cs b/BeWoPlanerMobil/Util/SignatureUtils.cs index e543647a4..fafcd28d1 100644 --- a/BeWoPlanerMobil/Util/SignatureUtils.cs +++ b/BeWoPlanerMobil/Util/SignatureUtils.cs @@ -1,9 +1,7 @@ using System; -using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; -using System.Linq; namespace BeWoPlanerMobil.Util { @@ -11,7 +9,7 @@ namespace BeWoPlanerMobil.Util { public static bool ValidateSignature(Bitmap signatureBitmap) { - if(signatureBitmap == null) + if(signatureBitmap is null) { return false; } @@ -41,37 +39,37 @@ namespace BeWoPlanerMobil.Util public static bool HasTransparentBackground(string base64Image) { - if (string.IsNullOrWhiteSpace(base64Image)) + if(string.IsNullOrWhiteSpace(base64Image)) { return true; } - if (base64Image.Contains(",")) + if(base64Image.Contains(",")) { base64Image = base64Image.Split(',')[1]; } var whitePixelCount = 0; - using (var bitmap = Base64StringToBitmap(base64Image)) + using(var bitmap = Base64StringToBitmap(base64Image)) { - if (bitmap.Width == 0 || bitmap.Height == 0) + if(bitmap.Width == 0 || bitmap.Height == 0) { return true; } - for (var x = 0; x < bitmap.Width; x++) + for(var x = 0; x < bitmap.Width; x++) { - for (var y = 0; y < bitmap.Height; y++) + for(var y = 0; y < bitmap.Height; y++) { var pixel = bitmap.GetPixel(x, y); - if (pixel.R == 255 && pixel.G == 255 && pixel.B == 255) + if(pixel.R == 255 && pixel.G == 255 && pixel.B == 255) { whitePixelCount++; } - if (whitePixelCount == 20) + if(whitePixelCount == 20) { return false; } diff --git a/BeWoPlanerMobil/Views/Report/ConfirmationReceiptSignaturePartial.cshtml b/BeWoPlanerMobil/Views/Report/ConfirmationReceiptSignaturePartial.cshtml new file mode 100644 index 000000000..7c32fd999 --- /dev/null +++ b/BeWoPlanerMobil/Views/Report/ConfirmationReceiptSignaturePartial.cshtml @@ -0,0 +1,102 @@ +@model BeWoPlanerMobil.Models.ReportModel + +@{ + var plural = Model.ConfirmationReceiptObject.NumberOfServiceRecords > 1 ? "en" : string.Empty; + + var leistungsplurarl = Model.ConfirmationReceiptObject.NumberOfServiceRecords > 1 ? "en" : string.Empty; + + var sigInfo = $"Unterschrift{plural} von {Model.Quittierungsbelegsunterschriftenobjekt.PersonName} für {Model.Quittierungsbelegsunterschriftenobjekt.ServiceRecordCount} erbrachte Leistung{leistungsplurarl} von {Model.Quittierungsbelegsunterschriftenobjekt.CustomerName} ({Model.Quittierungsbelegsunterschriftenobjekt.TimeSpanInfo})"; +} + +
+
+
+

@sigInfo

+ +
+
+
+ @* + ToDo: Hier die bereits geleisteten Unterschriften anzeigen + + xs: < 576px + sm: >= 576px + md: >= 768px + lg: >= 992px + xl: >= 1200px + + xs: maximal 1 + sm: maximal 1 + md: maximal 2 + lg: maximal 3 + xl: maximal 4 + *@ + +
+ @{ + var count = Model.SelectedConfirmationReceiptSignatures.Count; + + var colClass = $"col-sm-12 col-md-"; + + + } + + @foreach(var signature in Model.SelectedConfirmationReceiptSignatures) + { + var blubb = $"{(signature.NumberOfServiceRecords == 1 ? "eine" : signature.NumberOfServiceRecords.ToString())} Leistung{(signature.NumberOfServiceRecords != 1 ? "en" : string.Empty)}"; + +
+
+ Unterschrift von @signature.PersonName geleistet am @signature.InsTsStr +
+
+
+ Unterschrift von: +
+
+ @signature.PersonName +
+
+
+
+ Geleistet am: +
+
+ @signature.InsTsStr +
+
+
+
+ Geleistet für: +
+
+ @blubb +
+
+
+
+
+ } +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ + +
+
+
\ No newline at end of file diff --git a/BeWoPlanerMobil/Views/Report/QuittierungsbelegsResultPartial.cshtml b/BeWoPlanerMobil/Views/Report/QuittierungsbelegsResultPartial.cshtml index ba4d48597..14b54326e 100644 --- a/BeWoPlanerMobil/Views/Report/QuittierungsbelegsResultPartial.cshtml +++ b/BeWoPlanerMobil/Views/Report/QuittierungsbelegsResultPartial.cshtml @@ -28,6 +28,50 @@ showErrorPopup(error); } } + + function loadConfirmationReceiptSignatures(cardBodyId, identifier, isEmployee, isOverriding, canSign, customerOid) { + cardHeaderButtonClick(cardBodyId); + + $("#report-form-container").hide(); + $("#report-signature-container").addClass("d-block"); + + $("#report-signature-container").load("@Url.Action("FetchConfirmationReceiptSignatures", "Report")", { identifier: identifier, isEmployee: isEmployee }, function() { + var overrideAlert = $("#qb-sig-override-alert"); + if (isOverriding === true) { + overrideAlert.show(); + } else { + overrideAlert.hide(); + } + + if (canSign) { + $("#qb-sig-canvas-row, #qb-sig-canvas-container, #qb-sig-sketch-pad").show(); + } else { + $("#qb-sig-canvas-row, #qb-sig-canvas-container, #qb-sig-sketch-pad, #qb-sig-save-btn, #qb-sig-clear-canvas-btn").hide(); + } + + resizeCanvas("#qb-sig-sketch-pad", "#qb-sig-canvas-row"); + + var canvas = document.getElementById("qb-sig-sketch-pad"); + + var signaturePad = new SignaturePad(canvas, { backgroundColor: "rgba(255, 255, 255, 0)" }); + + var cancelButton = document.getElementById("qb-sig-cancel-btn"); + var saveButton = document.getElementById("qb-sig-save-btn"); + var clearButton = document.getElementById("qb-sig-clear-canvas-btn"); + + cancelButton.addEventListener("click", function () { + cancelSignature(canSign, signaturePad, "qb-sig-sketch-pad", "report-signature-container", "qb-sig-override-alert"); + }); + + saveButton.addEventListener("click", function () { + saveSignature(customerOid, isEmployee, isOverriding, signaturePad, "qb-sig-sketch-pad"); + }); + + clearButton.addEventListener("click", function () { + signaturePad.clear(); + }); + }); + }
@@ -166,8 +210,18 @@ }
@@ -179,9 +233,19 @@ } -
diff --git a/BeWoPlanerMobil/Views/Report/Report.cshtml b/BeWoPlanerMobil/Views/Report/Report.cshtml index 1a2b32d59..89e94c522 100644 --- a/BeWoPlanerMobil/Views/Report/Report.cshtml +++ b/BeWoPlanerMobil/Views/Report/Report.cshtml @@ -1,4 +1,5 @@ -@model BeWoPlanerMobil.Models.ReportModel +@using BeWoPlanerMobil.Util +@model BeWoPlanerMobil.Models.ReportModel @{ ViewBag.Title = "Quittierungsbeleg"; @@ -6,7 +7,7 @@ @@ -65,7 +66,13 @@ function createServiceOverview() { try { - $("#report-signatures-container").load("@Url.Action("LoadServiceOverview")"); + showSpinner(); + + $("#report-signatures-container").load("@Url.Action("LoadServiceOverview")", + function () { + hideSpinner(); + } + ); } catch (error) { showErrorPopup(error); } @@ -306,14 +313,16 @@ + +
+ @if(Html.IsInDebugMode()) + { + + } -
-
- -
-
- -
+
@@ -324,40 +333,9 @@
-
-
-
-

Unterschrift

- -
-
-
- -
-
-
- -
-
-
-
- -
-
-
-
- - -
-
-
+
-
@@ -392,4 +370,58 @@
- \ No newline at end of file + + + + + \ No newline at end of file diff --git a/BeWoPlanerMobil/Views/Scheduler/OneDaySchedulerPartial.cshtml b/BeWoPlanerMobil/Views/Scheduler/OneDaySchedulerPartial.cshtml index 41c946f84..a0f629c5b 100644 --- a/BeWoPlanerMobil/Views/Scheduler/OneDaySchedulerPartial.cshtml +++ b/BeWoPlanerMobil/Views/Scheduler/OneDaySchedulerPartial.cshtml @@ -255,20 +255,20 @@ @if(Model.HasRightToEditAppointment(appointment.Identifier) && !appointment.IsTask && appointment.CanBeEdited) { -
+
- @if(appointment.Oid.HasValue) - { - using(Html.BeginForm("SelectAppointmentToEdit", "Scheduler", FormMethod.Post)) - { -
- - -
- } - } + @if(appointment.Oid.HasValue) + { + using(Html.BeginForm("SelectAppointmentToEdit", "Scheduler", FormMethod.Post)) + { +
+ + +
+ } + }