Fix repartition rounding
This commit is contained in:
parent
9dd9167267
commit
40759f59d6
|
@ -11,13 +11,18 @@ export interface EstimationRangeProps {
|
||||||
|
|
||||||
export const EstimationRange: FunctionalComponent<EstimationRangeProps> = ({ project, estimation }) => {
|
export const EstimationRange: FunctionalComponent<EstimationRangeProps> = ({ project, estimation }) => {
|
||||||
const roundUp = getRoundUpEstimations(project);
|
const roundUp = getRoundUpEstimations(project);
|
||||||
let e: number|string = roundUp ? Math.ceil(estimation.e) : estimation.e;
|
let e: number|string = estimation.e;
|
||||||
let sd: number|string = roundUp ? Math.ceil(estimation.sd) : estimation.sd;
|
let sd: number|string = estimation.sd;
|
||||||
const max = e+sd;
|
let max = e+sd;
|
||||||
const min = Math.max(e-sd, 0);
|
let min = Math.max(e-sd, 0);
|
||||||
if (!roundUp) {
|
if (roundUp) {
|
||||||
sd = sd.toFixed(2);
|
sd = Math.ceil(sd);
|
||||||
e = e.toFixed(2);
|
e = Math.ceil(e);
|
||||||
|
max = Math.ceil(max);
|
||||||
|
min = Math.ceil(min);
|
||||||
|
} else {
|
||||||
|
sd = sd.toFixed(2);
|
||||||
|
e = e.toFixed(2);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { FunctionalComponent, h } from "preact";
|
import { FunctionalComponent, h } from "preact";
|
||||||
import { Project } from "../../models/project";
|
import { Project } from "../../models/project";
|
||||||
import { useProjectEstimations } from "../../hooks/use-project-estimations";
|
import { useProjectEstimations } from "../../hooks/use-project-estimations";
|
||||||
import { getCurrency, defaults, getTaskCategoryCost } from "../../models/params";
|
import { getCurrency, defaults, getTaskCategoryCost, getRoundUpEstimations } from "../../models/params";
|
||||||
import { getMinMaxCosts, Cost } from "../../util/stat";
|
import { getMinMaxCosts, Cost } from "../../util/stat";
|
||||||
import * as style from './style.module.css';
|
import * as style from './style.module.css';
|
||||||
import ProjectTimeUnit from "../../components/project-time-unit";
|
import ProjectTimeUnit from "../../components/project-time-unit";
|
||||||
|
@ -13,7 +13,7 @@ export interface FinancialPreviewProps {
|
||||||
const FinancialPreview: FunctionalComponent<FinancialPreviewProps> = ({ project }) => {
|
const FinancialPreview: FunctionalComponent<FinancialPreviewProps> = ({ project }) => {
|
||||||
const estimations = useProjectEstimations(project);
|
const estimations = useProjectEstimations(project);
|
||||||
const costs = getMinMaxCosts(project, estimations.p99);
|
const costs = getMinMaxCosts(project, estimations.p99);
|
||||||
|
const roundUp = getRoundUpEstimations(project);
|
||||||
return (
|
return (
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
<table class="table is-bordered is-striped is-fullwidth">
|
<table class="table is-bordered is-striped is-fullwidth">
|
||||||
|
@ -33,13 +33,13 @@ const FinancialPreview: FunctionalComponent<FinancialPreviewProps> = ({ project
|
||||||
<tr>
|
<tr>
|
||||||
<td class="is-narrow">Maximum</td>
|
<td class="is-narrow">Maximum</td>
|
||||||
<td>
|
<td>
|
||||||
<CostDetails project={project} cost={costs.max} />
|
<CostDetails project={project} cost={costs.max} roundUp={roundUp} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="is-narrow">Minimum</td>
|
<td class="is-narrow">Minimum</td>
|
||||||
<td>
|
<td>
|
||||||
<CostDetails project={project} cost={costs.min} />
|
<CostDetails project={project} cost={costs.min} roundUp={roundUp} />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -51,14 +51,15 @@ const FinancialPreview: FunctionalComponent<FinancialPreviewProps> = ({ project
|
||||||
export interface CostDetailsProps {
|
export interface CostDetailsProps {
|
||||||
project: Project
|
project: Project
|
||||||
cost: Cost
|
cost: Cost
|
||||||
|
roundUp: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CostDetails:FunctionalComponent<CostDetailsProps> = ({ project, cost }) => {
|
export const CostDetails:FunctionalComponent<CostDetailsProps> = ({ project, cost, roundUp }) => {
|
||||||
return (
|
return (
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>
|
<summary><strong>
|
||||||
≈ {cost.totalCost} {getCurrency(project)}</strong>
|
≈ {cost.totalCost} {getCurrency(project)}</strong>
|
||||||
<span class="is-pulled-right">{cost.totalTime} <ProjectTimeUnit project={project} /></span>
|
<span class="is-pulled-right">{ roundUp ? Math.ceil(cost.totalTime) : cost.totalTime.toFixed(2) } <ProjectTimeUnit project={project} /></span>
|
||||||
</summary>
|
</summary>
|
||||||
<table class={`table is-fullwidth`}>
|
<table class={`table is-fullwidth`}>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
@ -70,7 +71,7 @@ export const CostDetails:FunctionalComponent<CostDetailsProps> = ({ project, cos
|
||||||
<tr key={`task-category-cost-${taskCategory.id}`}>
|
<tr key={`task-category-cost-${taskCategory.id}`}>
|
||||||
<td class={`${style.noBorder} is-size-6`}>{taskCategory.label}</td>
|
<td class={`${style.noBorder} is-size-6`}>{taskCategory.label}</td>
|
||||||
<td class={`${style.noBorder} is-size-6`}>{details.cost} {getCurrency(project)}</td>
|
<td class={`${style.noBorder} is-size-6`}>{details.cost} {getCurrency(project)}</td>
|
||||||
<td class={`${style.noBorder} is-size-6`}>{details.time} <ProjectTimeUnit project={project} /> × {getTaskCategoryCost(taskCategory)} {getCurrency(project)}</td>
|
<td class={`${style.noBorder} is-size-6`}>{ roundUp ? Math.ceil(details.time) : details.time.toFixed(2) } <ProjectTimeUnit project={project} /> × {getTaskCategoryCost(taskCategory)} {getCurrency(project)}</td>
|
||||||
</tr>
|
</tr>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -39,11 +39,14 @@ export interface MeanRepartition {
|
||||||
|
|
||||||
export function getTaskCategoriesMeanRepartition(project: Project): MeanRepartition {
|
export function getTaskCategoriesMeanRepartition(project: Project): MeanRepartition {
|
||||||
let projectMean = getProjectWeightedMean(project);
|
let projectMean = getProjectWeightedMean(project);
|
||||||
|
|
||||||
const repartition: MeanRepartition = {};
|
const repartition: MeanRepartition = {};
|
||||||
|
|
||||||
Object.values(project.params.taskCategories).forEach(tc => {
|
Object.values(project.params.taskCategories).forEach(tc => {
|
||||||
repartition[tc.id] = getTaskCategoryWeightedMean(tc.id, project) / projectMean;
|
repartition[tc.id] = getTaskCategoryWeightedMean(tc.id, project) / projectMean;
|
||||||
if (Number.isNaN(repartition[tc.id])) repartition[tc.id] = 0;
|
if (Number.isNaN(repartition[tc.id])) repartition[tc.id] = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
return repartition;
|
return repartition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,18 +70,18 @@ export function getMinMaxCosts(project: Project, estimation: Estimation): MinMax
|
||||||
Object.values(project.params.taskCategories).forEach(tc => {
|
Object.values(project.params.taskCategories).forEach(tc => {
|
||||||
const cost = getTaskCategoryCost(tc);
|
const cost = getTaskCategoryCost(tc);
|
||||||
|
|
||||||
const maxTime = Math.ceil((estimation.e + estimation.sd) * repartition[tc.id]);
|
const maxTime = Math.round((estimation.e + estimation.sd) * repartition[tc.id]);
|
||||||
max.details[tc.id] = {
|
max.details[tc.id] = {
|
||||||
time: maxTime,
|
time: maxTime,
|
||||||
cost: maxTime * cost,
|
cost: Math.ceil(maxTime) * cost,
|
||||||
};
|
};
|
||||||
max.totalTime += max.details[tc.id].time;
|
max.totalTime += max.details[tc.id].time;
|
||||||
max.totalCost += max.details[tc.id].cost;
|
max.totalCost += max.details[tc.id].cost;
|
||||||
|
|
||||||
const minTime = Math.ceil((estimation.e - estimation.sd) * repartition[tc.id]);
|
const minTime = Math.round((estimation.e - estimation.sd) * repartition[tc.id]);
|
||||||
min.details[tc.id] = {
|
min.details[tc.id] = {
|
||||||
time: minTime,
|
time: minTime,
|
||||||
cost: minTime * cost,
|
cost: Math.ceil(minTime) * cost,
|
||||||
};
|
};
|
||||||
min.totalTime += min.details[tc.id].time;
|
min.totalTime += min.details[tc.id].time;
|
||||||
min.totalCost += min.details[tc.id].cost;
|
min.totalCost += min.details[tc.id].cost;
|
||||||
|
|
Loading…
Reference in New Issue