84 lines
2.7 KiB
Python
84 lines
2.7 KiB
Python
from django.db import models
|
|
|
|
from src.models.base import TimeStampedModel
|
|
from src.models.clients import Client
|
|
from src.models.projects import Project
|
|
from src.models.services import Service
|
|
|
|
|
|
class Invoice(TimeStampedModel):
|
|
STATUS_CHOICES = [
|
|
("DRAFT", "Draft"),
|
|
("SENT", "Sent"),
|
|
("PAID", "Paid"),
|
|
("OVERDUE", "Overdue"),
|
|
("CANCELLED", "Cancelled"),
|
|
]
|
|
client = models.ForeignKey(
|
|
Client, on_delete=models.CASCADE, related_name="invoices"
|
|
)
|
|
project = models.ForeignKey(
|
|
Project, on_delete=models.CASCADE, related_name="invoices"
|
|
)
|
|
invoice_number = models.CharField(max_length=20, unique=True, editable=False)
|
|
amount = models.DecimalField(max_digits=10, decimal_places=2)
|
|
date_issued = models.DateField(auto_now_add=True)
|
|
due_date = models.DateField()
|
|
status = models.CharField(max_length=10, choices=STATUS_CHOICES, default="DRAFT")
|
|
|
|
def save(self, *args, **kwargs):
|
|
if not self.id:
|
|
client_code = self.client.short_code # e.g., "NEX001"
|
|
|
|
# Find last invoice for this client
|
|
last_invoice = (
|
|
Invoice.objects.filter(invoice_number__startswith=f"{client_code}-")
|
|
.order_by("-invoice_number")
|
|
.first()
|
|
)
|
|
|
|
if last_invoice:
|
|
last_number = int(last_invoice.invoice_number.split("-")[1])
|
|
new_number = last_number + 1
|
|
else:
|
|
new_number = 1
|
|
|
|
# final format → NEX001-0001
|
|
self.invoice_number = f"{client_code}-{new_number:04d}"
|
|
|
|
super().save(*args, **kwargs)
|
|
|
|
def __str__(self):
|
|
return f"Invoice {self.invoice_number}"
|
|
|
|
|
|
class Expense(models.Model):
|
|
service = models.ForeignKey(
|
|
Service,
|
|
on_delete=models.SET_NULL,
|
|
null=True,
|
|
blank=True,
|
|
related_name="expenses",
|
|
)
|
|
description = models.CharField(max_length=255)
|
|
amount = models.DecimalField(max_digits=10, decimal_places=2)
|
|
date = models.DateField()
|
|
category = models.CharField(max_length=100, blank=True)
|
|
created_at = models.DateTimeField(auto_now_add=True)
|
|
|
|
def __str__(self):
|
|
return f"{self.description} - {self.amount}"
|
|
|
|
|
|
class Payment(models.Model):
|
|
invoice = models.ForeignKey(
|
|
Invoice, on_delete=models.CASCADE, related_name="payments"
|
|
)
|
|
amount = models.DecimalField(max_digits=10, decimal_places=2)
|
|
date = models.DateField()
|
|
method = models.CharField(max_length=50, blank=True)
|
|
transaction_id = models.CharField(max_length=100, blank=True)
|
|
|
|
def __str__(self):
|
|
return f"Payment of {self.amount} for {self.invoice}"
|