This commit is contained in:
123
backend/modules/invoicing/models.py
Normal file
123
backend/modules/invoicing/models.py
Normal file
@@ -0,0 +1,123 @@
|
||||
# backend/modules/invoicing/models.py
|
||||
|
||||
import datetime
|
||||
from django.utils import timezone
|
||||
from core.base_models import BaseModel
|
||||
from django.db import models, transaction
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.conf import settings
|
||||
from .utils import generate_invoice_number
|
||||
|
||||
class Invoice(BaseModel):
|
||||
# Identifikacija (UUID i created_at dolaze iz BaseModel)
|
||||
invoice_number = models.CharField(max_length=50, unique=True, verbose_name=_("Broj fakture"))
|
||||
|
||||
# Relacije
|
||||
creator = models.ForeignKey(
|
||||
settings.AUTH_USER_MODEL,
|
||||
on_delete=models.PROTECT,
|
||||
related_name="invoices"
|
||||
)
|
||||
client = models.ForeignKey(
|
||||
'crm.Client',
|
||||
on_delete=models.PROTECT,
|
||||
verbose_name=_("Klijent")
|
||||
)
|
||||
|
||||
# Financijski detalji
|
||||
amount = models.DecimalField(max_digits=12, decimal_places=2, verbose_name=_("Iznos"))
|
||||
currency = models.CharField(max_length=3, default="EUR")
|
||||
tax_rate = models.DecimalField(max_digits=4, decimal_places=2, default=25.00)
|
||||
|
||||
# Statusi
|
||||
status = models.CharField(
|
||||
max_length=20,
|
||||
choices=[
|
||||
('draft', 'Nacrt'),
|
||||
('sent', 'Poslano'),
|
||||
('paid', 'Plaćeno'),
|
||||
('cancelled', 'Stornirano')
|
||||
],
|
||||
default='draft'
|
||||
)
|
||||
|
||||
due_date = models.DateField(verbose_name=_("Rok plaćanja"))
|
||||
|
||||
class Meta:
|
||||
# Nasljeđujemo ordering iz BaseModel, ali ga možemo override-ati
|
||||
verbose_name = _("Faktura")
|
||||
verbose_name_plural = _("Fakture")
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.invoice_number} - {self.client}"
|
||||
|
||||
def get_total_amount(self):
|
||||
return self.items.aggregate(total=models.Sum(models.F('quantity') * models.F('unit_price')))['total'] or 0
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.invoice_number:
|
||||
self.invoice_number = generate_invoice_number()
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
class InvoiceItem(BaseModel):
|
||||
# Relacija prema fakturi
|
||||
invoice = models.ForeignKey(
|
||||
Invoice,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='items',
|
||||
verbose_name=_("Faktura")
|
||||
)
|
||||
|
||||
# Detalji stavke
|
||||
description = models.CharField(
|
||||
max_length=255,
|
||||
verbose_name=_("Opis stavke")
|
||||
)
|
||||
quantity = models.DecimalField(
|
||||
max_digits=10,
|
||||
decimal_places=2,
|
||||
default=1,
|
||||
verbose_name=_("Količina")
|
||||
)
|
||||
unit_price = models.DecimalField(
|
||||
max_digits=12,
|
||||
decimal_places=2,
|
||||
verbose_name=_("Cijena po jedinici")
|
||||
)
|
||||
|
||||
# Automatski izračun (property ne zauzima prostor u bazi)
|
||||
@property
|
||||
def total(self):
|
||||
return self.quantity * self.unit_price
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Stavka fakture")
|
||||
verbose_name_plural = _("Stavke fakture")
|
||||
|
||||
def __str__(self):
|
||||
# Koristimo prednost BaseModel __str__ metode
|
||||
return f"{self.description} ({self.quantity} x {self.unit_price})"
|
||||
|
||||
class InvoiceTransaction(BaseModel):
|
||||
# Polja specifična za fakturiranje
|
||||
invoice = models.ForeignKey(
|
||||
Invoice,
|
||||
on_delete=models.PROTECT,
|
||||
related_name='transactions',
|
||||
verbose_name=_("Faktura")
|
||||
)
|
||||
work_order = models.ForeignKey(
|
||||
'fleet.WorkOrder',
|
||||
on_delete=models.SET_NULL,
|
||||
related_name='invoice_transactions',
|
||||
null=True,
|
||||
blank=True,
|
||||
verbose_name=_("Putni nalog"),
|
||||
)
|
||||
invoice_number = models.CharField(max_length=50)
|
||||
amount = models.DecimalField(max_digits=10, decimal_places=2)
|
||||
payment_date = models.DateField(default=timezone.now)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Financijski zapis"
|
||||
verbose_name_plural = "Financijski zapisi"
|
||||
Reference in New Issue
Block a user