diff --git a/src/main/java/org/catrobat/jira/timesheet/rest/TimesheetRest.java b/src/main/java/org/catrobat/jira/timesheet/rest/TimesheetRest.java index 5659814..b764a2f 100644 --- a/src/main/java/org/catrobat/jira/timesheet/rest/TimesheetRest.java +++ b/src/main/java/org/catrobat/jira/timesheet/rest/TimesheetRest.java @@ -1182,7 +1182,7 @@ public Response updateTotalTargetHours(@Context HttpServletRequest request, @Pat return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); } - Response response = permissionService.checkUserPermission(); + Response response = permissionService.checkRootPermission(); if (response != null) return response; @@ -1201,6 +1201,36 @@ public Response updateTotalTargetHours(@Context HttpServletRequest request, @Pat } } + @POST + @Path("updateSubtractedHours/{hours}") + public Response updateSubtractedHours(@Context HttpServletRequest request, @PathParam("hours") int hours){ + ApplicationUser user; + + try { + user = permissionService.checkIfUserExists(); + } catch (PermissionException e) { + return Response.status(Response.Status.UNAUTHORIZED).entity(e.getMessage()).build(); + } + + Response response = permissionService.checkRootPermission(); + if (response != null) + return response; + + try{ + Timesheet sheet = sheetService.getTimesheetByUser(user.getKey()); + + if(sheet != null) { + sheet.setHoursDeducted(hours); + sheet.save(); + } + + return Response.ok(new JsonTimesheet(sheet)).build(); + } + catch (ServiceException e){ + return Response.status(Response.Status.CONFLICT).entity(e.getMessage()).build(); + } + } + @DELETE @Path("deleteLecture") @Consumes(MediaType.APPLICATION_JSON) diff --git a/src/main/java/org/catrobat/jira/timesheet/rest/json/JsonTimesheet.java b/src/main/java/org/catrobat/jira/timesheet/rest/json/JsonTimesheet.java index 94baf04..bfe6159 100644 --- a/src/main/java/org/catrobat/jira/timesheet/rest/json/JsonTimesheet.java +++ b/src/main/java/org/catrobat/jira/timesheet/rest/json/JsonTimesheet.java @@ -51,7 +51,7 @@ public final class JsonTimesheet { @JsonDeserialize(using = DateAndTimeDeserialize.class) private Date latestEntryDate; @XmlElement - private int targetHourPractice; + private int targetHoursRemaining; @XmlElement private int targetHours; @XmlElement @@ -71,16 +71,18 @@ public final class JsonTimesheet { public JsonTimesheet(Timesheet timesheet) { this.timesheetID = timesheet.getID(); this.userKey = timesheet.getUserKey(); - this.lectures = timesheet.getLectures(); - this.reason = timesheet.getReason(); - this.latestEntryDate = timesheet.getLatestEntryBeginDate(); - this.targetHourPractice = timesheet.getHoursCompleted(); + this.displayName = timesheet.getDisplayName(); + this.state = timesheet.getState(); + this.targetHours = timesheet.getTargetHours(); - this.targetHoursCompleted = timesheet.getHoursCompleted(); + this.lectures = timesheet.getLectures(); this.targetHoursRemoved = timesheet.getHoursDeducted(); - this.state = timesheet.getState(); - this.displayName = timesheet.getDisplayName(); + this.reason = timesheet.getReason(); + + this.targetHoursCompleted = timesheet.getHoursCompleted() - this.targetHoursRemoved; + this.targetHoursRemaining = this.targetHours - this.targetHoursCompleted; + this.latestEntryDate = timesheet.getLatestEntryBeginDate(); if (timesheet.firstEntry() != null) { this.firstEntryDate = timesheet.firstEntry().getBeginDate(); } @@ -133,12 +135,12 @@ public void setLatestEntryDate(Date latestEntryDate) { this.latestEntryDate = latestEntryDate; } - public int getTargetHourPractice() { - return targetHourPractice; + public int getTargetHoursRemaining() { + return targetHoursRemaining; } - public void setTargetHourPractice(int targetHourPractice) { - this.targetHourPractice = targetHourPractice; + public void setTargetHoursRemaining(int targetHoursRemaining) { + this.targetHoursRemaining = targetHoursRemaining; } @@ -203,7 +205,7 @@ public boolean equals(Object o) { if (latestEntryDate != that.latestEntryDate) { return false; } - if (targetHourPractice != that.targetHourPractice) { + if (targetHoursRemaining != that.targetHoursRemaining) { return false; } if (targetHours != that.targetHours) { @@ -231,7 +233,7 @@ public int hashCode() { result = 31 * result + lectures.hashCode(); result = 31 * result + reason.hashCode(); //result = 31 * result + latestEntryDate.hashCode(); - result = 31 * result + targetHourPractice; + result = 31 * result + targetHoursRemaining; result = 31 * result + targetHours; result = 31 * result + targetHoursCompleted; result = 31 * result + targetHoursRemoved; diff --git a/src/main/java/org/catrobat/jira/timesheet/rest/json/JsonUserInformation.java b/src/main/java/org/catrobat/jira/timesheet/rest/json/JsonUserInformation.java index 95581a4..d4caa50 100644 --- a/src/main/java/org/catrobat/jira/timesheet/rest/json/JsonUserInformation.java +++ b/src/main/java/org/catrobat/jira/timesheet/rest/json/JsonUserInformation.java @@ -57,11 +57,10 @@ public JsonUserInformation (Timesheet timesheet) { this.state = timesheet.getState(); this.latestEntryDate = timesheet.getLatestEntryBeginDate(); - this.remainingHours = (timesheet.getTargetHours() - timesheet.getHoursCompleted() - + timesheet.getHoursDeducted()); this.targetTotalHours = timesheet.getTargetHours(); + this.totalHours = timesheet.getHoursCompleted() - timesheet.getHoursDeducted(); + this.remainingHours = this.targetTotalHours - this.totalHours; - this.totalHours = timesheet.getHoursCompleted(); this.email = ComponentAccessor.getUserManager().getUserByKey(timesheet.getUserKey()).getEmailAddress(); this.timesheetID = timesheet.getID(); diff --git a/src/main/resources/css/timesheet.css b/src/main/resources/css/timesheet.css index 2a9537b..64e4d39 100644 --- a/src/main/resources/css/timesheet.css +++ b/src/main/resources/css/timesheet.css @@ -215,3 +215,14 @@ code { color: forestgreen; margin-left: 6px; } + +#edit-subtracted-hours{ + cursor: pointer; + margin-left: 6px; +} + +#submit-subtracted-hours{ + cursor: pointer; + color: forestgreen; + margin-left: 6px; +} diff --git a/src/main/resources/js/timesheet.js b/src/main/resources/js/timesheet.js index a670e50..d6b8ba8 100644 --- a/src/main/resources/js/timesheet.js +++ b/src/main/resources/js/timesheet.js @@ -94,13 +94,14 @@ AJS.toInit(function () { timesheetID: existingTimesheetData.timesheetID, lectures: lectures, reason: AJS.$("#timesheet-substract-hours-text").val(), - targetHourPractice: toFixed(AJS.$("#timesheet-hours-practical").val(), 2), - targetHours: AJS.$("#timesheet-hours-text").val(), - targetHoursCompleted: toFixed(AJS.$("#timesheet-hours-practical").val() - AJS.$("#timesheet-hours-substract").val(), 2), + targetHourPractice: toFixed(AJS.$("#timesheet-finished-hours").val(), 2), + targetHours: AJS.$("#timesheet-target-hours").val(), + targetHoursCompleted: toFixed(AJS.$("#timesheet-finished-hours").val() - AJS.$("#timesheet-hours-substract").val(), 2), targetHoursRemoved: toFixed(AJS.$("#timesheet-hours-substract").val(), 2), firstEntryDate: existingTimesheetData.firstEntryDate, latestEntryDate: existingTimesheetData.latestEntryDate, - state: existingTimesheetData.state + state: existingTimesheetData.state, + targetHoursRemaining: existingTimesheetData.targetHoursRemaining }; var timesheetUpdated = AJS.$.ajax({ @@ -235,7 +236,7 @@ function projectedFinishDate(timesheetData, entryData) { var entries = entryData[0]; var rem = timesheet.targetHours - timesheet.targetHoursCompleted + timesheet.targetHoursRemoved; if (rem <= 0) { - AJS.$("#timesheet-finish-date").val(new Date().toLocaleDateString("en-US")); + AJS.$("#timesheet-projected-finish").val(new Date().toLocaleDateString("en-US")); return; // already finished... } @@ -249,14 +250,14 @@ function projectedFinishDate(timesheetData, entryData) { } } if(sumLast30Days === 0) { - AJS.$("#timesheet-finish-date").val("Not enough entries to compute"); + AJS.$("#timesheet-projected-finish").val("Not enough entries to compute"); return; } var hoursLast30Days = sumLast30Days / (1000 * 60 * 60); var remDays = rem * 30 / hoursLast30Days; var finishDate = new Date(); finishDate.setDate(finishDate.getDate() + remDays); - AJS.$("#timesheet-finish-date").val(finishDate.toLocaleDateString("en-US")); + AJS.$("#timesheet-projected-finish").val(finishDate.toLocaleDateString("en-US")); } function setOwnerLabel(timesheet) { diff --git a/src/main/resources/js/timesheet/functions.js b/src/main/resources/js/timesheet/functions.js index 07254fe..74de93e 100644 --- a/src/main/resources/js/timesheet/functions.js +++ b/src/main/resources/js/timesheet/functions.js @@ -67,29 +67,27 @@ function calculateTime(timesheetData) { function initTimesheetInformationValues(timesheetData) { + var remaining_hours_rounded = toFixed(timesheetData.targetHoursRemaining, 2) + var finished_hours_rounded = toFixed(timesheetData.targetHoursCompleted, 2) var target_hours_rounded = toFixed(timesheetData.targetHours, 2); - var hours_done_rounded = toFixed(timesheetData.targetHoursCompleted, 2) - + toFixed(timesheetData.targetHoursRemoved, 2); - setProgressBar(target_hours_rounded, hours_done_rounded); + setProgressBar(target_hours_rounded, finished_hours_rounded); - AJS.$("#timesheet-hours-text").val(target_hours_rounded); - AJS.$("#timesheet-hours-ects").val(timesheetData.ects); - AJS.$("#timesheet-hours-practical").val(toFixed(calculateTime(timesheetData), 2)); - - AJS.$("#timesheet-hours-remain").val(toFixed(timesheetData.targetHours - - AJS.$("#timesheet-hours-practical").val() - timesheetData.targetHoursRemoved, 2)); + AJS.$("#timesheet-remaining-hours").val(remaining_hours_rounded); + AJS.$("#timesheet-finished-hours").val(finished_hours_rounded); + AJS.$("#timesheet-target-hours").val(target_hours_rounded); + AJS.$("#timesheet-subtracted-hours").val(toFixed(timesheetData.targetHoursRemoved, 2)); + AJS.$("#timesheet-subtracted-hours-text").val(timesheetData.reason); AJS.$("#edit-total-hours").on("click", function (e) { - AJS.$("#timesheet-hours-text").removeAttr("disabled"); + AJS.$("#timesheet-target-hours").removeAttr("disabled"); AJS.$("#submit-total-hours").css("visibility" , "visible"); }); AJS.$("#submit-total-hours").on("click", function (e) { console.log("submitting new total hours"); var value; - AJS.$("#timesheet-hours-text").val() === "" ? value = 0 : value = AJS.$("#timesheet-hours-text").val(); - + AJS.$("#timesheet-target-hours").val() === "" ? value = 0 : value = AJS.$("#timesheet-target-hours").val(); AJS.$.ajax({ url : restBaseUrl + "updateTotalTargetHours/" + value, type : "POST", @@ -104,12 +102,53 @@ function initTimesheetInformationValues(timesheetData) { updateCurrentTimesheetData(data); updateProgressBar(); - updateTimesheetInformationValues(timesheetData_); + initTimesheetInformationValues(timesheetData_); - AJS.$("#timesheet-hours-text").attr("disabled", "disabled"); + AJS.$("#timesheet-target-hours").attr("disabled", "disabled"); AJS.$("#submit-total-hours").css("visibility" , "hidden"); }, - fail : function (err) { + error : function (err) { + AJS.messages.error({ + title : "Error", + body : "Reason: " + err.responseText, + fadeout: true, + delay: 3000, + duration: 3000 + }) + } + }); + }); + + AJS.$("#edit-subtracted-hours").on("click", function (e) { + AJS.$("#timesheet-subtracted-hours").removeAttr("disabled"); + AJS.$("#submit-subtracted-hours").css("visibility" , "visible"); + }); + + AJS.$("#submit-subtracted-hours").on("click", function (e) { + console.log("submitting new subtracted hours"); + var value; + AJS.$("#timesheet-subtracted-hours").val() === "" ? value = 0 : value = AJS.$("#timesheet-subtracted-hours").val(); + + AJS.$.ajax({ + url : restBaseUrl + "updateSubtractedHours/" + value, + type : "POST", + success : function (data) { + AJS.messages.success({ + title : "Success", + body :"
Your data has been updated", + fadeout: true, + delay: 3000, + duration: 3000 + }); + + updateCurrentTimesheetData(data); + updateProgressBar(); + initTimesheetInformationValues(timesheetData_); + + AJS.$("#timesheet-subtracted-hours").attr("disabled", "disabled"); + AJS.$("#submit-subtracted-hours").css("visibility" , "hidden"); + }, + error : function (err) { AJS.messages.error({ title : "Error", body : "Reason: " + err.responseText, @@ -121,6 +160,9 @@ function initTimesheetInformationValues(timesheetData) { }); }); + AJS.$("#timesheet-target-hours").attr("disabled", "disabled"); + AJS.$("#timesheet-subtracted-hours").attr("disabled", "disabled"); + AJS.$("#lectures-container").empty(); var lectures = timesheetData.lectures; var splitted = lectures.split("@/@"); @@ -154,38 +196,9 @@ function initTimesheetInformationValues(timesheetData) { showLectureDeletionDialog(data); }); - if (isAdmin) { - AJS.$("#substractTimesheetHours").empty(); - AJS.$("#substractTimesheetHours").append("
"); - AJS.$("#substractTimesheetHours").append(""); - AJS.$("#substractTimesheetHours").append(""); - AJS.$("#substractTimesheetHours").append("
Shows your subtracted timesheet hours " + - "(only integers are supported)." + - "
The Remaining Timesheet Hours are increased by the value entered above.
"); - AJS.$("#substractTimesheetHours").append(""); - AJS.$("#substractTimesheetHours").append(""); - AJS.$("#substractTimesheetHours").append("
Reason(s) why some hours of your timesheet
have been \'terminated\'.
"); - AJS.$("#substractTimesheetHours").append("
"); - - //load values - AJS.$("#timesheet-substract-hours-text").val(timesheetData.reason); - AJS.$("#timesheet-hours-substract").val(toFixed(timesheetData.targetHoursRemoved, 2)); - } else { - AJS.$("#substractTimesheetHours").empty(); - AJS.$("#substractTimesheetHours").append("
"); - AJS.$("#substractTimesheetHours").append(""); - AJS.$("#substractTimesheetHours").append(""); - AJS.$("#substractTimesheetHours").append("
Shows your subtracted timesheet hours " + - "(only integers are supported)." + - "
The Remaining Timesheet Hours are increased by the value entered above.
"); - AJS.$("#substractTimesheetHours").append(""); - AJS.$("#substractTimesheetHours").append(""); - AJS.$("#substractTimesheetHours").append("
Reason(s) why some hours of your timesheet
have been \'terminated\'.
"); - AJS.$("#substractTimesheetHours").append("
"); - - //load values - AJS.$("#timesheet-substract-hours-text").val(timesheetData.reason); - AJS.$("#timesheet-hours-substract").val(toFixed(timesheetData.targetHoursRemoved, 2)); + if (!isAdmin) { + AJS.$("#edit-total-hours").css("visibility" , "hidden"); + AJS.$("#edit-subtracted-hours").css("visibility" , "hidden"); } } @@ -250,7 +263,7 @@ function deleteLecture(lecture, dialog){ updateCurrentTimesheetData(data); updateProgressBar(); - updateTimesheetInformationValues(timesheetData_); + initTimesheetInformationValues(timesheetData_); dialog.remove(); // console.log("that worked"); @@ -323,8 +336,7 @@ function updateTimesheetInfoData(){ type : "GET", success : function (data) { timesheetData_.entries = data; - updateTimesheetInformationValues(timesheetData_); - + initTimesheetInformationValues(timesheetData_); } }); } @@ -332,62 +344,6 @@ function updateTimesheetInfoData(){ } - - -function updateTimesheetInformationValues(timesheetData) { - -// console.log("updating timesheetInfo"); -// console.log(timesheetData); - - AJS.$("#lectures-container").empty(); - - var lecutures = timesheetData.lectures; - var splitted = lecutures.split("@/@"); - - splitted.forEach(function (item, index) { - var element; - index === 0 ? element = "
" : element = "
"; - element += ""; - element += "Delete Lecture"; - - if(index === 0) - element += "Add new Lecture to Account"; - - element += "
"; - - AJS.$("#lectures-container").append(element) - }); - - AJS.$("#timesheet-hours-substract").val(toFixed(timesheetData.targetHoursRemoved, 2)); - AJS.$("#timesheet-substract-hours-text").val(timesheetData.reason); - AJS.$("#timesheet-hours-text").val(toFixed(timesheetData.targetHours, 2)); - - AJS.$("#timesheet-hours-practical").val(toFixed(calculateTime(timesheetData), 2)); - - AJS.$("#timesheet-hours-remain").val(toFixed(timesheetData.targetHours - - AJS.$("#timesheet-hours-practical").val() - timesheetData.targetHoursRemoved, 2)); - - AJS.$("#timesheet-hours-ects").val(timesheetData.ects); - - AJS.$("#add-lecture").off(); - AJS.$(".delete-lecture"); - - AJS.$("#add-lecture").on("click.timesheet", function (e) { - e.preventDefault(); - - console.log("add lecture was clicked"); - showInitTimesheetReasonDialog(false); - }); - - AJS.$(".delete-lecture").on("click.timesheet", function (e) { - e.preventDefault(); - var data = e.target.getAttribute("data-lecture"); - - console.log("we want to delete a lecture"); - showLectureDeletionDialog(data); - }); -} - function toUTCTimeString(date) { var h = date.getUTCHours(), m = date.getUTCMinutes(); var string = diff --git a/src/main/resources/js/timesheet/table.js b/src/main/resources/js/timesheet/table.js index 9e3ae3b..2623534 100644 --- a/src/main/resources/js/timesheet/table.js +++ b/src/main/resources/js/timesheet/table.js @@ -848,7 +848,7 @@ function handleTimesheetReasonDataSuccess(data){ updateCurrentTimesheetData(data); updateProgressBar(); - updateTimesheetInformationValues(timesheetData_); + initTimesheetInformationValues(timesheetData_); console.log("handling init Success"); diff --git a/src/main/resources/timesheet.vm b/src/main/resources/timesheet.vm index 65bdb43..171efee 100644 --- a/src/main/resources/timesheet.vm +++ b/src/main/resources/timesheet.vm @@ -262,10 +262,10 @@
- - + +
Shows your remaining timesheet hours. @@ -273,10 +273,10 @@
- - + +
Shows your finished practical hours. @@ -284,10 +284,10 @@
- - + +
Shows your projected finish date based @@ -295,10 +295,10 @@
- - + + Edit Total hours @@ -321,7 +321,24 @@
-
+
+ + + + + Edit Subtracted hours + + +
+ The finished hours are decreased by the subtracted hours. Note that only integer values are allowed. +
+ + +
Reason(s) why some hours of your timesheet
have been 'terminated'.
+ +