192 lines
5.7 KiB
PHP
192 lines
5.7 KiB
PHP
<?php
|
|
|
|
namespace App\Models;
|
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Database\Eloquent\Relations\HasOne;
|
|
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
|
|
use Carbon\Carbon;
|
|
|
|
class Reservasi extends Model
|
|
{
|
|
use HasFactory;
|
|
|
|
protected $table = 'reservasi';
|
|
|
|
protected $fillable = [
|
|
'user_id',
|
|
'meja_id',
|
|
'name',
|
|
'phone',
|
|
'date',
|
|
'start_time',
|
|
'status',
|
|
'notes',
|
|
'total_harga',
|
|
'payment_method'
|
|
];
|
|
|
|
protected $casts = [
|
|
'date' => 'date',
|
|
'start_time' => 'datetime:H:i',
|
|
];
|
|
|
|
const STATUS_PENDING = 'pending';
|
|
const STATUS_CONFIRMED = 'confirmed';
|
|
const STATUS_COMPLETED = 'completed';
|
|
const STATUS_CANCELLED = 'cancelled';
|
|
|
|
/**
|
|
* Get the user that owns the reservation.
|
|
*/
|
|
public function user(): BelongsTo
|
|
{
|
|
return $this->belongsTo(User::class);
|
|
}
|
|
|
|
/**
|
|
* Get the table that is reserved.
|
|
*/
|
|
public function meja(): BelongsTo
|
|
{
|
|
return $this->belongsTo(Meja::class, 'meja_id');
|
|
}
|
|
|
|
/**
|
|
* Get the transaction associated with the reservation.
|
|
*/
|
|
public function transaksi(): HasOne
|
|
{
|
|
return $this->hasOne(Transaksi::class);
|
|
}
|
|
|
|
/**
|
|
* Get the transaction items through the transaction.
|
|
*/
|
|
public function detailPesanan(): HasManyThrough
|
|
{
|
|
return $this->hasManyThrough(
|
|
TransaksiItem::class,
|
|
Transaksi::class,
|
|
'reservasi_id', // Foreign key on transaksi table...
|
|
'transaksi_id', // Foreign key on transaksi_items table...
|
|
'id', // Local key on reservasi table...
|
|
'id' // Local key on transaksi table...
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check if a time slot is available for a specific table.
|
|
*/
|
|
public static function isTimeSlotAvailable($mejaId, $date, $startTime): bool
|
|
{
|
|
// Convert times to Carbon instances for comparison
|
|
$start = Carbon::parse($startTime);
|
|
$requestedDate = Carbon::parse($date);
|
|
|
|
// Check if the requested date and time is in the past
|
|
if ($requestedDate->isPast() && $requestedDate->isToday() && $start->isPast()) {
|
|
return false;
|
|
}
|
|
|
|
// Check for existing reservations at the same time slot
|
|
$conflictingReservations = self::where('meja_id', $mejaId)
|
|
->whereDate('date', $date)
|
|
->whereNotIn('status', [self::STATUS_CANCELLED])
|
|
->where('start_time', $startTime)
|
|
->exists();
|
|
|
|
return !$conflictingReservations;
|
|
}
|
|
|
|
/**
|
|
* Get all available time slots for a specific table and date
|
|
*/
|
|
public static function getAvailableTimeSlots($mejaId, $date)
|
|
{
|
|
// Get all reservations for this table on this date
|
|
$reservations = self::where('meja_id', $mejaId)
|
|
->whereDate('date', $date)
|
|
->whereNotIn('status', [self::STATUS_CANCELLED])
|
|
->get(['start_time']);
|
|
|
|
$timeSlots = [];
|
|
$startHour = 10; // 10:00
|
|
$endHour = 22; // 22:00
|
|
$interval = 30; // 30 minutes interval
|
|
|
|
for ($hour = $startHour; $hour < $endHour; $hour++) {
|
|
for ($minute = 0; $minute < 60; $minute += $interval) {
|
|
$currentTime = sprintf('%02d:%02d', $hour, $minute);
|
|
|
|
// Check if this time slot is available
|
|
if (self::isTimeSlotAvailable($mejaId, $date, $currentTime)) {
|
|
$timeSlots[] = [
|
|
'start_time' => $currentTime,
|
|
'is_available' => true
|
|
];
|
|
}
|
|
}
|
|
}
|
|
|
|
// If date is today, remove past time slots
|
|
if ($date == Carbon::today()->format('Y-m-d')) {
|
|
$currentTime = Carbon::now();
|
|
$timeSlots = array_filter($timeSlots, function($slot) use ($currentTime) {
|
|
return Carbon::parse($slot['start_time'])->gt($currentTime);
|
|
});
|
|
}
|
|
|
|
return array_values($timeSlots);
|
|
}
|
|
|
|
/**
|
|
* Update table status based on reservation status
|
|
*/
|
|
public function updateTableStatus()
|
|
{
|
|
if ($this->date == now()->format('Y-m-d')) {
|
|
$status = match($this->status) {
|
|
self::STATUS_CONFIRMED => 'dipesan',
|
|
self::STATUS_COMPLETED, self::STATUS_CANCELLED => 'tersedia',
|
|
default => null
|
|
};
|
|
|
|
if ($status) {
|
|
$this->meja()->update(['status' => $status]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get payment method display name
|
|
*/
|
|
public function getPaymentMethodDisplayAttribute()
|
|
{
|
|
$methods = [
|
|
'credit_card' => 'Kartu Kredit',
|
|
'mandiri_clickpay' => 'Mandiri Clickpay',
|
|
'cimb_clicks' => 'CIMB Clicks',
|
|
'bca_klikbca' => 'BCA KlikBCA',
|
|
'bca_klikpay' => 'BCA KlikPay',
|
|
'bri_epay' => 'BRI e-Pay',
|
|
'echannel' => 'Mandiri Bill Payment',
|
|
'permata_va' => 'Permata Virtual Account',
|
|
'bca_va' => 'BCA Virtual Account',
|
|
'bni_va' => 'BNI Virtual Account',
|
|
'bri_va' => 'BRI Virtual Account',
|
|
'other_va' => 'Virtual Account Bank Lain',
|
|
'gopay' => 'GoPay',
|
|
'shopeepay' => 'ShopeePay',
|
|
'qris' => 'QRIS',
|
|
'indomaret' => 'Indomaret',
|
|
'alfamart' => 'Alfamart',
|
|
'danamon_online' => 'Danamon Online Banking',
|
|
'akulaku' => 'Akulaku'
|
|
];
|
|
|
|
return $methods[$this->payment_method] ?? $this->payment_method;
|
|
}
|
|
}
|