add new api

This commit is contained in:
behruz-dev
2025-08-25 15:56:09 +05:00
parent 74ecc581ae
commit 30e0e3462f
15 changed files with 108 additions and 61 deletions

View File

@@ -0,0 +1,3 @@
from .celery import app as celery_app
__all__ = ['celery_app']

View File

@@ -1,11 +1,10 @@
import os import os
from celery import Celery from celery import Celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.base') os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.base')
app = Celery('config') app = Celery('config', broker="redis://redis:6379", backend="redis://redis:6379")
app.config_from_object('django.conf:settings', namespace='CELERY') app.config_from_object('django.conf:settings', namespace='CELERY')
app.autodiscover_tasks() app.autodiscover_tasks()

View File

@@ -1,6 +1,9 @@
from django.conf import settings from django.conf import settings
CELERY_BROKER_URL = 'redis://redis:6379/0' CELERY_BROKER_URL = 'redis://redis:6379'
CELERY_RESULT_BACKEND = "redis://redis:6379"
CELERY_ACCEPT_CONTENT = ['json'] CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json' CELERY_TASK_SERIALIZER = 'json'
CELERY_TIMEZONE = settings.TIME_ZONE CELERY_TIMEZONE = settings.TIME_ZONE
CELERY_ENABLED = True

View File

@@ -25,13 +25,13 @@ JAZZMIN_SETTINGS = {
"show_sidebar": True, "show_sidebar": True,
"navigation_expanded": True, "navigation_expanded": True,
"hide_apps": [], "hide_apps": [],
"hide_models": ["auth.Group"], "hide_models": ["auth.Group"],
"order_with_respect_to": ["auth"], "order_with_respect_to": ["auth"],
"custom_links": { "custom_links": {
"books": [{ "books": [{
"name": "Make Messages", "name": "Make Messages",
"url": "make_messages", "url": "make_messages",
"icon": "fas fa-comments", "icon": "fas fa-comments",
"permissions": ["books.view_book"] "permissions": ["books.view_book"]
}] }]
@@ -45,11 +45,10 @@ JAZZMIN_SETTINGS = {
"default_icon_parents": "fas fa-chevron-circle-right", "default_icon_parents": "fas fa-chevron-circle-right",
"default_icon_children": "fas fa-circle", "default_icon_children": "fas fa-circle",
"related_modal_active": True,
"use_google_fonts_cdn": True, "use_google_fonts_cdn": True,
"show_ui_builder": False, "show_ui_builder": False,
"changeform_format": "collapsible", "changeform_format": "collapsible",
"language_chooser": False, "language_chooser": False,
} }

View File

@@ -1,7 +1,7 @@
CACHES = { CACHES = {
"default": { "default": {
"BACKEND": 'django_redis.cache.RedisCache', "BACKEND": 'django_redis.cache.RedisCache',
"LOCATION": 'redis://redis:6379', "LOCATION": 'redis://redis:6379z',
"TIMEOUT": 300, "TIMEOUT": 300,
}, },
} }

View File

@@ -38,7 +38,6 @@ PACKAGES = [
'rest_framework_simplejwt', 'rest_framework_simplejwt',
'corsheaders', 'corsheaders',
'cacheops', 'cacheops',
# 'silk',
] ]
DJANGO_APPS = [ DJANGO_APPS = [
@@ -100,7 +99,6 @@ DATABASES = {
'PASSWORD': env.str('POSTGRES_PASSWORD'), 'PASSWORD': env.str('POSTGRES_PASSWORD'),
'HOST': env.str('POSTGRES_HOST'), 'HOST': env.str('POSTGRES_HOST'),
'PORT': env.str('POSTGRES_PORT'), 'PORT': env.str('POSTGRES_PORT'),
'CONN_MAX_AGE': 0
} }
} }
@@ -159,5 +157,5 @@ from config.conf.logs import *
from config.conf.cors_headers import * from config.conf.cors_headers import *
from config.conf.drf_yasg import * from config.conf.drf_yasg import *
from config.conf.jazzmin import * from config.conf.jazzmin import *
from config.conf.redis import * from config.conf.celery import *
from config.conf.celery import * from config.conf.redis import *

View File

