add finance app

This commit is contained in:
behruz-dev
2025-08-04 13:35:22 +05:00
parent 1dffabde44
commit bb8fbd4ca7
32 changed files with 336 additions and 69 deletions

View File

@@ -27,6 +27,7 @@ APPS = [
'core.apps.products', 'core.apps.products',
'core.apps.projects', 'core.apps.projects',
'core.apps.orders', 'core.apps.orders',
'core.apps.finance',
] ]
PACKAGES = [ PACKAGES = [

View File

@@ -20,6 +20,7 @@ urlpatterns = [
path('projects/', include('core.apps.projects.urls')), path('projects/', include('core.apps.projects.urls')),
path('products/', include('core.apps.products.urls')), path('products/', include('core.apps.products.urls')),
path('orders/', include('core.apps.orders.urls')), path('orders/', include('core.apps.orders.urls')),
path('finance/', include('core.apps.finance.urls')),
] ]
)), )),

View File

View File

@@ -0,0 +1 @@
from .cash_transaction import *

View File

@@ -0,0 +1,9 @@
from django.contrib import admin
from core.apps.finance.models import CashTransaction
@admin.register(CashTransaction)
class CachTransaction(admin.ModelAdmin):
list_display = ['id', 'name']
search_fields = ['name']

View File

@@ -0,0 +1,6 @@
from django.apps import AppConfig
class FinanceConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'core.apps.finance'

View File

@@ -0,0 +1,28 @@
# Generated by Django 5.2.4 on 2025-08-04 11:58
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='CashTransaction',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('name', models.CharField(max_length=200, unique=True)),
],
options={
'verbose_name': 'Kassa',
'verbose_name_plural': 'Kassalar',
},
),
]

View File

View File

@@ -0,0 +1 @@
from .cash_transaction import *

View File

@@ -0,0 +1,16 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from core.apps.shared.models import BaseModel
class CashTransaction(BaseModel):
name = models.CharField(max_length=200, unique=True)
def __str__(self):
return self.name
class Meta:
verbose_name = _('Kassa')
verbose_name_plural = _('Kassalar')

View File

@@ -0,0 +1,11 @@
from rest_framework import serializers
from core.apps.finance.models import CashTransaction
class CashTransactionListSerializer(serializers.ModelSerializer):
class Meta:
model = CashTransaction
fields = [
'id', 'name'
]

12
core/apps/finance/urls.py Normal file
View File

@@ -0,0 +1,12 @@
from django.urls import path, include
from core.apps.finance.views import cash_transaction as cash_views
urlpatterns = [
path('cash_transaction/', include(
[
path('list/', cash_views.CashTransactionListApiView.as_view()),
]
))
]

View File

View File

@@ -0,0 +1,14 @@
from rest_framework import generics
from core.apps.finance.models import CashTransaction
from core.apps.finance.serializers import cash_transaction as serializers
from core.apps.accounts.permissions.permissions import HasRolePermission
from core.apps.shared.paginations.custom import CustomPageNumberPagination
class CashTransactionListApiView(generics.ListAPIView):
permission_classes = [HasRolePermission]
required_permissions = []
serializer_class = serializers.CashTransactionListSerializer
queryset = CashTransaction.objects.all()
pagination_class = CustomPageNumberPagination

View File

@@ -0,0 +1,29 @@
# Generated by Django 5.2.4 on 2025-08-04 11:12
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('orders', '0003_delete_orderapplication'),
('projects', '0003_alter_project_folder'),
]
operations = [
migrations.RemoveField(
model_name='order',
name='project_department',
),
migrations.AddField(
model_name='order',
name='project_folder',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='order', to='projects.projectfolder'),
),
migrations.AlterField(
model_name='order',
name='project',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='orders', to='projects.project'),
),
]

View File

@@ -3,7 +3,7 @@ from django.utils.translation import gettext_lazy as _
from core.apps.shared.models import BaseModel from core.apps.shared.models import BaseModel
from core.apps.products.models import Product, Unity from core.apps.products.models import Product, Unity
from core.apps.projects.models import Project, ProjectDepartment from core.apps.projects.models import Project, ProjectFolder
from core.apps.accounts.models import User from core.apps.accounts.models import User
from core.apps.wherehouse.models import WhereHouse from core.apps.wherehouse.models import WhereHouse
@@ -21,11 +21,11 @@ class Order(BaseModel):
unity = models.ForeignKey( unity = models.ForeignKey(
Unity, on_delete=models.CASCADE, related_name='orders' Unity, on_delete=models.CASCADE, related_name='orders'
) )
project = models.ForeignKey( project_folder = models.ForeignKey(
Project, on_delete=models.CASCADE, related_name='orders' ProjectFolder, on_delete=models.CASCADE, related_name='order', null=True
) )
project_department = models.ForeignKey( project = models.ForeignKey(
ProjectDepartment, on_delete=models.DO_NOTHING, null=True, blank=True Project, on_delete=models.SET_NULL, related_name='orders', null=True, blank=True
) )
wherehouse = models.ForeignKey( wherehouse = models.ForeignKey(
WhereHouse, on_delete=models.CASCADE, related_name='orders' WhereHouse, on_delete=models.CASCADE, related_name='orders'

View File

@@ -11,11 +11,8 @@ from core.apps.products.serializers.unity import UnityListSerializer
from core.apps.wherehouse.models import WhereHouse from core.apps.wherehouse.models import WhereHouse
from core.apps.wherehouse.serializers.wherehouse import WhereHouseListSerializer from core.apps.wherehouse.serializers.wherehouse import WhereHouseListSerializer
# projects # projects
from core.apps.projects.models import Project, ProjectDepartment from core.apps.projects.models import Project, ProjectFolder
from core.apps.projects.serializers.project import ( from core.apps.projects.serializers.project import ProjectListSerializer
ProjectListSerializer,
ProjectDepartmentListSerializer
)
@@ -24,8 +21,8 @@ class OrderCreateSerializer(serializers.Serializer):
unity_id = serializers.UUIDField() unity_id = serializers.UUIDField()
quantity = serializers.IntegerField() quantity = serializers.IntegerField()
wherehouse_id = serializers.UUIDField() wherehouse_id = serializers.UUIDField()
project_id = serializers.UUIDField() project_id = serializers.UUIDField(required=False)
project_department_id = serializers.UUIDField(required=False) project_folder_id = serializers.UUIDField()
date = serializers.DateField() date = serializers.DateField()
def validate(self, data): def validate(self, data):
@@ -33,10 +30,10 @@ class OrderCreateSerializer(serializers.Serializer):
product = Product.objects.get(id=data['product_id']) product = Product.objects.get(id=data['product_id'])
unity = Unity.objects.get(id=data['unity_id']) unity = Unity.objects.get(id=data['unity_id'])
wherehouse = WhereHouse.objects.get(id=data['wherehouse_id']) wherehouse = WhereHouse.objects.get(id=data['wherehouse_id'])
project = Project.objects.get(id=data['project_id']) project_folder = ProjectFolder.objects.get(id=data['project_folder_id'])
if data.get('project_department_id'): if data.get('project_id'):
ProjectDepartment.objects.get( Project.objects.get(
id=data['project_department_id'] id=data['project_id']
) )
except Product.DoesNotExist: except Product.DoesNotExist:
raise serializers.ValidationError("Product not found") raise serializers.ValidationError("Product not found")
@@ -44,18 +41,18 @@ class OrderCreateSerializer(serializers.Serializer):
raise serializers.ValidationError("Unity not found") raise serializers.ValidationError("Unity not found")
except WhereHouse.DoesNotExist: except WhereHouse.DoesNotExist:
raise serializers.ValidationError("Where House not found") raise serializers.ValidationError("Where House not found")
except ProjectFolder.DoesNotExist:
raise serializers.ValidationError("Project Folder not found")
try:
if data.get('project_id'):
data['project'] = Project.objects.get(id=data['project_id'])
except Project.DoesNotExist: except Project.DoesNotExist:
raise serializers.ValidationError("Project not found") raise serializers.ValidationError("Project not found")
try:
if data.get('project_department_id'):
data['project_department'] = ProjectDepartment.objects.get(id=data['project_department_id'])
except ProjectDepartment.DoesNotExist:
raise serializers.ValidationError("Project Department not found")
data['product'] = product data['product'] = product
data['unity'] = unity data['unity'] = unity
data['wherehouse'] = wherehouse data['wherehouse'] = wherehouse
data['project'] = project data['project_folder'] = project_folder
return data return data
def create(self, validated_data): def create(self, validated_data):
@@ -64,8 +61,8 @@ class OrderCreateSerializer(serializers.Serializer):
product=validated_data.get('product'), product=validated_data.get('product'),
unity=validated_data.get('unity'), unity=validated_data.get('unity'),
wherehouse=validated_data.get('wherehouse'), wherehouse=validated_data.get('wherehouse'),
project_folder=validated_data.get('project_folder'),
project=validated_data.get('project'), project=validated_data.get('project'),
project_department=validated_data.get('project_department'),
quantity=validated_data.get('quantity'), quantity=validated_data.get('quantity'),
date=validated_data.get('date') date=validated_data.get('date')
) )
@@ -76,12 +73,12 @@ class OrderListSerializer(serializers.ModelSerializer):
product = ProductListSerializer() product = ProductListSerializer()
unity = UnityListSerializer() unity = UnityListSerializer()
project = ProjectListSerializer() project = ProjectListSerializer()
project_department = ProjectDepartmentListSerializer()
wherehouse = WhereHouseListSerializer() wherehouse = WhereHouseListSerializer()
project_folder = ProjectFolder()
class Meta: class Meta:
model = Order model = Order
fields = [ fields = [
'id', 'product', 'unity', 'quantity', 'project', 'project_department', 'id', 'product', 'unity', 'quantity', 'project', 'project_folder',
'wherehouse', 'date', 'status', 'employee' 'wherehouse', 'date', 'status', 'employee'
] ]

View File

@@ -10,7 +10,7 @@ from core.apps.shared.paginations.custom import CustomPageNumberPagination
class OrderListApiView(generics.ListAPIView): class OrderListApiView(generics.ListAPIView):
serializer_class = serializers.OrderListSerializer serializer_class = serializers.OrderListSerializer
queryset = Order.objects.select_related( queryset = Order.objects.select_related(
'product', 'unity', 'project', 'project_department', 'wherehouse' 'product', 'unity', 'project', 'project_folder', 'wherehouse'
) )
permission_classes = [HasRolePermission] permission_classes = [HasRolePermission]
required_permissions = [] required_permissions = []

View File

@@ -1 +1,2 @@
from .project import * from .project import *
from .builder import *

View File

@@ -0,0 +1,9 @@
from django.contrib import admin
from core.apps.projects.models import Builder
@admin.register(Builder)
class BuilderAdmin(admin.ModelAdmin):
list_display = ['id', 'name']

View File

@@ -1,24 +1,14 @@
from django.contrib import admin from django.contrib import admin
from core.apps.projects.models.project import ProjectDepartment, Project, ProjectFolder from core.apps.projects.models.project import Project, ProjectFolder
class ProjectDepartmentInline(admin.TabularInline):
model = ProjectDepartment
extra = 0
@admin.register(Project) @admin.register(Project)
class ProjectAdmin(admin.ModelAdmin): class ProjectAdmin(admin.ModelAdmin):
list_display = ['name', 'location', 'start_date', 'end_date'] list_display = ['name', 'location', 'start_date', 'end_date']
search_fields = ['name'] search_fields = ['name']
inlines = [ProjectDepartmentInline] inlines = []
@admin.register(ProjectDepartment)
class ProjectDepartmentAdmin(admin.ModelAdmin):
list_display = ['name', 'project']
search_fields = ['name']
@admin.register(ProjectFolder) @admin.register(ProjectFolder)

View File

@@ -0,0 +1,17 @@
# Generated by Django 5.2.4 on 2025-08-04 11:12
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('orders', '0004_remove_order_project_department_order_project_folder_and_more'),
('projects', '0003_alter_project_folder'),
]
operations = [
migrations.DeleteModel(
name='ProjectDepartment',
),
]

View File

@@ -0,0 +1,77 @@
# Generated by Django 5.2.4 on 2025-08-04 11:58
import django.db.models.deletion
import uuid
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('finance', '0001_initial'),
('projects', '0004_delete_projectdepartment'),
('wherehouse', '0002_stockmovemend'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Builder',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False, unique=True)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('name', models.CharField(max_length=200, unique=True)),
],
options={
'verbose_name': 'Quruvchi',
'verbose_name_plural': 'Quruvchilar',
},
),
migrations.AddField(
model_name='project',
name='area',
field=models.PositiveBigIntegerField(null=True),
),
migrations.AddField(
model_name='project',
name='benifit_plan',
field=models.PositiveBigIntegerField(null=True),
),
migrations.AddField(
model_name='project',
name='boss',
field=models.ManyToManyField(related_name='project_bosses', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='project',
name='cash_transaction',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='projects', to='finance.cashtransaction'),
),
migrations.AddField(
model_name='project',
name='currency',
field=models.CharField(choices=[('usd', 'usd'), ('uzs', 'uzs')], default='uzs', max_length=3),
),
migrations.AddField(
model_name='project',
name='foreman',
field=models.ManyToManyField(related_name='project_foremans', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='project',
name='other_members',
field=models.ManyToManyField(related_name='project_members', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='project',
name='wherehouse',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='projects', to='wherehouse.wherehouse'),
),
migrations.AddField(
model_name='project',
name='builder',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='projects', to='projects.builder'),
),
]

View File

@@ -1 +1,2 @@
from .project import * from .project import *
from .builder import *

View File

@@ -0,0 +1,15 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from core.apps.shared.models import BaseModel
class Builder(BaseModel):
name = models.CharField(max_length=200, unique=True)
def __str__(self):
return self.name
class Meta:
verbose_name = _('Quruvchi')
verbose_name_plural = _('Quruvchilar')

View File

@@ -2,6 +2,10 @@ from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from core.apps.shared.models import BaseModel from core.apps.shared.models import BaseModel
from core.apps.projects.models.builder import Builder
from core.apps.accounts.models.user import User
from core.apps.wherehouse.models.wherehouse import WhereHouse
from core.apps.finance.models import CashTransaction
class ProjectFolder(BaseModel): class ProjectFolder(BaseModel):
@@ -23,6 +27,25 @@ class Project(BaseModel):
folder = models.ForeignKey( folder = models.ForeignKey(
ProjectFolder, on_delete=models.SET_NULL, null=True, blank=True, related_name='projects' ProjectFolder, on_delete=models.SET_NULL, null=True, blank=True, related_name='projects'
) )
builder = models.ForeignKey(
Builder, on_delete=models.CASCADE, related_name='projects', null=True
)
area = models.PositiveBigIntegerField(null=True)
# project workers
boss = models.ManyToManyField(User, related_name='project_bosses')
foreman = models.ManyToManyField(User, related_name='project_foremans')
other_members = models.ManyToManyField(User, related_name='project_members')
# project settings
wherehouse = models.ForeignKey(
WhereHouse, on_delete=models.CASCADE, related_name='projects', null=True
)
cash_transaction = models.ForeignKey(
CashTransaction, on_delete=models.CASCADE, related_name='projects', null=True
)
currency = models.CharField(choices=[('usd', 'usd'),('uzs','uzs')], max_length=3, default='uzs')
benifit_plan = models.PositiveBigIntegerField(null=True)
def __str__(self): def __str__(self):
return self.name return self.name
@@ -30,17 +53,3 @@ class Project(BaseModel):
class Meta: class Meta:
verbose_name = _('Loyiha') verbose_name = _('Loyiha')
verbose_name_plural = _('Loyihalar') verbose_name_plural = _('Loyihalar')
class ProjectDepartment(BaseModel):
project = models.ForeignKey(
Project, on_delete=models.CASCADE, related_name='project_departments'
)
name = models.CharField(max_length=200)
def __str__(self):
return self.name
class Meta:
verbose_name = _("Loyiha Bo'limi")
verbose_name_plural = _("Loyiha Bo'limlari")

View File

@@ -0,0 +1,9 @@
from rest_framework import serializers
from core.apps.projects.models import Builder
class BuilderListSerializer(serializers.ModelSerializer):
class Meta:
model = Builder
fields = ['id', 'name']

View File

@@ -2,15 +2,7 @@ from django.db import transaction
from rest_framework import serializers from rest_framework import serializers
from core.apps.projects.models.project import Project, ProjectDepartment, ProjectFolder from core.apps.projects.models.project import Project, ProjectFolder
class ProjectDepartmentListSerializer(serializers.ModelSerializer):
class Meta:
model = ProjectDepartment
fields = [
'id', 'name'
]
class ProjectListSerializer(serializers.ModelSerializer): class ProjectListSerializer(serializers.ModelSerializer):
@@ -22,12 +14,10 @@ class ProjectListSerializer(serializers.ModelSerializer):
class ProjectDetailSerialzier(serializers.ModelSerializer): class ProjectDetailSerialzier(serializers.ModelSerializer):
project_departments = ProjectDepartmentListSerializer(many=True)
class Meta: class Meta:
model = Project model = Project
fields = [ fields = [
'id', 'name', 'location', 'start_date', 'end_date', 'project_departments' 'id', 'name', 'location', 'start_date', 'end_date',
] ]

View File

@@ -1,6 +1,7 @@
from django.urls import path, include from django.urls import path, include
from core.apps.projects.views import project as project_views from core.apps.projects.views import project as project_views
from core.apps.projects.views import builder as builder_views
urlpatterns = [ urlpatterns = [
path('project/', include( path('project/', include(
@@ -16,5 +17,10 @@ urlpatterns = [
path('list/', project_views.ProjectFolderListApiView.as_view()), path('list/', project_views.ProjectFolderListApiView.as_view()),
path('create/project/', project_views.ProjectFolderCreateProjectApiView.as_view()), path('create/project/', project_views.ProjectFolderCreateProjectApiView.as_view()),
] ]
)),
path('builder/', include(
[
path('list/', builder_views.BuilderListApiView.as_view()),
]
)) ))
] ]

View File

@@ -0,0 +1,17 @@
from rest_framework import generics
from core.apps.projects.models import Builder
from core.apps.projects.serializers import builder as serializers
from core.apps.accounts.permissions.permissions import HasRolePermission
from core.apps.shared.paginations.custom import CustomPageNumberPagination
class BuilderListApiView(generics.ListAPIView):
serializer_class = serializers.BuilderListSerializer
queryset = Builder.objects.all()
permission_classes = [HasRolePermission]
required_permissions = []
pagination_class = CustomPageNumberPagination

View File

@@ -1,7 +1,7 @@
from rest_framework import generics, status from rest_framework import generics, status
from rest_framework.response import Response from rest_framework.response import Response
from core.apps.projects.models.project import Project, ProjectDepartment, ProjectFolder from core.apps.projects.models.project import Project, ProjectFolder
from core.apps.projects.serializers import project as serializers from core.apps.projects.serializers import project as serializers
from core.apps.accounts.permissions.permissions import HasRolePermission from core.apps.accounts.permissions.permissions import HasRolePermission
from core.apps.shared.paginations.custom import CustomPageNumberPagination from core.apps.shared.paginations.custom import CustomPageNumberPagination
@@ -17,7 +17,7 @@ class ProjectListApiView(generics.ListAPIView):
class ProjectDetailApiView(generics.RetrieveAPIView): class ProjectDetailApiView(generics.RetrieveAPIView):
serializer_class = serializers.ProjectDetailSerialzier serializer_class = serializers.ProjectDetailSerialzier
queryset = Project.objects.prefetch_related('project_departments') queryset = Project.objects.all()
permission_classes = [HasRolePermission] permission_classes = [HasRolePermission]
required_permissions = [] required_permissions = []
lookup_field = 'id' lookup_field = 'id'