All checks were successful
Deploy production / deploy (push) Successful in 10m8s
97 lines
3.5 KiB
Python
97 lines
3.5 KiB
Python
"""Balance-only corrections, deliberately unrelated to payroll input lines."""
|
|
|
|
import uuid
|
|
from decimal import Decimal
|
|
|
|
from django.conf import settings
|
|
from django.core.exceptions import ValidationError
|
|
from django.core.validators import MinValueValidator
|
|
from django.db import models
|
|
|
|
from finance.enums import PayrollCarryoverDirection
|
|
|
|
|
|
class PayrollBalanceAdjustment(models.Model):
|
|
employee = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
on_delete=models.PROTECT,
|
|
related_name="payroll_balance_adjustments",
|
|
)
|
|
effective_period = models.ForeignKey(
|
|
"finance.PayrollPeriod",
|
|
on_delete=models.PROTECT,
|
|
related_name="balance_adjustments",
|
|
)
|
|
source_period = models.ForeignKey(
|
|
"finance.PayrollPeriod",
|
|
on_delete=models.PROTECT,
|
|
null=True,
|
|
blank=True,
|
|
related_name="referenced_balance_adjustments",
|
|
)
|
|
direction = models.CharField(
|
|
max_length=20, choices=PayrollCarryoverDirection.choices
|
|
)
|
|
amount = models.DecimalField(
|
|
max_digits=19,
|
|
decimal_places=2,
|
|
validators=[MinValueValidator(Decimal("0.01"))],
|
|
)
|
|
reason = models.CharField(max_length=1000, blank=True)
|
|
request_id = models.UUIDField(default=uuid.uuid4, unique=True, editable=False)
|
|
created_by = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
on_delete=models.PROTECT,
|
|
related_name="payroll_balance_adjustments_created",
|
|
)
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
voided_at = models.DateTimeField(null=True, blank=True)
|
|
voided_by = models.ForeignKey(
|
|
settings.AUTH_USER_MODEL,
|
|
on_delete=models.PROTECT,
|
|
null=True,
|
|
blank=True,
|
|
related_name="payroll_balance_adjustments_voided",
|
|
)
|
|
void_reason = models.CharField(max_length=1000, blank=True)
|
|
|
|
class Meta:
|
|
ordering = ["-effective_period__date_from", "-created_at", "-pk"]
|
|
verbose_name = "Ручная корректировка остатка"
|
|
verbose_name_plural = "Ручные корректировки остатков"
|
|
constraints = [
|
|
models.CheckConstraint(
|
|
condition=models.Q(amount__gt=0),
|
|
name="balance_adjustment_positive",
|
|
),
|
|
models.CheckConstraint(
|
|
condition=models.Q(direction__in=["company_owes", "employee_owes"]),
|
|
name="balance_adjustment_direction",
|
|
),
|
|
models.CheckConstraint(
|
|
condition=(
|
|
models.Q(
|
|
voided_at__isnull=True, voided_by__isnull=True, void_reason=""
|
|
)
|
|
| models.Q(voided_at__isnull=False, voided_by__isnull=False)
|
|
),
|
|
name="balance_adjustment_void_consistent",
|
|
),
|
|
]
|
|
|
|
@property
|
|
def contribution(self):
|
|
return self.amount if self.direction == "company_owes" else -self.amount
|
|
|
|
def clean(self):
|
|
super().clean()
|
|
if self.source_period_id and self.effective_period_id:
|
|
if self.source_period.currency != self.effective_period.currency:
|
|
raise ValidationError(
|
|
{"source_period": "Валюты периодов должны совпадать."}
|
|
)
|
|
if self.source_period.date_to >= self.effective_period.date_from:
|
|
raise ValidationError(
|
|
{"source_period": "Выберите более ранний период."}
|
|
)
|