@@ -81,8 +81,6 @@ class MultipleOrderCreateSerializer(serializers.Serializer):
date=common_date, date=common_date,
employee=self.context.get('user'), employee=self.context.get('user'),
)) ))
create_inventory.delay(resource['wherehouse'],resource['quantity'],resource)
created_orders = Order.objects.bulk_create(orders) created_orders = Order.objects.bulk_create(orders)
return created_orders return created_orders

View File

@@ -6,6 +6,7 @@ from core.apps.orders.models import Party, PartyAmount, Order, DeletedParty
from core.apps.orders.serializers.order import MultipleOrderAddSerializer, OrderListSerializer from core.apps.orders.serializers.order import MultipleOrderAddSerializer, OrderListSerializer
from core.apps.accounts.models import User from core.apps.accounts.models import User
from core.apps.counterparty.serializers.counterparty import CounterpartyListPartySerializer from core.apps.counterparty.serializers.counterparty import CounterpartyListPartySerializer
from core.apps.orders.tasks.order import create_inventory
from core.apps.shared.models import UsdCourse from core.apps.shared.models import UsdCourse
from core.apps.products.models import Product, Unity from core.apps.products.models import Product, Unity
from core.apps.projects.models import Project, ProjectFolder from core.apps.projects.models import Project, ProjectFolder
@@ -33,7 +34,7 @@ class PartyCreateSerializer(serializers.Serializer):
raise serializers.ValidationError("User not found") raise serializers.ValidationError("User not found")
data['user'] = user data['user'] = user
return data return data
def create(self, validated_data): def create(self, validated_data):
with transaction.atomic(): with transaction.atomic():
resources = validated_data.pop('resources') resources = validated_data.pop('resources')
@@ -50,12 +51,13 @@ class PartyCreateSerializer(serializers.Serializer):
quantity=resource.get('quantity'), quantity=resource.get('quantity'),
unit_amount=resource.get('unit_amount'), unit_amount=resource.get('unit_amount'),
currency=resource.get('currency'), currency=resource.get('currency'),
amount=resource.get('amount'), amount=resource.get('amount'),
employee=self.context.get('user'), employee=self.context.get('user'),
qqs_price=resource.get('qqs_price'), qqs_price=resource.get('qqs_price'),
total_price=resource.get('total_price'), total_price=resource.get('total_price'),
qqs=resource.get('qqs'), qqs=resource.get('qqs'),
)) ))
create_inventory.delay(resource['wherehouse_id'], resource['quantity'], resource['product_id'], resource['unity_id'], resource['total_price'])
if validated_data.get('currency') == 'uzs': if validated_data.get('currency') == 'uzs':
if resource.get('currency') == 'usd': if resource.get('currency') == 'usd':
usd_value = UsdCourse.objects.first().value usd_value = UsdCourse.objects.first().value
@@ -129,7 +131,7 @@ class PartyListSerializer(serializers.ModelSerializer):
'id': obj.mediator.id, 'id': obj.mediator.id,
'full_name': obj.mediator.full_name 'full_name': obj.mediator.full_name
} }
def get_counterparty(self, obj): def get_counterparty(self, obj):
counterparties = obj.orders.values("counterparty__id", "counterparty__name").distinct() counterparties = obj.orders.values("counterparty__id", "counterparty__name").distinct()
counterparties = [ counterparties = [
@@ -155,7 +157,7 @@ class DeletedPartyCreateSerializer(serializers.Serializer):
comment=validated_data.get('comment'), comment=validated_data.get('comment'),
party=validated_data.get('party') party=validated_data.get('party')
) )
class DeletedPartyListSerializer(serializers.ModelSerializer): class DeletedPartyListSerializer(serializers.ModelSerializer):
party_number = serializers.IntegerField(source='party.number') party_number = serializers.IntegerField(source='party.number')
@@ -167,13 +169,13 @@ class DeletedPartyListSerializer(serializers.ModelSerializer):
fields = [ fields = [
'id', 'deleted_date', 'party_number', 'party_total_price', 'mediator' 'id', 'deleted_date', 'party_number', 'party_total_price', 'mediator'
] ]
def get_mediator(self, obj): def get_mediator(self, obj):
return { return {
'id': obj.party.mediator.id, 'id': obj.party.mediator.id,
'name': obj.party.mediator.full_name 'name': obj.party.mediator.full_name
} }
class PartyOrderUpdateSerializer(serializers.Serializer): class PartyOrderUpdateSerializer(serializers.Serializer):
order_id = serializers.UUIDField() order_id = serializers.UUIDField()
@@ -214,7 +216,7 @@ class PartyOrderUpdateSerializer(serializers.Serializer):
counterparty = Counterparty.objects.filter(id=data['counterparty_id']).first() counterparty = Counterparty.objects.filter(id=data['counterparty_id']).first()
if not counterparty: if not counterparty:
raise serializers.ValidationError(f"Counterparty not found on {order.id}") raise serializers.ValidationError(f"Counterparty not found on {order.id}")
data['order'] = order data['order'] = order
data['product'] = product data['product'] = product
data['unity'] = unity data['unity'] = unity
@@ -234,12 +236,12 @@ class PartyUpdateSerializer(serializers.ModelSerializer):
] ]
extra_kwargs = { extra_kwargs = {
'mediator': {'required': False}, 'mediator': {'required': False},
'delivery_date': {'required': False}, 'delivery_date': {'required': False},
'payment_date': {'required':False}, 'payment_date': {'required':False},
'comment': {'required': False}, 'comment': {'required': False},
'audit': {'required': False}, 'audit': {'required': False},
'audit_comment': {'required': False}, 'audit_comment': {'required': False},
'discount': {'required': False}, 'discount': {'required': False},
'discount_currency': {'required': False}, 'discount_currency': {'required': False},
} }
@@ -251,7 +253,7 @@ class PartyUpdateSerializer(serializers.ModelSerializer):
instance.delivery_date = validated_data.get('delivery_date', instance.delivery_date) instance.delivery_date = validated_data.get('delivery_date', instance.delivery_date)
instance.payment_date = validated_data.get('payment_date', instance.payment_date) instance.payment_date = validated_data.get('payment_date', instance.payment_date)
instance.save() instance.save()
for order_data in orders_data: for order_data in orders_data:
order = order_data['order'] order = order_data['order']
order.product = order_data['product'] order.product = order_data['product']
@@ -266,22 +268,22 @@ class PartyUpdateSerializer(serializers.ModelSerializer):
order.project_folder = order_data['project_folder'] order.project_folder = order_data['project_folder']
if 'project' in order_data: if 'project' in order_data:
order.project = order_data['project'] order.project = order_data['project']
update_orders.append(order) update_orders.append(order)
Order.objects.bulk_update( Order.objects.bulk_update(
update_orders, update_orders,
fields=[ fields=[
'product', 'product',
'unity', 'unity',
'wherehouse', 'wherehouse',
'counterparty', 'counterparty',
'quantity', 'quantity',
'unit_amount', 'unit_amount',
'currency', 'currency',
'total_price', 'total_price',
'project_folder', 'project_folder',
'project' 'project'
] ]
) )
return instance return instance

