diff --git a/core/apps/counterparty/urls.py b/core/apps/counterparty/urls.py index b8ea64e..fa43ecd 100644 --- a/core/apps/counterparty/urls.py +++ b/core/apps/counterparty/urls.py @@ -18,6 +18,7 @@ urlpatterns = [ path("/", cp_views.CounterpartyDetailApiView.as_view()), path('/un_archive/', cp_views.UnArchiveCounterpartyApiView.as_view()), path("/statistics/", cp_views.CounterPartyIncomeExpenceStatisticsApiView.as_view()), + path('/akt_statistics/', cp_views.CounterpartyAKTApiView.as_view()), ] )), path('counterparty_folder/', include( diff --git a/core/apps/counterparty/views/counterparty.py b/core/apps/counterparty/views/counterparty.py index 296ac91..e64bc3c 100644 --- a/core/apps/counterparty/views/counterparty.py +++ b/core/apps/counterparty/views/counterparty.py @@ -18,6 +18,11 @@ from core.apps.counterparty.serializers import counterparty as serializers from core.apps.counterparty.filters.counterparty import CounterpartyFilter # finance from core.apps.finance.models import Expence, Income +from core.apps.finance.serializers.income import IncomeListSerializer +from core.apps.finance.serializers.expence import ExpenceListSerializer +# orders +from core.apps.orders.models import Party +from core.apps.orders.serializers.party import PartyDetailSerializer class CounterpartyListApiView(generics.ListAPIView): @@ -264,4 +269,79 @@ class CounterPartyIncomeExpenceStatisticsApiView(views.APIView): } } - return Response(data, status=200) \ No newline at end of file + return Response(data, status=200) + + + +class CounterpartyAKTApiView(views.APIView): + permission_classes = [HasRolePermission] + + def get(self, request, id): + # TODO: filterlar + date = request.query_params.get('date', None) + end_date = request.query_params.get('end_date', None) + project_folder = request.query_params.getlist('folder', None) + project = request.query_params.getlist('project', None) + currency = request.query_params.get('currency', 'uzs') + + counterparty = get_object_or_404(Counterparty, id=id) + parties = Party.objects.filter( + orders__counterparty=counterparty, is_deleted=False, process=100, payment_percentage=100 + ).distinct().order_by('-created_at') + expences = Expence.objects.filter(counterparty=counterparty, is_deleted=False).distinct().order_by('-created_at') + incomes = Income.objects.filter(counterparty=counterparty, is_deleted=False).distinct().order_by('-created_at') + + # TODO: date va end date boyicha filter + if date: + parties = parties.filter(close_date__gte=date) + expences = expences.filter(created_at__gte=date) + incomes = incomes.filter(created_at__gte=date) + if end_date: + parties = parties.filter(close_date__lte=end_date) + expences = expences.filter(created_at__lte=end_date) + incomes = incomes.filter(created_at__lte=end_date) + + # TODO: project folder va project boyicha filter + if project_folder: + parties = parties.filter(orders__project_folder=project_folder).distinct() + expences = expences.filter(project_folder=project_folder) + incomes = incomes.filter(project_folder=project_folder) + if project: + parties = parties.filter(orders__project=project).distinct() + expences = expences.filter(project=project) + incomes = incomes.filter(project=project) + + # TODO: currency boyicha filter + if currency: + parties = parties.filter(currency=currency) + expences = expences.filter(currency=currency) + incomes = incomes.filter(currency=currency) + + # TODO: total kreditni hisoblash kerak: Sum(party total_price) + Sum(income total_price) + parties_total_price = parties.aggregate(total_price=Sum('party_amount__total_price'))['total_price'] or 0 + income_total_price = incomes.aggregate(total_price=Sum('price'))['total_price'] or 0 + total_kredit = Decimal(parties_total_price) + Decimal(income_total_price) + + # TODO: total debitni hisoblash kerak: Sum(expence total_price) + expence_total_balance = expences.aggregate(total_price=Sum('price'))['total_price'] or 0 + total_debit = expence_total_balance + + # TODO: final balanceni hisoblash kerak: total_kredit - total_debit = final balance => negative or positive + final_balance = total_kredit - total_debit + + # TODO: final balance typeni topish kerak -> debit or kredit: if negative == debit, positive == kredit + type = 'debit' if final_balance < 0 else 'kredit' + + response = { + "parties": PartyDetailSerializer(parties, many=True).data, + "expences": ExpenceListSerializer(expences, many=True).data, + "incomes": IncomeListSerializer(incomes, many=True).data, + "total_kredit": str(total_kredit), + "total_debit": str(total_debit), + "final_balance": { + "balance": str(final_balance) if not str(final_balance).startswith('-') else str(final_balance).replace('-', ''), + "type": type, + } + } + + return Response(response, status=200) \ No newline at end of file diff --git a/core/apps/orders/admin/party.py b/core/apps/orders/admin/party.py index 3514d9f..b7158f7 100644 --- a/core/apps/orders/admin/party.py +++ b/core/apps/orders/admin/party.py @@ -14,18 +14,17 @@ class PartyAdmin(admin.ModelAdmin): list_display = [ "id", "number", - "mediator", - "delivery_date", - "payment_date", - "is_deleted", "party_amount__total_price", - "currency" + "currency", + 'process', + 'payment_percentage', ] inlines = [PartyAmountInline] search_fields = [ "number", "orders__counterparty__name" ] autocomplete_fields = ['orders'] + ordering = ['-number'] def get_queryset(self, request): return super().get_queryset(request).select_related('party_amount', 'mediator').prefetch_related('orders') diff --git a/core/apps/orders/management/commands/import_party.py b/core/apps/orders/management/commands/import_party.py index 27fb052..dc7d4ae 100644 --- a/core/apps/orders/management/commands/import_party.py +++ b/core/apps/orders/management/commands/import_party.py @@ -15,19 +15,18 @@ token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2JhY2tlbmQuYX headers = {"Authorization": f"Bearer {token}"} -def get_data(page): - url = f"https://backend.app.uyqur.uz/main/supply/order-view?size=1000&page={page}" - response = requests.get(url, headers=headers) +# def get_data(page): +# url = f"https://backend.app.uyqur.uz/main/supply/order-view?size=1000&page={page}" +# response = requests.get(url, headers=headers) - if response.status_code == 200: - return response.json() - print(response.json()) +# if response.status_code == 200: +# return response.json() +# print(response.json()) class Command(BaseCommand): def handle(self, *args, **options): - for page in range(1,6): - data = get_data(page) + for page in range(1,10479): statuses = { "open": "NEW", "ordered": "PARTY_IS_MADE", @@ -39,10 +38,10 @@ class Command(BaseCommand): "partially_recieved": "PROCESS" } - for item in data["data"]["data"]: - url = f"https://backend.app.uyqur.uz/main/supply/order-view?id={item['id']}" - res = requests.get(url, headers=headers) - data = res.json()["data"] + url = f"https://backend.app.uyqur.uz/main/supply/order-view?id={page}" + res = requests.get(url, headers=headers) + data = res.json()["data"] + if data: user = None if data.get("agent"): user = User.objects.filter(full_name=data["agent"]["full_name"]).first() @@ -120,7 +119,8 @@ class Command(BaseCommand): "paid_amount": paid_amount, "payment_amount": must_pay_amount, "debt_amount": debt_amount, - "total_expense_amount": item['total_expense_amount'], + # "total_expense_amount": item['total_expense_amount'], }, ) + print(page) self.stdout.write("Parties added") \ No newline at end of file diff --git a/core/apps/orders/management/commands/import_party_by_number.py b/core/apps/orders/management/commands/import_party_by_number.py index 551002e..5491bc6 100644 --- a/core/apps/orders/management/commands/import_party_by_number.py +++ b/core/apps/orders/management/commands/import_party_by_number.py @@ -15,13 +15,6 @@ token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2JhY2tlbmQuYX headers = {"Authorization": f"Bearer {token}"} -# def get_data(page): -# url = f"https://backend.app.uyqur.uz/main/supply/order-view?size=1000&page={page}" -# response = requests.get(url, headers=headers) - -# if response.status_code == 200: -# return response.json() - class Command(BaseCommand): def add_arguments(self, parser): diff --git a/core/apps/orders/management/commands/update_party_percentage.py b/core/apps/orders/management/commands/update_party_percentage.py index 68cfd2e..a808f69 100644 --- a/core/apps/orders/management/commands/update_party_percentage.py +++ b/core/apps/orders/management/commands/update_party_percentage.py @@ -1,8 +1,6 @@ import json - import requests from django.core.management import BaseCommand - from core.apps.accounts.models import User from core.apps.counterparty.models import Counterparty from core.apps.orders.models import Order, Party, PartyAmount @@ -12,25 +10,46 @@ from core.apps.projects.models import Project, ProjectFolder from core.apps.wherehouse.models import WhereHouse token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2JhY2tlbmQuYXBwLnV5cXVyLnV6L21haW4vYXV0aC9sb2dpbiIsImlhdCI6MTc2Mjk1MjUxNiwiZXhwIjoxNzYzMDM4OTE2LCJuYmYiOjE3NjI5NTI1MTYsImp0aSI6IkVlcW1lVVluMUR0VTNvUDciLCJzdWIiOiIxMDQiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.64QPbq6CeJqXubai4nMfH9RlJIJ0YUPFfJ298ar4YGQ" - headers = {"Authorization": f"Bearer {token}"} def get_data(page): url = f"https://backend.app.uyqur.uz/main/supply/order-view?size=1000&page={page}" response = requests.get(url, headers=headers) - if response.status_code == 200: return response.json() - class Command(BaseCommand): - def handle(self, *args, **options): - for page in range(1,6): - data = get_data(page) - for data in data['data']['data']: - Party.objects.filter(number=data['id']).update( - payment_percentage=data["payment_percent"], - process=data["percent"], - ) - self.stdout.write("Parties added") \ No newline at end of file + for page in range(1, 100): + data = get_data(page) + + for item in data['data']['data']: + try: + # Party ID orqali topish va yangilash + party = Party.objects.get(number=item["id"]) + party.number = item["id"] + party.payment_percentage = item["payment_percent"] + party.process = item["percent"] + party.save() + + self.stdout.write( + self.style.SUCCESS( + f'Party {item["id"]} updated successfully' + ) + ) + except Party.DoesNotExist: + self.stdout.write( + self.style.WARNING( + f'Party {item["id"]} not found' + ) + ) + except Exception as e: + self.stdout.write( + self.style.ERROR( + f'Error updating Party {item["id"]}: {str(e)}' + ) + ) + + self.stdout.write( + self.style.SUCCESS('All parties processed') + ) \ No newline at end of file diff --git a/core/apps/orders/models/party.py b/core/apps/orders/models/party.py index 760936a..9a54630 100644 --- a/core/apps/orders/models/party.py +++ b/core/apps/orders/models/party.py @@ -68,7 +68,6 @@ class Party(BaseModel): percentage += order.completion_percentage if percentage > 0 and count > 0: self.process = percentage / count - # self.party_amount.save() return super().save(*args, **kwargs) diff --git a/core/apps/orders/views/order.py b/core/apps/orders/views/order.py index fbf1d44..b5d5ae2 100644 --- a/core/apps/orders/views/order.py +++ b/core/apps/orders/views/order.py @@ -17,7 +17,7 @@ class OrderListApiView(generics.ListAPIView): serializer_class = serializers.OrderListSerializer queryset = Order.objects.select_related( 'product', 'unity', 'project', 'project_folder', 'wherehouse' - ).filter(type='order') + ).filter(type='order').order_by('-created_at') permission_classes = [HasRolePermission] pagination_class = CustomPageNumberPagination filter_backends = [DjangoFilterBackend, filters.SearchFilter]