feat: implement variant3 (loose, pool fr+sa+so, fr-priority)
This commit is contained in:
parent
c460a20c00
commit
a675763206
2 changed files with 129 additions and 1 deletions
|
|
@ -591,6 +591,86 @@ runner.test('classifyDuties: Tag vor Feiertag (Mi vor Christi Himmelfahrt) zaehl
|
|||
t.assertEqual(result.weekday, 0, 'weekday=0');
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Variants - variant3 (loose: 2 qualifying days, pool fr+sa+so)
|
||||
// ============================================================================
|
||||
|
||||
runner.test('variant3: unter Schwelle (1 sa) -> not eligible, bonus 0', (t) => {
|
||||
const classified = { fr: 0, sa: 1, so: 0, weekday: 4 };
|
||||
const r = variant3(classified, false);
|
||||
t.assertFalse(r.eligible, 'eligible=false');
|
||||
t.assertEqual(r.bonus, 0, 'bonus=0');
|
||||
t.assertEqual(r.variantId, 3, 'variantId=3');
|
||||
});
|
||||
|
||||
runner.test('variant3: 2x sa -> eligible, beide abgezogen, bonus 0', (t) => {
|
||||
const classified = { fr: 0, sa: 2, so: 0, weekday: 0 };
|
||||
const r = variant3(classified, false);
|
||||
t.assertTrue(r.eligible, 'eligible=true');
|
||||
t.assertEqual(r.deduction.sa, 2, 'sa-deduction=2');
|
||||
t.assertEqual(r.paidShares.sa, 0, 'sa-paid=0');
|
||||
t.assertEqual(r.bonus, 0, 'bonus=0');
|
||||
});
|
||||
|
||||
runner.test('variant3: Friday priority fr->so->sa', (t) => {
|
||||
// fr=2, sa=1, so=1, weekday=0 -> 2 von fr abgezogen, sa+so voll bezahlt
|
||||
const classified = { fr: 2, sa: 1, so: 1, weekday: 0 };
|
||||
const r = variant3(classified, false);
|
||||
t.assertTrue(r.eligible, 'eligible=true');
|
||||
t.assertEqual(r.deduction.fr, 2, 'fr-deduction=2');
|
||||
t.assertEqual(r.deduction.so, 0, 'so-deduction=0');
|
||||
t.assertEqual(r.deduction.sa, 0, 'sa-deduction=0');
|
||||
t.assertEqual(r.paidShares.fr, 0, 'fr-paid=0');
|
||||
t.assertEqual(r.paidShares.so, 1, 'so-paid=1');
|
||||
t.assertEqual(r.paidShares.sa, 1, 'sa-paid=1');
|
||||
t.assertEqual(r.bonus, 2 * 450, 'bonus = 2 * 450 = 900');
|
||||
});
|
||||
|
||||
runner.test('variant3: fr=1, sa=1, so=0 -> fr+sa abgezogen', (t) => {
|
||||
const classified = { fr: 1, sa: 1, so: 0, weekday: 0 };
|
||||
const r = variant3(classified, false);
|
||||
t.assertEqual(r.deduction.fr, 1, 'fr=1');
|
||||
t.assertEqual(r.deduction.so, 0, 'so=0');
|
||||
t.assertEqual(r.deduction.sa, 1, 'sa=1');
|
||||
t.assertEqual(r.bonus, 0, 'bonus=0');
|
||||
});
|
||||
|
||||
runner.test('variant3: weekday wird voll bezahlt, nicht abgezogen', (t) => {
|
||||
const classified = { fr: 1, sa: 1, so: 0, weekday: 3 };
|
||||
const r = variant3(classified, false);
|
||||
t.assertEqual(r.paidShares.weekday, 3, 'weekday-paid=3');
|
||||
t.assertEqual(r.deduction.weekday, 0, 'weekday-deduction=0');
|
||||
t.assertEqual(r.bonus, 3 * 250, 'bonus = 3 * 250 = 750');
|
||||
});
|
||||
|
||||
runner.test('variant3: Urlaubsmodus halbiert Schwelle auf 1', (t) => {
|
||||
const classified = { fr: 0, sa: 0.5, so: 0.5, weekday: 0 };
|
||||
const r = variant3(classified, true);
|
||||
t.assertTrue(r.eligible, 'eligible=true (Schwelle 1)');
|
||||
// Abzug 1 aus Pool, fr-Prio -> so zuerst (fr=0), dann sa
|
||||
t.assertEqual(r.deduction.fr, 0, 'fr=0');
|
||||
t.assertEqual(r.deduction.so, 0.5, 'so=0.5');
|
||||
t.assertEqual(r.deduction.sa, 0.5, 'sa=0.5');
|
||||
t.assertEqual(r.bonus, 0, 'bonus=0');
|
||||
});
|
||||
|
||||
runner.test('variant3: Urlaubsmodus, halbe sa und 1 fr -> fr-Prio frisst 1', (t) => {
|
||||
const classified = { fr: 1, sa: 0.5, so: 0, weekday: 0 };
|
||||
const r = variant3(classified, true);
|
||||
t.assertTrue(r.eligible, 'eligible=true');
|
||||
t.assertEqual(r.deduction.fr, 1, 'fr=1');
|
||||
t.assertEqual(r.deduction.sa, 0, 'sa unangetastet');
|
||||
t.assertEqual(r.paidShares.sa, 0.5, 'sa-paid=0.5');
|
||||
t.assertEqual(r.bonus, 0.5 * 450, 'bonus = 0.5 * 450 = 225');
|
||||
});
|
||||
|
||||
runner.test('variant3: threshold-Shape ist {pool: 2} normal, {pool: 1} im Urlaub', (t) => {
|
||||
const r1 = variant3({ fr: 0, sa: 2, so: 0, weekday: 0 }, false);
|
||||
const r2 = variant3({ fr: 0, sa: 1, so: 0, weekday: 0 }, true);
|
||||
t.assertEqual(r1.threshold.pool, 2, 'normal pool=2');
|
||||
t.assertEqual(r2.threshold.pool, 1, 'vacation pool=1');
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// Display Functions
|
||||
// ============================================================================
|
||||
|
|
|
|||
50
variants.js
50
variants.js
|
|
@ -42,7 +42,55 @@ function variant2(classified, isVacation) {
|
|||
}
|
||||
|
||||
function variant3(classified, isVacation) {
|
||||
throw new Error('variant3: not implemented');
|
||||
const RATE_NORMAL = 250;
|
||||
const RATE_WEEKEND = 450;
|
||||
const poolThreshold = isVacation ? 1 : 2;
|
||||
const totalDeduction = isVacation ? 1 : 2;
|
||||
|
||||
const pool = classified.fr + classified.sa + classified.so;
|
||||
const eligible = pool >= poolThreshold - 1e-9;
|
||||
|
||||
if (!eligible) {
|
||||
return {
|
||||
variantId: 3,
|
||||
eligible: false,
|
||||
threshold: { pool: poolThreshold },
|
||||
deduction: { fr: 0, sa: 0, so: 0, weekday: 0 },
|
||||
paidShares: { fr: 0, sa: 0, so: 0, weekday: 0 },
|
||||
bonus: 0,
|
||||
isWinner: false
|
||||
};
|
||||
}
|
||||
|
||||
// Friday priority: fr -> so -> sa
|
||||
let remaining = totalDeduction;
|
||||
const deduction = { fr: 0, sa: 0, so: 0, weekday: 0 };
|
||||
for (const slot of ['fr', 'so', 'sa']) {
|
||||
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: Math.max(0, classified.sa - deduction.sa),
|
||||
so: Math.max(0, classified.so - deduction.so),
|
||||
weekday: classified.weekday // weekday never deducted in V3
|
||||
};
|
||||
|
||||
const bonus = (paidShares.fr + paidShares.sa + paidShares.so) * RATE_WEEKEND
|
||||
+ paidShares.weekday * RATE_NORMAL;
|
||||
|
||||
return {
|
||||
variantId: 3,
|
||||
eligible: true,
|
||||
threshold: { pool: poolThreshold },
|
||||
deduction,
|
||||
paidShares,
|
||||
bonus,
|
||||
isWinner: false
|
||||
};
|
||||
}
|
||||
|
||||
// Expose globally
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue