38086-vm/accounting/models.py
2026-02-03 03:17:21 +00:00

73 lines
3.0 KiB
Python

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}"