339 lines
13 KiB
Python
339 lines
13 KiB
Python
from decimal import Decimal
|
|
# django
|
|
from django.shortcuts import get_object_or_404
|
|
from django.db.models import Sum, Q, F
|
|
from django.utils.timezone import now
|
|
|
|
# django rest framework
|
|
from rest_framework import generics, views
|
|
from rest_framework.response import Response
|
|
|
|
# django filters
|
|
from django_filters.rest_framework.backends import DjangoFilterBackend
|
|
|
|
# accounts app
|
|
from core.apps.accounts.permissions.permissions import HasRolePermission
|
|
# orders app
|
|
from core.apps.orders.serializers import party as serializers
|
|
from core.apps.orders.models import Party, DeletedParty
|
|
from core.apps.orders.filters.party import PartyFilter
|
|
from core.apps.orders.tasks.order import create_inventory
|
|
# finance app
|
|
from core.apps.finance.models import Expence
|
|
from core.apps.finance.serializers.expence import ExpenceListSerializer
|
|
# sharede
|
|
from core.apps.shared.models import UsdCourse
|
|
|
|
|
|
class PartyCreateApiView(generics.GenericAPIView):
|
|
serializer_class = serializers.PartyCreateSerializer
|
|
queryset = Party.objects.all()
|
|
permission_classes = [HasRolePermission]
|
|
|
|
def post(self, request):
|
|
serializer = self.serializer_class(data=request.data, context={'user': request.user})
|
|
if serializer.is_valid(raise_exception=True):
|
|
serializer.save()
|
|
return Response(
|
|
{'success': True, 'message': "party created"},
|
|
status=200
|
|
)
|
|
return Response(
|
|
{'success': False, 'message': 'error while party created', 'error': serializer.errors},
|
|
status=400
|
|
)
|
|
|
|
|
|
class PartyListApiView(generics.GenericAPIView):
|
|
serializer_class = serializers.PartyListSerializer
|
|
queryset = Party.objects.select_related('party_amount').exclude(is_deleted=True).order_by('-number').distinct()
|
|
permission_classes = [HasRolePermission]
|
|
filter_backends = [DjangoFilterBackend]
|
|
filterset_class = PartyFilter
|
|
|
|
def get(self, request):
|
|
search = request.query_params.get('search')
|
|
parties = self.filter_queryset(self.get_queryset())
|
|
if search:
|
|
parties = parties.filter(number__istartswith=search)
|
|
page = self.paginate_queryset(parties)
|
|
if page is not None:
|
|
serializer = self.serializer_class(page, many=True)
|
|
return self.get_paginated_response(serializer.data)
|
|
serializer = self.serializer_class(parties, many=True)
|
|
return Response(serializer.data, status=200)
|
|
|
|
|
|
class PartyDetailApiView(generics.GenericAPIView):
|
|
permission_classes = [HasRolePermission]
|
|
serializer_class = serializers.PartyDetailSerializer
|
|
queryset = Party.objects.select_related('party_amount').prefetch_related('orders')
|
|
|
|
def get(self, request, id):
|
|
party = Party.objects.select_related('party_amount').prefetch_related('orders').filter(id=id).first()
|
|
if not party:
|
|
return Response({'success': False, 'message': 'party not found'}, status=404)
|
|
serializer = self.serializer_class(party)
|
|
return Response(serializer.data, status=200)
|
|
|
|
|
|
class PartyDeleteApiView(generics.GenericAPIView):
|
|
serializer_class = serializers.DeletedPartyCreateSerializer
|
|
queryset = Party.objects.all()
|
|
permission_classes = [HasRolePermission]
|
|
|
|
def post(self, request, party_id):
|
|
serializer = self.serializer_class(data=request.data, context={'party_id': party_id, 'user': request.user})
|
|
if serializer.is_valid(raise_exception=True):
|
|
serializer.save()
|
|
return Response(
|
|
{'success': True, 'message': 'Party deleted'},
|
|
status=200
|
|
)
|
|
return Response(
|
|
{'success': False, 'message': 'error while deletign party', 'error': serializer.errors},
|
|
status=400
|
|
)
|
|
|
|
|
|
class DeletedPartyListApiView(generics.GenericAPIView):
|
|
serializer_class = serializers.DeletedPartyListSerializer
|
|
queryset = DeletedParty.objects.select_related('party').order_by('created_at')
|
|
permission_classes = [HasRolePermission]
|
|
|
|
def get(self, request):
|
|
search = request.query_params.get('q')
|
|
deleted_parties = DeletedParty.objects.select_related('party')
|
|
if search:
|
|
deleted_parties = deleted_parties.filter(
|
|
Q(party__number__istartswith=search)|
|
|
Q(party__comment__istartswith=search)|
|
|
Q(command__istartswith=search)
|
|
)
|
|
page = self.paginate_queryset(deleted_parties)
|
|
if page is not None:
|
|
serializer = self.serializer_class(page, many=True)
|
|
return self.get_paginated_response(serializer.data)
|
|
return Response(serializer.data, status=200)
|
|
|
|
|
|
class PartyUpdateApiView(generics.GenericAPIView):
|
|
serializer_class = serializers.PartyUpdateSerializer
|
|
queryset = Party.objects.all()
|
|
permission_classes = [HasRolePermission]
|
|
pagination_class = None
|
|
|
|
def patch(self, request, id):
|
|
party = get_object_or_404(Party, id=id)
|
|
serializer = self.serializer_class(data=request.data, instance=party, partial=True)
|
|
if serializer.is_valid(raise_exception=True):
|
|
serializer.save()
|
|
return Response({
|
|
'success': True, 'message': 'update',
|
|
}, status=200)
|
|
return Response({'success': False, 'error': serializer.errors}, status=400)
|
|
|
|
|
|
class OrderDeleteToPartyApiView(generics.GenericAPIView):
|
|
serializer_class = None
|
|
permission_classes = [HasRolePermission]
|
|
queryset = None
|
|
|
|
|
|
def delete(self, request, party_id, order_id):
|
|
party = get_object_or_404(Party, id=party_id)
|
|
|
|
order = party.orders.filter(id=order_id).first()
|
|
if not order:
|
|
return Response(
|
|
{'success': False, 'error_message': 'Order does not belong to the party'},
|
|
status=400
|
|
)
|
|
|
|
party.orders.remove(order)
|
|
return Response({'success': True, 'message': 'Order removed from party'}, status=200)
|
|
|
|
|
|
class PartyChangeStatusToIsMadeApiView(generics.GenericAPIView):
|
|
serializer_class = serializers.ReceiveMultipleOrderSerializer
|
|
queryset = Party.objects.all()
|
|
permission_classes = [HasRolePermission]
|
|
pagination_class = None
|
|
|
|
def post(self, request, party_id):
|
|
serializer = self.serializer_class(data=request.data)
|
|
if not serializer.is_valid(raise_exception=True):
|
|
return Response({"success": False, "message": serializer.errors}, status=400)
|
|
party = get_object_or_404(Party, id=party_id)
|
|
data = serializer.validated_data
|
|
percentage = 0
|
|
for item in data['product']:
|
|
order_id = item['order_id']
|
|
product_quantity = item['product_quantity']
|
|
product_receive_date = item['product_receive_date']
|
|
for order in party.orders.all():
|
|
if order.id == order_id:
|
|
completion_percentage = (product_quantity / order.quantity) * 100
|
|
create_inventory.delay(
|
|
order.wherehouse.id,
|
|
order.quantity,
|
|
order.product.id,
|
|
order.unity.id,
|
|
order.unit_amount * Decimal(order.quantity),
|
|
order.project_folder.id if order.project_folder else None,
|
|
order.project.id if order.project else None,
|
|
order.unit_amount,
|
|
order.currency,
|
|
)
|
|
order.received_count += product_quantity
|
|
order.received_date = product_receive_date
|
|
order.completion_percentage = completion_percentage
|
|
order.save()
|
|
percentage += completion_percentage
|
|
if percentage == 100:
|
|
party.status = 'PARTY_IS_MADE'
|
|
party.process = percentage
|
|
party.closed_date = now().date()
|
|
party.save()
|
|
return Response(
|
|
{'success': True, 'message': 'party updated'},
|
|
status=200
|
|
)
|
|
|
|
|
|
class PartyPaymentApiView(generics.GenericAPIView):
|
|
serializer_class = serializers.PartyExpenceCreateSerializer
|
|
queryset = Expence.objects.all()
|
|
permission_classes = [HasRolePermission]
|
|
|
|
def post(self, request):
|
|
ser = self.serializer_class(data=request.data, context={'user': request.user})
|
|
if ser.is_valid():
|
|
ser.save()
|
|
return Response(
|
|
{
|
|
'success': True,
|
|
'message': 'partiyage tolov qilindi'
|
|
},
|
|
status=200
|
|
)
|
|
return Response(
|
|
{
|
|
'success': False,
|
|
'message': 'partiyaga tolov qilishda xatolik yuz berdi',
|
|
'error': ser.errors,
|
|
},
|
|
status=400
|
|
)
|
|
|
|
|
|
class PartyStatisticsApiView(generics.GenericAPIView):
|
|
permission_classes = [HasRolePermission]
|
|
serializer_class = None
|
|
queryset = Party.objects.all()
|
|
filter_backends = [DjangoFilterBackend]
|
|
filterset_class = PartyFilter
|
|
pagination_class = None
|
|
|
|
def get(self, request):
|
|
queryset = self.filter_queryset(self.queryset)
|
|
today = now().date()
|
|
|
|
usd_course = Decimal(
|
|
UsdCourse.objects.first().value if UsdCourse.objects.exists() else 12000
|
|
)
|
|
|
|
usd = queryset.filter(currency='usd', is_deleted=False).aggregate(
|
|
total_price_usd=Sum('party_amount__calculated_amount'),
|
|
cost_amount_usd=Sum('party_amount__cost_amount'),
|
|
calculated_amount_usd=Sum('party_amount__calculated_amount'),
|
|
paid_amount_usd=Sum('party_amount__paid_amount'),
|
|
payment_amount_usd=Sum('party_amount__payment_amount'),
|
|
overdue_payments_usd=Sum(
|
|
'party_amount__payment_amount',
|
|
filter=Q(payment_date__lt=today)
|
|
)
|
|
)
|
|
|
|
uzs = queryset.filter(currency='uzs', is_deleted=False).aggregate(
|
|
total_price_uzs=Sum('party_amount__calculated_amount'),
|
|
cost_amount_uzs=Sum('party_amount__cost_amount'),
|
|
calculated_amount_uzs=Sum('party_amount__calculated_amount'),
|
|
paid_amount_uzs=Sum('party_amount__paid_amount'),
|
|
payment_amount_uzs=Sum('party_amount__payment_amount'),
|
|
overdue_payments_uzs=Sum(
|
|
'party_amount__payment_amount',
|
|
filter=Q(payment_date__lt=today)
|
|
)
|
|
)
|
|
|
|
def safe(x):
|
|
return Decimal(x) if x is not None else Decimal(0)
|
|
|
|
|
|
total = {
|
|
"total_price": safe(uzs["total_price_uzs"]) + (safe(usd["total_price_usd"]) * usd_course),
|
|
"cost_amount": safe(uzs["cost_amount_uzs"]) + (safe(usd["cost_amount_usd"]) * usd_course),
|
|
"calculated_amount": safe(uzs["calculated_amount_uzs"]) + (safe(usd["calculated_amount_usd"]) * usd_course),
|
|
"paid_amount": safe(uzs["paid_amount_uzs"]) + (safe(usd["paid_amount_usd"]) * usd_course),
|
|
"payment_amount": safe(uzs["payment_amount_uzs"]) + (safe(usd["payment_amount_usd"]) * usd_course),
|
|
"overdue_payments": safe(uzs["overdue_payments_uzs"]) + (safe(usd["overdue_payments_usd"]) * usd_course),
|
|
}
|
|
|
|
res = {
|
|
"usd": usd,
|
|
"uzs": uzs,
|
|
"total_balance": total
|
|
}
|
|
return Response(res, status=200)
|
|
|
|
|
|
class DeleteMultiplePartyApiView(views.APIView):
|
|
permission_classes = [HasRolePermission]
|
|
|
|
def delete(self, request):
|
|
ids = request.data.get("party_ids", [])
|
|
if not ids:
|
|
return Response({"detail": "party_ids kerak"}, status=400)
|
|
|
|
deleted_count, _ = Party.objects.filter(id__in=ids).delete()
|
|
return Response({"deleted": deleted_count}, status=200)
|
|
|
|
|
|
class ChangeConfirmationPartyApiView(views.APIView):
|
|
permission_classes = [HasRolePermission]
|
|
|
|
def post(self, request, id):
|
|
party = get_object_or_404(Party, id=id)
|
|
confirmation = request.data.get('confirmation', None)
|
|
if not confirmation:
|
|
return Response({
|
|
'success': False, 'message': 'confirmation field is required'
|
|
}, status=400)
|
|
party.confirmation = confirmation
|
|
party.save()
|
|
return Response(
|
|
{
|
|
'success': True,
|
|
'message': 'confirmation changed successfully',
|
|
},
|
|
status=200
|
|
)
|
|
|
|
|
|
class PartyPaymentHistoryApiView(generics.GenericAPIView):
|
|
permission_classes = [HasRolePermission]
|
|
serializer_class = ExpenceListSerializer
|
|
queryset = Expence.objects.select_related('counterparty', 'user')
|
|
pagination_class = None
|
|
|
|
def get(self, request, id):
|
|
party = get_object_or_404(Party, id=id)
|
|
expences = self.queryset.filter(party=party)
|
|
serializer = self.serializer_class(expences, many=True)
|
|
return Response(
|
|
{
|
|
'success': True,
|
|
'data': serializer.data,
|
|
}, status=200
|
|
) |