feat(web): replace remaining "Soon" stubs with real pages
- Live Tracking: Leaflet map (CDN) showing active truck positions,
auto-refresh every 10s, sidebar list with speed + last update.
- Finance / Payments: filterable list of payments with mark-paid
action that runs admin fulfillment.
- Settings: notification-preferences form bound to /me/notification-
preferences.
Backend:
- New admin payments index endpoint
GET /admin/payments + POST /admin/payments/{uuid}/mark-paid (moved
out of /admin/live/* for clarity).
Sidebar groups now reflect what's live: Operations (Trips, Live
Tracking), Planning (Routes, Teams, Trucks, DOPs, Dumpsites), People
(Users, Households, Partner Stores), QR, Areas, Finance, Reports,
Settings. Trip Calendar + Incidents remain "Soon" — backends ready,
UI work pending. Dashboard backend-status copy updated to 13/13
modules / 171 tests.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -81,6 +81,53 @@ class PaymentController extends ApiController
|
||||
]);
|
||||
}
|
||||
|
||||
public function adminIndex(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'status' => ['nullable', 'in:pending,processing,paid,failed,refunded'],
|
||||
'purpose' => ['nullable', 'in:resident_code_purchase,store_inventory_purchase'],
|
||||
'q' => ['nullable', 'string', 'max:100'],
|
||||
'per_page' => ['nullable', 'integer', 'min:1', 'max:100'],
|
||||
]);
|
||||
$perPage = (int) $request->input('per_page', 25);
|
||||
|
||||
$payments = Payment::query()
|
||||
->with('payer')
|
||||
->when($request->filled('status'), fn ($q) => $q->where('status', $request->string('status')))
|
||||
->when($request->filled('purpose'), fn ($q) => $q->where('purpose', $request->string('purpose')))
|
||||
->when($request->filled('q'), function ($q) use ($request) {
|
||||
$term = '%'.$request->string('q').'%';
|
||||
$q->where(fn ($qq) => $qq->where('uuid', 'like', $term)
|
||||
->orWhereHas('payer', fn ($p) => $p->where('email', 'like', $term)->orWhere('phone', 'like', $term)));
|
||||
})
|
||||
->orderByDesc('id')
|
||||
->paginate($perPage);
|
||||
|
||||
return $this->ok(
|
||||
$payments->getCollection()->map(fn (Payment $p) => [
|
||||
'id' => $p->uuid,
|
||||
'payer' => [
|
||||
'name' => $p->payer?->full_name,
|
||||
'email' => $p->payer?->email,
|
||||
],
|
||||
'purpose' => $p->purpose,
|
||||
'amount_centavos' => $p->amount_centavos,
|
||||
'currency' => $p->currency,
|
||||
'provider' => $p->provider,
|
||||
'status' => $p->status,
|
||||
'paid_at' => $p->paid_at?->toIso8601String(),
|
||||
'created_at' => $p->created_at?->toIso8601String(),
|
||||
])->all(),
|
||||
null,
|
||||
[
|
||||
'page' => $payments->currentPage(),
|
||||
'per_page' => $payments->perPage(),
|
||||
'total' => $payments->total(),
|
||||
'last_page' => $payments->lastPage(),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin manually marks a payment paid (used for cash-paid resident
|
||||
* purchases or when the manual driver is in effect). Triggers the
|
||||
|
||||
Reference in New Issue
Block a user