counterparty: counterparty akt api added

This commit is contained in:
behruz-dev
2025-11-13 16:28:00 +05:00
parent acd4bfd30d
commit d7b9264546
8 changed files with 133 additions and 42 deletions

View File

@@ -18,6 +18,7 @@ urlpatterns = [
path("<uuid:id>/", cp_views.CounterpartyDetailApiView.as_view()), path("<uuid:id>/", cp_views.CounterpartyDetailApiView.as_view()),
path('<uuid:id>/un_archive/', cp_views.UnArchiveCounterpartyApiView.as_view()), path('<uuid:id>/un_archive/', cp_views.UnArchiveCounterpartyApiView.as_view()),
path("<uuid:id>/statistics/", cp_views.CounterPartyIncomeExpenceStatisticsApiView.as_view()), path("<uuid:id>/statistics/", cp_views.CounterPartyIncomeExpenceStatisticsApiView.as_view()),
path('<uuid:id>/akt_statistics/', cp_views.CounterpartyAKTApiView.as_view()),
] ]
)), )),
path('counterparty_folder/', include( path('counterparty_folder/', include(

View File

@@ -18,6 +18,11 @@ from core.apps.counterparty.serializers import counterparty as serializers
from core.apps.counterparty.filters.counterparty import CounterpartyFilter from core.apps.counterparty.filters.counterparty import CounterpartyFilter
# finance # finance
from core.apps.finance.models import Expence, Income 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): class CounterpartyListApiView(generics.ListAPIView):
@@ -264,4 +269,79 @@ class CounterPartyIncomeExpenceStatisticsApiView(views.APIView):
} }
} }
return Response(data, status=200) 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)

View File

@@ -14,18 +14,17 @@ class PartyAdmin(admin.ModelAdmin):
list_display = [ list_display = [
"id", "id",
"number", "number",
"mediator",
"delivery_date",
"payment_date",
"is_deleted",
"party_amount__total_price", "party_amount__total_price",
"currency" "currency",
'process',
'payment_percentage',
] ]
inlines = [PartyAmountInline] inlines = [PartyAmountInline]
search_fields = [ search_fields = [
"number", "orders__counterparty__name" "number", "orders__counterparty__name"
] ]
autocomplete_fields = ['orders'] autocomplete_fields = ['orders']
ordering = ['-number']
def get_queryset(self, request): def get_queryset(self, request):
return super().get_queryset(request).select_related('party_amount', 'mediator').prefetch_related('orders') return super().get_queryset(request).select_related('party_amount', 'mediator').prefetch_related('orders')

View File

@@ -15,19 +15,18 @@ token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2JhY2tlbmQuYX
headers = {"Authorization": f"Bearer {token}"} headers = {"Authorization": f"Bearer {token}"}
def get_data(page): # def get_data(page):
url = f"https://backend.app.uyqur.uz/main/supply/order-view?size=1000&page={page}" # url = f"https://backend.app.uyqur.uz/main/supply/order-view?size=1000&page={page}"
response = requests.get(url, headers=headers) # response = requests.get(url, headers=headers)
if response.status_code == 200: # if response.status_code == 200:
return response.json() # return response.json()
print(response.json()) # print(response.json())
class Command(BaseCommand): class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
for page in range(1,6): for page in range(1,10479):
data = get_data(page)
statuses = { statuses = {
"open": "NEW", "open": "NEW",
"ordered": "PARTY_IS_MADE", "ordered": "PARTY_IS_MADE",
@@ -39,10 +38,10 @@ class Command(BaseCommand):
"partially_recieved": "PROCESS" "partially_recieved": "PROCESS"
} }
for item in data["data"]["data"]: url = f"https://backend.app.uyqur.uz/main/supply/order-view?id={page}"
url = f"https://backend.app.uyqur.uz/main/supply/order-view?id={item['id']}" res = requests.get(url, headers=headers)
res = requests.get(url, headers=headers) data = res.json()["data"]
data = res.json()["data"] if data:
user = None user = None
if data.get("agent"): if data.get("agent"):
user = User.objects.filter(full_name=data["agent"]["full_name"]).first() user = User.objects.filter(full_name=data["agent"]["full_name"]).first()
@@ -120,7 +119,8 @@ class Command(BaseCommand):
"paid_amount": paid_amount, "paid_amount": paid_amount,
"payment_amount": must_pay_amount, "payment_amount": must_pay_amount,
"debt_amount": debt_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") self.stdout.write("Parties added")

View File

@@ -15,13 +15,6 @@ token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2JhY2tlbmQuYX
headers = {"Authorization": f"Bearer {token}"} 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): class Command(BaseCommand):
def add_arguments(self, parser): def add_arguments(self, parser):

View File

@@ -1,8 +1,6 @@
import json import json
import requests import requests
from django.core.management import BaseCommand from django.core.management import BaseCommand
from core.apps.accounts.models import User from core.apps.accounts.models import User
from core.apps.counterparty.models import Counterparty from core.apps.counterparty.models import Counterparty
from core.apps.orders.models import Order, Party, PartyAmount 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 from core.apps.wherehouse.models import WhereHouse
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2JhY2tlbmQuYXBwLnV5cXVyLnV6L21haW4vYXV0aC9sb2dpbiIsImlhdCI6MTc2Mjk1MjUxNiwiZXhwIjoxNzYzMDM4OTE2LCJuYmYiOjE3NjI5NTI1MTYsImp0aSI6IkVlcW1lVVluMUR0VTNvUDciLCJzdWIiOiIxMDQiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.64QPbq6CeJqXubai4nMfH9RlJIJ0YUPFfJ298ar4YGQ" token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2JhY2tlbmQuYXBwLnV5cXVyLnV6L21haW4vYXV0aC9sb2dpbiIsImlhdCI6MTc2Mjk1MjUxNiwiZXhwIjoxNzYzMDM4OTE2LCJuYmYiOjE3NjI5NTI1MTYsImp0aSI6IkVlcW1lVVluMUR0VTNvUDciLCJzdWIiOiIxMDQiLCJwcnYiOiIyM2JkNWM4OTQ5ZjYwMGFkYjM5ZTcwMWM0MDA4NzJkYjdhNTk3NmY3In0.64QPbq6CeJqXubai4nMfH9RlJIJ0YUPFfJ298ar4YGQ"
headers = {"Authorization": f"Bearer {token}"} headers = {"Authorization": f"Bearer {token}"}
def get_data(page): def get_data(page):
url = f"https://backend.app.uyqur.uz/main/supply/order-view?size=1000&page={page}" url = f"https://backend.app.uyqur.uz/main/supply/order-view?size=1000&page={page}"
response = requests.get(url, headers=headers) response = requests.get(url, headers=headers)
if response.status_code == 200: if response.status_code == 200:
return response.json() return response.json()
class Command(BaseCommand): class Command(BaseCommand):
def handle(self, *args, **options): def handle(self, *args, **options):
for page in range(1,6): for page in range(1, 100):
data = get_data(page) data = get_data(page)
for data in data['data']['data']:
Party.objects.filter(number=data['id']).update( for item in data['data']['data']:
payment_percentage=data["payment_percent"], try:
process=data["percent"], # Party ID orqali topish va yangilash
) party = Party.objects.get(number=item["id"])
self.stdout.write("Parties added") 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')
)

View File

@@ -68,7 +68,6 @@ class Party(BaseModel):
percentage += order.completion_percentage percentage += order.completion_percentage
if percentage > 0 and count > 0: if percentage > 0 and count > 0:
self.process = percentage / count self.process = percentage / count
# self.party_amount.save()
return super().save(*args, **kwargs) return super().save(*args, **kwargs)

View File

@@ -17,7 +17,7 @@ class OrderListApiView(generics.ListAPIView):
serializer_class = serializers.OrderListSerializer serializer_class = serializers.OrderListSerializer
queryset = Order.objects.select_related( queryset = Order.objects.select_related(
'product', 'unity', 'project', 'project_folder', 'wherehouse' 'product', 'unity', 'project', 'project_folder', 'wherehouse'
).filter(type='order') ).filter(type='order').order_by('-created_at')
permission_classes = [HasRolePermission] permission_classes = [HasRolePermission]
pagination_class = CustomPageNumberPagination pagination_class = CustomPageNumberPagination
filter_backends = [DjangoFilterBackend, filters.SearchFilter] filter_backends = [DjangoFilterBackend, filters.SearchFilter]