Author: meynier Date: 2013-07-23 16:51:55 +0200 (Tue, 23 Jul 2013) New Revision: 373 Url: http://chorem.org/projects/chorem/repository/revisions/373 Log: Added a page that displays all the employees of a company and allows to edit the informations. It will also allow to calculate the average daily cost. Added: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/EmployeeEditAction.java trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/employeeEdit.jsp trunk/chorem-webmotion/src/main/webapp/js/employeeEdit.js Modified: trunk/chorem-webmotion/src/main/resources/mapping trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardMultiProject.jsp trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/decorator.jsp Added: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/EmployeeEditAction.java =================================================================== --- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/EmployeeEditAction.java (rev 0) +++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/EmployeeEditAction.java 2013-07-23 14:51:55 UTC (rev 373) @@ -0,0 +1,274 @@ +package org.chorem.webmotion.actions; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collection; +import java.util.Comparator; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.debux.webmotion.server.WebMotionController; +import org.chorem.ChoremClient; +import org.chorem.ChoremUtil; +import org.debux.webmotion.server.call.Call; +import org.debux.webmotion.server.render.Render; +import org.chorem.entities.Closed; +import org.chorem.entities.Company; +import org.chorem.entities.CompanyImpl; +import org.chorem.entities.Employee; +import org.chorem.entities.EmployeeImpl; +import org.chorem.entities.Interval; +import org.chorem.entities.Quotation; +import org.chorem.entities.Project; +import org.chorem.entities.Task; +import org.chorem.entities.Time; +import org.chorem.entities.Worker; +import org.chorem.project.QuotationCalculation; +import org.nuiton.wikitty.entities.Wikitty; +import org.nuiton.wikitty.query.WikittyQuery; +import org.nuiton.wikitty.query.WikittyQueryMaker; +import org.nuiton.wikitty.query.WikittyQueryResult; + +/** + * + * @author meynier + * + */ +public class EmployeeEditAction extends WebMotionController { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(EmployeeEditAction.class); + + /** + * Return the view for a single quotation + * @param client Chorem client + * @param id Project ID (useless here) + * @param quotationFilter Quotation id + * @return + */ + public Render employeeFilter(ChoremClient client, Company company) { + //get all the empoyees from the default company + + + + + List<Company> companies = client.findAllByQuery(Company.class, + new WikittyQueryMaker().exteq("Company").end()).getAll(); + + //Order by name + WikittyQuery employeeQuery = new WikittyQueryMaker().eq(Employee.ELEMENT_FIELD_EMPLOYEE_COMPANY, company).end(); + + WikittyQueryResult<Employee> employeeResult = client.findAllByQuery(Employee.class, employeeQuery); + + List<EmployeeData> employees = new ArrayList<EmployeeData>(); + for(Employee e : employeeResult.getAll()) { + employees.add(new EmployeeData(e, client)); + } + //simply return them lol + return renderView("employeeEdit.jsp", + "employees",employees, + "companies", companies, + "company", new CompanyImpl(client.restore(company.getWikittyId())), + "title", "Employee edit"); + } + + + public Render requestEmployeeEdit(ChoremClient client, String companyId, String addExtension, Call call) { + Company company = null; + + if(companyId == null) + company = client.getDefaultCompany(); + else { + company = new CompanyImpl(client.restore(companyId)); + } + + if(call != null) { + Wikitty w = client.restore(company.getWikittyId()); + Map<String, Object> params = call.getExtractParameters(); + for(String key : params.keySet()) { + //Prevent false data + if((key.equals("CompanyHR.dailyReturn") + || key.equals("CompanyHR.dailyHoursWorked"))) { + try { + double value = Double.parseDouble(((String[])params.get(key))[0]); + w.setFqField(key, value); + } + catch(java.lang.NumberFormatException e) { + System.err.println(e.getMessage());//TODO : user output + } + + } + } + + client.store(w); + } + + if(addExtension != null && addExtension.equals("true")) { + Wikitty w = client.restore(company.getWikittyId()); + w.addExtension(client.restoreExtensionLastVersion("CompanyHR")); + client.store(w); + } + + return employeeFilter(client, company); + } + + public Render editEmployeeValues(ChoremClient client, String employeeId, String salaryStr + , String productivityRateStr, String partialTimeStr, String dailyReturnStr) { + Wikitty employeeWikitty = client.restore(employeeId); + Employee employee = new EmployeeImpl(employeeWikitty); + if(!employeeWikitty.hasExtension("EmployeeHR")) { + employeeWikitty.addExtension(client.restoreExtensionLastVersion("EmployeeHR")); + } + + double salary = 0, productivityRate = 0, partialTime = 0, dailyReturn = 0; + List<ErrorJson> errors = new ArrayList<ErrorJson>(); + try { + salary = Double.parseDouble(salaryStr); + } + catch (java.lang.NumberFormatException e) { + errors.add(new ErrorJson("salary", "Salary must be a real number")); + } + + try{ + productivityRate = Double.parseDouble(productivityRateStr); + } + catch (java.lang.NumberFormatException e) { + errors.add(new ErrorJson("productivityRate", "Productivity rate must be a real number")); + } + + try { + partialTime = Double.parseDouble(partialTimeStr); + } + catch (java.lang.NumberFormatException e) { + errors.add(new ErrorJson("partialTime", "Partial time must be a real number")); + } + + try { + dailyReturn = Double.parseDouble(dailyReturnStr); + } + catch (java.lang.NumberFormatException e) { + errors.add(new ErrorJson("dailyReturn", "Daily return must be a real number")); + } + + if(productivityRate > 100 || productivityRate < 0) { + errors.add(new ErrorJson("productivityRate", "Productivity rate must be between 0 and 100")); + } + if(partialTime > 100 || partialTime < 0) { + errors.add(new ErrorJson("partialTime", "Partial time must be between 0 and 100")); + } + if(errors.size() != 0) + return renderJSON("data", "error", "errors", errors); + + + if(salary != 0) + employeeWikitty.setFqField("EmployeeHR.salary", salary); + employeeWikitty.setFqField("EmployeeHR.productivityRate", productivityRate); + employeeWikitty.setFqField("EmployeeHR.partialTime", partialTime); + employeeWikitty.setFqField("EmployeeHR.dailyReturn", dailyReturn); + client.store(employeeWikitty); + + + EmployeeData data = new EmployeeData(new EmployeeImpl(employeeWikitty), client); + + EmployeeJson json = new EmployeeJson( + data.getSalary() + "", + data.getProductivityRate(), + data.getPartialTime(), + data.getDailyReturn(), + data.getDailyHoursWorked() + ); + + return renderJSON("data", json); + + } + public class ErrorJson { + private String errorMessage; + private String field; + + public ErrorJson (String field, String message) { + this.field = field; + this.errorMessage = message; + } + } + + public class EmployeeJson { + + private String salary; + private double productivityRate; + private double partialTime; + private double dailyReturn; + private double dailyHoursWorked; + + public EmployeeJson(String salary, double productivityRate, double partialTime, + double dailyReturn, double dailyHoursWorked) { + this.salary = salary; + this.productivityRate = productivityRate; + this.partialTime = partialTime; + this.dailyReturn = dailyReturn; + this.dailyHoursWorked = dailyHoursWorked; + } + + } + + public class EmployeeData { + + private Employee e; + private String salary; + private double productivityRate; + private double partialTime; + private double dailyReturn; + private double dailyHoursWorked; + + + public EmployeeData(Employee e, ChoremClient client) { + Wikitty w = client.restore(e.getWikittyId()); + if(w.hasExtension("EmployeeHR")) { + this.salary = w.getFieldAsDouble("EmployeeHR", "salary") + ""; + this.productivityRate = w.getFieldAsDouble("EmployeeHR", "productivityRate"); + this.partialTime = w.getFieldAsDouble("EmployeeHR", "partialTime"); + } + else { + this.salary = "Non renseigné"; + this.productivityRate = 100; + this.partialTime = 100; + } + this.dailyReturn = client.getDailyReturn(e); + this.dailyHoursWorked = client.getDailyHoursWorked(e); + this.e = e; + } + + public Employee getObject() { + return e; + } + + public String getSalary() { + return salary; + } + + public double getDailyReturn() { + return dailyReturn; + } + + public double getDailyHoursWorked() { + return dailyHoursWorked; + } + public double getProductivityRate() { + return productivityRate; + } + public double getPartialTime() { + return partialTime; + } + + + + } + +} Modified: trunk/chorem-webmotion/src/main/resources/mapping =================================================================== --- trunk/chorem-webmotion/src/main/resources/mapping 2013-07-22 08:16:20 UTC (rev 372) +++ trunk/chorem-webmotion/src/main/resources/mapping 2013-07-23 14:51:55 UTC (rev 373) @@ -11,6 +11,7 @@ * /fragment/* DecoratorFilter.decorate wmDecoratorNo=true * /sales/funnel/json/* DecoratorFilter.decorate wmDecoratorNo=true * /project/json/* DecoratorFilter.decorate wmDecoratorNo=true +* /admin/employeeEdit/json/* DecoratorFilter.decorate wmDecoratorNo=true * /ascii/* DecoratorFilter.decorate wmDecoratorNo=true * /rest/* DecoratorFilter.decorate wmDecoratorNo=true GET /* DecoratorFilter.decorate @@ -51,6 +52,8 @@ * /fragment/sales/{method} action:sales.SalesAction.{method} * /admin view:contact.jsp * /admin/importExport view:admin/importExport.jsp +* /admin/employeeEdit action:EmployeeEditAction.requestEmployeeEdit +* /admin/employeeEdit/json/{method}/{employeeId} action:EmployeeEditAction.{method} * /admin/{method} action:AdminAction.{method} * /contact view:contact.jsp * /report view:report.jsp Modified: trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardMultiProject.jsp =================================================================== --- trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardMultiProject.jsp 2013-07-22 08:16:20 UTC (rev 372) +++ trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardMultiProject.jsp 2013-07-23 14:51:55 UTC (rev 373) @@ -56,8 +56,8 @@ <th><abbr title="Taux journalier moyen">TJM</abbr> reel</th> <th>Gain attendu</th> <th>Perte/gain</th> - <th>Average SRP</th> - <th>Real SRP</th> + <th>Average CJM</th> + <th>Real CJM</th> </tr> </thead> <c:forEach var="q" items="${quotations}"> @@ -85,9 +85,9 @@ <td class="currency"> <f:formatNumber type="currency" maxFractionDigits="2" value="${calculations[q].getLossOrProfit()}" /></td> <td> <f:formatNumber type="number" - maxFractionDigits="2" value="${calculations[q].getAvgSrp()}" /></td> + maxFractionDigits="2" value="${calculations[q].getAvgReturn()}" /></td> <td> <f:formatNumber type="number" - maxFractionDigits="2" value="${calculations[q].getRealSrp()}" /></td> + maxFractionDigits="2" value="${calculations[q].getRealReturn()}" /></td> </tr> </tbody> Modified: trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/decorator.jsp =================================================================== --- trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/decorator.jsp 2013-07-22 08:16:20 UTC (rev 372) +++ trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/decorator.jsp 2013-07-23 14:51:55 UTC (rev 373) @@ -220,6 +220,8 @@ <li><a href="<c:url value="/admin/importExport"/>">Import/Export</a></li> <li class="divider"></li> <li><a href="<c:url value="/admin/reindex"/>">Reindex</a></li> + <li class="divider"></li> + <li><a href="<c:url value="/admin/employeeEdit"/>">Employee edit</a></li> </ul> </li> </ul> Added: trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/employeeEdit.jsp =================================================================== --- trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/employeeEdit.jsp (rev 0) +++ trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/employeeEdit.jsp 2013-07-23 14:51:55 UTC (rev 373) @@ -0,0 +1,112 @@ +<%-- + #%L + Chorem webmotion + $Id:$ + $HeadURL:$ + %% + Copyright (C) 2011 - 2012 CodeLutin + %% + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + #L% + --%> +<%@page contentType="text/html" pageEncoding="UTF-8"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="f"%> +<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%> +<%@ taglib uri="/WEB-INF/wikitty.tld" prefix="w"%> + +<f:setLocale value="${locale}" /> + + + +<h1>${title}</h1> + +<form method="GET" id="companyForm"> + +<select class="filterBox" name="companyId" id="companySelect"> + <option>Choisir une entreprise</option> + <c:forEach var="c" items="${companies}"> + <option value="${c.wikittyId}" + <c:if test="${company.equals(c)}">selected</c:if> + >${c.name}</option> + </c:forEach> + </select> +</form> + +<form class="well form-inline" method="POST" id="company"> +<h4>${company.name}</h4> +<input type="hidden" name="companyId" value="${company.wikittyId}"/> +<c:if test='${company.wikitty.hasExtension("CompanyHR")}'> +Heures par jour : <w:input wikitty="${company.wikitty}" fqfield="CompanyHR.dailyHoursWorked"/> +CJM : <w:input wikitty="${company.wikitty}" fqfield="CompanyHR.dailyReturn"/> +<button class="btn btn-success" id="companyBtn"> + <i class="icon-ok icon-white"></i> + Mettre à jour + </button> +</c:if> +<c:if test='${!company.wikitty.hasExtension("CompanyHR")}'> +Valeurs par défaut (<a href='variables'>Modifier</a>) :<br/> +Heures par jour : <input type="test" value="${client.getConfiguration().getDailyHoursWorked()}" disabled/> +CJM : <input type="test" value="${client.getConfiguration().getDailyReturn()}" disabled/> +<button class="btn btn-success" id="companyBtn"> + <i class="icon-plus icon-white"></i> + <input type="hidden" name="addExtension" value="true"/> + Ajouter extension HR + </button> +</c:if> + +</form> + + +<table class="table table-striped table-bordered table-condensed"> + <thead> + <th>Employé</th> + <th>Salaire</th> + <th>Heures par jour</th> + <th>Taux de productivité</th> + <th>Temps partiel</th> + <th>CJM</th> + <th>Edit</th> + </thead> + <tbody> + <c:set var="count" value="0"/> + <c:forEach items="${employees}" var="employee"> + <tr class="row${count}" id="${employee.object.wikittyId}"> + <td class="person"><w:display wikitty="${employee.object.wikitty}" + fqfield="Employee.person" label="" /> + </td> + <td class="salary"> + ${employee.salary} + </td> + <td class="dailyHoursWorked"><f:formatNumber type="number" + maxFractionDigits="2" value="${employee.dailyHoursWorked}"/></td> + <td class="productivityRate"><f:formatNumber type="number" + maxFractionDigits="2" value="${employee.productivityRate}"/>%</td> + <td class="partialTime"><f:formatNumber type="number" + maxFractionDigits="2" value="${employee.partialTime}"/>%</td> + <td class="dailyReturn"><f:formatNumber type="number" + maxFractionDigits="2" value="${employee.dailyReturn}"/> + <a class="cjmRefresh" style="cursor:pointer"> + <i class="icon icon-refresh"></i></a></td> + <td class="rowEdit"><a class="employeeEdit" style="cursor:pointer"><i class="icon icon-edit"></i></a></td> + + </tr> + <c:set var="count" value="${count + 1}"/> + </c:forEach> + </tbody> +</table> + +<script src="<c:url value='/js/employeeEdit.js'/>"></script> + + Added: trunk/chorem-webmotion/src/main/webapp/js/employeeEdit.js =================================================================== --- trunk/chorem-webmotion/src/main/webapp/js/employeeEdit.js (rev 0) +++ trunk/chorem-webmotion/src/main/webapp/js/employeeEdit.js 2013-07-23 14:51:55 UTC (rev 373) @@ -0,0 +1,110 @@ + + +$(document).ready(function() { + + + + $("#companySelect").change(function() { + $("#companyForm").submit(); + }); + + $(".employeeEdit").click(employeeEdit); + + function employeeEdit() { + var row = $(this).parent().parent(); + var salary = row.find(".salary"); + var prod = row.find(".productivityRate"); + var time = row.find(".partialTime"); + var cjm = row.find(".dailyReturn"); + + salary.attr("oldVal", $.trim(salary.html())); + salary.html("<input type = 'text' size='3' value='"+$.trim(salary.html())+"'/>"); + prod.attr("oldVal", $.trim(prod.html())); + prod.html("<input type = 'text' size='3' value='"+$.trim(prod.html()).replace('%','')+"'/>"); + time.attr("oldVal", $.trim(time.html())); + time.html("<input type = 'text' size='3' value='"+$.trim(time.html()).replace('%','')+"'/>"); + cjm.attr("oldVal", $.trim(cjm.html())); + cjm.html("<input type = 'text' size='3' value='"+$.trim(cjm.html()).replace('%','')+"'/>"); + + + + + $(this).parent().html("<a class='editOk' style='cursor:pointer'><i class='icon icon-ok'></i></a>" + + "<a class='editCancel' style='cursor:pointer'><i class='icon icon-remove'></i></a>" + ); + row.find(".editCancel").click(editCancel); + row.find(".editOk").click(editOk); + + } + + function editCancel() { + + var row = $(this).parent().parent(); + + var salary = row.find(".salary"); + var prod = row.find(".productivityRate"); + var time = row.find(".partialTime"); + var cjm = row.find('.dailyReturn'); + + salary.html($.trim(salary.attr('oldVal'))); + prod.html($.trim(prod.attr('oldVal'))); + time.html($.trim(time.attr('oldVal'))); + cjm.html($.trim(cjm.attr('oldVal'))); + + + $(this).parent().html("<a class='employeeEdit' style='cursor:pointer'><i class='icon icon-edit'></i></a>" + ); + row.find(".employeeEdit").click(employeeEdit); + + } + + function editOk() { + var row = $(this).parent().parent(); + var cell = $(this).parent(); + + var salary = row.find(".salary"); + var prod = row.find(".productivityRate"); + var time = row.find(".partialTime"); + var cjm = row.find(".dailyReturn"); + + var salaryVal = $.trim(salary.find("input").attr('value')); + var prodVal = $.trim(prod.find("input").attr('value')); + var timeVal = $.trim(time.find("input").attr('value')); + var cjmVal = $.trim(cjm.find("input").attr('value')); + + $.get(createUrl("/admin/employeeEdit/json/editEmployeeValues/",row.attr("id"), "?salaryStr=", + salaryVal, "&productivityRateStr=", prodVal, "&partialTimeStr=", timeVal, + "&dailyReturnStr=", cjmVal), + function(ret){ + console.log(ret); + var data = ret['data']; + + if(data === "error") { + row.find("input").css("background-color", "white"); + row.find(".errorMessage").remove(); + var errors = ret['errors']; + for(var i = 0; i < errors.length; i++) { + row.find("." + errors[i]["field"]+" input").css("background-color", "#FF5555"); + row.find("." + errors[i]["field"]).append( + "<span class='errorMessage'>"+errors[i]["errorMessage"]+"</span>"); + } + } + else + { + salary.html(data['salary']); + prod.html(data["productivityRate"]+"%"); + time.html(data['partialTime']+"%"); + cjm.html(data['dailyReturn']); + row.find('.dailyHoursWorked').html(data['dailyHoursWorked']); + cell.html("<a class='employeeEdit' style='cursor:pointer'><i class='icon icon-edit'></i></a>"); + } + + row.find(".employeeEdit").click(employeeEdit); + } + ); + + + } + + +}); \ No newline at end of file