Merge pull request #24 from xoliqberdiyev/test

Test
This commit is contained in:
xolikberdiyev
2025-10-28 16:04:24 +05:00
committed by GitHub
15 changed files with 266 additions and 97 deletions

View File

@@ -30,6 +30,7 @@ APPS = [
'core.apps.orders', 'core.apps.orders',
'core.apps.finance', 'core.apps.finance',
'core.apps.counterparty', 'core.apps.counterparty',
'core.apps.notifications',
] ]
PACKAGES = [ PACKAGES = [

View File

@@ -35,6 +35,7 @@ urlpatterns = [
path('orders/', include('core.apps.orders.urls')), path('orders/', include('core.apps.orders.urls')),
path('finance/', include('core.apps.finance.urls')), path('finance/', include('core.apps.finance.urls')),
path('counterparties/', include('core.apps.counterparty.urls')), path('counterparties/', include('core.apps.counterparty.urls')),
path('notifications/', include('core.apps.notifications.urls')),
] ]
)), )),

View File

View File

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

View File

@@ -0,0 +1,31 @@
# Generated by Django 5.2.4 on 2025-10-28 15:45
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 = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Notification',
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)),
('token', models.CharField(max_length=255, unique=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to=settings.AUTH_USER_MODEL)),
],
options={
'abstract': False,
},
),
]

View File

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

View File

@@ -0,0 +1,9 @@
from django.db import models
from core.apps.shared.models import BaseModel
from core.apps.accounts.models import User
class Notification(BaseModel):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='notifications')
token = models.CharField(max_length=255, unique=True)

View File

@@ -0,0 +1,11 @@
from rest_framework import serializers
from core.apps.notifications.models import Notification
class NotificationSerializer(serializers.ModelSerializer):
class Meta:
model = Notification
fields = [
'token'
]

View File

@@ -0,0 +1,7 @@
from django.urls import path
from core.apps.notifications.views import notification
urlpatterns = [
path('device/register/', notification.RegisterExpoPushToken.as_view()),
]

View File

@@ -0,0 +1,8 @@
from core.apps.notifications.models import Notification
from core.apps.notifications.utils.send_notification import send_notification
def notify_user(user, title, body):
tokens = Notification.objects.filter(user=user)
for token in tokens:
send_notification(token.token, title, body)

View File

@@ -0,0 +1,16 @@
import requests
def send_notification(token, title, body, data=None):
message = {
"to": token,
"sound": "default",
"title": title,
"body": body,
"data": data or {},
}
response = requests.post(
"https://exp.host/--/api/v2/push/send",
json=message,
headers={"Content-Type": "application/json"}
)
return response.json()

View File

