This commit is contained in:
alfinfadli16 2025-06-13 03:30:09 +07:00
parent eb637d4fed
commit 660d53ad8a
4 changed files with 108 additions and 246 deletions

View File

@ -9,152 +9,53 @@
class RiwayatController extends Controller class RiwayatController extends Controller
{ {
/**
* Menampilkan daftar riwayat pemesanan
*/
public function index() public function index()
{ {
// Ambil data sewa yang terkait dengan user yang sedang login dan bukan draft
$sewas = Sewa::with(['paket', 'kota']) $sewas = Sewa::with(['paket', 'kota'])
->where('user_id', Auth::id()) ->where('user_id', Auth::id())
->where('status', '!=', 'draft') ->where('status', '!=', 'draft')
->orderBy('created_at', 'desc') ->orderBy('created_at', 'desc')
->get(); ->get();
return view('riwayat', compact('sewas')); return view('riwayat', compact('sewas'));
} }
/** public function updateStatus(Request $request, $id)
* Menampilkan detail riwayat pemesanan
*/
public function show($id)
{ {
$sewa = Sewa::with(['paket', 'kota', 'user']) if (Auth::user()->tipe_pengguna !== 'admin') {
->findOrFail($id); return redirect()->route('dashboard')->with('error', 'Akses ditolak.');
// Pastikan yang melihat adalah pemilik pesanan
if ($sewa->user_id != Auth::id() && !Auth::user()->tipe_pengguna == 'admin') {
return redirect()->route('riwayat')
->with('error', 'Anda tidak memiliki akses untuk melihat pesanan ini.');
} }
// Jika request adalah AJAX, kembalikan response JSON $request->validate([
if (request()->ajax()) { 'status' => 'required|in:completed'
return response()->json([ ]);
'id' => $sewa->id,
'tanggal_pembayaran' => $sewa->tanggal_pembayaran ? $sewa->tanggal_pembayaran->format('d/m/Y H:i') : null,
'status_pembayaran' => $sewa->nominal_pembayaran
? ($sewa->nominal_pembayaran >= $sewa->total_harga ? 'Lunas' : 'DP ' . number_format(($sewa->nominal_pembayaran / $sewa->total_harga) * 100, 0) . '%')
: 'Belum Bayar',
'lokasi' => $sewa->lokasi,
'kota' => $sewa->kota,
'ongkir' => $sewa->ongkir,
'bukti_pembayaran' => $sewa->bukti_pembayaran,
'jenis_jaminan' => $sewa->jenis_jaminan,
'foto_jaminan' => $sewa->foto_jaminan
]);
}
return view('detail-riwayat', compact('sewa'));
}
/**
* Membatalkan pemesanan
*/
public function cancel($id)
{
$sewa = Sewa::findOrFail($id); $sewa = Sewa::findOrFail($id);
// Pastikan yang membatalkan adalah pemilik pesanan if ($sewa->status !== 'confirmed') {
if ($sewa->user_id != Auth::id()) { return back()->with('error', 'Status hanya bisa diubah jika saat ini adalah confirmed.');
return redirect()->route('riwayat')
->with('error', 'Anda tidak memiliki akses untuk membatalkan pesanan ini.');
} }
// Izinkan pembatalan untuk status yang belum selesai atau dibatalkan $sewa->status = $request->status;
if (in_array($sewa->status, ['completed', 'dibatalkan', 'ongoing'])) {
return redirect()->route('riwayat')
->with('error', 'Pesanan ini tidak dapat dibatalkan karena status sudah ' . $sewa->status);
}
// Tambahkan catatan jika pembatalan setelah disetujui
if ($sewa->status === 'confirmed') {
$sewa->catatan = ($sewa->catatan ? $sewa->catatan . "\n" : '') .
"[DIBATALKAN OLEH PENYEWA SETELAH DISETUJUI] - " . now();
}
$sewa->status = 'dibatalkan';
$sewa->save(); $sewa->save();
$message = 'Pesanan berhasil dibatalkan.'; return back()->with('success', 'Status berhasil diperbarui menjadi completed.');
if ($sewa->status === 'confirmed') {
$message .= ' Mohon hubungi admin untuk informasi biaya pembatalan.';
}
return redirect()->route('riwayat')
->with('success', $message);
} }
/**
* Halaman untuk admin melihat semua riwayat pesanan
*/
public function adminIndex()
{
// Hanya admin yang bisa akses
if (!Auth::user()->tipe_pengguna == 'admin') {
return redirect()->route('dashboard');
}
$sewas = Sewa::with(['paket', 'user'])
->orderBy('created_at', 'desc')
->get();
return view('admin.riwayat', compact('sewas'));
}
/**
* Mengubah status pemesanan (khusus admin)
*/
public function updateStatus(Request $request, $id)
{
if (Auth::user()->tipe_pengguna !== 'admin') {
return redirect()->route('dashboard')->with('error', 'Akses ditolak.');
}
$sewa = Sewa::findOrFail($id);
if ($sewa->status !== 'confirmed') {
return back()->with('error', 'Status hanya bisa diubah jika saat ini adalah confirmed.');
}
if ($request->status !== 'completed') {
return back()->with('error', 'Status hanya bisa diubah menjadi completed.');
}
$sewa->status = 'completed';
$sewa->save();
return back()->with('success', 'Status berhasil diperbarui menjadi completed.');
}
public function hapus($id) public function hapus($id)
{ {
$sewa = Sewa::findOrFail($id); $sewa = Sewa::findOrFail($id);
// Pastikan yang menghapus adalah pemilik pesanan
if ($sewa->user_id != Auth::id()) { if ($sewa->user_id != Auth::id()) {
return redirect()->route('riwayat') return redirect()->route('riwayat')
->with('error', 'Anda tidak memiliki akses untuk menghapus pesanan ini.'); ->with('error', 'Anda tidak memiliki akses untuk menghapus pesanan ini.');
} }
// Hanya bisa menghapus pesanan yang sudah selesai atau dibatalkan
if (!in_array($sewa->status, ['completed', 'dibatalkan'])) { if (!in_array($sewa->status, ['completed', 'dibatalkan'])) {
return redirect()->route('riwayat') return redirect()->route('riwayat')
->with('error', 'Hanya pesanan yang sudah selesai atau dibatalkan yang dapat dihapus.'); ->with('error', 'Hanya pesanan yang sudah selesai atau dibatalkan yang dapat dihapus.');
} }
// Hapus file bukti pembayaran dan jaminan jika ada
if ($sewa->bukti_pembayaran) { if ($sewa->bukti_pembayaran) {
Storage::disk('public')->delete($sewa->bukti_pembayaran); Storage::disk('public')->delete($sewa->bukti_pembayaran);
} }

View File

@ -13,21 +13,37 @@ class Chat extends Model
'sewa_id', 'sewa_id',
'sender_id', 'sender_id',
'receiver_id', 'receiver_id',
'admin_id', // tambahkan
'message', 'message',
'is_read' 'is_read',
]; ];
protected $casts = [ protected $casts = [
'is_read' => 'boolean' 'is_read' => 'boolean',
]; ];
/**
* Relasi ke model Sewa.
*/
public function sewa() public function sewa()
{ {
return $this->belongsTo(Sewa::class); return $this->belongsTo(Sewa::class);
} }
/**
* Relasi ke pengirim pesan (User).
*/
public function sender() public function sender()
{ {
return $this->belongsTo(User::class, 'sender_id'); return $this->belongsTo(User::class, 'sender_id');
} }
/**
* Relasi ke penerima pesan (User).
*/
public function receiver()
{
return $this->belongsTo(User::class, 'receiver_id');
}
} }

