td class="lines-num lines-num-new">
- if end:
- dt = parse_datetime(end)
- if dt:
- qs = qs.filter(paid_at__lte=dt)
-
- response = HttpResponse(content_type="text/csv")
- response["Content-Disposition"] = "attachment; filename=payouts.csv"
- writer = csv.writer(response)
- writer.writerow(["organization", "customer", "amount", "currency", "paid_at", "reference", "pickup_id"])
- for p in qs.iterator():
- writer.writerow([
- p.organization.code,
- p.customer.name,
- p.amount,
- p.currency_code,
- p.paid_at.isoformat(),
- p.reference,
- p.pickup_id or "",
- ])
- return response
+# Billing-related views moved to billing/views.py
# Documents UI --------------------------------------------------------------
@@ -1024,3 +968,36 @@ def service_toggle_enabled(request, pk: int):
item.save(update_fields=["is_enabled"])
messages.success(request, f"Service '{item.title}' {'enabled' if item.is_enabled else 'disabled'}.")
return redirect("recycle_core:services_list")
+
+
+@require_POST
+@owner_required
+def services_reorder(request):
+ """Reorder ProvidedService.display_order for the current organization.
+
+ Expects JSON body with {"ids": [<service_id>, ...]} in the new order (top→bottom).
+ """
+ try:
+ data = json.loads(request.body.decode("utf-8"))
+ ids = data.get("ids", [])
+ if not isinstance(ids, list):
+ return JsonResponse({"ok": False, "error": "Invalid payload."}, status=400)
+ except Exception:
+ return JsonResponse({"ok": False, "error": "Malformed JSON."}, status=400)
+
+ org = getattr(request, "org", None)
+ # Fetch only services belonging to this org and requested ids
+ qs = ProvidedService.objects.filter(organization=org, id__in=ids)
+ existing = {obj.id: obj for obj in qs}
+
+ # Enforce order based on the incoming list; skip unknown ids
+ with transaction.atomic():
+ for idx, sid in enumerate(ids):
+ obj = existing.get(sid)
+ if not obj:
+ continue
+ if obj.display_order != idx:
+ obj.display_order = idx
+ obj.save(update_fields=["display_order"])
+
+ return JsonResponse({"ok": True})
|
||
| 22 | 22 |
|
| 23 | 23 |
|
| 24 | 24 |
|
| 25 |
|
|
| 26 |
|
|
| 27 |
|
|
| 28 |
|
|
| 29 | 25 |
|
| 30 | 26 |
|
| 31 | 27 |
|
|
||
| 34 | 30 |
|
| 35 | 31 |
|
| 36 | 32 |
|
| 33 |
|
|
| 37 | 34 |
|
| 38 | 35 |
|
| 39 | 36 |
|