@@ -0,0 +1,20 @@
from rest_framework import generics, status
from rest_framework.response import Response
from core.apps.notifications.serializers import notification as serializers
from core.apps.notifications.models import Notification
class RegisterExpoPushToken(generics.GenericAPIView):
serializer_class = serializers.NotificationSerializer
queryset = Notification.objects.all()
def post(self, request):
serializer = self.serializer_class(data=request.data)
if serializer.is_valid():
Notification.objects.update_or_create(
user=request.user,
token=serializer.validated_data['token']
)
return Response({"message": "Token saqlandi"}, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

View File

@@ -16,6 +16,8 @@ from core.apps.projects.models import Project, ProjectFolder
from core.apps.projects.serializers.project import ProjectListSerializer, ProjectFolderListSerializer from core.apps.projects.serializers.project import ProjectListSerializer, ProjectFolderListSerializer
# counterparty # counterparty
from core.apps.counterparty.models import Counterparty from core.apps.counterparty.models import Counterparty
# notifications
from core.apps.notifications.utils.notify_user import notify_user
class OrderCreateSerializer(serializers.Serializer): class OrderCreateSerializer(serializers.Serializer):
@@ -71,7 +73,7 @@ class MultipleOrderCreateSerializer(serializers.Serializer):
orders = [] orders = []
for resource in resources: for resource in resources:
orders.append(Order( order = Order(
product=resource['product'], product=resource['product'],
unity=resource['unity'], unity=resource['unity'],
wherehouse=resource['wherehouse'], wherehouse=resource['wherehouse'],
@@ -80,8 +82,16 @@ class MultipleOrderCreateSerializer(serializers.Serializer):
quantity=resource['quantity'], quantity=resource['quantity'],
date=common_date, date=common_date,
employee=self.context.get('user'), employee=self.context.get('user'),
)) )
orders.append(order)
body = f"""
{user.full_name} {order.project_folder.name} uchun {order.wherehouse.name} ombor ga {order.quantity} {order.unity.value} {order.product.name} ga buyurtma berdi. Buyurtma
yetkazish sanasi {common_date}
"""
notify_user(user=self.context.get("user"), title="Ta'minot",body=body)
created_orders = Order.objects.bulk_create(orders) created_orders = Order.objects.bulk_create(orders)
user = self.context.get('user')
return created_orders return created_orders

View File

@@ -1,10 +1,14 @@
from django.db import transaction from django.db import transaction
from rest_framework import serializers from rest_framework import serializers
from core.apps.wherehouse.models import StockMovemend, StockMovmendProduct, Inventory, WhereHouse from core.apps.products.models import Product, Unity
from core.apps.products.models import Unity, Product from core.apps.projects.models import Project, ProjectFolder
from core.apps.projects.models import ProjectFolder, Project from core.apps.wherehouse.models import (
Inventory,
StockMovemend,
StockMovmendProduct,
WhereHouse,
)
class StockMovmendProductSerializer(serializers.Serializer): class StockMovmendProductSerializer(serializers.Serializer):
@@ -12,10 +16,10 @@ class StockMovmendProductSerializer(serializers.Serializer):
quantity = serializers.IntegerField() quantity = serializers.IntegerField()
def validate(self, data): def validate(self, data):
inventory = Inventory.objects.filter(id=data['inventory_id']).first() inventory = Inventory.objects.filter(id=data["inventory_id"]).first()
if not inventory: if not inventory:
raise serializers.ValidationError("Inventory not found") raise serializers.ValidationError("Inventory not found")
data['inventory'] = inventory data["inventory"] = inventory
return data return data
@@ -29,117 +33,150 @@ class StockMovmendCreateSerializer(serializers.Serializer):
comment = serializers.CharField(required=False) comment = serializers.CharField(required=False)
def validate(self, data): def validate(self, data):
if data.get('project_folder_id'): if data.get("project_folder_id"):
project_folder = ProjectFolder.objects.filter(id=data['project_folder_id']).first() project_folder = ProjectFolder.objects.filter(
id=data["project_folder_id"]
).first()
if not project_folder: if not project_folder:
raise serializers.ValidationError("Project Folder not found") raise serializers.ValidationError("Project Folder not found")
data['project_folder'] = project_folder data["project_folder"] = project_folder
if data.get('project_id'): if data.get("project_id"):
project = Project.objects.filter(id=data['project_id']).first() project = Project.objects.filter(id=data["project_id"]).first()
if not project: if not project:
raise serializers.ValidationError("Project not found") raise serializers.ValidationError("Project not found")
data['project'] = project data["project"] = project
wherehouse_to = WhereHouse.objects.filter(id=data['wherehouse_to_id']).first() wherehouse_to = WhereHouse.objects.filter(id=data["wherehouse_to_id"]).first()
if not wherehouse_to: if not wherehouse_to:
raise serializers.ValidationError("WhereHouse to not found") raise serializers.ValidationError("WhereHouse to not found")
wherehouse_from = WhereHouse.objects.filter(id=data['wherehouse_from_id']).first() wherehouse_from = WhereHouse.objects.filter(
id=data["wherehouse_from_id"]
).first()
if not wherehouse_from: if not wherehouse_from:
raise serializers.ValidationError("WhereHouse from not found") raise serializers.ValidationError("WhereHouse from not found")
data['wherehouse_to'] = wherehouse_to data["wherehouse_to"] = wherehouse_to
data['wherehouse_from'] = wherehouse_from data["wherehouse_from"] = wherehouse_from
return data return data
def create(self, validated_data): def create(self, validated_data):
with transaction.atomic(): with transaction.atomic():
products = validated_data.pop('products') products = validated_data.pop("products")
stock_movemend = StockMovemend.objects.create( stock_movemend = StockMovemend.objects.create(
project_folder=validated_data.get('project_folder'), project_folder=validated_data.get("project_folder"),
project=validated_data.get('project'), project=validated_data.get("project"),
date=validated_data.get('date'), date=validated_data.get("date"),
comment=validated_data.get('comment'), comment=validated_data.get("comment"),
wherehouse_to=validated_data.get('wherehouse_to'), wherehouse_to=validated_data.get("wherehouse_to"),
wherehouse_from=validated_data.get('wherehouse_from'), wherehouse_from=validated_data.get("wherehouse_from"),
recipient=self.context.get('user'), recipient=self.context.get("user"),
) )
movmend_products = [] movmend_products = []
for product in products: for product in products:
movmend_products.append(StockMovmendProduct( movmend_products.append(
inventory=product.get('inventory'), StockMovmendProduct(
quantity=product.get('quantity'), inventory=product.get("inventory"),
stock_movemend=stock_movemend, quantity=product.get("quantity"),
)) stock_movemend=stock_movemend,
)
)
StockMovmendProduct.objects.bulk_create(movmend_products) StockMovmendProduct.objects.bulk_create(movmend_products)
return stock_movemend return stock_movemend
class StockMovemendProductListSerializer(serializers.ModelSerializer): class StockMovemendProductListSerializer(serializers.ModelSerializer):
product = serializers.SerializerMethodField(method_name='get_product') product = serializers.SerializerMethodField(method_name="get_product")
unity = serializers.SerializerMethodField(method_name='get_unity') unity = serializers.SerializerMethodField(method_name="get_unity")
class Meta: class Meta:
model = StockMovmendProduct model = StockMovmendProduct
fields = [ fields = ["id", "product", "unity", "quantity"]
'id', 'product', 'unity', 'quantity'
]
def get_product(self, obj): def get_product(self, obj):
return { return (
'id': obj.inventory.product.id, {
'type': obj.inventory.product.type, "id": obj.inventory.product.id,
'name': obj.inventory.product.name, "type": obj.inventory.product.type,
} "name": obj.inventory.product.name,
}
if obj.inventory.product
else None
)
def get_unity(self, obj): def get_unity(self, obj):
return { return (
'id': obj.inventory.unity.id, {
'value': obj.inventory.unity.value, "id": obj.inventory.unity.id,
} "value": obj.inventory.unity.value,
}
if obj.inventory.unity
else None
)
class StockMovemendListSerializer(serializers.ModelSerializer): class StockMovemendListSerializer(serializers.ModelSerializer):
movemend_products = StockMovemendProductListSerializer(many=True) movemend_products = StockMovemendProductListSerializer(many=True)
wherehouse_to = serializers.SerializerMethodField(method_name='get_wherehouse_to') wherehouse_to = serializers.SerializerMethodField(method_name="get_wherehouse_to")
wherehouse_from = serializers.SerializerMethodField(method_name='get_wherehouse_from') wherehouse_from = serializers.SerializerMethodField(
recipient = serializers.SerializerMethodField(method_name='get_recipient') method_name="get_wherehouse_from"
project_folder = serializers.SerializerMethodField(method_name='get_project_folder') )
project = serializers.SerializerMethodField(method_name='get_project') recipient = serializers.SerializerMethodField(method_name="get_recipient")
project_folder = serializers.SerializerMethodField(method_name="get_project_folder")
project = serializers.SerializerMethodField(method_name="get_project")
class Meta: class Meta:
model = StockMovemend model = StockMovemend
fields = [ fields = [
'id', 'number', 'wherehouse_to', 'wherehouse_from', 'recipient', 'project_folder', "id",
'project', 'movemend_type', 'date', 'comment', 'movemend_products' "number",
"wherehouse_to",
"wherehouse_from",
"recipient",
"project_folder",
"project",
"movemend_type",
"date",
"comment",
"movemend_products",
] ]
def get_wherehouse_to(self, obj): def get_wherehouse_to(self, obj):
return { return (
'id': obj.wherehouse_to.id, {
'name': obj.wherehouse_to.name, "id": obj.wherehouse_to.id,
} "name": obj.wherehouse_to.name,
}
if obj.wherehouse_to
else None
)
def get_wherehouse_from(self, obj): def get_wherehouse_from(self, obj):
return { return (
'id': obj.wherehouse_from.id, {
'name': obj.wherehouse_from.name, "id": obj.wherehouse_from.id,
} "name": obj.wherehouse_from.name,
}
if obj.wherehouse_from
else None
)
def get_recipient(self, obj): def get_recipient(self, obj):
return { return (
'id': obj.recipient.id, {
'full_name': obj.recipient.full_name, "id": obj.recipient.id,
} if obj.recipient else None "full_name": obj.recipient.full_name,
}
if obj.recipient
else None
)
def get_project_folder(self, obj): def get_project_folder(self, obj):
return { return (
'id': obj.project_folder.id, {"id": obj.project_folder.id, "name": obj.project_folder.name}
'name': obj.project_folder.name if obj.project_folder
} else None
)
def get_project(self, obj): def get_project(self, obj):
return { return {"id": obj.project.id, "name": obj.project.name} if obj.project else None
'id': obj.project.id,
'name': obj.project.name
} if obj.project else None
class StockMovemendProductUpdateSerializer(serializers.Serializer): class StockMovemendProductUpdateSerializer(serializers.Serializer):
@@ -147,12 +184,16 @@ class StockMovemendProductUpdateSerializer(serializers.Serializer):
quantity = serializers.IntegerField() quantity = serializers.IntegerField()
def validate(self, data): def validate(self, data):
movemend_product = StockMovmendProduct.objects.filter(id=data['movemend_product_id']).first() movemend_product = StockMovmendProduct.objects.filter(
id=data["movemend_product_id"]
).first()
if not movemend_product: if not movemend_product:
raise serializers.ValidationError("Stock Movemend Product not found") raise serializers.ValidationError("Stock Movemend Product not found")
if movemend_product.inventory.quantity < data['quantity']: if movemend_product.inventory.quantity < data["quantity"]:
raise serializers.ValidationError("invalid quantity, quantity must les than product quantity") raise serializers.ValidationError(
data['movemend_product'] = movemend_product "invalid quantity, quantity must les than product quantity"
)
data["movemend_product"] = movemend_product
return data return data
@@ -162,31 +203,38 @@ class StockMovemendUpdateSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = StockMovemend model = StockMovemend
fields = [ fields = [
'wherehouse_to', 'project_folder', 'project', 'date', "wherehouse_to",
'comment', 'movemend_products' "project_folder",
"project",
"date",
"comment",
"movemend_products",
] ]
extra_kwargs = {'wherehouse_to': {'required': False}} extra_kwargs = {"wherehouse_to": {"required": False}}
def update(self, instance, validated_data): def update(self, instance, validated_data):
with transaction.atomic(): with transaction.atomic():
instance.wherehouse_to = validated_data.get('wherehouse_to', instance.wherehouse_to) instance.wherehouse_to = validated_data.get(
instance.project_folder = validated_data.get('project_folder', instance.project_folder) "wherehouse_to", instance.wherehouse_to
instance.project = validated_data.get('project', instance.project) )
instance.date = validated_data.get('date', instance.date) instance.project_folder = validated_data.get(
instance.comment = validated_data.get('comment', instance.comment) "project_folder", instance.project_folder
)
instance.project = validated_data.get("project", instance.project)
instance.date = validated_data.get("date", instance.date)
instance.comment = validated_data.get("comment", instance.comment)
instance.save() instance.save()
movemend_products = validated_data.pop('movemend_products', []) movemend_products = validated_data.pop("movemend_products", [])
if movemend_products: if movemend_products:
updated_products = [] updated_products = []
for product_data in movemend_products: for product_data in movemend_products:
product = product_data['movemend_product'] product = product_data["movemend_product"]
product.quantity = product_data['quantity'] product.quantity = product_data["quantity"]
updated_products.append(product) updated_products.append(product)
StockMovmendProduct.objects.bulk_update( StockMovmendProduct.objects.bulk_update(
updated_products, updated_products, fields=["quantity"]
fields=['quantity']
) )
return instance return instance