View File

@ -1,123 +1,63 @@
@extends('layouts.app') @extends('layouts.app')
@section('title', 'Riwayat Sewa - Admin INUFA')
@section('header', 'Manajemen Riwayat Sewa')
@section('content') @section('content')
<div class="bg-white rounded-lg shadow-lg p-6"> <div class="container">
@if(count($sewas) > 0) <h2>Riwayat Pemesanan</h2>
<div class="overflow-x-auto">
<table class="min-w-full bg-white"> @if(session('success'))
<thead> <div class="alert alert-success">{{ session('success') }}</div>
<tr class="bg-gray-100"> @endif
<th class="py-3 px-4 text-left">No</th> @if(session('error'))
<th class="py-3 px-4 text-left">Tanggal</th> <div class="alert alert-danger">{{ session('error') }}</div>
<th class="py-3 px-4 text-left">Customer</th> @endif
<th class="py-3 px-4 text-left">Paket</th>
<th class="py-3 px-4 text-left">Total Harga</th> <table class="table table-bordered">
<th class="py-3 px-4 text-left">Nominal Pembayaran</th> <thead>
<th class="py-3 px-4 text-left">Sisa Pembayaran</th> <tr>
<th class="py-3 px-4 text-left">Status</th> <th>No</th>
<th class="py-3 px-4 text-center">Aksi</th> <th>Paket</th>
</tr> <th>Kota</th>
</thead> <th>Status</th>
<tbody> <th>Total Harga</th>
@foreach($sewas as $index => $sewa) <th>Aksi</th>
@php </tr>
$user = optional($sewa->user); </thead>
$paket = optional($sewa->paket); <tbody>
$sisaPembayaran = $sewa->total_harga - ($sewa->nominal_pembayaran ?? 0); @forelse($sewas as $index => $sewa)
@endphp <tr>
<tr class="border-b hover:bg-gray-50"> <td>{{ $index + 1 }}</td>
<td class="py-3 px-4">{{ $index + 1 }}</td> <td>{{ $sewa->paket->nama_paket ?? '-' }}</td>
<td class="py-3 px-4">{{ $sewa->created_at->format('d/m/Y') }}</td> <td>{{ $sewa->kota->nama_kota ?? '-' }}</td>
<td class="py-3 px-4"> <td>
<div class="text-sm"> <span class="badge bg-info">{{ ucfirst($sewa->status) }}</span>
<p class="font-medium text-gray-900">{{ $user->name ?? '-' }}</p>
<p class="text-gray-500">{{ $user->email ?? '-' }}</p>
</div>
</td> </td>
<td class="py-3 px-4">{{ $paket->nama_paket ?? '-' }}</td> <td>Rp {{ number_format($sewa->total_harga, 0, ',', '.') }}</td>
<td class="py-3 px-4">Rp {{ number_format($sewa->total_harga, 0, ',', '.') }}</td> <td>
<td class="py-3 px-4"> <!-- Tombol tandai completed (hanya admin & status confirmed) -->
Rp {{ number_format($sewa->nominal_pembayaran ?? 0, 0, ',', '.') }} @if(Auth::user()->tipe_pengguna === 'admin' && $sewa->status === 'confirmed')
</td> <form action="{{ route('riwayat.updateStatus', $sewa->id) }}" method="POST" style="display:inline;">
<td class="py-3 px-4"> @csrf
@if($sisaPembayaran > 0) <input type="hidden" name="status" value="completed">
<span class="text-red-600 font-medium"> <button type="submit" class="btn btn-success btn-sm" onclick="return confirm('Tandai sebagai LUNAS / completed?')">Tandai Lunas</button>
Rp {{ number_format($sisaPembayaran, 0, ',', '.') }} </form>
</span> @endif
@else
<span class="text-green-600 font-medium">Lunas</span> <!-- Tombol hapus (jika status sudah selesai atau dibatalkan) -->
@if($sewa->user_id == Auth::id() && in_array($sewa->status, ['completed', 'dibatalkan']))
<form action="{{ url('/riwayat/hapus/'.$sewa->id) }}" method="POST" style="display:inline;">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger btn-sm" onclick="return confirm('Yakin ingin menghapus riwayat ini?')">Hapus</button>
</form>
@endif @endif
</td> </td>
<td class="py-3 px-4">
<span class="px-2 py-1 rounded-full text-xs font-semibold
@if($sewa->status == 'pending') bg-yellow-100 text-yellow-800
@elseif($sewa->status == 'confirmed') bg-blue-100 text-blue-800
@elseif($sewa->status == 'ongoing') bg-indigo-100 text-indigo-800
@elseif($sewa->status == 'completed') bg-green-100 text-green-800
@elseif($sewa->status == 'dibatalkan') bg-red-100 text-red-800
@endif">
{{ ucfirst($sewa->status) }}
</span>
</td>
<td class="py-3 px-4">
<div class="flex flex-col sm:flex-row justify-center sm:space-x-2 space-y-2 sm:space-y-0">
<!-- Tombol Detail -->
<a href="{{ route('admin.riwayat.show', $sewa->id) }}"
class="bg-blue-600 text-white px-3 py-1 rounded hover:bg-blue-700 text-sm">
Detail
</a>
<!-- Tombol Chat -->
<a href="{{ route('chat.show', $sewa->user_id) }}"
class="bg-green-500 text-white px-3 py-1 rounded hover:bg-green-600 text-sm">
Chat
</a>
@if($sewa->status === 'confirmed')
<!-- Tombol Tandai Selesai -->
<form action="{{ route('admin.riwayat.status', $sewa->id) }}" method="POST" class="inline">
@csrf
@method('PUT')
<input type="hidden" name="status" value="completed">
<button type="submit"
onclick="return confirm('Ubah status menjadi Completed?')"
class="bg-purple-600 text-white px-3 py-1 rounded hover:bg-purple-700 text-sm">
Tandai Selesai
</button>
</form>
@endif
@if(!in_array($sewa->status, ['completed', 'dibatalkan']))
<!-- Form Update Status -->
<form action="{{ route('admin.riwayat.status', $sewa->id) }}" method="POST">
@csrf
@method('PUT')
<select name="status"
onchange="this.form.submit()"
class="rounded-md border-gray-300 text-sm shadow-sm focus:border-blue-300 focus:ring focus:ring-blue-200 focus:ring-opacity-50">
<option value="pending" {{ $sewa->status == 'pending' ? 'selected' : '' }}>Pending</option>
<option value="confirmed" {{ $sewa->status == 'confirmed' ? 'selected' : '' }}>Confirmed</option>
<option value="ongoing" {{ $sewa->status == 'ongoing' ? 'selected' : '' }}>Ongoing</option>
<option value="completed" {{ $sewa->status == 'completed' ? 'selected' : '' }}>Completed</option>
<option value="dibatalkan" {{ $sewa->status == 'dibatalkan' ? 'selected' : '' }}>Dibatalkan</option>
</select>
</form>
@endif
</div>
</td>
</tr> </tr>
@endforeach @empty
</tbody> <tr>
</table> <td colspan="6">Tidak ada riwayat pemesanan.</td>
</div> </tr>
@else @endforelse
<div class="text-center py-8"> </tbody>
<p class="text-gray-500">Belum ada riwayat pemesanan</p> </table>
</div>
@endif
</div> </div>
@endsection @endsection

