3.9 KiB
Payroll Core
payroll_core is a deterministic, project-independent calculation package.
It contains no Django, database, network, Celery or EUSRR imports. A host
application resolves employees and approved inputs, calls the calculator, and
persists the returned immutable snapshot.
Guarantees
- every monetary and quantity value is
Decimal; floats are rejected; - each displayed money line is rounded once before totals are summed;
- calculation uses a fixed local decimal context and does not depend on the host process context;
- rules are immutable, effective-dated and versioned;
- inputs, rules and calculation output have canonical SHA-256 fingerprints;
- reconciliation warnings have a separate fingerprint, so legacy checkpoints never alter calculation identity but cannot be changed unnoticed;
- explicit line kinds carry direction, so a negative correction cannot become a double negative;
- legacy spreadsheet totals are reconciliation checkpoints, never inputs;
- the result is independent of the order of input lines.
Example matching the June 2026 spreadsheet
from datetime import date
from decimal import Decimal
from payroll_core import (
DeterministicPayrollCalculator,
ExpectedTotals,
InputLine,
LineKind,
PayrollPeriod,
PayrollRequest,
PayrollRules,
PointPolicy,
)
period = PayrollPeriod(date(2026, 6, 1), date(2026, 6, 30))
request = PayrollRequest(
employee_ref="employee:42",
period=period,
currency="RUB",
base_accrual=Decimal("80000"),
base_source_ref="rate:42:revision:1",
point_base_accrual=Decimal("95000"),
target_points=Decimal("110"),
actual_points=Decimal("110"),
point_rate=Decimal("100"),
lines=(
InputLine(
line_id="bonus:1",
code="BONUS",
label="Bonus",
kind=LineKind.EARNING,
amount=Decimal("15000"),
source_ref="excel:june:row-2:bonus",
),
InputLine(
line_id="correction:1",
code="MANUAL_CORRECTION",
label="Manual correction",
kind=LineKind.ADJUSTMENT_CREDIT,
amount=Decimal("20000"),
reason="Approved accounting correction",
source_ref="excel:june:row-2:correction",
),
),
expected_totals=ExpectedTotals(
point_amount=Decimal("0"),
gross=Decimal("115000"),
recalculated_gross=Decimal("115000"),
payable=Decimal("115000"),
),
)
rules = PayrollRules(
ruleset_id="company-standard",
version="2026.07.1",
effective_from=date(2026, 1, 1),
point_policy=PointPolicy.EXCESS_ONLY,
)
result = DeterministicPayrollCalculator().calculate(request, rules)
assert result.totals.payable == Decimal("115000.00")
The initial EXCESS_ONLY point policy pays only points above the target:
max(actual - target, 0) * point_rate. It never creates an implicit penalty
for a shortfall. This policy must remain in shadow/reconciliation mode until
the company confirms how points work for other rows.
PROPORTIONAL_WITH_EXCESS produces a signed point adjustment. Below target it
uses the complete point basis supplied by the host:
point_base_accrual * actual / target - point_base_accrual. Above target it
uses (actual - target) * point_rate. Keeping the basis separate from the base
accrual preserves the original input lines while making the adjustment visible.
Host boundary
The core knows an employee only as an opaque employee_ref. The host adapter
is responsible for authorization, rate resolution, maker-checker approval,
transactions, audit, publication, acknowledgements and notifications.
EUSRR maps the spreadsheet point basis to base accrual plus bonus inputs. It
keeps the configured excess point price nullable: when blank, the host supplies
the current in-norm display price and marks it as automatic. The core then uses
the unrounded point_base_accrual / target_points formula, without persisting
the derived value.