from django.db import models from django.utils.translation import gettext_lazy as _ from django.utils import timezone from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType class Account(models.Model): ACCOUNT_TYPES = [ ('asset', _('Asset')), ('liability', _('Liability')), ('equity', _('Equity')), ('income', _('Income')), ('expense', _('Expense')), ] code = models.CharField(_("Account Code"), max_length=20, unique=True) name_en = models.CharField(_("Name (English)"), max_length=100) name_ar = models.CharField(_("Name (Arabic)"), max_length=100) account_type = models.CharField(_("Account Type"), max_length=20, choices=ACCOUNT_TYPES) description = models.TextField(_("Description"), blank=True) is_active = models.BooleanField(_("Is Active"), default=True) created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"{self.code} - {self.name_en} / {self.name_ar}" @property def balance(self): # Calculate balance: Sum(debit) - Sum(credit) items = self.journal_items.all() debits = items.filter(type='debit').aggregate(total=models.Sum('amount'))['total'] or 0 credits = items.filter(type='credit').aggregate(total=models.Sum('amount'))['total'] or 0 # Standard balances: # Assets/Expenses: Debit - Credit # Liabilities/Equity/Income: Credit - Debit if self.account_type in ['asset', 'expense']: return debits - credits else: return credits - debits class JournalEntry(models.Model): date = models.DateField(_("Date"), default=timezone.now) description = models.TextField(_("Description")) reference = models.CharField(_("Reference"), max_length=100, blank=True) # Generic relationship to the source document (Sale, Purchase, Expense, etc.) content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE, null=True, blank=True) object_id = models.PositiveIntegerField(null=True, blank=True) content_object = GenericForeignKey('content_type', 'object_id') created_at = models.DateTimeField(auto_now_add=True) def __str__(self): return f"Entry {self.id} - {self.date} ({self.description[:30]})" class Meta: verbose_name_plural = _("Journal Entries") class JournalItem(models.Model): TYPE_CHOICES = [ ('debit', _('Debit')), ('credit', _('Credit')), ] entry = models.ForeignKey(JournalEntry, on_delete=models.CASCADE, related_name="items") account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name="journal_items") type = models.CharField(_("Type"), max_length=10, choices=TYPE_CHOICES) amount = models.DecimalField(_("Amount"), max_digits=15, decimal_places=3) notes = models.CharField(_("Notes"), max_length=255, blank=True) def __str__(self): return f"{self.type.capitalize()}: {self.account.name_en} - {self.amount}"