Author: meynier Date: 2013-07-16 17:41:06 +0200 (Tue, 16 Jul 2013) New Revision: 364 Url: http://chorem.org/projects/chorem/repository/revisions/364 Log: Added avgSrp and realSrp calculations (which also needs the new methods getTimes and getPercentages) and enhanced some calculations Added: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/Calculation.java trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/TaskCalculation.java Modified: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/QuotationCalculation.java Added: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/Calculation.java =================================================================== --- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/Calculation.java (rev 0) +++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/Calculation.java 2013-07-16 15:41:06 UTC (rev 364) @@ -0,0 +1,268 @@ +package org.chorem.webmotion.actions.project; + +import java.util.HashMap; +import java.util.Set; + +import org.chorem.ChoremClient; +import org.chorem.entities.Employee; + +/** + * Unit to calculate various elements for a Quotation or a Task. + * May be extended for other extensions (Project, for example), but it's not the original purpose. + * @author gwenn + * + * @param <T> Type of element (Task or Quotation) + */ +public abstract class Calculation<T> { + + /**Main object (Task or Quotation)*/ + protected T e; + /** Chorme client */ + protected ChoremClient client; + /** Total price of the object */ + protected double amount; + /** Estimated number of days */ + protected double nbDays; + + protected static final int SEC_PER_HOUR = 3600; + protected static final int WORKING_HOURS_PER_DAY = 7; + /* Seuil de rentabilite productif */ + + //attributes to store the calculations + private Double adr = null; + private Double realDays = null; + private Double deltaDays = null; + private Double realAdr = null; + private Double expectedProfit = null; + private Double lossOrProfit = null; + private Double resultPerDay = null; + private Double avgSrp = null; + private Double realSrp = null; + + + /** + * + * @param e Element that will serve for the calculations + * @param amount Amount of this element + * @param nbDays Estimated number of days for this element + * @param client Instance of ChoremClient + */ + public Calculation(T e, double amount, double nbDays, ChoremClient client) { + this.e = e; + this.client = client; + this.amount = amount; + this.nbDays = nbDays; + } + + /** + * Makes all the calcuations and store them into the attributes + */ + public void calculate() { + + this.adr = adr(); + this.realDays = realDays(); + this.deltaDays = deltaDays(); + this.realAdr = realAdr(); + this.expectedProfit = expectedProfit(); + this.lossOrProfit = lossOrProfit(); + this.resultPerDay = resultPerDay(); + this.avgSrp = avgSrp(); + this.realSrp = realSrp(); + } + + /** + * Calculates the real number of days from the Time objects. + * @return + */ + public abstract double realDays(); + + + /** + * Return the percentages for the current object + * @return + */ + protected abstract HashMap<Employee, Double> getTimes(); + + /** + * Return the percentages for the current object + * @return + */ + protected abstract HashMap<Employee, Double> getPercentages(); + + public HashMap<Employee, Double> getTimePercentages() { + HashMap<Employee, Double> times = getTimes(); + HashMap<Employee, Double> timePercentages = new HashMap<Employee, Double>(); + double sum = 0; + Set<Employee> keySet = times.keySet(); + for (Employee key : keySet) { + sum+= times.get(key); + } + for (Employee key : keySet) { + timePercentages.put(key, (times.get(key)/sum)*100); + } + + + return timePercentages; + } + /** + * Return the average Srp for all the employees, ponderated by the percentages + * @return + */ + public double avgSrp() { + + //Fetch the percentages per employee + HashMap<Employee, Double> percentages = getPercentages(); + if(percentages.size() == 0) { + return client.getConfiguration().getDailyReturn(); + } + Set<Employee> keySet = percentages.keySet(); + double avgSrp = 0; + for(Employee key : keySet) { + avgSrp += client.getDailyReturn(key)*(percentages.get(key)/100); + } + + return avgSrp; + } + + /** + * Calculates the real daily return from the different times object and the daily return of the employees. + * @return + */ + public double realSrp() { + HashMap<Employee, Double> times = getTimes(); + if(times.size() == 0) { + return client.getConfiguration().getDailyReturn(); + } + double realSrp = 0; + Set<Employee> keySet = times.keySet(); + for(Employee key : keySet) { + double srp = client.getDailyReturn(key); + double hoursPerDay = client.getConfiguration().getDailyHoursWorked(); + + //TODO :Find a way to use the different work hours + + //} + realSrp += srp* ( times.get(key) / hoursPerDay ) ; + } + realSrp = realSrp/getRealDays(); + + return realSrp; + } + + /** + * Returns the average daily rate, which is the amount divided by the estimated number of days. + * @return the ADR + */ + public double adr() { + return amount/nbDays; + } + + + + /** + * Gives the difference between the real number of days and the estimated value + * @return + */ + public double deltaDays() { + return getRealDays() - nbDays; + } + + /** + * Calculates the real ADR from the real number of days. + * @return + */ + public double realAdr() { + double realDays = getRealDays(); + + return amount/realDays; + } + + /** + * Profit calculated from the estimated ADR and the estimated numer of days + * @return + */ + public double expectedProfit() { + return amount - (nbDays*getAvgSrp()); + } + + /** + * Real profit (or loss) done when the quotation is closed. + * @return + */ + public double lossOrProfit() { + return amount - (getRealDays() * getRealSrp()); + } + + /** + * Average profit/loss per day + * @return + */ + public double resultPerDay() { + return getLossOrProfit() / getRealDays(); + } + + + + /* ########################################################################################## + * ######################### GETTERS ####################################################### + * ########################################################################################## + * + * The getters returns the attributes if it has been calculated and calculates directly the value otherwise + */ + + public double getAdr() { + if(adr == null) + return adr(); + else + return adr; + } + public double getRealDays() { + if(realDays == null) + return realDays(); + else + return realDays; + } + public double getDeltaDays() { + if(deltaDays == null) + return deltaDays; + else + return deltaDays; + } + public double getRealAdr() { + if(realAdr == null) + return realAdr(); + else + return realAdr; + } + public double getExpectedProfit() { + if(expectedProfit == null) + return expectedProfit(); + else + return expectedProfit; + } + public double getLossOrProfit() { + if(lossOrProfit == null) + return lossOrProfit(); + else + return lossOrProfit; + } + public double getResultPerDay() { + if(resultPerDay == null) + return resultPerDay(); + else + return resultPerDay; + } + + public double getAvgSrp() { + if(avgSrp == null) + return avgSrp(); + else + return avgSrp; + } + public double getRealSrp() { + if(realSrp == null) + return realSrp(); + else + return realSrp; + } +} Modified: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/QuotationCalculation.java =================================================================== --- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/QuotationCalculation.java 2013-07-16 15:13:01 UTC (rev 363) +++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/QuotationCalculation.java 2013-07-16 15:41:06 UTC (rev 364) @@ -1,65 +1,79 @@ package org.chorem.webmotion.actions.project; -import java.util.ArrayList; -import java.util.Collection; +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; -import org.chorem.entities.Time; -import org.nuiton.wikitty.query.WikittyQuery; -import org.nuiton.wikitty.query.WikittyQueryMaker; -import org.nuiton.wikitty.query.WikittyQueryResult; +import java.util.Set; public class QuotationCalculation extends Calculation<Quotation> { public QuotationCalculation(Quotation q, ChoremClient client) { super(q, q.getAmount(), q.getEstimatedDays(), client); } - + @Override public double realDays() { - //test if quotation is finished - if(e.getExtensionNames().contains("Closed")) { - //Calculate the days from the times objects - WikittyQuery taskQuery = new WikittyQueryMaker() - .eq(Task.ELEMENT_FIELD_TASK_QUOTATION, e) - .end(); - - WikittyQueryResult<Task> result = - client.findAllByQuery(Task.class, taskQuery); - Collection<Time> times = new ArrayList<Time>(); - for(Task t : result.getAll()) { - WikittyQuery timeQuery = new WikittyQueryMaker() - .eq(Time.ELEMENT_FIELD_TIME_TASK, t) - .end(); - WikittyQueryResult<Time> timeResult = client.findAllByQuery(Time.class, timeQuery); - times.addAll(timeResult.getAll()); + double totalTime = 0; + //For each task + for(Task t : client.getTasks(e)) { + //Sum the real days of the tasks objects + totalTime+=new TaskCalculation(t, client).getRealDays(); + } + return totalTime; + + } + + @Override + public HashMap<Employee, Double> getPercentages() { + HashMap<Employee, Double> percentages = new HashMap<Employee, Double>(); + List<Task> tasks = client.getTasks(e); + for(Task t : tasks) { + + HashMap<Employee, Double> taskPercentages = new TaskCalculation(t, client).getPercentages(); + for(Employee emp : taskPercentages.keySet()) { + if(percentages.containsKey(emp)) { + //We temporaly put the sum in the map. + percentages.put(emp, percentages.get(emp) + taskPercentages.get(emp)); + } + else { + percentages.put(emp, taskPercentages.get(emp)); + } + } - double totalTime = 0; - for(Time t : times) { - System.out.println("HEURE TRAVAILLEES : " - + (getPeriodInSeconds(t.getBeginDate(), t.getEndDate())/SEC_PER_HOUR) ); - totalTime += getPeriodInSeconds(t.getBeginDate(), t.getEndDate()); - } - return (totalTime / SEC_PER_HOUR) / WORKING_HOURS_PER_DAY; } - else { - //nbDays + day extensions from tasks - WikittyQuery taskQuery = new WikittyQueryMaker() - .eq(Task.ELEMENT_FIELD_TASK_QUOTATION, e) - .end(); - - WikittyQueryResult<Task> result = - client.findAllByQuery(Task.class, taskQuery); - - double totalDayExt = 0; - for(Task t : result.getAll()) { - totalDayExt += t.getDayExtension(); + + //Caluculate the average for each employee + Set<Employee> keySet = percentages.keySet(); + for(Employee emp : keySet) { + percentages.put(emp, percentages.get(emp)/tasks.size()); + } + return percentages; + } + + + @Override + public HashMap<Employee, Double> getTimes() { + HashMap<Employee, Double> times = new HashMap<Employee, Double>(); + + for(Task t : client.getTasks(e)) { + + HashMap<Employee, Double> taskPercentages = new TaskCalculation(t, client).getTimes(); + for(Employee emp : taskPercentages.keySet()) { + if(times.containsKey(emp)) { + times.put(emp, times.get(emp) + taskPercentages.get(emp)); + } + else { + times.put(emp, taskPercentages.get(emp)); + } + } - return nbDays + totalDayExt; - + } + + return times; } - } Added: trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/TaskCalculation.java =================================================================== --- trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/TaskCalculation.java (rev 0) +++ trunk/chorem-webmotion/src/main/java/org/chorem/webmotion/actions/project/TaskCalculation.java 2013-07-16 15:41:06 UTC (rev 364) @@ -0,0 +1,99 @@ +package org.chorem.webmotion.actions.project; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; + +import org.chorem.ChoremClient; +import org.chorem.ChoremUtil; +import org.chorem.entities.Employee; +import org.chorem.entities.Task; +import org.chorem.entities.Time; +import org.chorem.entities.Worker; +import org.nuiton.wikitty.query.WikittyQuery; +import org.nuiton.wikitty.query.WikittyQueryMaker; +import org.nuiton.wikitty.query.WikittyQueryResult; + +public class TaskCalculation extends Calculation<Task> { + public TaskCalculation(Task t, ChoremClient client) { + super(t, t.getPrice(), t.getEstimatedDays(), client); + } + + @Override + public double realDays() { + //test if task is finished + if(e.getStatus().equalsIgnoreCase("Closed")) { + //Calculate the days from the times objects + Collection<Time> times = new ArrayList<Time>(); + + //Fetch the time objects linked to this task + WikittyQuery timeQuery = new WikittyQueryMaker() + .eq(Time.ELEMENT_FIELD_TIME_TASK, e) + .end(); + WikittyQueryResult<Time> timeResult = client.findAllByQuery(Time.class, timeQuery); + times.addAll(timeResult.getAll()); + + double totalTime = 0; + //For each time object + for(Time t : times) { + //Get the number of hours worked + Double hours = ChoremUtil.getPeriodInHours(t.getBeginDate(), t.getEndDate()); + + Double days = hours / client.getDailyHoursWorked(t.getEmployee(false)); + + totalTime += days; + } + return totalTime; + } + else { + //estimated days + day extension + return nbDays + e.getDayExtension(); + + } + } + + @Override + protected HashMap<Employee, Double> getPercentages() { + HashMap<Employee, Double> pct = new HashMap<Employee, Double>(); + //get all the Worker objects + WikittyQuery workerQuery = new WikittyQueryMaker() + .eq(Worker.ELEMENT_FIELD_WORKER_TASK, e) + .end(); + WikittyQueryResult<Worker> workerResult = client.findAllByQuery(Worker.class, workerQuery); + + //For each worker, get the percentages assigned on the task + for(Worker w : workerResult.getAll()) { + if(w.getEmployee() != null) { + pct.put(w.getEmployee(false), (double)w.getPercentage()); + } + } + + return pct; + } + + @Override + protected HashMap<Employee, Double> getTimes() { + HashMap<Employee, Double> times = new HashMap<Employee, Double>(); + + //Feth the time objects from the task + WikittyQuery timeQuery = new WikittyQueryMaker() + .eq(Time.ELEMENT_FIELD_TIME_TASK, e) + .end(); + WikittyQueryResult<Time> timeResult = client.findAllByQuery(Time.class, timeQuery); + + for(Time t : timeResult.getAll()) { + Employee emp = t.getEmployee(false); + if(emp != null) { + if(times.containsKey(emp)) { + times.put(emp, times.get(emp) + (ChoremUtil.getPeriodInHours(t.getBeginDate(), t.getEndDate())) ); + } + else { + times.put(emp,ChoremUtil.getPeriodInHours(t.getBeginDate(), t.getEndDate())); + } + } + + } + + return times; + } +}