"""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": "Выберите более ранний период."} )