Skip to content

Commit 9487243

Browse files
adereisclaude
andcommitted
Add tests for filter + override + budget scaling interaction
Verify that global filters, bonus override employees (pro-rata leave), and budget scaling work correctly together without double-counting or miscalculating pool allocations. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 3c1e882 commit 9487243

1 file changed

Lines changed: 211 additions & 0 deletions

File tree

tests/test_filter_integration.py

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,3 +1274,214 @@ def test_proportional_scaling_uses_all_employees_not_filtered(self, client, team
12741274
assert abs(result['total_allocated'] - expected_pool) < 1, (
12751275
f"Total allocated should be ${expected_pool}, got ${result['total_allocated']}"
12761276
)
1277+
1278+
1279+
class TestFilterWithOverrideAndBudgetScaling:
1280+
"""Test interaction between global filters, bonus overrides, and budget scaling.
1281+
1282+
Regression tests ensuring that:
1283+
1. Budget override scales proportionally when employees are filtered
1284+
2. Override employees (pro-rata leave) get their fixed % correctly
1285+
3. Remaining pool is correctly reduced by override amounts
1286+
4. All three features work together without double-counting or miscalculation
1287+
"""
1288+
1289+
@pytest.fixture
1290+
def team_with_override_employee(self, db_session):
1291+
"""Create a team with a mix of normal and override employees.
1292+
1293+
Team composition (all ICs to avoid manager filter complexity):
1294+
- 3 Normal employees: $10,000 each in bonus targets ($30,000 total)
1295+
- 1 Override employee: $10,000 target, 50% override (pro-rata leave)
1296+
- Total team: $40,000 in bonus targets
1297+
"""
1298+
employees = [
1299+
# Normal employees
1300+
Employee(
1301+
associate_id='NORM001',
1302+
associate='Normal One',
1303+
supervisory_organization='Team Alpha (Manager)',
1304+
current_job_profile='Software Engineer',
1305+
management_level='Individual Contributor (Prof Level 3)',
1306+
current_base_pay_manager_currency=100000.0,
1307+
currency='USD',
1308+
bonus_target_manager_currency=10000.0,
1309+
performance_rating_percent=100.0,
1310+
),
1311+
Employee(
1312+
associate_id='NORM002',
1313+
associate='Normal Two',
1314+
supervisory_organization='Team Alpha (Manager)',
1315+
current_job_profile='Software Engineer',
1316+
management_level='Individual Contributor (Prof Level 3)',
1317+
current_base_pay_manager_currency=100000.0,
1318+
currency='USD',
1319+
bonus_target_manager_currency=10000.0,
1320+
performance_rating_percent=110.0, # Slightly above average
1321+
),
1322+
Employee(
1323+
associate_id='NORM003',
1324+
associate='Normal Three',
1325+
supervisory_organization='Team Alpha (Manager)',
1326+
current_job_profile='Senior Software Engineer',
1327+
management_level='Individual Contributor (Prof Level 4)',
1328+
current_base_pay_manager_currency=120000.0,
1329+
currency='USD',
1330+
bonus_target_manager_currency=10000.0,
1331+
performance_rating_percent=90.0, # Slightly below average
1332+
),
1333+
# Override employee (pro-rata leave)
1334+
Employee(
1335+
associate_id='LEAVE001',
1336+
associate='Leave Employee',
1337+
supervisory_organization='Team Alpha (Manager)',
1338+
current_job_profile='Software Engineer',
1339+
management_level='Individual Contributor (Prof Level 3)',
1340+
current_base_pay_manager_currency=100000.0,
1341+
currency='USD',
1342+
bonus_target_manager_currency=10000.0,
1343+
performance_rating_percent=None, # No rating needed for override
1344+
bonus_override_percent=50.0, # 50% pro-rata
1345+
special_case_notes='Paternity leave Apr-Sep',
1346+
),
1347+
]
1348+
1349+
for emp in employees:
1350+
db_session.add(emp)
1351+
db_session.commit()
1352+
return employees
1353+
1354+
def test_budget_scaling_with_override_employee(self, client, team_with_override_employee):
1355+
"""Budget override should scale, then override bonus deducted from scaled pool.
1356+
1357+
With $40,000 total targets and a $40,000 budget override:
1358+
- Full pool = $40,000
1359+
- Override employee gets $5,000 (50% of $10,000 target)
1360+
- Remaining pool for normal employees = $35,000
1361+
- Normal employees compete for $35,000 based on their ratings
1362+
"""
1363+
from app import calculate_bonus_for_employees, get_all_employees
1364+
from models import BonusSettings, get_db
1365+
1366+
# Set budget override
1367+
db = get_db()
1368+
settings = db.query(BonusSettings).first()
1369+
if not settings:
1370+
settings = BonusSettings()
1371+
db.add(settings)
1372+
settings.budget_override = 40000.0
1373+
settings.workday_pool = 40000.0
1374+
db.commit()
1375+
1376+
all_employees = get_all_employees()
1377+
assert len(all_employees) == 4, "Should have 4 employees total"
1378+
1379+
# Verify override employee is present
1380+
override_emp = next((e for e in all_employees if e['Associate ID'] == 'LEAVE001'), None)
1381+
assert override_emp is not None, "Override employee should exist"
1382+
assert override_emp.get('bonus_override_percent') == 50.0
1383+
1384+
# Calculate bonuses
1385+
params = {'upside_exponent': 1.35, 'downside_exponent': 1.9}
1386+
all_targets = sum(
1387+
emp.get('Bonus Target Manager Currency') or 0
1388+
for emp in all_employees
1389+
)
1390+
assert all_targets == 40000, f"Total targets should be $40,000, got ${all_targets}"
1391+
1392+
result = calculate_bonus_for_employees(
1393+
all_employees,
1394+
params,
1395+
budget_override=40000.0,
1396+
workday_pool=40000.0,
1397+
all_targets_sum=all_targets
1398+
)
1399+
1400+
# Override employee should get exactly $5,000 (50% of $10,000)
1401+
override_result = next(
1402+
(r for r in result['results'] if r['employee']['Associate ID'] == 'LEAVE001'),
1403+
None
1404+
)
1405+
assert override_result is not None, "Override employee should have a result"
1406+
assert override_result['is_override'] is True
1407+
assert abs(override_result['final_bonus'] - 5000) < 1, (
1408+
f"Override employee should get $5,000, got ${override_result['final_bonus']}"
1409+
)
1410+
1411+
# Total allocated should equal budget override ($40,000)
1412+
assert abs(result['total_allocated'] - 40000) < 100, (
1413+
f"Total allocated should be ~$40,000, got ${result['total_allocated']}"
1414+
)
1415+
1416+
def test_filter_plus_override_plus_budget_scaling(self, client, team_with_override_employee):
1417+
"""Three-way interaction: filter excludes some, override uses fixed %, budget scales.
1418+
1419+
Scenario: Exclude NORM003 (Senior Engineer) via employee ID filter
1420+
- Filtered targets: $30,000 (3 remaining employees)
1421+
- Budget $40,000 scales to $30,000 (75% of full pool)
1422+
- Override employee still gets $5,000 (from scaled pool)
1423+
- Remaining pool for NORM001, NORM002: $25,000
1424+
"""
1425+
from app import calculate_bonus_for_employees, get_all_employees, apply_employee_filters
1426+
from models import BonusSettings, get_db
1427+
1428+
db = get_db()
1429+
settings = db.query(BonusSettings).first()
1430+
if not settings:
1431+
settings = BonusSettings()
1432+
db.add(settings)
1433+
settings.budget_override = 40000.0
1434+
settings.workday_pool = 40000.0
1435+
db.commit()
1436+
1437+
all_employees = get_all_employees()
1438+
all_targets = sum(
1439+
emp.get('Bonus Target Manager Currency') or 0
1440+
for emp in all_employees
1441+
)
1442+
1443+
# Apply filter to exclude NORM003
1444+
filter_params = {'exclude_ids': ['NORM003']}
1445+
filtered_team, _ = apply_employee_filters(all_employees, filter_params)
1446+
assert len(filtered_team) == 3, "Should have 3 employees after filtering"
1447+
1448+
# Verify NORM003 is excluded
1449+
assert not any(e['Associate ID'] == 'NORM003' for e in filtered_team)
1450+
1451+
# Calculate filtered targets
1452+
filtered_targets = sum(
1453+
emp.get('Bonus Target Manager Currency') or 0
1454+
for emp in filtered_team
1455+
)
1456+
assert filtered_targets == 30000, f"Filtered targets should be $30,000, got ${filtered_targets}"
1457+
1458+
# Calculate bonuses with proportional scaling
1459+
params = {'upside_exponent': 1.35, 'downside_exponent': 1.9}
1460+
result = calculate_bonus_for_employees(
1461+
filtered_team,
1462+
params,
1463+
budget_override=40000.0,
1464+
workday_pool=40000.0,
1465+
all_targets_sum=all_targets # Use ALL employees' targets for proportion
1466+
)
1467+
1468+
# Scaled pool should be 75% of $40,000 = $30,000
1469+
expected_pool = 40000 * (filtered_targets / all_targets) # 40000 * 0.75 = 30000
1470+
assert abs(result['total_pool'] - expected_pool) < 1, (
1471+
f"Scaled pool should be ${expected_pool}, got ${result['total_pool']}"
1472+
)
1473+
1474+
# Override employee should still get $5,000 (50% of their $10,000 target)
1475+
override_result = next(
1476+
(r for r in result['results'] if r['employee']['Associate ID'] == 'LEAVE001'),
1477+
None
1478+
)
1479+
assert override_result is not None
1480+
assert abs(override_result['final_bonus'] - 5000) < 1, (
1481+
f"Override employee should get $5,000 even when filtered, got ${override_result['final_bonus']}"
1482+
)
1483+
1484+
# Total allocated should be close to scaled pool ($30,000)
1485+
assert abs(result['total_allocated'] - 30000) < 100, (
1486+
f"Total allocated should be ~$30,000, got ${result['total_allocated']}"
1487+
)

0 commit comments

Comments
 (0)