import { Task, TaskCategory, TaskID, getTaskWeightedMean, TaskCategoryID, getTaskStandardDeviation } from './task'; import { Params, defaults, getTaskCategoryCost } from "./params"; import { Estimation } from '../hooks/useProjectEstimations'; export type ProjectID = string; export interface Project { id: ProjectID label: string description: string tasks: Tasks params: Params } export interface Tasks { [id: string]: Task } export function newProject(): Project { return { id: "", label: "", description: "", tasks: {}, params: { ...defaults }, }; } export function getProjectWeightedMean(p : Project): number { return Object.values(p.tasks).reduce((sum: number, t: Task) => { sum += getTaskWeightedMean(t); return sum; }, 0); } export function getTaskCategoryWeightedMean(taskCategoryId: TaskCategoryID, p : Project): number { return Object.values(p.tasks).filter(t => t.category === taskCategoryId).reduce((sum: number, t: Task) => { sum += getTaskWeightedMean(t); return sum; }, 0); } export function getProjectStandardDeviation(p : Project): number { return Math.sqrt(Object.values(p.tasks).reduce((sum: number, t: Task) => { sum += Math.pow(getTaskStandardDeviation(t), 2); return sum; }, 0)); } export interface MeanRepartition { [id: string]: number } export function getTaskCategoriesMeanRepartition(project: Project): MeanRepartition { let projectMean = getProjectWeightedMean(project); const repartition: MeanRepartition = {}; Object.values(project.params.taskCategories).forEach(tc => { repartition[tc.id] = getTaskCategoryWeightedMean(tc.id, project) / projectMean; if (Number.isNaN(repartition[tc.id])) repartition[tc.id] = 0; }); return repartition; } export interface MinMaxCost { max: Cost min: Cost } export interface Cost { totalCost: number totalTime: number details: { [taskCategoryId: string]: { time: number, cost: number } } } export function getMinMaxCosts(project: Project, estimation: Estimation): MinMaxCost { const max: Cost = {totalCost: 0, totalTime: 0, details: {}}; const min: Cost = {totalCost: 0, totalTime: 0, details: {}}; const repartition = getTaskCategoriesMeanRepartition(project); Object.values(project.params.taskCategories).forEach(tc => { const cost = getTaskCategoryCost(tc); const maxTime = Math.round((estimation.e + estimation.sd) * repartition[tc.id]); max.details[tc.id] = { time: maxTime, cost: Math.ceil(maxTime) * cost, }; max.totalTime += max.details[tc.id].time; max.totalCost += max.details[tc.id].cost; const minTime = Math.round((estimation.e - estimation.sd) * repartition[tc.id]); min.details[tc.id] = { time: minTime, cost: Math.ceil(minTime) * cost, }; min.totalTime += min.details[tc.id].time; min.totalCost += min.details[tc.id].cost; }); return { max, min }; }