Initial commit: standalone Django accounting API with admin JWT authorization

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Shayan Azadi
2026-07-01 00:29:25 +03:30
commit 066276743a
21 changed files with 1279 additions and 0 deletions

View File

@@ -0,0 +1,211 @@
# Generated by Django 4.2.7 on 2026-06-30 09:26
from django.db import migrations, models
import django.db.models.deletion
import uuid
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Account',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('code', models.CharField(db_index=True, max_length=20, unique=True)),
('name', models.CharField(max_length=150)),
('type', models.CharField(choices=[('asset', 'Asset'), ('liability', 'Liability'), ('equity', 'Equity'), ('income', 'Income'), ('expense', 'Expense')], max_length=20)),
('is_group', models.BooleanField(default=False)),
('opening_balance', models.FloatField(default=0)),
('created_at', models.DateTimeField(auto_now_add=True)),
('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='children', to='accounting.account')),
],
options={
'db_table': 'accounting_accounts',
'ordering': ['code'],
},
),
migrations.CreateModel(
name='Employee',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('code', models.CharField(blank=True, default='', max_length=50)),
('name', models.CharField(max_length=150)),
('position', models.CharField(blank=True, default='', max_length=120)),
('base_salary', models.FloatField(default=0)),
('insurance_no', models.CharField(blank=True, default='', max_length=50)),
('hire_date', models.DateField(blank=True, null=True)),
('active', models.BooleanField(default=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
],
options={
'db_table': 'accounting_employees',
'ordering': ['name'],
},
),
migrations.CreateModel(
name='Invoice',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('kind', models.CharField(choices=[('sale', 'Sale'), ('purchase', 'Purchase')], max_length=20)),
('number', models.PositiveIntegerField(default=0)),
('date', models.DateField()),
('status', models.CharField(choices=[('draft', 'Draft'), ('confirmed', 'Confirmed'), ('paid', 'Paid')], default='draft', max_length=20)),
('note', models.TextField(blank=True, default='')),
('created_at', models.DateTimeField(auto_now_add=True)),
],
options={
'db_table': 'accounting_invoices',
'ordering': ['-date', '-number'],
},
),
migrations.CreateModel(
name='Party',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('kind', models.CharField(choices=[('customer', 'Customer'), ('supplier', 'Supplier')], max_length=20)),
('name', models.CharField(max_length=150)),
('phone', models.CharField(blank=True, default='', max_length=30)),
('economic_code', models.CharField(blank=True, default='', max_length=50)),
('address', models.TextField(blank=True, default='')),
('opening_balance', models.FloatField(default=0)),
('created_at', models.DateTimeField(auto_now_add=True)),
],
options={
'db_table': 'accounting_parties',
'ordering': ['name'],
},
),
migrations.CreateModel(
name='Product',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('code', models.CharField(db_index=True, max_length=50)),
('name', models.CharField(max_length=150)),
('unit', models.CharField(blank=True, default='', max_length=30)),
('sale_price', models.FloatField(default=0)),
('purchase_price', models.FloatField(default=0)),
('stock', models.FloatField(default=0)),
('reorder_level', models.FloatField(default=0)),
('created_at', models.DateTimeField(auto_now_add=True)),
],
options={
'db_table': 'accounting_products',
'ordering': ['name'],
},
),
migrations.CreateModel(
name='Voucher',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('number', models.PositiveIntegerField(default=0)),
('date', models.DateField()),
('description', models.TextField(blank=True, default='')),
('status', models.CharField(choices=[('draft', 'Draft'), ('posted', 'Posted')], default='draft', max_length=20)),
('source', models.CharField(blank=True, db_index=True, default='', max_length=120)),
('created_at', models.DateTimeField(auto_now_add=True)),
],
options={
'db_table': 'accounting_vouchers',
'ordering': ['-date', '-number'],
},
),
migrations.CreateModel(
name='VoucherLine',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('description', models.CharField(blank=True, default='', max_length=255)),
('debit', models.FloatField(default=0)),
('credit', models.FloatField(default=0)),
('account', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='voucher_lines', to='accounting.account')),
('voucher', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='lines', to='accounting.voucher')),
],
options={
'db_table': 'accounting_voucher_lines',
},
),
migrations.CreateModel(
name='TreasuryTxn',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('number', models.PositiveIntegerField(default=0)),
('kind', models.CharField(choices=[('receipt', 'Receipt'), ('payment', 'Payment')], max_length=20)),
('method', models.CharField(choices=[('cash', 'Cash'), ('bank', 'Bank'), ('cheque', 'Cheque')], default='bank', max_length=20)),
('date', models.DateField()),
('amount', models.FloatField(default=0)),
('reference', models.CharField(blank=True, default='', max_length=120)),
('description', models.TextField(blank=True, default='')),
('created_at', models.DateTimeField(auto_now_add=True)),
('party', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='treasury_txns', to='accounting.party')),
],
options={
'db_table': 'accounting_treasury_txns',
'ordering': ['-date', '-number'],
},
),
migrations.CreateModel(
name='Payslip',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('period', models.CharField(blank=True, default='', max_length=20)),
('base_salary', models.FloatField(default=0)),
('overtime', models.FloatField(default=0)),
('bonus', models.FloatField(default=0)),
('deductions', models.FloatField(default=0)),
('insurance', models.FloatField(default=0)),
('tax', models.FloatField(default=0)),
('created_at', models.DateTimeField(auto_now_add=True)),
('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='payslips', to='accounting.employee')),
],
options={
'db_table': 'accounting_payslips',
'ordering': ['-period'],
},
),
migrations.CreateModel(
name='InvoiceLine',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('quantity', models.FloatField(default=0)),
('unit_price', models.FloatField(default=0)),
('discount', models.FloatField(default=0)),
('tax_rate', models.FloatField(default=0)),
('invoice', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='lines', to='accounting.invoice')),
('product', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='invoice_lines', to='accounting.product')),
],
options={
'db_table': 'accounting_invoice_lines',
},
),
migrations.AddField(
model_name='invoice',
name='party',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='invoices', to='accounting.party'),
),
migrations.CreateModel(
name='CompanySettings',
fields=[
('id', models.PositiveSmallIntegerField(default=1, primary_key=True, serialize=False)),
('name', models.CharField(blank=True, default='', max_length=150)),
('economic_code', models.CharField(blank=True, default='', max_length=50)),
('fiscal_year', models.CharField(blank=True, default='', max_length=20)),
('base_currency', models.CharField(blank=True, default='تومان', max_length=20)),
('tax_rate', models.FloatField(default=0)),
('address', models.TextField(blank=True, default='')),
('phone', models.CharField(blank=True, default='', max_length=40)),
('bank_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='accounting.account')),
('customer_payable_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='accounting.account')),
('owner_payable_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='accounting.account')),
('owner_share_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='accounting.account')),
('sales_income_account', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='accounting.account')),
],
options={
'db_table': 'accounting_company_settings',
},
),
]

View File

@@ -0,0 +1,27 @@
from django.db import migrations
from accounting.seeding import seed_default_data
def seed(apps, schema_editor):
Account = apps.get_model('accounting', 'Account')
CompanySettings = apps.get_model('accounting', 'CompanySettings')
seed_default_data(Account, CompanySettings)
def unseed(apps, schema_editor):
Account = apps.get_model('accounting', 'Account')
CompanySettings = apps.get_model('accounting', 'CompanySettings')
CompanySettings.objects.all().delete()
Account.objects.all().delete()
class Migration(migrations.Migration):
dependencies = [
('accounting', '0001_initial'),
]
operations = [
migrations.RunPython(seed, unseed),
]

View File

@@ -0,0 +1 @@