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.finance',
'core.apps.counterparty',
'core.apps.notifications',
]
PACKAGES = [

View File

@@ -35,6 +35,7 @@ urlpatterns = [
path('orders/', include('core.apps.orders.urls')),
path('finance/', include('core.apps.finance.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
# counterparty
from core.apps.counterparty.models import Counterparty
# notifications
from core.apps.notifications.utils.notify_user import notify_user
class OrderCreateSerializer(serializers.Serializer):
@@ -71,7 +73,7 @@ class MultipleOrderCreateSerializer(serializers.Serializer):
orders = []
for resource in resources:
orders.append(Order(
order = Order(
product=resource['product'],
unity=resource['unity'],
wherehouse=resource['wherehouse'],
@@ -80,8 +82,16 @@ class MultipleOrderCreateSerializer(serializers.Serializer):
quantity=resource['quantity'],
date=common_date,
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)
user = self.context.get('user')
return created_orders

View File

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