382 lines
13 KiB
Python
382 lines
13 KiB
Python
from django.db.models import F, Sum
|
||
|
||
from core.apps.management.forms import DeviceForm, IncomeForm, WarehouseForm, UserCreateForm, ExpenseFormEmployee, \
|
||
ExpenseFormManager, ExpenseFormBusinessman, ReportForm
|
||
from django.db import transaction
|
||
from django.shortcuts import render, redirect
|
||
from core.apps.management.forms import ToyMovementForm, ToyMovementFormEmployee
|
||
from django.contrib.auth.decorators import login_required
|
||
from core.apps.management.decorators import role_required
|
||
from core.apps.management.forms import UserCreateFormManagerToEmployee, UserCreateFormBusinessman
|
||
from core.apps.management.forms.RentForm import RentForm
|
||
from core.apps.management.models import ToyMovement, Warehouse, Report
|
||
|
||
|
||
@login_required
|
||
@role_required(["manager", "businessman"])
|
||
def create_device(request):
|
||
user = request.user
|
||
|
||
if request.method == "POST":
|
||
form = DeviceForm(request.POST, user=user)
|
||
if form.is_valid():
|
||
form.save()
|
||
return redirect("dashboard")
|
||
else:
|
||
form = DeviceForm(user=user)
|
||
|
||
return render(
|
||
request,
|
||
"common/create/device_create.html",
|
||
{
|
||
"form": form,
|
||
"title": "Aparat Yaratish"
|
||
}
|
||
)
|
||
|
||
|
||
@login_required
|
||
@role_required(["employee"])
|
||
def create_income(request):
|
||
if request.method == "POST":
|
||
form = IncomeForm(request.POST, user=request.user)
|
||
if form.is_valid():
|
||
income = form.save(commit=False)
|
||
if request.user.role == "employee":
|
||
income.amount = None
|
||
income.save()
|
||
return redirect("income_list")
|
||
else:
|
||
form = IncomeForm(user=request.user)
|
||
return render(request, "common/create/income_create.html", {"form": form})
|
||
|
||
@login_required
|
||
@role_required(['manager', 'businessman'])
|
||
def create_income_manager_and_businessman(request):
|
||
if request.method == "POST":
|
||
form = IncomeForm(request.POST, user=request.user)
|
||
if form.is_valid():
|
||
with transaction.atomic():
|
||
income = form.save(commit=False)
|
||
income.created_by = request.user
|
||
income.save()
|
||
|
||
warehouse = income.warehouse
|
||
warehouse.toys_count += income.amount
|
||
warehouse.save()
|
||
return redirect("common/create/income_create.html")
|
||
else:
|
||
form = IncomeForm(user=request.user)
|
||
return render(request=request, template_name="common/create/income_create.html", context={"form": form})
|
||
|
||
@login_required
|
||
def create_expense(request):
|
||
user = request.user
|
||
|
||
# select form based on role
|
||
if user.role == "employee":
|
||
form_class = ExpenseFormEmployee
|
||
elif user.role == "manager":
|
||
form_class = ExpenseFormManager
|
||
else: # businessman or superuser
|
||
form_class = ExpenseFormBusinessman
|
||
|
||
if request.method == "POST":
|
||
form = form_class(request.POST)
|
||
if form.is_valid():
|
||
with transaction.atomic():
|
||
expense = form.save(commit=False)
|
||
expense.created_by = user
|
||
|
||
# AUTO CONFIRM for manager & businessman
|
||
if user.role in ["manager", "businessman"]:
|
||
expense.is_confirmed = True
|
||
expense.confirmed_by = user
|
||
|
||
expense.save()
|
||
|
||
return redirect("dashboard")
|
||
else:
|
||
form = form_class()
|
||
|
||
return render(request, "common/create/expense_create.html", {
|
||
"form": form,
|
||
"title": "Xarajat qoʻshish",
|
||
"user_role": user.role
|
||
})
|
||
|
||
|
||
@login_required
|
||
@role_required(["businessman"])
|
||
def create_warehouse(request):
|
||
form = WarehouseForm(request.POST or None)
|
||
if form.is_valid():
|
||
form.save()
|
||
return redirect("businessman_dashboard")
|
||
|
||
return render(request, "common/create/warehouse_create.html", {
|
||
"form": form,
|
||
"title": "Sklad Yaratish"
|
||
})
|
||
|
||
|
||
@login_required
|
||
@role_required(["manager", "businessman"])
|
||
def create_user(request):
|
||
if request.user.role == "businessman":
|
||
form_class = UserCreateFormBusinessman
|
||
form_kwargs = {}
|
||
redirect_to = "businessman_dashboard"
|
||
|
||
else: # manager
|
||
form_class = UserCreateFormManagerToEmployee
|
||
form_kwargs = {"manager": request.user}
|
||
redirect_to = "manager_dashboard"
|
||
|
||
form = form_class(request.POST or None, **form_kwargs)
|
||
|
||
if form.is_valid():
|
||
form.save()
|
||
return redirect(redirect_to)
|
||
|
||
return render(request, "common/create/user_create.html", {
|
||
"form": form,
|
||
"title": "Foydalanuvchi yaratish",
|
||
})
|
||
|
||
@login_required
|
||
def create_toy_movement(request):
|
||
user = request.user
|
||
|
||
if user.role == "employee":
|
||
form_class = ToyMovementFormEmployee
|
||
else:
|
||
form_class = ToyMovementForm
|
||
|
||
if request.method == "POST":
|
||
form = form_class(request.POST, user=user)
|
||
|
||
if form.is_valid():
|
||
with transaction.atomic():
|
||
|
||
quantity = form.cleaned_data["quantity"]
|
||
|
||
if user.role == "employee":
|
||
# Auto determine warehouse by region
|
||
from_wh = Warehouse.objects.select_for_update().filter(
|
||
region=user.region
|
||
).first()
|
||
|
||
if not from_wh:
|
||
form.add_error(None, "No warehouse assigned to your region.")
|
||
return render(request,
|
||
"common/create/toy_movement_create.html",
|
||
{"form": form})
|
||
|
||
if from_wh.toys_count < quantity:
|
||
form.add_error("quantity", "Not enough toys in warehouse.")
|
||
return render(request,
|
||
"common/create/toy_movement_create.html",
|
||
{"form": form})
|
||
|
||
# Deduct stock
|
||
Warehouse.objects.filter(pk=from_wh.pk).update(
|
||
toys_count=F("toys_count") - quantity
|
||
)
|
||
|
||
movement = form.save(commit=False)
|
||
movement.movement_type = "from_warehouse"
|
||
movement.from_warehouse = from_wh
|
||
movement.to_warehouse = None
|
||
movement.created_by = user
|
||
movement.save()
|
||
|
||
else:
|
||
# Manager / Businessman normal logic
|
||
from_wh = form.cleaned_data["from_warehouse"]
|
||
movement_type = form.cleaned_data["movement_type"]
|
||
to_wh = form.cleaned_data.get("to_warehouse")
|
||
|
||
from_wh = Warehouse.objects.select_for_update().get(pk=from_wh.pk)
|
||
|
||
if from_wh.toys_count < quantity:
|
||
form.add_error("quantity", "Not enough toys in warehouse.")
|
||
return render(request,
|
||
"common/create/toy_movement_create.html",
|
||
{"form": form})
|
||
|
||
Warehouse.objects.filter(pk=from_wh.pk).update(
|
||
toys_count=F("toys_count") - quantity
|
||
)
|
||
|
||
if movement_type == "between_warehouses" and to_wh:
|
||
to_wh = Warehouse.objects.select_for_update().get(pk=to_wh.pk)
|
||
Warehouse.objects.filter(pk=to_wh.pk).update(
|
||
toys_count=F("toys_count") + quantity
|
||
)
|
||
|
||
movement = form.save(commit=False)
|
||
movement.created_by = user
|
||
movement.save()
|
||
|
||
return redirect("dashboard")
|
||
|
||
else:
|
||
form = form_class(user=user)
|
||
|
||
return render(
|
||
request,
|
||
"common/create/toy_movement_create.html",
|
||
{"form": form}
|
||
)
|
||
|
||
@login_required
|
||
@role_required(["manager", "businessman"])
|
||
def create_toy_movement_auto(request):
|
||
user = request.user
|
||
|
||
if request.method == "POST":
|
||
form = ToyMovementForm(request.POST, user=user)
|
||
|
||
if form.is_valid():
|
||
with transaction.atomic():
|
||
# Get cleaned data
|
||
from_wh = form.cleaned_data.get("from_warehouse")
|
||
to_wh = form.cleaned_data.get("to_warehouse")
|
||
movement_type = form.cleaned_data.get("movement_type")
|
||
quantity = form.cleaned_data.get("quantity")
|
||
|
||
# Validate warehouse exists
|
||
if not from_wh:
|
||
form.add_error("from_warehouse", "Source warehouse is required.")
|
||
return render(request, "common/create/toy_movement_create.html", {"form": form})
|
||
|
||
# Lock and get fresh warehouse data
|
||
from_wh = Warehouse.objects.select_for_update().get(pk=from_wh.pk)
|
||
|
||
# Check stock
|
||
if from_wh.toys_count < quantity:
|
||
form.add_error("quantity", "Not enough toys in warehouse.")
|
||
return render(request, "common/create/toy_movement_create.html", {"form": form})
|
||
|
||
# Deduct from source warehouse
|
||
Warehouse.objects.filter(pk=from_wh.pk).update(
|
||
toys_count=F("toys_count") - quantity
|
||
)
|
||
|
||
# Add to destination warehouse if between_warehouses
|
||
if movement_type == "between_warehouses" and to_wh:
|
||
to_wh = Warehouse.objects.select_for_update().get(pk=to_wh.pk)
|
||
Warehouse.objects.filter(pk=to_wh.pk).update(
|
||
toys_count=F("toys_count") + quantity
|
||
)
|
||
|
||
# Save movement
|
||
movement = form.save(commit=False)
|
||
movement.created_by = user
|
||
movement.save()
|
||
|
||
return redirect("toy_movement_list")
|
||
else:
|
||
# Form has errors, display them
|
||
return render(request, "common/create/toy_movement_create.html", {"form": form})
|
||
|
||
else:
|
||
# GET request → render the create form
|
||
form = ToyMovementForm(user=user)
|
||
|
||
return render(
|
||
request,
|
||
"common/create/toy_movement_create.html",
|
||
{"form": form}
|
||
)
|
||
|
||
@login_required
|
||
@role_required(["manager", "businessman"])
|
||
def create_rent(request):
|
||
|
||
if request.method == "POST":
|
||
form = RentForm(request.POST)
|
||
if form.is_valid():
|
||
rent = form.save(commit=False)
|
||
rent.created_by = request.user
|
||
rent.save()
|
||
return redirect("dashboard")
|
||
else:
|
||
form = RentForm()
|
||
|
||
return render(request, "common/create/rent_create.html", {"form":form, "title":"Create Rent"})
|
||
|
||
@login_required
|
||
@role_required(["employee"])
|
||
def create_report(request):
|
||
|
||
if request.method == "POST":
|
||
form = ReportForm(request.POST, user=request.user)
|
||
|
||
if form.is_valid():
|
||
|
||
# 🔥 Employee MUST have warehouse
|
||
if not request.user.warehouse:
|
||
form.add_error(None, "Sizga ombor biriktirilmagan.")
|
||
return render(
|
||
request,
|
||
"common/create/report_create.html",
|
||
{"form": form, "title": "Yakuniy Hisobot"}
|
||
)
|
||
|
||
device = form.cleaned_data["device"]
|
||
entered_quantity = form.cleaned_data["quantity"]
|
||
|
||
with transaction.atomic():
|
||
|
||
# ✅ 1. Save last entered quantity as ToyMovement
|
||
ToyMovement.objects.create(
|
||
movement_type="from_warehouse",
|
||
from_warehouse=request.user.warehouse,
|
||
device=device,
|
||
quantity=entered_quantity,
|
||
created_by=request.user,
|
||
)
|
||
|
||
# ✅ 2. Find last report for this device
|
||
last_report = Report.objects.filter(
|
||
device=device
|
||
).order_by("-created_at").first()
|
||
|
||
if last_report:
|
||
last_time = last_report.created_at
|
||
|
||
total_since_last = ToyMovement.objects.filter(
|
||
device=device,
|
||
created_at__gt=last_time
|
||
).aggregate(
|
||
total=Sum("quantity")
|
||
)["total"] or 0
|
||
else:
|
||
total_since_last = ToyMovement.objects.filter(
|
||
device=device
|
||
).aggregate(
|
||
total=Sum("quantity")
|
||
)["total"] or 0
|
||
|
||
# ✅ 3. Create Report
|
||
Report.objects.create(
|
||
device=device,
|
||
quantity=total_since_last,
|
||
created_by=request.user
|
||
)
|
||
|
||
return redirect("employee_dashboard")
|
||
|
||
else:
|
||
form = ReportForm(user=request.user)
|
||
|
||
return render(
|
||
request,
|
||
"common/create/report_create.html",
|
||
{
|
||
"form": form,
|
||
"title": "Yakuniy Hisobot"
|
||
}
|
||
) |