73 lines
3.0 KiB
Python
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}" |