Add sales types, party adjustments, FunZone party fields, and treasury fee support

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Shayan Azadi
2026-07-03 03:15:52 +03:30
parent 5dd29c41d6
commit 5fb79fb7f0
8 changed files with 366 additions and 3 deletions

View File

@@ -40,6 +40,11 @@ class Party(models.Model):
('customer', 'Customer'),
('supplier', 'Supplier'),
]
EXTERNAL_SOURCES = [
('', 'Manual'),
('funzone_customer', 'FunZone Customer'),
('funzone_owner', 'FunZone Owner'),
]
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
kind = models.CharField(max_length=20, choices=PARTY_KINDS)
@@ -48,11 +53,33 @@ class Party(models.Model):
economic_code = models.CharField(max_length=50, blank=True, default='')
address = models.TextField(blank=True, default='')
opening_balance = models.FloatField(default=0)
external_id = models.UUIDField(null=True, blank=True, db_index=True)
external_source = models.CharField(
max_length=30, choices=EXTERNAL_SOURCES, blank=True, default=''
)
first_name = models.CharField(max_length=100, blank=True, default='')
last_name = models.CharField(max_length=100, blank=True, default='')
username = models.CharField(max_length=100, blank=True, default='')
email = models.EmailField(blank=True, default='')
national_code = models.CharField(max_length=20, blank=True, default='')
iban = models.CharField(max_length=34, blank=True, default='')
wallet_balance = models.FloatField(default=0)
is_active = models.BooleanField(default=True)
is_verified = models.BooleanField(default=False)
birthday = models.DateField(null=True, blank=True)
venues = models.JSONField(default=list, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'accounting_parties'
ordering = ['name']
constraints = [
models.UniqueConstraint(
fields=['external_id', 'external_source'],
condition=models.Q(external_id__isnull=False),
name='unique_external_party',
),
]
def __str__(self):
return self.name
@@ -120,6 +147,51 @@ class VoucherLine(models.Model):
return f"Line {self.account_id} D:{self.debit} C:{self.credit}"
class SalesType(models.Model):
"""A sales category (نوع فروش) referenced by sales documents."""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
code = models.CharField(max_length=50, db_index=True)
name = models.CharField(max_length=150)
description = models.TextField(blank=True, default='')
active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'accounting_sales_types'
ordering = ['code']
def __str__(self):
return f"{self.code} - {self.name}"
class PartyAdjustment(models.Model):
"""Debit/credit notice adjusting a customer receivable (اعلامیه بدهکار/بستانکار)."""
ADJUSTMENT_KINDS = [
('debit', 'Debit'),
('credit', 'Credit'),
]
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
number = models.PositiveIntegerField(default=0)
party = models.ForeignKey(
Party, on_delete=models.CASCADE, related_name='adjustments'
)
kind = models.CharField(max_length=20, choices=ADJUSTMENT_KINDS)
date = models.DateField()
amount = models.FloatField(default=0)
description = models.TextField(blank=True, default='')
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
db_table = 'accounting_party_adjustments'
ordering = ['-date', '-number']
def __str__(self):
return f"{self.kind} notice #{self.number}"
class Invoice(models.Model):
"""A sales or purchase invoice (فاکتور)."""
@@ -127,6 +199,11 @@ class Invoice(models.Model):
('sale', 'Sale'),
('purchase', 'Purchase'),
]
DOCUMENT_TYPES = [
('proforma', 'Proforma'),
('invoice', 'Invoice'),
('return', 'Return'),
]
STATUS_CHOICES = [
('draft', 'Draft'),
('confirmed', 'Confirmed'),
@@ -135,10 +212,19 @@ class Invoice(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
kind = models.CharField(max_length=20, choices=INVOICE_KINDS)
document_type = models.CharField(
max_length=20, choices=DOCUMENT_TYPES, default='invoice'
)
number = models.PositiveIntegerField(default=0)
party = models.ForeignKey(
Party, on_delete=models.SET_NULL, null=True, blank=True, related_name='invoices'
)
sales_type = models.ForeignKey(
SalesType, on_delete=models.SET_NULL, null=True, blank=True, related_name='invoices'
)
related_invoice = models.ForeignKey(
'self', on_delete=models.SET_NULL, null=True, blank=True, related_name='derived_docs'
)
date = models.DateField()
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft')
note = models.TextField(blank=True, default='')
@@ -194,8 +280,12 @@ class TreasuryTxn(models.Model):
Party, on_delete=models.SET_NULL, null=True, blank=True, related_name='treasury_txns'
)
amount = models.FloatField(default=0)
tax_amount = models.FloatField(default=0)
platform_profit_amount = models.FloatField(default=0)
owner_net_amount = models.FloatField(default=0)
reference = models.CharField(max_length=120, blank=True, default='')
description = models.TextField(blank=True, default='')
source = models.CharField(max_length=120, blank=True, default='')
created_at = models.DateTimeField(auto_now_add=True)
class Meta: