From f757e429069fec068211abd23ad94d9f8829d3a1 Mon Sep 17 00:00:00 2001 From: behruz-dev Date: Fri, 1 Aug 2025 16:36:27 +0500 Subject: [PATCH] add orders app and add new model on products --- config/settings/base.py | 1 + config/urls.py | 1 + core/apps/orders/__init__.py | 0 core/apps/orders/admin/__init__.py | 1 + core/apps/orders/admin/order.py | 14 ++++ core/apps/orders/apps.py | 10 +++ core/apps/orders/migrations/0001_initial.py | 55 +++++++++++++++ core/apps/orders/migrations/__init__.py | 0 core/apps/orders/models/__init__.py | 1 + core/apps/orders/models/order.py | 54 +++++++++++++++ core/apps/orders/serializers/__init__.py | 0 core/apps/orders/serializers/order.py | 75 +++++++++++++++++++++ core/apps/orders/urls.py | 11 +++ core/apps/orders/views/__init__.py | 0 core/apps/orders/views/order.py | 18 +++++ core/apps/products/admin/__init__.py | 3 +- core/apps/products/admin/unity.py | 9 +++ core/apps/products/migrations/0003_unity.py | 27 ++++++++ core/apps/products/models/__init__.py | 3 +- core/apps/products/models/unity.py | 15 +++++ core/apps/products/serializers/unity.py | 9 +++ core/apps/products/urls.py | 9 ++- core/apps/products/views/unity.py | 13 ++++ 23 files changed, 326 insertions(+), 3 deletions(-) create mode 100644 core/apps/orders/__init__.py create mode 100644 core/apps/orders/admin/__init__.py create mode 100644 core/apps/orders/admin/order.py create mode 100644 core/apps/orders/apps.py create mode 100644 core/apps/orders/migrations/0001_initial.py create mode 100644 core/apps/orders/migrations/__init__.py create mode 100644 core/apps/orders/models/__init__.py create mode 100644 core/apps/orders/models/order.py create mode 100644 core/apps/orders/serializers/__init__.py create mode 100644 core/apps/orders/serializers/order.py create mode 100644 core/apps/orders/urls.py create mode 100644 core/apps/orders/views/__init__.py create mode 100644 core/apps/orders/views/order.py create mode 100644 core/apps/products/admin/unity.py create mode 100644 core/apps/products/migrations/0003_unity.py create mode 100644 core/apps/products/models/unity.py create mode 100644 core/apps/products/serializers/unity.py create mode 100644 core/apps/products/views/unity.py diff --git a/config/settings/base.py b/config/settings/base.py index 6d0e12c..26b3ffb 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -26,6 +26,7 @@ APPS = [ 'core.apps.wherehouse', 'core.apps.products', 'core.apps.projects', + 'core.apps.orders', ] PACKAGES = [ diff --git a/config/urls.py b/config/urls.py index e832e4c..509ec93 100644 --- a/config/urls.py +++ b/config/urls.py @@ -19,6 +19,7 @@ urlpatterns = [ path('wherehouses/', include('core.apps.wherehouse.urls')), path('projects/', include('core.apps.projects.urls')), path('products/', include('core.apps.products.urls')), + path('orders/', include('core.apps.orders.urls')), ] )), diff --git a/core/apps/orders/__init__.py b/core/apps/orders/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/apps/orders/admin/__init__.py b/core/apps/orders/admin/__init__.py new file mode 100644 index 0000000..5c48881 --- /dev/null +++ b/core/apps/orders/admin/__init__.py @@ -0,0 +1 @@ +from .order import * \ No newline at end of file diff --git a/core/apps/orders/admin/order.py b/core/apps/orders/admin/order.py new file mode 100644 index 0000000..a7f69c5 --- /dev/null +++ b/core/apps/orders/admin/order.py @@ -0,0 +1,14 @@ +from django.contrib import admin + +from core.apps.orders.models import Order, OrderApplication + + +@admin.register(Order) +class OrderAdmin(admin.ModelAdmin): + list_display = ['quantity', 'product', 'unity', 'project', 'wherehouse'] + list_display = ['unity', 'project', 'wherehouse'] + + +@admin.register(OrderApplication) +class OrderApplicationAdmin(admin.ModelAdmin): + list_display = ['employee', 'status'] diff --git a/core/apps/orders/apps.py b/core/apps/orders/apps.py new file mode 100644 index 0000000..4250ca1 --- /dev/null +++ b/core/apps/orders/apps.py @@ -0,0 +1,10 @@ +from django.apps import AppConfig + + +class OrdersConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'core.apps.orders' + + def ready(self): + from . import admin + \ No newline at end of file diff --git a/core/apps/orders/migrations/0001_initial.py b/core/apps/orders/migrations/0001_initial.py new file mode 100644 index 0000000..3b4581b --- /dev/null +++ b/core/apps/orders/migrations/0001_initial.py @@ -0,0 +1,55 @@ +# Generated by Django 5.2.4 on 2025-08-01 16:05 + +import django.db.models.deletion +import uuid +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('products', '0003_unity'), + ('projects', '0001_initial'), + ('wherehouse', '0002_stockmovemend'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Order', + 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)), + ('date', models.DateField()), + ('quantity', models.PositiveBigIntegerField(default=1)), + ('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to='products.product')), + ('project', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to='projects.project')), + ('project_department', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='projects.projectdepartment')), + ('unity', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to='products.unity')), + ('wherehouse', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='orders', to='wherehouse.wherehouse')), + ], + options={ + 'verbose_name': 'Buyurtma', + 'verbose_name_plural': 'Buyurtmalar', + }, + ), + migrations.CreateModel( + name='OrderApplication', + 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)), + ('status', models.CharField(choices=[('NEW', 'yangi'), ('CANCELLED', 'bekor qilindi'), ('ACCEPTED', 'qabul qilindi')], max_length=20)), + ('employee', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='applications', to=settings.AUTH_USER_MODEL)), + ('orders', models.ManyToManyField(related_name='applications', to='orders.order')), + ], + options={ + 'verbose_name': 'Ariza', + 'verbose_name_plural': 'Arizalar', + }, + ), + ] diff --git a/core/apps/orders/migrations/__init__.py b/core/apps/orders/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/apps/orders/models/__init__.py b/core/apps/orders/models/__init__.py new file mode 100644 index 0000000..5c48881 --- /dev/null +++ b/core/apps/orders/models/__init__.py @@ -0,0 +1 @@ +from .order import * \ No newline at end of file diff --git a/core/apps/orders/models/order.py b/core/apps/orders/models/order.py new file mode 100644 index 0000000..c6726c6 --- /dev/null +++ b/core/apps/orders/models/order.py @@ -0,0 +1,54 @@ +from django.db import models +from django.utils.translation import gettext_lazy as _ + +from core.apps.shared.models import BaseModel +from core.apps.products.models import Product, Unity +from core.apps.projects.models import Project, ProjectDepartment +from core.apps.accounts.models import User +from core.apps.wherehouse.models import WhereHouse + + +class Order(BaseModel): + product = models.ForeignKey( + Product, on_delete=models.CASCADE, related_name='orders' + ) + unity = models.ForeignKey( + Unity, on_delete=models.CASCADE, related_name='orders' + ) + project = models.ForeignKey( + Project, on_delete=models.CASCADE, related_name='orders' + ) + project_department = models.ForeignKey( + ProjectDepartment, on_delete=models.DO_NOTHING, null=True, blank=True + ) + wherehouse = models.ForeignKey( + WhereHouse, on_delete=models.CASCADE, related_name='orders' + ) + date = models.DateField() + quantity = models.PositiveBigIntegerField(default=1) + + def __str__(self): + return f"{self.product} {self.unity} quantity order" + + class Meta: + verbose_name = _("Buyurtma") + verbose_name_plural = _("Buyurtmalar") + + +class OrderApplication(BaseModel): + STATUS = ( + ('NEW', 'yangi'), + ('CANCELLED', "bekor qilindi"), + ('ACCEPTED', 'qabul qilindi'), + ) + + orders = models.ManyToManyField(Order, related_name="applications") + employee = models.ForeignKey(User, on_delete=models.CASCADE, related_name='applications') + status = models.CharField(max_length=20, choices=STATUS) + + def __str__(self): + return f"{self.employee} application" + + class Meta: + verbose_name = _("Ariza") + verbose_name_plural = _("Arizalar") \ No newline at end of file diff --git a/core/apps/orders/serializers/__init__.py b/core/apps/orders/serializers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/apps/orders/serializers/order.py b/core/apps/orders/serializers/order.py new file mode 100644 index 0000000..d3339d8 --- /dev/null +++ b/core/apps/orders/serializers/order.py @@ -0,0 +1,75 @@ +from django.db import transaction + +from rest_framework import serializers + +from core.apps.orders.models import Order, OrderApplication +from core.apps.products.models import Product, Unity +from core.apps.wherehouse.models import WhereHouse +from core.apps.projects.models import Project, ProjectDepartment + + +class OrderCreateSerializer(serializers.Serializer): + product_id = serializers.UUIDField() + unity_id = serializers.UUIDField() + quantity = serializers.IntegerField() + wherehouse_id = serializers.UUIDField() + project_id = serializers.UUIDField() + project_department_id = serializers.UUIDField(required=False) + date = serializers.DateField() + + def validate(self, data): + try: + product = Product.objects.get(id=data['product_id']) + unity = Unity.objects.get(id=data['unity_id']) + wherehouse = WhereHouse.objects.get(id=data['wherehouse_id']) + project = Project.objects.get(id=data['project_id']) + if data.get('project_department_id'): + project_department = ProjectDepartment.objects.get( + id=data['project_department_id'] + ) + except Product.DoesNotExist: + raise serializers.ValidationError("Product not found") + except Unity.DoesNotExist: + raise serializers.ValidationError("Unity not found") + except WhereHouse.DoesNotExist: + raise serializers.ValidationError("Where House not found") + except Project.DoesNotExist: + 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['unity'] = unity + data['wherehouse'] = wherehouse + data['project'] = project + return data + + +class OrderApplicationCreateSerializer(serializers.Serializer): + orders = serializers.ListSerializer(child=OrderCreateSerializer()) + + def create(self, validated_data): + employee = self.context.get('user') + orders_data = validated_data.pop('orders') + application = OrderApplication.objects.create( + employee=employee, status="NEW" + ) + + order_objs = [] + for order_data in orders_data: + order_objs.append(Order( + product=order_data['product'], + unity=order_data['unity'], + quantity=order_data['quantity'], + wherehouse=order_data['wherehouse'], + project=order_data['project'], + project_department=order_data.get('project_department'), + date=order_data['date'] + )) + + created_orders = Order.objects.bulk_create(order_objs) + application.orders.add(*created_orders) + return application \ No newline at end of file diff --git a/core/apps/orders/urls.py b/core/apps/orders/urls.py new file mode 100644 index 0000000..11e200e --- /dev/null +++ b/core/apps/orders/urls.py @@ -0,0 +1,11 @@ +from django.urls import path, include + +from core.apps.orders.views import order as order_views + +urlpatterns = [ + path('order_application/', include( + [ + path('create/', order_views.OrderApplicationCreateApiView.as_view()), + ] + )), +] \ No newline at end of file diff --git a/core/apps/orders/views/__init__.py b/core/apps/orders/views/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/core/apps/orders/views/order.py b/core/apps/orders/views/order.py new file mode 100644 index 0000000..dbb3e0b --- /dev/null +++ b/core/apps/orders/views/order.py @@ -0,0 +1,18 @@ +from rest_framework import generics, response +from rest_framework.response import Response + +from core.apps.orders.models import Order, OrderApplication +from core.apps.orders.serializers import order as serializers +from core.apps.accounts.permissions.permissions import HasRolePermission + + +class OrderApplicationCreateApiView(generics.CreateAPIView): + serializer_class = serializers.OrderApplicationCreateSerializer + queryset = OrderApplication.objects.all() + permission_classes = [HasRolePermission] + required_permissions = [] + + def get_serializer_context(self): + context = super().get_serializer_context() + context['user'] = self.request.user + return context \ No newline at end of file diff --git a/core/apps/products/admin/__init__.py b/core/apps/products/admin/__init__.py index 610e401..ba3c14a 100644 --- a/core/apps/products/admin/__init__.py +++ b/core/apps/products/admin/__init__.py @@ -1 +1,2 @@ -from .product import * \ No newline at end of file +from .product import * +from .unity import * \ No newline at end of file diff --git a/core/apps/products/admin/unity.py b/core/apps/products/admin/unity.py new file mode 100644 index 0000000..be7a78d --- /dev/null +++ b/core/apps/products/admin/unity.py @@ -0,0 +1,9 @@ +from django.contrib import admin + +from core.apps.products.models.unity import Unity + + +@admin.register(Unity) +class UnityAdmin(admin.ModelAdmin): + list_display = ['value'] + search_fields = ['value'] \ No newline at end of file diff --git a/core/apps/products/migrations/0003_unity.py b/core/apps/products/migrations/0003_unity.py new file mode 100644 index 0000000..8f50ae1 --- /dev/null +++ b/core/apps/products/migrations/0003_unity.py @@ -0,0 +1,27 @@ +# Generated by Django 5.2.4 on 2025-08-01 16:05 + +import uuid +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('products', '0002_alter_product_options'), + ] + + operations = [ + migrations.CreateModel( + name='Unity', + 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)), + ('value', models.CharField(max_length=50)), + ], + options={ + 'verbose_name': 'Birlik', + 'verbose_name_plural': 'Birliklar', + }, + ), + ] diff --git a/core/apps/products/models/__init__.py b/core/apps/products/models/__init__.py index 610e401..ba3c14a 100644 --- a/core/apps/products/models/__init__.py +++ b/core/apps/products/models/__init__.py @@ -1 +1,2 @@ -from .product import * \ No newline at end of file +from .product import * +from .unity import * \ No newline at end of file diff --git a/core/apps/products/models/unity.py b/core/apps/products/models/unity.py new file mode 100644 index 0000000..7ac63c1 --- /dev/null +++ b/core/apps/products/models/unity.py @@ -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 Unity(BaseModel): + value = models.CharField(max_length=50) + + def __str__(self): + return self.value + + class Meta: + verbose_name = _('Birlik') + verbose_name_plural = _("Birliklar") \ No newline at end of file diff --git a/core/apps/products/serializers/unity.py b/core/apps/products/serializers/unity.py new file mode 100644 index 0000000..f716d4a --- /dev/null +++ b/core/apps/products/serializers/unity.py @@ -0,0 +1,9 @@ +from rest_framework import serializers + +from core.apps.products.models import Unity + + +class UnityListSerializer(serializers.ModelSerializer): + class Meta: + model = Unity + fields = ['id', 'value'] \ No newline at end of file diff --git a/core/apps/products/urls.py b/core/apps/products/urls.py index e101b31..b4a2ac0 100644 --- a/core/apps/products/urls.py +++ b/core/apps/products/urls.py @@ -1,11 +1,18 @@ from django.urls import path, include from core.apps.products.views import product as product_views +from core.apps.products.views import unity as unity_views + urlpatterns = [ path('product/', include( [ path('list/', product_views.ProductListApiView.as_view()), ] - )) + )), + path('unity/', include( + [ + path('list/', unity_views.UnityListApiView.as_view()), + ] + )), ] \ No newline at end of file diff --git a/core/apps/products/views/unity.py b/core/apps/products/views/unity.py new file mode 100644 index 0000000..f49192f --- /dev/null +++ b/core/apps/products/views/unity.py @@ -0,0 +1,13 @@ +from rest_framework import generics, status +from rest_framework.response import Response + +from core.apps.products.models import Unity +from core.apps.products.serializers import unity as serializers +from core.apps.accounts.permissions.permissions import HasRolePermission + + +class UnityListApiView(generics.ListAPIView): + serializer_class = serializers.UnityListSerializer + queryset = Unity.objects.all() + permission_classes = [HasRolePermission] + required_permissions = [] \ No newline at end of file