View File

@@ -6,9 +6,9 @@ from core.apps.wherehouse.models.inventory import Inventory
@shared_task @shared_task
def create_inventory(wherehouse, quantity, product, unity, price): def create_inventory(wherehouse, quantity, product, unity, price):
Inventory.objects.create( Inventory.objects.create(
wherehouse__id=wherehouse, wherehouse_id=wherehouse,
quantity=quantity, quantity=quantity,
product__id=product, product_id=product,
unity__id=unity, unity_id=unity,
price=price price=price
) )

View File

@@ -3,9 +3,9 @@ from rest_framework import serializers
from core.apps.wherehouse.models.inventory import Inventory from core.apps.wherehouse.models.inventory import Inventory
class WhereHouseInventoryListSerializer(serializers.ModelSerializer): class InventoryListSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Inventory model = Inventory
fields = [ fields = [
'id', 'quantity', 'product' 'id', 'quantity', 'product', 'price', 'unity'
] ]

View File

@@ -3,7 +3,7 @@ from django.db import transaction
from rest_framework import serializers from rest_framework import serializers
from core.apps.wherehouse.models.wherehouse import WhereHouse from core.apps.wherehouse.models.wherehouse import WhereHouse
from core.apps.wherehouse.serializers.inventory import WhereHouseInventoryListSerializer from core.apps.wherehouse.serializers.inventory import InventoryListSerializer
from core.apps.company.serializers.branch import BranchListSerializer from core.apps.company.serializers.branch import BranchListSerializer
from core.apps.company.models import Branch from core.apps.company.models import Branch
@@ -39,7 +39,7 @@ class WhereHouseCreateSerializer(serializers.Serializer):
raise serializers.ValidationError("Branch not found") raise serializers.ValidationError("Branch not found")
data['branch'] = branch data['branch'] = branch
return data return data
def create(self, validated_data): def create(self, validated_data):
with transaction.atomic(): with transaction.atomic():
return WhereHouse.objects.create( return WhereHouse.objects.create(
@@ -55,10 +55,10 @@ class WhereHouseUpdateSerializer(serializers.ModelSerializer):
fields = [ fields = [
'name', 'address', 'branch' 'name', 'address', 'branch'
] ]
def update(self, instance, validated_data): def update(self, instance, validated_data):
instance.name = validated_data.get('name', instance.name) instance.name = validated_data.get('name', instance.name)
instance.address = validated_data.get('address', instance.address) instance.address = validated_data.get('address', instance.address)
instance.branch = validated_data.get('branch', instance.branch) instance.branch = validated_data.get('branch', instance.branch)
instance.save() instance.save()
return instance return instance

View File

@@ -1,6 +1,7 @@
from django.urls import path, include from django.urls import path, include
from core.apps.wherehouse.views import wherehouse as wherehouse_views from core.apps.wherehouse.views import wherehouse as wherehouse_views
from core.apps.wherehouse.views import inventory as inventory_views
urlpatterns = [ urlpatterns = [
@@ -13,4 +14,9 @@ urlpatterns = [
path('<uuid:id>/update/', wherehouse_views.WhereHouseUpdateApiView.as_view()), path('<uuid:id>/update/', wherehouse_views.WhereHouseUpdateApiView.as_view()),
] ]
)), )),
] path('inventory/', include(
[
path('<uuid:wherehouse_id>/list/', inventory_views.InventoryListApiView.as_view()),
]
)),
]

