Corp/backend/tests/finance/test_payroll_tasks.py
2026-09-07 19:43:48 +03:00

105 lines
3.4 KiB
Python

from datetime import date
from decimal import Decimal
import pytest
from django.conf import settings
from finance.enums import PayrollPeriodStatus
from finance.models import PayrollAuditEvent, PayrollPeriod
from finance.payroll.carryovers import create_carryover
from finance.tasks import ensure_monthly_payroll_period, open_monthly_payroll_period
pytestmark = pytest.mark.django_db
def test_monthly_period_task_is_scheduled_for_first_day():
task = settings.CELERY_BEAT_SCHEDULE["open-monthly-payroll-period"]
assert task["task"] == "finance.tasks.open_monthly_payroll_period"
assert task["schedule"].day_of_month == {1}
assert task["schedule"].hour == {0}
assert task["schedule"].minute == {5}
def test_ensure_monthly_payroll_period_opens_full_calendar_month():
period, created = ensure_monthly_payroll_period(date(2026, 8, 1))
assert created is True
assert period.code == "2026-08"
assert period.name == "Август 2026"
assert period.date_from == date(2026, 8, 1)
assert period.date_to == date(2026, 8, 31)
assert period.pay_date is None
assert period.currency == "RUB"
assert period.status == PayrollPeriodStatus.OPEN
assert period.created_by is None
event = PayrollAuditEvent.objects.get(
action="payroll.period_created",
period=period,
)
assert event.actor is None
assert event.metadata == {"channel": "automation", "schedule": "monthly"}
def test_ensure_monthly_payroll_period_is_idempotent():
first, first_created = ensure_monthly_payroll_period(date(2028, 2, 1))
second, second_created = ensure_monthly_payroll_period(date(2028, 2, 15))
assert first_created is True
assert second_created is False
assert second.pk == first.pk
assert first.date_to == date(2028, 2, 29)
assert PayrollPeriod.objects.count() == 1
assert (
PayrollAuditEvent.objects.filter(
action="payroll.period_created",
period=first,
).count()
== 1
)
def test_monthly_task_uses_local_current_month(monkeypatch):
monkeypatch.setattr("finance.tasks.timezone.localdate", lambda: date(2026, 9, 1))
result = open_monthly_payroll_period()
period = PayrollPeriod.objects.get(pk=result["period_id"])
assert result == {"period_id": period.pk, "code": "2026-09", "created": True}
assert period.date_from == date(2026, 9, 1)
assert period.date_to == date(2026, 9, 30)
def test_monthly_period_opening_does_not_materialize_legacy_manual_carryover(
user_factory,
):
manager = user_factory(email="period.carryover.manager@example.test")
employee = user_factory(email="period.carryover.employee@example.test")
source = PayrollPeriod.objects.create(
code="2026-07",
name="Июль 2026",
date_from=date(2026, 7, 1),
date_to=date(2026, 7, 31),
currency="RUB",
status=PayrollPeriodStatus.CLOSED,
created_by=manager,
)
carryover = create_carryover(
source_period=source,
employee=employee,
direction="company_owes",
amount=Decimal("700.00"),
reason="Остаток июля",
actor=manager,
)
assert carryover.target_period_id is None
target, created = ensure_monthly_payroll_period(date(2026, 8, 1))
assert created is True
carryover.refresh_from_db()
assert target.status == PayrollPeriodStatus.OPEN
assert carryover.target_period_id is None
assert carryover.generated_input_line_id is None