Chorem-commits
Threads by month
- ----- 2026 -----
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
August 2013
- 4 participants
- 13 discussions
r381 - in trunk/chorem-webmotion/src/main: java/org/chorem/webmotion/actions java/org/chorem/webmotion/actions/project webapp/WEB-INF/jsp webapp/js
by meynier@users.chorem.org 07 Aug '13
by meynier@users.chorem.org 07 Aug '13
07 Aug '13
Author: meynier
Date: 2013-08-07 15:35:46 +0200 (Wed, 07 Aug 2013)
New Revision: 381
Url: http://chorem.org/projects/chorem/repository/revisions/381
Log:
Various small modifications on the dashboards
Modified:
trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/EmployeeEditAction.java
trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/DashboardProjectAction.java
trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/GanttAction.java
trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardMultiProject.jsp
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/java/org/chorem/webmotion/actions/EmployeeEditAction.java
===================================================================
--- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/EmployeeEditAction.java 2013-08-07 13:34:26 UTC (rev 380)
+++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/EmployeeEditAction.java 2013-08-07 13:35:46 UTC (rev 381)
@@ -1,19 +1,10 @@
package org.chorem.webmotion.actions;
-import java.text.NumberFormat;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Collection;
import java.util.Collections;
-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;
@@ -22,21 +13,13 @@
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.EmployeeHR;
import org.chorem.entities.EmployeeHRImpl;
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.AdcCalculation;
-import org.chorem.project.QuotationCalculation;
import org.nuiton.wikitty.entities.Wikitty;
import org.nuiton.wikitty.query.WikittyQuery;
import org.nuiton.wikitty.query.WikittyQueryMaker;
@@ -53,18 +36,14 @@
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 a page with an array with the employees of the specified company
+ * @param client chorem client
+ * @param company employees will be fetched from this company
* @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();
@@ -79,7 +58,7 @@
}
Collections.sort(employees);
- //simply return them lol
+ //simply return them
return renderView("employeeEdit.jsp",
"employees",employees,
"companies", companies,
@@ -88,6 +67,15 @@
}
+ /**
+ * generate a page to edit the employees
+ *
+ * @param client choorem client
+ * @param companyId
+ * @param addExtension
+ * @param call
+ * @return
+ */
public Render requestEmployeeEdit(ChoremClient client, String companyId, String addExtension, Call call) {
Company company = null;
@@ -127,12 +115,19 @@
return employeeFilter(client, company);
}
+ /**
+ * Ajax request for the adc calculation
+ *
+ * @param client chorme client
+ * @param employeeId id of the employee that needs an adc calculation
+ * @return adc
+ */
public Render requestAdc(ChoremClient client, String employeeId) {
Wikitty w = client.restore(employeeId);
EmployeeHR e = new EmployeeHRImpl(w);
- AdcCalculation adcCalc = new AdcCalculation(e, client);
- double adc = adcCalc.getAdc();
+ double adc = AdcCalculation.getAdc(client, e);
+
w.setField("EmployeeHR", "dailyReturn", adc);
client.store(w);
@@ -141,16 +136,56 @@
}
+ /**
+ * Ajax request for the adc calculation of multiple employees of the same company
+ *
+ * @param client chorme client
+ * @param employeeId id of the employees that needs an adc calculation
+ * @return adc
+ */
+ public Render requestMultipleAdc(ChoremClient client, String employeeId) {
+ List<Wikitty> w = client.restore(ChoremUtil.asList(",", employeeId));
+ List<EmployeeHR> employees = new ArrayList<EmployeeHR>();
+ for(int i = 0; i< w.size(); i++) {
+ employees.add(new EmployeeHRImpl(w.get(i)));
+ }
+
+ HashMap<String, Double> adcs = AdcCalculation.getMultipleAdc(client, employees);
+ for(int i = 0; i< w.size(); i++) {
+ Wikitty wi = w.get(i);
+ wi.setField("EmployeeHR", "dailyReturn", adcs.get(wi.getWikittyId()));
+ client.store(wi);
+ }
+ for(String s : adcs.keySet()) {
+ int iadc = (int)(adcs.get(s)*100);
+ adcs.put(s, (double)(iadc/100.0));
+ }
+ return renderJSON("adcs", adcs);
+ }
+
+ /**
+ * Ajax requets to modify the employee values
+ *
+ * @param client chorme client
+ * @param employeeId id of the employee to modify
+ * @param salaryStr new salary in String format
+ * @param productivityRateStr new prod rate in String format
+ * @param partialTimeStr new partial time in String format
+ * @param dailyReturnStr new daily return in String format
+ * @return
+ */
public Render editEmployeeValues(ChoremClient client, String employeeId, String salaryStr
- , String productivityRateStr, String partialTimeStr, String dailyReturnStr) {
+ , String productivityRateStr, String partialTimeStr, String dailyReturnStr, String otherPaymentsStr) {
Wikitty employeeWikitty = client.restore(employeeId);
Employee employee = new EmployeeImpl(employeeWikitty);
- if(!employeeWikitty.hasExtension("EmployeeHR")) {
- employeeWikitty.addExtension(client.restoreExtensionLastVersion("EmployeeHR"));
+ if(!employeeWikitty.hasExtension(EmployeeHR.EXT_EMPLOYEEHR)) {
+ employeeWikitty.addExtension(client.restoreExtensionLastVersion(EmployeeHR.EXT_EMPLOYEEHR));
}
- double salary = 0, productivityRate = 0, partialTime = 0, dailyReturn = 0;
+ double salary = 0, productivityRate = 0, partialTime = 0, dailyReturn = 0, otherPayments = 0;
+
+ //Try to parse the strings and generates if errors if it fails
List<ErrorJson> errors = new ArrayList<ErrorJson>();
try {
salary = Double.parseDouble(salaryStr);
@@ -180,6 +215,14 @@
errors.add(new ErrorJson("dailyReturn", "Daily return must be a real number"));
}
+ try {
+ otherPayments = Double.parseDouble(otherPaymentsStr);
+ }
+ catch (java.lang.NumberFormatException e) {
+ errors.add(new ErrorJson("dailyReturn", "Other payments must be a real number"));
+ }
+
+ //Verify that the percentages are between 0 and 100
if(productivityRate > 100 || productivityRate < 0) {
errors.add(new ErrorJson("productivityRate", "Productivity rate must be between 0 and 100"));
}
@@ -191,10 +234,11 @@
if(salary != 0)
- employeeWikitty.setFqField("EmployeeHR.salary", salary);
- employeeWikitty.setFqField("EmployeeHR.productivityRate", productivityRate);
- employeeWikitty.setFqField("EmployeeHR.partialTime", partialTime);
- employeeWikitty.setFqField("EmployeeHR.dailyReturn", dailyReturn);
+ employeeWikitty.setFqField(EmployeeHR.FQ_FIELD_EMPLOYEEHR_SALARY, salary);
+ employeeWikitty.setFqField(EmployeeHR.FQ_FIELD_EMPLOYEEHR_PRODUCTIVITYRATE, productivityRate);
+ employeeWikitty.setFqField(EmployeeHR.FQ_FIELD_EMPLOYEEHR_PARTIALTIME, partialTime);
+ employeeWikitty.setFqField(EmployeeHR.FQ_FIELD_EMPLOYEEHR_DAILYRETURN, dailyReturn);
+ employeeWikitty.setFqField(EmployeeHR.FQ_FIELD_EMPLOYEEHR_OTHERPAYMENTS, otherPayments);
client.store(employeeWikitty);
@@ -205,12 +249,19 @@
data.getProductivityRate(),
data.getPartialTime(),
data.getDailyReturn(),
- data.getDailyHoursWorked()
+ data.getDailyHoursWorked(),
+ data.getOtherPayments()
);
return renderJSON("data", json);
}
+
+ /**
+ * Class used to store an error
+ * @author gwenn
+ *
+ */
public class ErrorJson {
private String errorMessage;
private String field;
@@ -221,6 +272,13 @@
}
}
+ /**
+ * Structure used to store information about an employee
+ * Used for the AJAX request
+ *
+ * @author gwenn
+ *
+ */
public class EmployeeJson {
private String salary;
@@ -228,18 +286,25 @@
private double partialTime;
private double dailyReturn;
private double dailyHoursWorked;
+ private double otherPayments;
public EmployeeJson(String salary, double productivityRate, double partialTime,
- double dailyReturn, double dailyHoursWorked) {
+ double dailyReturn, double dailyHoursWorked, double otherPayments) {
this.salary = salary;
this.productivityRate = productivityRate;
this.partialTime = partialTime;
this.dailyReturn = dailyReturn;
this.dailyHoursWorked = dailyHoursWorked;
+ this.otherPayments = otherPayments;
}
-
}
-
+
+ /**
+ * Structure used to store information about an employee
+ * used for the standard http request
+ * @author gwenn
+ *
+ */
public class EmployeeData implements Comparable{
private Employee e;
@@ -248,19 +313,22 @@
private double partialTime;
private double dailyReturn;
private double dailyHoursWorked;
+ private double otherPayments;
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");
+ if(w.hasExtension(EmployeeHR.EXT_EMPLOYEEHR)) {
+ this.salary = w.getFieldAsDouble(EmployeeHR.EXT_EMPLOYEEHR, EmployeeHR.FIELD_EMPLOYEEHR_SALARY) + "";
+ this.productivityRate = w.getFieldAsDouble(EmployeeHR.EXT_EMPLOYEEHR, EmployeeHR.FIELD_EMPLOYEEHR_PRODUCTIVITYRATE);
+ this.partialTime = w.getFieldAsDouble(EmployeeHR.EXT_EMPLOYEEHR, EmployeeHR.FIELD_EMPLOYEEHR_PARTIALTIME);
+ this.otherPayments = w.getFieldAsDouble(EmployeeHR.EXT_EMPLOYEEHR, EmployeeHR.FIELD_EMPLOYEEHR_OTHERPAYMENTS);
}
else {
this.salary = "Non renseigné";
this.productivityRate = 100;
this.partialTime = 100;
+ this.otherPayments = 0;
}
this.dailyReturn = client.getDailyReturn(e);
//Simple trick to limit to 2 numbers after digit
@@ -296,6 +364,9 @@
public double getPartialTime() {
return partialTime;
}
+ public double getOtherPayments() {
+ return otherPayments;
+ }
@Override
public int compareTo(Object o) {
Modified: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/DashboardProjectAction.java
===================================================================
--- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/DashboardProjectAction.java 2013-08-07 13:34:26 UTC (rev 380)
+++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/DashboardProjectAction.java 2013-08-07 13:35:46 UTC (rev 381)
@@ -27,6 +27,7 @@
import org.chorem.entities.Time;
import org.chorem.entities.Worker;
import org.chorem.project.QuotationCalculation;
+import org.chorem.project.TotalQuotationCalculation;
import org.nuiton.wikitty.entities.Wikitty;
import org.nuiton.wikitty.query.WikittyQuery;
import org.nuiton.wikitty.query.WikittyQueryMaker;
@@ -100,7 +101,7 @@
if(id != null && !id.equals(""))
projectQueryMaker.ideq(id);
else
- projectQueryMaker.exteq("Project");
+ projectQueryMaker.exteq(Project.EXT_PROJECT);
WikittyQuery projectQuery = projectQueryMaker.end();
projectResult = client.findAllByQuery(Project.class, projectQuery);
@@ -181,13 +182,18 @@
calc.calculate();
calculations.put(q, calc);
}
+
+ TotalQuotationCalculation total = new TotalQuotationCalculation(
+ new ArrayList<QuotationCalculation>(calculations.values()));
+
return renderView("dashboardMultiProject.jsp",
"title", "Tableau de bord projets",
"locale", client.getUserLocale(),
"quotations", quotations,
- "calculations", calculations);
+ "calculations", calculations,
+ "total", total);
}
@@ -210,7 +216,7 @@
if(id != null && !id.equals(""))
employeeQueryMaker.ideq(id);
else {
- employeeQueryMaker.exteq("Employee");
+ employeeQueryMaker.exteq(Employee.EXT_EMPLOYEE);
}
WikittyQueryResult<Employee> employeeResult = client.findAllByQuery(Employee.class,employeeQueryMaker.end());
List<Employee> employeeList = employeeResult.getAll();
@@ -218,7 +224,7 @@
//Fetch all the tasks on the interval
WikittyQueryMaker taskQueryMaker = new WikittyQueryMaker()
.and()
- .exteq("Task");
+ .exteq(Task.EXT_TASK);
if(quotationFilters!=null) {
taskQueryMaker.or();
@@ -315,6 +321,7 @@
percentages.put(e, p);
}
+
//Calculates the average working time
Calendar gFrom = new GregorianCalendar();
@@ -365,4 +372,6 @@
}
}
+
+
}
Modified: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/GanttAction.java
===================================================================
--- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/GanttAction.java 2013-08-07 13:34:26 UTC (rev 380)
+++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/GanttAction.java 2013-08-07 13:35:46 UTC (rev 381)
@@ -15,6 +15,7 @@
import org.chorem.ChoremClient;
import org.chorem.entities.Quotation;
import org.chorem.entities.Task;
+import org.chorem.entities.TaskStatus;
import org.debux.webmotion.server.WebMotionController;
import org.debux.webmotion.server.render.Render;
import org.nuiton.wikitty.entities.Wikitty;
@@ -47,19 +48,19 @@
for(Task t : taskResult.getAll()) {
if(t.getBeginDate() != null && t.getEndDate() != null) {
- if(t.getStatus().equals("SCHEDULED")) {
+ if(t.getStatus().equalsIgnoreCase("scheduled")) {
customClass = "ganttBlue";
}
- else if(t.getStatus().equals("STARTED")) {
+ else if(t.getStatus().equalsIgnoreCase("started")) {
customClass = "ganttGreen";
}
- else if(t.getStatus().equals("FINISHED")) {
+ else if(t.getStatus().equalsIgnoreCase("finished")) {
customClass = "ganttRed";
}
- else if(t.getStatus().equals("CLOSED")) {
+ else if(t.getStatus().equalsIgnoreCase("closed")) {
customClass = "ganttGrey";
}
-
+
Values[] v = null;
if(t.getDayExtension() != 0)
v= new Values[2];
Modified: trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardMultiProject.jsp
===================================================================
--- trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardMultiProject.jsp 2013-08-07 13:34:26 UTC (rev 380)
+++ trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/dashboardMultiProject.jsp 2013-08-07 13:35:46 UTC (rev 381)
@@ -51,17 +51,18 @@
<th>Montant</th>
<th>Nombre de jours estimés</th>
<th><abbr title="Taux journalier moyen">TJM</abbr></th>
+ <th>Gain attendu</th>
<th>Nombre de jours rééls</th>
+ <th><abbr title="Taux journalier moyen">TJM</abbr> reel</th>
<th>Différence estimation/réél</th>
- <th><abbr title="Taux journalier moyen">TJM</abbr> reel</th>
- <th>Gain attendu</th>
<th>Perte/gain</th>
- <th>Average CJM</th>
- <th>Real CJM</th>
+ <th>CJM estimé</th>
+ <th>CJM réel</th>
</tr>
</thead>
+ <tbody>
<c:forEach var="q" items="${quotations}">
- <tbody>
+
<tr>
<td><w:display wikitty="${q.wikitty}" fqfield="Quotation.customer" label=""/></td>
<td><w:display wikitty="${q.wikitty}" fqfield="Quotation.project" label=""/>
@@ -73,16 +74,18 @@
<td class="number"> <f:formatNumber type="number"
maxFractionDigits="2" value="${calculations[q].getAdr()}" /></td>
+
+ <td class="currency"> <f:formatNumber type="currency"
+ maxFractionDigits="2" value="${calculations[q].getExpectedProfit()}" /></td>
<td class="number"> <f:formatNumber type="number"
maxFractionDigits="2" value="${calculations[q].getRealDays()}" /></td>
+
<td class="number"> <f:formatNumber type="number"
+ maxFractionDigits="2" value="${calculations[q].getRealAdr()}" /></td>
+ <td class="number"> <f:formatNumber type="number"
maxFractionDigits="2" value="${calculations[q].getDeltaDays()}" /></td>
- <td class="number"> <f:formatNumber type="number"
- maxFractionDigits="2" value="${calculations[q].getRealAdr()}" /></td>
<td class="currency"> <f:formatNumber type="currency"
- maxFractionDigits="2" value="${calculations[q].getExpectedProfit()}" /></td>
- <td class="currency"> <f:formatNumber type="currency"
maxFractionDigits="2" value="${calculations[q].getLossOrProfit()}" /></td>
<td> <f:formatNumber type="number"
maxFractionDigits="2" value="${calculations[q].getAvgReturn()}" /></td>
@@ -90,8 +93,34 @@
maxFractionDigits="2" value="${calculations[q].getRealReturn()}" /></td>
</tr>
- </tbody>
+
</c:forEach>
+ <tr>
+ <td><b>Total</b></td>
+ <td></td>
+ <td ><f:formatNumber type="number"
+ maxFractionDigits="2" value="${total.getAmount()}" /></td>
+ <td class="number"><f:formatNumber type="number"
+ maxFractionDigits="2" value="${total.getEstimatedDays()}" /></td>
+ <td class="currency"><!--<f:formatNumber type="currency"
+ maxFractionDigits="2" value="${total.getAdr()}" />--></td>
+ <td class="currency"><f:formatNumber type="currency"
+ maxFractionDigits="2" value="${total.getExpectedProfit()}" /></td>
+ <td class="number"><f:formatNumber type="number"
+ maxFractionDigits="2" value="${total.getRealDays()}" /></td>
+ <td class="currency"><!--<f:formatNumber type="currency"
+ maxFractionDigits="2" value="${total.getRealAdr()}" />--></td>
+ <td class="number"><!--<f:formatNumber type="number"
+ maxFractionDigits="2" value="${total.getDeltaDays()}" />--></td>
+ <td class="currency"><f:formatNumber type="currency"
+ maxFractionDigits="2" value="${total.getLossOrProfit()}" /></td>
+ <td class="currency"><!--<f:formatNumber type="currency"
+ maxFractionDigits="2" value="${total.getAvgReturn()}" />--></td>
+ <td class="currency"><!--<f:formatNumber type="currency"
+ maxFractionDigits="2" value="${total.getRealReturn()}" />--></td>
+
+ </tr>
+ </tbody>
</table>
Modified: trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/employeeEdit.jsp
===================================================================
--- trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/employeeEdit.jsp 2013-08-07 13:34:26 UTC (rev 380)
+++ trunk/chorem-webmotion/src/main/webapp/WEB-INF/jsp/employeeEdit.jsp 2013-08-07 13:35:46 UTC (rev 381)
@@ -45,7 +45,7 @@
</form>
<form class="well form-inline" method="POST" id="company">
-<h4>${company.name}</h4>
+<h4><a href="<c:url value="/wikitty/view/${company.wikittyId}"/>">${company.wikitty}</a></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"/>
@@ -81,14 +81,17 @@
<i class="icon-remove icon-white"></i>
Tout annuler
</button>
+
<img class="spinner" style="display:none" src="<c:url value='/img/ajax-loader.gif'/>"/>
+<form style='display:inline;' id='searchForm'>Recherche : <input type="text" id="searchInput"/></form>
<table class="table table-striped table-bordered table-condensed tableEdit">
<thead>
<th>Employé</th>
<th>Salaire</th>
+ <th>Autres rémunérations</th>
<th>Heures par jour</th>
+ <th>Temps de travail</th>
<th>Taux de productivité</th>
- <th>Temps partiel</th>
<th>CJM <a class="allCjmRefresh" style="cursor:pointer">
<i class="icon icon-refresh"></i></a></th>
<th>Edit</th>
@@ -103,12 +106,16 @@
<td class="edit salary">
${employee.salary}
</td>
+ <td class="otherPayments">
+ ${employee.otherPayments}
+ </td>
<td class="dailyHoursWorked"><f:formatNumber type="number"
maxFractionDigits="2" value="${employee.dailyHoursWorked}"/></td>
+ <td class="partialTime"><f:formatNumber type="number"
+ maxFractionDigits="2" value="${employee.partialTime}"/>%</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"
<c:if test='${employee.object.wikitty.hasExtension("EmployeeHR")}'>
refresh="true"
Modified: trunk/chorem-webmotion/src/main/webapp/js/employeeEdit.js
===================================================================
--- trunk/chorem-webmotion/src/main/webapp/js/employeeEdit.js 2013-08-07 13:34:26 UTC (rev 380)
+++ trunk/chorem-webmotion/src/main/webapp/js/employeeEdit.js 2013-08-07 13:35:46 UTC (rev 381)
@@ -12,10 +12,8 @@
$(".employeeEdit").click(employeeEdit);
$(".cjmRefresh").click(calculateAdc);
+ $('.allCjmRefresh').click(calculateMultipleAdc);
- $('.allCjmRefresh').click(function() {
- $('.cjmRefresh').click();
- });
$('#editAllBtn').click(function() {
$('.employeeEdit').click();
@@ -29,16 +27,36 @@
$('.editCancel').click();
});
+ $('#searchForm').submit(function() {
+ $('.tableEdit tbody tr').each(function() {
+
+ var name = $.trim($(this).find('.person').text().toLowerCase());
+ //alert(name + "/" + name.indexOf($('#searchInput').val()));
+ if(name.indexOf($('#searchInput').val().toLowerCase()) !== -1 ) {
+ $(this).show();
+ }
+ else {
+ $(this).hide();
+ }
+
+ });
+
+ return false;
+ });
+
function employeeEdit() {
var row = $(this).parent().parent();
var salary = row.find(".salary");
+ var other = row.find(".otherPayments");
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())+"'/>");
+ other.attr("oldVal", $.trim(other.html()));
+ other.html("<input type = 'text' size='3' value='"+$.trim(other.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()));
@@ -60,11 +78,13 @@
var row = $(this).parent().parent();
var salary = row.find(".salary");
+ var other = row.find(".otherPayments");
var prod = row.find(".productivityRate");
var time = row.find(".partialTime");
var cjm = row.find('.dailyReturn');
salary.html($.trim(salary.attr('oldVal')));
+ other.html($.trim(other.attr('oldVal')));
prod.html($.trim(prod.attr('oldVal')));
time.html($.trim(time.attr('oldVal')));
@@ -86,11 +106,13 @@
var cell = $(this).parent();
var salary = row.find(".salary");
+ var other = row.find(".otherPayments");
var prod = row.find(".productivityRate");
var time = row.find(".partialTime");
var cjm = row.find(".dailyReturn");
var salaryVal = $.trim(salary.find("input").attr('value'));
+ var otherVal = $.trim(other.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'));
@@ -104,7 +126,7 @@
}
$.get(createUrl("/admin/employeeEdit/json/editEmployeeValues/",row.attr("id"), "?salaryStr=",
salaryVal, "&productivityRateStr=", prodVal, "&partialTimeStr=", timeVal,
- "&dailyReturnStr=", cjmVal),
+ "&dailyReturnStr=", cjmVal, "&otherPaymentsStr=", otherVal),
function(ret){
var data = ret['data'];
@@ -127,6 +149,7 @@
else
{
salary.html(data['salary']);
+ other.html(data['otherPayments']);
prod.html(data["productivityRate"]+"%");
time.html(data['partialTime']+"%");
displayDailyReturn(row, data['dailyReturn'], true);
@@ -162,12 +185,39 @@
$.get(createUrl("/admin/employeeEdit/json/requestAdc/",row.attr("id")),
function(ret){
var adc = ret['adc'];
- displayDailyReturn(row, adc);
+ displayDailyReturn(row, adc, true);
displayEdit(row);
});
}
+ function calculateMultipleAdc() {
+
+ var cjmCells = $('.cjmRefresh').parent();
+ var rows = cjmCells.parent();
+ blockDailyReturn(rows);
+ blockEdit(rows);
+ var str = "";
+ for(var i = 0; i < rows.length; i++) {
+ str = str + $(rows[i]).attr('id');
+ if(i != (rows.length -1)) {
+ str= str + ',';
+ }
+
+ }
+ console.log(str);
+ $.get(createUrl("/admin/employeeEdit/json/requestMultipleAdc/",str),
+ function(ret){
+ var adcs = ret['adcs'];
+ for(var i in adcs) {
+ var row = $('#'+i);
+ displayDailyReturn(row, adcs[i], true);
+ displayEdit(row);
+ }
+ });
+
+ }
+
function blockEdit(row) {
row.find('.cellEdit').html('<img src="../img/ajax-loader.gif"/>');
}
1
0
r380 - in trunk/chorem-entities/src/main/java/org/chorem: . project
by meynier@users.chorem.org 07 Aug '13
by meynier@users.chorem.org 07 Aug '13
07 Aug '13
Author: meynier
Date: 2013-08-07 15:34:26 +0200 (Wed, 07 Aug 2013)
New Revision: 380
Url: http://chorem.org/projects/chorem/repository/revisions/380
Log:
Added the total calculation and various other small modifications
Added:
trunk/chorem-entities/src/main/java/org/chorem/project/TotalQuotationCalculation.java
Modified:
trunk/chorem-entities/src/main/java/org/chorem/ChoremClient.java
trunk/chorem-entities/src/main/java/org/chorem/project/AdcCalculation.java
trunk/chorem-entities/src/main/java/org/chorem/project/QuotationCalculation.java
Modified: trunk/chorem-entities/src/main/java/org/chorem/ChoremClient.java
===================================================================
--- trunk/chorem-entities/src/main/java/org/chorem/ChoremClient.java 2013-08-01 14:16:31 UTC (rev 379)
+++ trunk/chorem-entities/src/main/java/org/chorem/ChoremClient.java 2013-08-07 13:34:26 UTC (rev 380)
@@ -32,6 +32,7 @@
import org.chorem.entities.ConfigurationImpl;
import org.chorem.entities.ContactDetails;
import org.chorem.entities.Employee;
+import org.chorem.entities.EmployeeHR;
import org.chorem.entities.Invoice;
import org.chorem.entities.InvoiceMigration;
import org.chorem.entities.Quotation;
@@ -400,12 +401,13 @@
if(e.getCompany(false) != null)
companyW = restore(e.getCompany(false).getWikittyId());
- if(w.hasExtension("EmployeeHR") && w.getFieldAsDouble("EmployeeHR", "dailyReturn") != 0) {
- return w.getFieldAsDouble("EmployeeHR", "dailyReturn");
+ if(w.hasExtension(EmployeeHR.EXT_EMPLOYEEHR) &&
+ w.getFieldAsDouble(EmployeeHR.EXT_EMPLOYEEHR, EmployeeHR.FIELD_EMPLOYEEHR_DAILYRETURN) != 0) {
+ return w.getFieldAsDouble(EmployeeHR.EXT_EMPLOYEEHR, EmployeeHR.FIELD_EMPLOYEEHR_DAILYRETURN);
}
- else if(companyW != null && companyW.hasExtension("CompanyHR")
- && companyW.getFieldAsDouble("CompanyHR", "dailyReturn") != 0) {
- return companyW.getFieldAsDouble("CompanyHR", "dailyReturn");
+ else if(companyW != null && companyW.hasExtension(CompanyHR.EXT_COMPANYHR)
+ && companyW.getFieldAsDouble(CompanyHR.EXT_COMPANYHR, EmployeeHR.FIELD_EMPLOYEEHR_DAILYRETURN) != 0) {
+ return companyW.getFieldAsDouble(CompanyHR.EXT_COMPANYHR, EmployeeHR.FIELD_EMPLOYEEHR_DAILYRETURN);
}
else {
return this.getConfiguration().getDailyReturn();
@@ -423,13 +425,14 @@
if(e.getCompany(false) != null)
companyW = restore(e.getCompany(false).getWikittyId());
- if(companyW.hasExtension("CompanyHR") && companyW.getFieldAsDouble("CompanyHR", "dailyHoursWorked") != 0) {
- if(w.hasExtension("EmployeeHR") && w.getFieldAsDouble("EmployeeHR", "partialTime") != 0) {
- return companyW.getFieldAsDouble("CompanyHR", "dailyHoursWorked") *
- (w.getFieldAsDouble("EmployeeHR", "partialTime")/100);
+ if(companyW.hasExtension(CompanyHR.EXT_COMPANYHR) &&
+ companyW.getFieldAsDouble(CompanyHR.EXT_COMPANYHR,CompanyHR.FIELD_COMPANYHR_DAILYHOURSWORKED) != 0) {
+ if(w.hasExtension(EmployeeHR.EXT_EMPLOYEEHR) && w.getFieldAsDouble(EmployeeHR.EXT_EMPLOYEEHR, EmployeeHR.FIELD_EMPLOYEEHR_PARTIALTIME) != 0) {
+ return companyW.getFieldAsDouble(CompanyHR.EXT_COMPANYHR, CompanyHR.FIELD_COMPANYHR_DAILYHOURSWORKED) *
+ (w.getFieldAsDouble(EmployeeHR.EXT_EMPLOYEEHR, EmployeeHR.FIELD_EMPLOYEEHR_PARTIALTIME)/100);
}
else {
- return companyW.getFieldAsDouble("CompanyHR", "dailyHoursWorked");
+ return companyW.getFieldAsDouble(CompanyHR.EXT_COMPANYHR, CompanyHR.FIELD_COMPANYHR_DAILYHOURSWORKED);
}
}
Modified: trunk/chorem-entities/src/main/java/org/chorem/project/AdcCalculation.java
===================================================================
--- trunk/chorem-entities/src/main/java/org/chorem/project/AdcCalculation.java 2013-08-01 14:16:31 UTC (rev 379)
+++ trunk/chorem-entities/src/main/java/org/chorem/project/AdcCalculation.java 2013-08-07 13:34:26 UTC (rev 380)
@@ -3,12 +3,14 @@
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
+import java.util.HashMap;
import java.util.List;
import org.chorem.ChoremClient;
import org.chorem.ChoremUtil;
import org.chorem.entities.Employee;
import org.chorem.entities.EmployeeHR;
+import org.chorem.entities.FinancialTransaction;
import org.chorem.entities.Interval;
import org.chorem.entities.Quotation;
import org.chorem.entities.Time;
@@ -17,57 +19,57 @@
import org.nuiton.wikitty.query.WikittyQueryMaker;
import org.nuiton.wikitty.query.WikittyQueryResult;
+import com.arjuna.ats.jta.transaction.Transaction;
+
public class AdcCalculation {
- ChoremClient client;
- EmployeeHR e;
- Company company;
- Date start;
- Date end;
/**
* Calculates the total gains made by the company in one year
* @return
*/
- public double getTotalGain() {
+ public static double getTotalExpenses(ChoremClient client, Company company, Date start, Date end) {
- WikittyQuery gainQuery = new WikittyQueryMaker()
+ WikittyQuery expenseQuery = new WikittyQueryMaker()
.and()
- .exteq("Closed")
- .containsOne(Quotation.ELEMENT_FIELD_QUOTATION_SUPPLIER, getEmployeesHR())
+ .exteq(FinancialTransaction.EXT_FINANCIALTRANSACTION)
.or()
- .bw(Interval.FQ_FIELD_INTERVAL_BEGINDATE, start, end)
- .bw(Interval.FQ_FIELD_INTERVAL_ENDDATE, start, end)
+ .containsOne(FinancialTransaction.ELEMENT_FIELD_FINANCIALTRANSACTION_PAYER, getEmployeesHR(client, company))
+ .eq(FinancialTransaction.ELEMENT_FIELD_FINANCIALTRANSACTION_PAYER, company)
+ .close()
+ .bw(FinancialTransaction.ELEMENT_FIELD_FINANCIALTRANSACTION_PAYMENTDATE, start, end)
.end();
- WikittyQueryResult<Quotation> result = client.findAllByQuery(Quotation.class, gainQuery);
+ WikittyQueryResult<FinancialTransaction> result = client.findAllByQuery(FinancialTransaction.class, expenseQuery);
double total = 0;
- for(Quotation q : result.getAll()) {
- total += q.getAmount();
+ for(FinancialTransaction ft : result.getAll()) {
+ total += ft.getAmount();
}
return total;
}
+
+
/**
* calculates all the salaries of the employees ponderated by the productivity rate
* @return
*/
- public double getTotalSalaries() {
+ public static double getTotalSalaries(ChoremClient client, Company company) {
//pondéré par pct de productivité
double total = 0;
- for(EmployeeHR e : getEmployeesHR()) {
+ for(EmployeeHR e : getEmployeesHR(client, company)) {
total += e.getSalary() * (e.getProductivityRate()/100);
}
return total;
}
- private List<EmployeeHR> getEmployeesHR() {
+ private static List<EmployeeHR> getEmployeesHR(ChoremClient client, Company company) {
WikittyQuery employeeQuery = new WikittyQueryMaker().and()
- .exteq("EmployeeHR")
+ .exteq(EmployeeHR.EXT_EMPLOYEEHR)
.eq(Employee.ELEMENT_FIELD_EMPLOYEE_COMPANY, company)
.end();
WikittyQueryResult<EmployeeHR> result = client.findAllByQuery(EmployeeHR.class, employeeQuery);
@@ -76,17 +78,17 @@
}
/**
- * Calculates the sum of all the tims object linked to the company
+ * Calculates the sum of all the times object linked to the company
* @return
*/
- public double getTotalTimes() {
+ public static double getTotalTimes(ChoremClient client, Company company, Date start, Date end) {
WikittyQuery empQuery = new WikittyQueryMaker()
.eq(Employee.ELEMENT_FIELD_EMPLOYEE_COMPANY, company).end();
WikittyQueryResult<Employee> empResult = client.findAllByQuery(Employee.class, empQuery);
WikittyQuery timeQuery = new WikittyQueryMaker()
.and()
- .exteq("Time")
+ .exteq(Time.EXT_TIME)
.containsOne(Time.ELEMENT_FIELD_TIME_EMPLOYEE, empResult.getAll())
.or()
.bw(Interval.FQ_FIELD_INTERVAL_BEGINDATE, start, end)
@@ -102,38 +104,76 @@
return total;
}
- public double getAdc() {
+ /**
+ * Returns the employee's adc
+ * @return
+ */
+ public static double getAdc(ChoremClient client, EmployeeHR e) {
+ Company company = e.getCompany(false);
+ Date end = new GregorianCalendar().getTime();
+ Calendar cstart = new GregorianCalendar();
+ cstart.add(Calendar.YEAR, -1);
+ Date start = cstart.getTime();
- double expenses = getTotalGain();
- double salaries = getTotalSalaries();
- double times = getTotalTimes();
+ double expenses = getTotalExpenses(client, company, start, end);
+ double salaries = getTotalSalaries(client, company);
+ double times = getTotalTimes(client, company, start, end);
double dailyHoursWorked = client.getDailyHoursWorked(e);
- double dailySalary = client.restore(e.getWikittyId()).getFieldAsDouble("EmployeeHR", "salary")/21.5;
- System.out.println("GAIN : " + expenses);
- System.out.println("SALAIRES : " + salaries);
+ double dailySalary = client.restore(e.getWikittyId())
+ .getFieldAsDouble(EmployeeHR.EXT_EMPLOYEEHR,EmployeeHR.FIELD_EMPLOYEEHR_SALARY)/21.5;
+
+ System.out.println("EXPENSES : " + expenses);
+ System.out.println("SALARIES : " + salaries);
System.out.println("TIMES : " + times);
- System.out.println("DAILY HW : " + dailyHoursWorked);
- System.out.println("DAILY SALARY : " + dailySalary);
+ System.out.println("DHW : " + dailyHoursWorked);
+ System.out.println("SALARY : " + dailySalary);
+
+
double adc = ( (expenses/salaries)/times ) * dailyHoursWorked * dailySalary;
+ //dailySalary = dailySalary *1.6; //charges patronales
+ //double adc = dailySalary;
-
return adc;
}
-
- public AdcCalculation(EmployeeHR e, ChoremClient client) {
- this.e = e;
- this.company = e.getCompany(false);
- this.client = client;
- this.end = new GregorianCalendar().getTime();
- Calendar start = new GregorianCalendar();
- start.add(Calendar.YEAR, -1);
- this.start = start.getTime();
+ public static HashMap<String, Double> getMultipleAdc(ChoremClient client, List<EmployeeHR> employees) {
+ if(employees.size() == 0)
+ return null;
+ Company company = employees.get(0).getCompany(false);
+ Date end = new GregorianCalendar().getTime();
+ Calendar cstart = new GregorianCalendar();
+ cstart.add(Calendar.YEAR, -1);
+ Date start = cstart.getTime();
+
+ double expenses = getTotalExpenses(client, company, start, end);
+ double salaries = getTotalSalaries(client, company);
+ double times = getTotalTimes(client, company, start, end);
+
+ HashMap<String, Double> adcs = new HashMap<String, Double>();
+ for(EmployeeHR e : employees) {
+ double dailyHoursWorked = client.getDailyHoursWorked(e);
+ double dailySalary = client.restore(e.getWikittyId())
+ .getFieldAsDouble(EmployeeHR.EXT_EMPLOYEEHR, EmployeeHR.FIELD_EMPLOYEEHR_SALARY)/21.5;
+ System.out.println("EXPENSES : " + expenses);
+ System.out.println("SALAIRES : " + salaries);
+ System.out.println("TIMES : " + times);
+ System.out.println("DAILY HW : " + dailyHoursWorked);
+ System.out.println("DAILY SALARY : " + dailySalary);
+ adcs.put(e.getWikittyId(),( (expenses/salaries)/times ) * dailyHoursWorked * dailySalary);
+ }
+ //dailySalary = dailySalary *1.6; //charges patronales
+ //double adc = dailySalary;
+
+ return adcs;
+
}
+
+
+
}
Modified: trunk/chorem-entities/src/main/java/org/chorem/project/QuotationCalculation.java
===================================================================
--- trunk/chorem-entities/src/main/java/org/chorem/project/QuotationCalculation.java 2013-08-01 14:16:31 UTC (rev 379)
+++ trunk/chorem-entities/src/main/java/org/chorem/project/QuotationCalculation.java 2013-08-07 13:34:26 UTC (rev 380)
@@ -7,7 +7,6 @@
import org.chorem.entities.Employee;
import org.chorem.entities.Quotation;
import org.chorem.entities.Task;
-import java.util.Set;
public class QuotationCalculation extends Calculation<Quotation> {
Added: trunk/chorem-entities/src/main/java/org/chorem/project/TotalQuotationCalculation.java
===================================================================
--- trunk/chorem-entities/src/main/java/org/chorem/project/TotalQuotationCalculation.java (rev 0)
+++ trunk/chorem-entities/src/main/java/org/chorem/project/TotalQuotationCalculation.java 2013-08-07 13:34:26 UTC (rev 380)
@@ -0,0 +1,122 @@
+package org.chorem.project;
+
+import java.util.HashMap;
+import java.util.List;
+
+import org.chorem.ChoremClient;
+import org.chorem.entities.Employee;
+import org.chorem.entities.Quotation;
+import org.chorem.entities.Task;
+
+public class TotalQuotationCalculation extends Calculation<Quotation> {
+
+
+ private List<QuotationCalculation> calculations;
+
+ public TotalQuotationCalculation(List<QuotationCalculation> calculations) {
+ super(null, totalAmount(calculations), totalEstimatedDays(calculations), null);
+ //super(q, q.getAmount(), q.getEstimatedDays(), client);
+ this.calculations = calculations;
+ }
+
+ private static double totalAmount(List<QuotationCalculation> calculations) {
+ double total = 0;
+ for(QuotationCalculation q : calculations) {
+ total += q.getObject().getAmount();
+
+ }
+ return total;
+ }
+
+ private static double totalEstimatedDays(List<QuotationCalculation> calculations) {
+ double total = 0;
+ for(QuotationCalculation q : calculations) {
+ total += q.getObject().getEstimatedDays();
+
+ }
+ return total;
+ }
+
+ public double getAmount() {
+ return amount;
+ }
+
+ public double getEstimatedDays() {
+ return nbDays;
+ }
+
+
+ @Override
+ public double realDays() {
+ double total = 0;
+ for(QuotationCalculation q : calculations) {
+ total += q.getRealDays();
+
+ }
+ return total;
+
+ }
+
+ @Override
+ public double avgReturn() {
+
+ double total = 0;
+ for(QuotationCalculation q : calculations) {
+ total += q.getAvgReturn();
+
+ }
+ return total;
+ }
+
+ @Override
+ public double realReturn() {
+ double total = 0;
+ for(QuotationCalculation q : calculations) {
+ total += q.getRealReturn();
+
+ }
+ return total;
+ }
+
+ @Override
+ public double expectedProfit() {
+ double total = 0;
+ for(QuotationCalculation q : calculations) {
+ total += q.getExpectedProfit();
+
+ }
+ return total;
+ }
+
+ @Override
+ public double lossOrProfit() {
+ double total = 0;
+ for(QuotationCalculation q : calculations) {
+ total += q.getLossOrProfit();
+
+ }
+ return total;
+ }
+
+
+
+
+
+
+ @Override
+ public HashMap<Employee, Double> getPercentages() {
+ return null;
+ }
+
+ @Override
+ public HashMap<Employee, Double> getTimePercentages() {
+ return null;
+ }
+
+
+ @Override
+ public HashMap<Employee, Double> getTimes() {
+ return null;
+ }
+
+}
1
0
Author: meynier
Date: 2013-08-01 16:16:31 +0200 (Thu, 01 Aug 2013)
New Revision: 379
Url: http://chorem.org/projects/chorem/repository/revisions/379
Log:
Added otherPayments in extension EmployeeHR
Modified:
trunk/chorem-entities/src/main/xmi/chorem-model.properties
trunk/chorem-entities/src/main/xmi/chorem-model.zargo
Modified: trunk/chorem-entities/src/main/xmi/chorem-model.properties
===================================================================
--- trunk/chorem-entities/src/main/xmi/chorem-model.properties 2013-07-29 14:51:52 UTC (rev 378)
+++ trunk/chorem-entities/src/main/xmi/chorem-model.properties 2013-08-01 14:16:31 UTC (rev 379)
@@ -104,7 +104,7 @@
#
# EmployeeHR
#
-org.chorem.entities.EmployeeHR.class.tagvalue.version=3.0
+org.chorem.entities.EmployeeHR.class.tagvalue.version=4.0
org.chorem.entities.EmployeeHR.class.tagvalue.toString=%Employee.person$s (%Employee.company$s) HR
org.chorem.entities.EmployeeHR.attribute.type.tagvalue.help=Le type de contrat de travail (CDI, CDD, Stage, ...)
org.chorem.entities.EmployeeHR.attribute.type.tagvalue.choiceQuery=SELECT EmployeeHR.type WHERE extension=EmployeeHR
@@ -117,6 +117,7 @@
org.chorem.entities.EmployeeHR.attribute.productivityRate.tagvalue.help=Taux de productivité
org.chorem.entities.EmployeeHR.attribute.partialTime.tagvalue.help=Taux de travail (temps complet:100, mi-temps:50)
org.chorem.entities.EmployeeHR.attribute.partialTime.tagvalue.default=100
+org.chorem.entities.EmployeeHR.attribute.otherPayments.tagvalue.help=Remuneration autre que salaire (prime, etc.)
#
# Evaluation (a mettre ici)
#
Modified: trunk/chorem-entities/src/main/xmi/chorem-model.zargo
===================================================================
(Binary files differ)
1
0