feat: implement variant1 (1 fr+so + 3 weekday, fr-priority)
This commit is contained in:
parent
a675763206
commit
591a2773cc
2 changed files with 115 additions and 1 deletions
|
|
@ -671,6 +671,69 @@ runner.test('variant3: threshold-Shape ist {pool: 2} normal, {pool: 1} im Urlaub
|
||||||
t.assertEqual(r2.threshold.pool, 1, 'vacation pool=1');
|
t.assertEqual(r2.threshold.pool, 1, 'vacation pool=1');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Variants - variant1 (1 fr+so + 3 weekday)
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
runner.test('variant1: Schwelle nicht erreicht (fr+so=0)', (t) => {
|
||||||
|
const r = variant1({ fr: 0, sa: 5, so: 0, weekday: 3 }, false);
|
||||||
|
t.assertFalse(r.eligible, 'eligible=false');
|
||||||
|
t.assertEqual(r.bonus, 0, 'bonus=0');
|
||||||
|
});
|
||||||
|
|
||||||
|
runner.test('variant1: Schwelle nicht erreicht (weekday<3)', (t) => {
|
||||||
|
const r = variant1({ fr: 1, sa: 5, so: 0, weekday: 2 }, false);
|
||||||
|
t.assertFalse(r.eligible, 'eligible=false');
|
||||||
|
t.assertEqual(r.bonus, 0, 'bonus=0');
|
||||||
|
});
|
||||||
|
|
||||||
|
runner.test('variant1: Spec-Beispiel fr=2,sa=1,so=0,weekday=4 -> 1150', (t) => {
|
||||||
|
const r = variant1({ fr: 2, sa: 1, so: 0, weekday: 4 }, false);
|
||||||
|
t.assertTrue(r.eligible, 'eligible=true');
|
||||||
|
t.assertEqual(r.deduction.fr, 1, 'fr-deduction=1 (Fr-Prio)');
|
||||||
|
t.assertEqual(r.deduction.so, 0, 'so-deduction=0');
|
||||||
|
t.assertEqual(r.deduction.sa, 0, 'sa nicht abgezogen');
|
||||||
|
t.assertEqual(r.deduction.weekday, 3, 'weekday-deduction=3');
|
||||||
|
t.assertEqual(r.paidShares.fr, 1, 'fr-paid=1');
|
||||||
|
t.assertEqual(r.paidShares.sa, 1, 'sa-paid=1');
|
||||||
|
t.assertEqual(r.paidShares.so, 0, 'so-paid=0');
|
||||||
|
t.assertEqual(r.paidShares.weekday, 1, 'weekday-paid=1');
|
||||||
|
t.assertEqual(r.bonus, 1150, 'bonus = (1+1+0)*450 + 1*250 = 1150');
|
||||||
|
});
|
||||||
|
|
||||||
|
runner.test('variant1: nur so vorhanden -> 1 von so abgezogen', (t) => {
|
||||||
|
const r = variant1({ fr: 0, sa: 0, so: 1, weekday: 3 }, false);
|
||||||
|
t.assertTrue(r.eligible, 'eligible=true');
|
||||||
|
t.assertEqual(r.deduction.fr, 0, 'fr-deduction=0');
|
||||||
|
t.assertEqual(r.deduction.so, 1, 'so-deduction=1');
|
||||||
|
t.assertEqual(r.deduction.weekday, 3, 'weekday-deduction=3');
|
||||||
|
t.assertEqual(r.bonus, 0, 'bonus=0');
|
||||||
|
});
|
||||||
|
|
||||||
|
runner.test('variant1: sa wird voll bezahlt, nicht abgezogen', (t) => {
|
||||||
|
const r = variant1({ fr: 1, sa: 2, so: 0, weekday: 3 }, false);
|
||||||
|
t.assertEqual(r.deduction.sa, 0, 'sa-deduction=0');
|
||||||
|
t.assertEqual(r.paidShares.sa, 2, 'sa-paid=2');
|
||||||
|
// bonus = (0+2+0)*450 + 0*250 = 900
|
||||||
|
t.assertEqual(r.bonus, 900, 'bonus=900');
|
||||||
|
});
|
||||||
|
|
||||||
|
runner.test('variant1: Urlaubsmodus halbiert Schwellen (0.5 + 1.5)', (t) => {
|
||||||
|
const r = variant1({ fr: 0.5, sa: 0, so: 0, weekday: 1.5 }, true);
|
||||||
|
t.assertTrue(r.eligible, 'eligible=true im Urlaub');
|
||||||
|
t.assertEqual(r.threshold.frSo, 0.5, 'threshold.frSo=0.5');
|
||||||
|
t.assertEqual(r.threshold.weekday, 1.5, 'threshold.weekday=1.5');
|
||||||
|
t.assertEqual(r.deduction.fr, 0.5, 'fr-deduction=0.5');
|
||||||
|
t.assertEqual(r.deduction.weekday, 1.5, 'weekday-deduction=1.5');
|
||||||
|
t.assertEqual(r.bonus, 0, 'bonus=0');
|
||||||
|
});
|
||||||
|
|
||||||
|
runner.test('variant1: threshold-Shape normal {frSo:1, weekday:3}', (t) => {
|
||||||
|
const r = variant1({ fr: 1, sa: 0, so: 0, weekday: 3 }, false);
|
||||||
|
t.assertEqual(r.threshold.frSo, 1, 'threshold.frSo=1');
|
||||||
|
t.assertEqual(r.threshold.weekday, 3, 'threshold.weekday=3');
|
||||||
|
});
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Display Functions
|
// Display Functions
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|
|
||||||
53
variants.js
53
variants.js
|
|
@ -34,7 +34,58 @@ function classifyDuties(duties, holidayProvider) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function variant1(classified, isVacation) {
|
function variant1(classified, isVacation) {
|
||||||
throw new Error('variant1: not implemented');
|
const RATE_NORMAL = 250;
|
||||||
|
const RATE_WEEKEND = 450;
|
||||||
|
const frSoThreshold = isVacation ? 0.5 : 1;
|
||||||
|
const weekdayThreshold = isVacation ? 1.5 : 3;
|
||||||
|
const frSoDeduction = isVacation ? 0.5 : 1;
|
||||||
|
const weekdayDeduction = isVacation ? 1.5 : 3;
|
||||||
|
|
||||||
|
const frSoPool = classified.fr + classified.so;
|
||||||
|
const eligible = (frSoPool >= frSoThreshold - 1e-9)
|
||||||
|
&& (classified.weekday >= weekdayThreshold - 1e-9);
|
||||||
|
|
||||||
|
if (!eligible) {
|
||||||
|
return {
|
||||||
|
variantId: 1,
|
||||||
|
eligible: false,
|
||||||
|
threshold: { frSo: frSoThreshold, weekday: weekdayThreshold },
|
||||||
|
deduction: { fr: 0, sa: 0, so: 0, weekday: 0 },
|
||||||
|
paidShares: { fr: 0, sa: 0, so: 0, weekday: 0 },
|
||||||
|
bonus: 0,
|
||||||
|
isWinner: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Friday priority within fr+so pool: fr first, then so
|
||||||
|
let remaining = frSoDeduction;
|
||||||
|
const deduction = { fr: 0, sa: 0, so: 0, weekday: weekdayDeduction };
|
||||||
|
for (const slot of ['fr', 'so']) {
|
||||||
|
const take = Math.min(remaining, classified[slot]);
|
||||||
|
deduction[slot] = take;
|
||||||
|
remaining -= take;
|
||||||
|
if (remaining <= 1e-9) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
const paidShares = {
|
||||||
|
fr: Math.max(0, classified.fr - deduction.fr),
|
||||||
|
sa: classified.sa, // sa never deducted in V1
|
||||||
|
so: Math.max(0, classified.so - deduction.so),
|
||||||
|
weekday: Math.max(0, classified.weekday - deduction.weekday)
|
||||||
|
};
|
||||||
|
|
||||||
|
const bonus = (paidShares.fr + paidShares.sa + paidShares.so) * RATE_WEEKEND
|
||||||
|
+ paidShares.weekday * RATE_NORMAL;
|
||||||
|
|
||||||
|
return {
|
||||||
|
variantId: 1,
|
||||||
|
eligible: true,
|
||||||
|
threshold: { frSo: frSoThreshold, weekday: weekdayThreshold },
|
||||||
|
deduction,
|
||||||
|
paidShares,
|
||||||
|
bonus,
|
||||||
|
isWinner: false
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function variant2(classified, isVacation) {
|
function variant2(classified, isVacation) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue