From 241d3c1f20a2904b06858f572845c33725f81f7d Mon Sep 17 00:00:00 2001 From: Abdulaziz Axmadaliyev Date: Thu, 19 Feb 2026 12:24:00 +0500 Subject: [PATCH] Businessman uchun statistikalar qo'shildi! --- .../0002_alter_expense_expense_type.py | 18 + core/apps/management/models/expense.py | 1 - .../templates/common/lists/report_list.html | 351 +++++++++++------- core/apps/management/urls.py | 2 +- core/apps/management/views/common/list.py | 135 +++++-- 5 files changed, 339 insertions(+), 168 deletions(-) create mode 100644 core/apps/management/migrations/0002_alter_expense_expense_type.py diff --git a/core/apps/management/migrations/0002_alter_expense_expense_type.py b/core/apps/management/migrations/0002_alter_expense_expense_type.py new file mode 100644 index 0000000..be14f13 --- /dev/null +++ b/core/apps/management/migrations/0002_alter_expense_expense_type.py @@ -0,0 +1,18 @@ +# Generated by Django 5.2.7 on 2026-02-19 07:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('management', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='expense', + name='expense_type', + field=models.CharField(choices=[('salary', 'Maosh'), ('utilities', 'Kommunal toβ€˜lovlar'), ('maintenance', 'Texnik xizmat'), ('food', 'Oziq-ovqat'), ('transport', "Yo'lkira"), ('other', 'Boshqa')], default='other', max_length=20), + ), + ] diff --git a/core/apps/management/models/expense.py b/core/apps/management/models/expense.py index e63fee8..3c06a4a 100644 --- a/core/apps/management/models/expense.py +++ b/core/apps/management/models/expense.py @@ -8,7 +8,6 @@ class Expense(models.Model): MAINTENANCE = "maintenance", "Texnik xizmat" FOOD = "food", "Oziq-ovqat" TRANSPORT = "transport", "Yo'lkira" - BUY_TOYS = "buy_toys", "OΚ»yinchoqlar sotib olish" OTHER = "other", "Boshqa" amount = models.DecimalField(max_digits=12, decimal_places=2) diff --git a/core/apps/management/templates/common/lists/report_list.html b/core/apps/management/templates/common/lists/report_list.html index 29852f3..4668796 100644 --- a/core/apps/management/templates/common/lists/report_list.html +++ b/core/apps/management/templates/common/lists/report_list.html @@ -1,164 +1,237 @@ {% extends "base.html" %} -{% block title %}Hisobotlar{% endblock %} +{% block title %}Qurilma Statistikasi{% endblock %} {% block content %} -
-

{{ title|default:"Hisobotlar" }}

-
-
- {% if reports %} - {% for report in reports %} -
-
-
- {{ report.device.address }} -
-
#{{ forloop.counter }}
-
+
-
-
- Miqdor: - {{ report.quantity }} dona -
-
- Sana: - {{ report.created_at|date:"d.m.Y H:i" }} -
-
- Yaratgan: - {{ report.created_by.get_full_name }} -
-
-
- {% endfor %} - {% else %} -
-

Hech qanday hisobot topilmadi

+ + + + +
+
+ +
- {% endif %} +
+ + +
+
+ + +
+
+ + Tozalash +
+
+ + +
+
+ πŸ’° +
+
Jami Kirim
+
{{ total_kirim|floatformat:0 }} so'm
+
+
+
+ πŸ“‰ +
+
Jami Xarajat
+
{{ total_xarajat|floatformat:0 }} so'm
+
+
+
+ {% if total_foyda >= 0 %}πŸ“ˆ{% else %}πŸ“‰{% endif %} +
+
Jami Foyda
+
{{ total_foyda|floatformat:0 }} so'm
+
+
+
+ + +
+ + + + + + + + + + + + + + {% if rows %} + {% for row in rows %} + + + + + + + + + + {% endfor %} + {% else %} + + + + {% endif %} + +
#QurilmaMiqdorKirimXarajatFoydaSana
{{ forloop.counter }}{{ row.device_name }}{{ row.quantity }}{{ row.kirim|floatformat:0 }} so'm{{ row.xarajat|floatformat:0 }} so'm + + {% if row.foyda >= 0 %}+{% endif %}{{ row.foyda|floatformat:0 }} + + {{ row.date }}
Hech qanday ma'lumot topilmadi
+
+ + + + +
{% endblock %} \ No newline at end of file diff --git a/core/apps/management/urls.py b/core/apps/management/urls.py index 7fd76bc..f00e344 100644 --- a/core/apps/management/urls.py +++ b/core/apps/management/urls.py @@ -25,7 +25,7 @@ urlpatterns = [ path("list/warehouse/", views.warehouse_list, name="warehouse_list"), path("list/user/", views.user_list, name="user_list"), path("list/toy-movement/", views.toy_movement_list, name="toy_movement_list"), - path("list/reports/", views.report_list, name="report_list"), + path("list/reports/", views.device_statistics, name="report_list"), path("list/toy-movement-statistics/", views.toy_movement_statistics, name="toy_movement_statistics"), # Edit path("edit/device//", views.edit_device, name="edit_device"), diff --git a/core/apps/management/views/common/list.py b/core/apps/management/views/common/list.py index 7761f45..f611dc2 100644 --- a/core/apps/management/views/common/list.py +++ b/core/apps/management/views/common/list.py @@ -1,8 +1,11 @@ -from django.shortcuts import render -from django.contrib.auth.decorators import login_required -from core.apps.management.models import Device, Income, Expense, Warehouse, ToyMovement, Report +from core.apps.management.models import Device, Income, Expense, Warehouse, ToyMovement from core.apps.accounts.models import User +from django.contrib.auth.decorators import login_required from core.apps.management.decorators import role_required +from decimal import Decimal +from django.db.models import Sum +from django.shortcuts import render + @login_required @role_required(["manager", "businessman"]) @@ -150,36 +153,114 @@ def device_payment_list(request): } ) -from django.contrib.auth.decorators import login_required -from django.shortcuts import render -from django.db.models import Q - -from core.apps.management.models import Report -from core.apps.management.decorators import role_required @login_required -@role_required(['manager', 'businessman']) -def report_list(request): - reports = ( - Report.objects - .select_related("device", "device__district", "created_by") - .order_by("-created_at") - ) +@role_required(["businessman", "manager"]) +def device_statistics(request): + """ + Har bir ToyMovement uchun kirim / xarajat / foyda hisoblaydi. - if request.user.role == "manager": - reports = reports.filter( - device__district__region=request.user.region - ) + Formula: + narx1 = oylik maosh / 30 + narx2 = narx1 / aparat soni (maosh ulushi, qurilma/kun) + narx3 = kunlik umumiy xarajat / aparat soni (boshqa umumiy / kun) + narx4 = arenda / 30 (shu qurilma arenda / kun) + xarajat = narx2 + narx3 + narx4 + kirim = harakat miqdori * o'yinchoq narxi + foyda = kirim - xarajat + """ - return render( - request, - "common/lists/report_list.html", - { - "reports": reports, - "title": "Hisobotlar" - } + # ── FILTERS ────────────────────────────────────────────────── + start_date = request.GET.get("start_date") + end_date = request.GET.get("end_date") + device_id = request.GET.get("device") + + qs = ToyMovement.objects.select_related("device", "created_by").filter( + device__isnull=False ) + if start_date: + qs = qs.filter(created_at__date__gte=start_date) + if end_date: + qs = qs.filter(created_at__date__lte=end_date) + if device_id: + qs = qs.filter(device_id=device_id) + + qs = qs.order_by("-created_at") + + # ── SHARED CONSTANTS ───────────────────────────────────────── + total_devices = Device.objects.count() or 1 + + # Latest toy price + latest_income = Income.objects.order_by("-created_at").first() + price_per_toy = latest_income.price_per_toy if latest_income else Decimal("0") + + # Total confirmed salary β†’ narx1 β†’ narx2 + total_salary = Expense.objects.filter( + expense_type=Expense.ExpenseType.SALARY, + is_confirmed=True, + ).aggregate(s=Sum("amount"))["s"] or Decimal("0") + + narx1 = total_salary / 30 + narx2 = narx1 / total_devices + + # General (non-device-specific, non-salary) confirmed expenses β†’ narx3 + total_general = Expense.objects.filter( + is_confirmed=True, + device__isnull=True, + ).exclude( + expense_type=Expense.ExpenseType.SALARY + ).aggregate(s=Sum("amount"))["s"] or Decimal("0") + + narx3 = (total_general / 30) / total_devices + + # ── BUILD ROWS ──────────────────────────────────────────────── + rows = [] + total_kirim = Decimal("0") + total_xarajat = Decimal("0") + total_foyda = Decimal("0") + + for mv in qs: + device = mv.device + + # KIRIM + kirim = Decimal(mv.quantity) * price_per_toy + + # narx4 β€” rent for this device per day + narx4 = Decimal(device.amount) / 30 if device.amount else Decimal("0") + + # Direct device expenses (maintenance etc.) / 30 + direct = Expense.objects.filter( + device=device, is_confirmed=True + ).aggregate(s=Sum("amount"))["s"] or Decimal("0") + narx_direct = direct / 30 + + xarajat = narx2 + narx3 + narx4 + narx_direct + foyda = kirim - xarajat + + total_kirim += kirim + total_xarajat += xarajat + total_foyda += foyda + + rows.append({ + "device_name": device.address, + "quantity": mv.quantity, + "kirim": kirim, + "xarajat": xarajat, + "foyda": foyda, + "date": mv.created_at.strftime("%d.%m.%Y %H:%M"), + }) + + return render(request, "common/lists/report_list.html", { + "rows": rows, + "devices": Device.objects.order_by("address"), + "total_kirim": total_kirim, + "total_xarajat": total_xarajat, + "total_foyda": total_foyda, + "price_per_toy": price_per_toy, + }) + + @login_required @role_required(["employee"])