View File

@@ -0,0 +1,25 @@
from django.shortcuts import get_object_or_404
from rest_framework import generics, views
from rest_framework.response import Response
from core.apps.wherehouse.serializers import inventory as serializers
from core.apps.wherehouse.models import WhereHouse, Inventory
from core.apps.accounts.permissions.permissions import HasRolePermission
class InventoryListApiView(generics.GenericAPIView):
serializer_class = serializers.InventoryListSerializer
queryset = Inventory.objects.all()
permissions_class = [HasRolePermission]
required_permissions = ['wherehouse']
def get(self, request, wherehouse_id):
wherehouse = get_object_or_404(WhereHouse, id=wherehouse_id)
inventories = Inventory.objects.filter(wherehouse=wherehouse)
page = self.paginate_queryset(inventories)
if page is not None:
serializer = self.serializer_class(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.serializer_class(inventories, many=True)
return Response(serializer.data, status=200)

View File

@@ -50,8 +50,6 @@ services:
networks: networks:
- uyqur - uyqur
image: redis image: redis
ports:
- "6380:6379"
celery: celery:
build: build:
@@ -64,4 +62,7 @@ services:
- redis - redis
- web - web
networks: networks:
- uyqur - uyqur
environment:
- CELERY_BROKER_URL=redis://redis:6379/0
- CELERY_RESULT_BACKEND=redis://redis:6379/0

View File

@@ -1,13 +1,26 @@
FROM python:3.13-alpine FROM python:3.12
ENV PYTHONPYCACHEPREFIX=/dev/null
RUN apk update && apk add git gettext
WORKDIR /code WORKDIR /code
COPY requirements.txt /code/requirements.txt RUN apt-get update && \
apt-get install -y \
gdal-bin \
libgdal-dev \
python3-gdal \
libgeos-dev \
libproj-dev \
g++ \
make \
wget \
libfontconfig \
libxrender1 \
libjpeg-dev \
xfonts-base && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN --mount=type=cache,target=/root/.cache/pip pip install -r requirements.txt
CMD ["sh", "./entrypoint.sh"] COPY ./ /code
RUN --mount=type=cache,target=/root/.cache/pip python3 -m pip install -r requirements.txt
CMD ["sh", "./resources/scripts/entrypoint.sh"]