-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f9fadb4
commit 778d644
Showing
6 changed files
with
451 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# Generated by Django 5.0.7 on 2024-09-12 07:27 | ||
|
||
import django.db.models.deletion | ||
from django.conf import settings | ||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [ | ||
('clients', '0001_initial'), | ||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='Application', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('created_at', models.DateTimeField(auto_now_add=True)), | ||
('updated_at', models.DateTimeField(auto_now=True)), | ||
('loan_type', models.CharField(choices=[('PERSONAL_LOAN', 'Personal Loan'), ('BUSINESS_LOAN', 'Business Loan'), ('MORTGAGE', 'Mortgage'), ('STUDENT_LOAN', 'Student Loan'), ('CAR_LOAN', 'Car Loan')], max_length=32)), | ||
('amount_requested', models.DecimalField(decimal_places=2, max_digits=12)), | ||
('currency', models.CharField(choices=[('USD', 'US Dollar'), ('UZS', 'Uzbekistani Som'), ('EUR', 'Euro')], default='UZS', max_length=3)), | ||
('application_date', models.DateField(auto_now_add=True)), | ||
('status', models.CharField(choices=[('PENDING', 'Pending'), ('APPROVED', 'Approved'), ('REJECTED', 'Rejected'), ('UNDER_REVIEW', 'Under Review'), ('DISBURSED', 'Disbursed')], default='PENDING', max_length=20)), | ||
('loan_purpose', models.TextField(blank=True, null=True)), | ||
('interest_rate', models.DecimalField(blank=True, decimal_places=2, max_digits=5, null=True)), | ||
('repayment_period_months', models.IntegerField(blank=True, null=True)), | ||
('reference_number', models.CharField(max_length=128, unique=True)), | ||
('approved_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='approved_applications', to=settings.AUTH_USER_MODEL)), | ||
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='applications', to='clients.client')), | ||
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='created_applications', to=settings.AUTH_USER_MODEL)), | ||
], | ||
options={ | ||
'verbose_name': 'Loan Application', | ||
'verbose_name_plural': 'Loan Applications', | ||
'ordering': ['-created_at'], | ||
}, | ||
), | ||
migrations.CreateModel( | ||
name='ApplicationSchedule', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('created_at', models.DateTimeField(auto_now_add=True)), | ||
('updated_at', models.DateTimeField(auto_now=True)), | ||
('due_date', models.DateField()), | ||
('installment_amount', models.DecimalField(decimal_places=2, max_digits=12)), | ||
('is_paid', models.BooleanField(default=False)), | ||
('application', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='schedules', to='applications.application')), | ||
], | ||
options={ | ||
'verbose_name': 'Application Schedule', | ||
'verbose_name_plural': 'Application Schedules', | ||
'ordering': ['due_date'], | ||
}, | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,87 @@ | ||
from django.db import models | ||
from apps.common.models import BaseModel | ||
from apps.clients.models import Client | ||
from apps.users.models import User | ||
|
||
# Create your models here. | ||
|
||
class ApplicationStatusChoices(models.TextChoices): | ||
PENDING = "PENDING", "Pending" | ||
APPROVED = "APPROVED", "Approved" | ||
REJECTED = "REJECTED", "Rejected" | ||
UNDER_REVIEW = "UNDER_REVIEW", "Under Review" | ||
DISBURSED = "DISBURSED", "Disbursed" | ||
|
||
|
||
class LoanTypeChoices(models.TextChoices): | ||
PERSONAL_LOAN = "PERSONAL_LOAN", "Personal Loan" | ||
BUSINESS_LOAN = "BUSINESS_LOAN", "Business Loan" | ||
MORTGAGE = "MORTGAGE", "Mortgage" | ||
STUDENT_LOAN = "STUDENT_LOAN", "Student Loan" | ||
CAR_LOAN = "CAR_LOAN", "Car Loan" | ||
|
||
|
||
class CurrencyChoices(models.TextChoices): | ||
USD = "USD", "US Dollar" | ||
UZS = "UZS", "Uzbekistani Som" | ||
EUR = "EUR", "Euro" | ||
|
||
|
||
class Application(BaseModel): | ||
client = models.ForeignKey( | ||
Client, on_delete=models.CASCADE, related_name="applications" | ||
) | ||
loan_type = models.CharField(max_length=32, choices=LoanTypeChoices.choices) | ||
amount_requested = models.DecimalField(max_digits=12, decimal_places=2) | ||
currency = models.CharField( | ||
max_length=3, choices=CurrencyChoices.choices, default=CurrencyChoices.UZS | ||
) | ||
|
||
application_date = models.DateField(auto_now_add=True) | ||
status = models.CharField( | ||
max_length=20, | ||
choices=ApplicationStatusChoices.choices, | ||
default=ApplicationStatusChoices.PENDING, | ||
) | ||
|
||
created_by = models.ForeignKey( | ||
User, on_delete=models.CASCADE, related_name="created_applications" | ||
) | ||
approved_by = models.ForeignKey( | ||
User, | ||
on_delete=models.CASCADE, | ||
related_name="approved_applications", | ||
blank=True, | ||
null=True, | ||
) | ||
|
||
loan_purpose = models.TextField(blank=True, null=True) | ||
interest_rate = models.DecimalField( | ||
max_digits=5, decimal_places=2, blank=True, null=True | ||
) | ||
repayment_period_months = models.IntegerField(blank=True, null=True) | ||
reference_number = models.CharField(max_length=128, unique=True) | ||
|
||
def __str__(self): | ||
return f"Application {self.reference_number} - {self.client} - {self.amount_requested} {self.currency}" | ||
|
||
class Meta: | ||
verbose_name = "Loan Application" | ||
verbose_name_plural = "Loan Applications" | ||
ordering = ["-created_at"] | ||
|
||
|
||
class ApplicationSchedule(BaseModel): | ||
application = models.ForeignKey( | ||
Application, on_delete=models.CASCADE, related_name="schedules" | ||
) | ||
due_date = models.DateField() | ||
installment_amount = models.DecimalField(max_digits=12, decimal_places=2) | ||
is_paid = models.BooleanField(default=False) | ||
|
||
def __str__(self): | ||
return f"Installment {self.id} for Application {self.application.reference_number} due on {self.due_date}" | ||
|
||
class Meta: | ||
verbose_name = "Application Schedule" | ||
verbose_name_plural = "Application Schedules" | ||
ordering = ["due_date"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# Generated by Django 5.0.7 on 2024-09-12 07:27 | ||
|
||
import django.db.models.deletion | ||
from django.conf import settings | ||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [ | ||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='Borrower', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('created_at', models.DateTimeField(auto_now_add=True)), | ||
('updated_at', models.DateTimeField(auto_now=True)), | ||
('borrower_type', models.CharField(choices=[('INDIVIDUAL', 'Individual'), ('COMPANY', 'Company')], max_length=32)), | ||
('full_name', models.CharField(max_length=255)), | ||
('date_of_birth', models.DateField(blank=True, null=True)), | ||
('identification_number', models.CharField(max_length=64, unique=True)), | ||
('contact_email', models.EmailField(blank=True, max_length=254, null=True)), | ||
('contact_phone', models.CharField(blank=True, max_length=20, null=True)), | ||
('address', models.TextField(blank=True, null=True)), | ||
('status', models.CharField(choices=[('ACTIVE', 'Active'), ('INACTIVE', 'Inactive'), ('BLACKLISTED', 'Blacklisted')], default='ACTIVE', max_length=32)), | ||
('approved_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='approved_borrowers', to=settings.AUTH_USER_MODEL)), | ||
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='created_borrowers', to=settings.AUTH_USER_MODEL)), | ||
], | ||
options={ | ||
'verbose_name': 'Borrower', | ||
'verbose_name_plural': 'Borrowers', | ||
'ordering': ['full_name'], | ||
}, | ||
), | ||
migrations.CreateModel( | ||
name='BorrowerDocument', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('created_at', models.DateTimeField(auto_now_add=True)), | ||
('updated_at', models.DateTimeField(auto_now=True)), | ||
('document_type', models.CharField(max_length=64)), | ||
('document_number', models.CharField(max_length=128)), | ||
('document_file', models.FileField(upload_to='borrower_documents/')), | ||
('expiration_date', models.DateField(blank=True, null=True)), | ||
('issued_date', models.DateField(blank=True, null=True)), | ||
('borrower', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documents', to='borrowers.borrower')), | ||
], | ||
options={ | ||
'verbose_name': 'Borrower Document', | ||
'verbose_name_plural': 'Borrower Documents', | ||
'ordering': ['document_type'], | ||
}, | ||
), | ||
migrations.CreateModel( | ||
name='BorrowerFinancialInfo', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('created_at', models.DateTimeField(auto_now_add=True)), | ||
('updated_at', models.DateTimeField(auto_now=True)), | ||
('annual_income', models.DecimalField(blank=True, decimal_places=2, max_digits=15, null=True)), | ||
('credit_score', models.IntegerField(blank=True, null=True)), | ||
('total_outstanding_debt', models.DecimalField(blank=True, decimal_places=2, max_digits=15, null=True)), | ||
('total_loans', models.IntegerField(default=0)), | ||
('borrower', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='financial_info', to='borrowers.borrower')), | ||
], | ||
options={ | ||
'verbose_name': 'Borrower Financial Info', | ||
'verbose_name_plural': 'Borrower Financial Infos', | ||
}, | ||
), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,91 @@ | ||
from django.db import models | ||
from apps.common.models import BaseModel | ||
from apps.users.models import User | ||
|
||
# Create your models here. | ||
|
||
class BorrowerTypeChoices(models.TextChoices): | ||
INDIVIDUAL = "INDIVIDUAL", "Individual" | ||
COMPANY = "COMPANY", "Company" | ||
|
||
|
||
class BorrowerStatusChoices(models.TextChoices): | ||
ACTIVE = "ACTIVE", "Active" | ||
INACTIVE = "INACTIVE", "Inactive" | ||
BLACKLISTED = "BLACKLISTED", "Blacklisted" | ||
|
||
|
||
class Borrower(BaseModel): | ||
borrower_type = models.CharField(max_length=32, choices=BorrowerTypeChoices.choices) | ||
full_name = models.CharField(max_length=255) # For both individuals and companies | ||
date_of_birth = models.DateField(blank=True, null=True) # Only for individuals | ||
identification_number = models.CharField( | ||
max_length=64, unique=True | ||
) # National ID, tax number, etc. | ||
contact_email = models.EmailField(blank=True, null=True) | ||
contact_phone = models.CharField(max_length=20, blank=True, null=True) | ||
address = models.TextField(blank=True, null=True) | ||
status = models.CharField( | ||
max_length=32, | ||
choices=BorrowerStatusChoices.choices, | ||
default=BorrowerStatusChoices.ACTIVE, | ||
) | ||
created_by = models.ForeignKey( | ||
User, on_delete=models.CASCADE, related_name="created_borrowers" | ||
) | ||
approved_by = models.ForeignKey( | ||
User, | ||
on_delete=models.CASCADE, | ||
related_name="approved_borrowers", | ||
blank=True, | ||
null=True, | ||
) | ||
|
||
def __str__(self): | ||
return f"{self.full_name} ({self.borrower_type})" | ||
|
||
class Meta: | ||
verbose_name = "Borrower" | ||
verbose_name_plural = "Borrowers" | ||
ordering = ["full_name"] | ||
|
||
|
||
class BorrowerFinancialInfo(BaseModel): | ||
borrower = models.OneToOneField( | ||
Borrower, on_delete=models.CASCADE, related_name="financial_info" | ||
) | ||
annual_income = models.DecimalField( | ||
max_digits=15, decimal_places=2, blank=True, null=True | ||
) # Can apply for both individuals and companies | ||
credit_score = models.IntegerField(blank=True, null=True) | ||
total_outstanding_debt = models.DecimalField( | ||
max_digits=15, decimal_places=2, blank=True, null=True | ||
) | ||
total_loans = models.IntegerField(default=0) | ||
|
||
def __str__(self): | ||
return f"Financial Info for {self.borrower.full_name}" | ||
|
||
class Meta: | ||
verbose_name = "Borrower Financial Info" | ||
verbose_name_plural = "Borrower Financial Infos" | ||
|
||
|
||
class BorrowerDocument(BaseModel): | ||
borrower = models.ForeignKey( | ||
Borrower, on_delete=models.CASCADE, related_name="documents" | ||
) | ||
document_type = models.CharField( | ||
max_length=64 | ||
) # E.g., Passport, Tax Document, Utility Bill, etc. | ||
document_number = models.CharField(max_length=128) | ||
document_file = models.FileField(upload_to="borrower_documents/") | ||
expiration_date = models.DateField(blank=True, null=True) | ||
issued_date = models.DateField(blank=True, null=True) | ||
|
||
def __str__(self): | ||
return f"{self.document_type} for {self.borrower.full_name}" | ||
|
||
class Meta: | ||
verbose_name = "Borrower Document" | ||
verbose_name_plural = "Borrower Documents" | ||
ordering = ["document_type"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# Generated by Django 5.0.7 on 2024-09-12 07:27 | ||
|
||
import django.db.models.deletion | ||
from django.conf import settings | ||
from django.db import migrations, models | ||
|
||
|
||
class Migration(migrations.Migration): | ||
|
||
initial = True | ||
|
||
dependencies = [ | ||
('clients', '0001_initial'), | ||
migrations.swappable_dependency(settings.AUTH_USER_MODEL), | ||
] | ||
|
||
operations = [ | ||
migrations.CreateModel( | ||
name='Loan', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('created_at', models.DateTimeField(auto_now_add=True)), | ||
('updated_at', models.DateTimeField(auto_now=True)), | ||
('loan_type', models.CharField(choices=[('PERSONAL_LOAN', 'Personal Loan'), ('BUSINESS_LOAN', 'Business Loan'), ('MORTGAGE', 'Mortgage'), ('STUDENT_LOAN', 'Student Loan'), ('CAR_LOAN', 'Car Loan')], max_length=32)), | ||
('amount_disbursed', models.DecimalField(decimal_places=2, max_digits=12)), | ||
('currency', models.CharField(choices=[('USD', 'US Dollar'), ('UZS', 'Uzbekistani Som'), ('EUR', 'Euro')], default='UZS', max_length=3)), | ||
('disbursement_date', models.DateField(auto_now_add=True)), | ||
('status', models.CharField(choices=[('ACTIVE', 'Active'), ('PAID_OFF', 'Paid Off'), ('DEFAULTED', 'Defaulted'), ('CLOSED', 'Closed'), ('UNDER_REVIEW', 'Under Review'), ('PENDING_DISBURSEMENT', 'Pending Disbursement')], default='PENDING_DISBURSEMENT', max_length=32)), | ||
('interest_rate', models.DecimalField(decimal_places=2, max_digits=5)), | ||
('repayment_period_months', models.IntegerField()), | ||
('total_amount_due', models.DecimalField(decimal_places=2, max_digits=12)), | ||
('reference_number', models.CharField(max_length=128, unique=True)), | ||
('approved_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='approved_loans', to=settings.AUTH_USER_MODEL)), | ||
('client', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='loans', to='clients.client')), | ||
('created_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='created_loans', to=settings.AUTH_USER_MODEL)), | ||
], | ||
options={ | ||
'verbose_name': 'Loan', | ||
'verbose_name_plural': 'Loans', | ||
'ordering': ['-created_at'], | ||
}, | ||
), | ||
migrations.CreateModel( | ||
name='LoanRepaymentSchedule', | ||
fields=[ | ||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||
('created_at', models.DateTimeField(auto_now_add=True)), | ||
('updated_at', models.DateTimeField(auto_now=True)), | ||
('due_date', models.DateField()), | ||
('installment_amount', models.DecimalField(decimal_places=2, max_digits=12)), | ||
('is_paid', models.BooleanField(default=False)), | ||
('loan', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='repayment_schedules', to='loans.loan')), | ||
], | ||
options={ | ||
'verbose_name': 'Loan Repayment Schedule', | ||
'verbose_name_plural': 'Loan Repayment Schedules', | ||
'ordering': ['due_date'], | ||
}, | ||
), | ||
] |
Oops, something went wrong.