|
|
|
@ -12,26 +12,42 @@ import {
|
|
|
|
|
import Big from "big.js";
|
|
|
|
|
import Markdown from "./Markdown";
|
|
|
|
|
|
|
|
|
|
export const calculateAgileQuantity = (
|
|
|
|
|
hoursPerStoryPoint = 0,
|
|
|
|
|
riskFactor = 0,
|
|
|
|
|
minPoints = 0,
|
|
|
|
|
maxPoints = 0
|
|
|
|
|
) => {
|
|
|
|
|
if (minPoints > maxPoints) {
|
|
|
|
|
maxPoints = minPoints;
|
|
|
|
|
}
|
|
|
|
|
const minHours = minPoints * hoursPerStoryPoint;
|
|
|
|
|
const maxHours = maxPoints * hoursPerStoryPoint;
|
|
|
|
|
|
|
|
|
|
const minWeighted = new Big(-1).plus(riskFactor).abs().mul(minHours);
|
|
|
|
|
const maxWeighted = new Big(riskFactor).mul(maxHours);
|
|
|
|
|
|
|
|
|
|
const quantity = minWeighted.plus(maxWeighted).round().toNumber();
|
|
|
|
|
|
|
|
|
|
return quantity;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const getQuantity = (position: Position, state: StoreObject) => {
|
|
|
|
|
let quantity = position.quantity;
|
|
|
|
|
|
|
|
|
|
if (position.type === POSITION_TYPE_AGILE) {
|
|
|
|
|
const min = position.agilePointsMin || 0;
|
|
|
|
|
let max = position.agilePointsMax || 0;
|
|
|
|
|
if (min > max) {
|
|
|
|
|
max = min;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const minHours = min * state.agileHoursPerStoryPoint;
|
|
|
|
|
const maxHours = max * state.agileHoursPerStoryPoint;
|
|
|
|
|
const agileRiskFactor =
|
|
|
|
|
position.agileRiskFactor != null
|
|
|
|
|
? position.agileRiskFactor
|
|
|
|
|
: state.agileRiskFactor;
|
|
|
|
|
const normalizedRiskFactor = new Big(agileRiskFactor).mul(2).minus(1);
|
|
|
|
|
const minWeighted = new Big(1).minus(normalizedRiskFactor).mul(minHours);
|
|
|
|
|
const maxWeighted = new Big(1).plus(normalizedRiskFactor).mul(maxHours);
|
|
|
|
|
quantity = minWeighted.plus(maxWeighted).div(2).round().toNumber();
|
|
|
|
|
quantity = calculateAgileQuantity(
|
|
|
|
|
state.agileHoursPerStoryPoint,
|
|
|
|
|
agileRiskFactor,
|
|
|
|
|
min,
|
|
|
|
|
max
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return quantity;
|
|
|
|
|