View File

@ -150,7 +150,12 @@
Route::get('/riwayat/{id}', [RiwayatController::class, 'show'])->name('riwayat.show'); Route::get('/riwayat/{id}', [RiwayatController::class, 'show'])->name('riwayat.show');
Route::put('/riwayat/{id}/status', [RiwayatController::class, 'updateStatus'])->name('riwayat.status'); Route::put('/riwayat/{id}/status', [RiwayatController::class, 'updateStatus'])->name('riwayat.status');
Route::get('/riwayat/{id}/update-payment', [RiwayatController::class, 'showUpdatePaymentForm'])->name('riwayat.show-update-payment'); Route::get('/riwayat/{id}/update-payment', [RiwayatController::class, 'showUpdatePaymentForm'])->name('riwayat.show-update-payment');
Route::put('/riwayat/{id}/update-payment', [RiwayatController::class, 'updatePayment'])->name('riwayat.update-payment'); // Route::put('/riwayat/{id}/update-payment', [RiwayatController::class, 'updatePayment'])->name('riwayat.update-payment');
// Route::post('/riwayat/update-status/{id}', [RiwayatController::class, 'updateStatus'])->name('riwayat.updateStatus');
Route::post('/riwayat/update-status/{id}', [\App\Http\Controllers\RiwayatController::class, 'updateStatus'])->name('riwayat.updateStatus');
Route::delete('/riwayat/hapus/{id}', [\App\Http\Controllers\RiwayatController::class, 'hapus']);
Route::get('/riwayat', [\App\Http\Controllers\RiwayatController::class, 'index'])->name('riwayat');
// Verifikasi Pembayaran // Verifikasi Pembayaran
Route::get('/verifikasi', [App\Http\Controllers\Admin\VerifikasiController::class, 'index'])->name('verifikasi.index'); Route::get('/verifikasi', [App\Http\Controllers\Admin\VerifikasiController::class, 'index'])->name('verifikasi.index');