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)) + { +
+ + +
+ } + }