Midtrans Berhasil
This commit is contained in:
parent
4de8cac352
commit
4e1dfd6f24
|
@ -5,13 +5,23 @@
|
||||||
|
|
||||||
use App\Models\Booking;
|
use App\Models\Booking;
|
||||||
use App\Models\Table;
|
use App\Models\Table;
|
||||||
|
use App\Services\MidtransService;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Support\Facades\Auth;
|
use Illuminate\Support\Facades\Auth;
|
||||||
use Carbon\Carbon;
|
use Carbon\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
class BookingController extends Controller
|
class BookingController extends Controller
|
||||||
{
|
{
|
||||||
|
protected $midtransService;
|
||||||
|
|
||||||
|
public function __construct(MidtransService $midtransService)
|
||||||
|
{
|
||||||
|
$this->midtransService = $midtransService;
|
||||||
|
}
|
||||||
|
|
||||||
public function store(Request $request) {
|
public function store(Request $request) {
|
||||||
|
try {
|
||||||
$request->validate([
|
$request->validate([
|
||||||
'table_id' => 'required|exists:tables,id',
|
'table_id' => 'required|exists:tables,id',
|
||||||
'start_time' => 'required|date',
|
'start_time' => 'required|date',
|
||||||
|
@ -27,22 +37,64 @@ public function store(Request $request) {
|
||||||
->where('end_time', '>', $request->start_time);
|
->where('end_time', '>', $request->start_time);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
->where('status', '!=', 'cancelled') // skip booking yang dibatalkan
|
->where('status', '!=', 'cancelled')
|
||||||
|
->where('status', '!=', 'expired')
|
||||||
->exists();
|
->exists();
|
||||||
|
|
||||||
if ($conflict) {
|
if ($conflict) {
|
||||||
return response()->json(['message' => 'Meja sudah dibooking di jam tersebut'], 409);
|
return response()->json(['message' => 'Meja sudah dibooking di jam tersebut'], 409);
|
||||||
}
|
}
|
||||||
|
|
||||||
Booking::create([
|
// Hitung total biaya
|
||||||
|
$table = Table::findOrFail($request->table_id);
|
||||||
|
$startTime = Carbon::parse($request->start_time);
|
||||||
|
$endTime = Carbon::parse($request->end_time);
|
||||||
|
$duration = $endTime->diffInHours($startTime);
|
||||||
|
$totalAmount = $duration * $table->price_per_hour;
|
||||||
|
|
||||||
|
// Buat booking dengan status pending
|
||||||
|
$booking = Booking::create([
|
||||||
'table_id' => $request->table_id,
|
'table_id' => $request->table_id,
|
||||||
'user_id' => Auth::id(),
|
'user_id' => Auth::id(),
|
||||||
'start_time' => $request->start_time,
|
'start_time' => $request->start_time,
|
||||||
'end_time' => $request->end_time,
|
'end_time' => $request->end_time,
|
||||||
'status' => 'booked',
|
'status' => 'pending',
|
||||||
|
'total_amount' => $totalAmount,
|
||||||
|
'payment_expired_at' => now()->addHours(24), // Expired dalam 24 jam
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return response()->json(['message' => 'Booking berhasil']);
|
// Dapatkan snap token dari Midtrans
|
||||||
|
$snapToken = $this->midtransService->createTransaction($booking);
|
||||||
|
|
||||||
|
if (!$snapToken) {
|
||||||
|
throw new \Exception('Failed to get snap token from Midtrans');
|
||||||
|
}
|
||||||
|
|
||||||
|
\Log::info('Booking created successfully:', [
|
||||||
|
'booking_id' => $booking->id,
|
||||||
|
'snap_token' => $snapToken
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Booking berhasil dibuat, silahkan lakukan pembayaran',
|
||||||
|
'booking_id' => $booking->id,
|
||||||
|
'total_amount' => $totalAmount,
|
||||||
|
'snap_token' => $snapToken
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
\Log::error('Booking error:', [
|
||||||
|
'message' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (isset($booking)) {
|
||||||
|
$booking->delete(); // Hapus booking jika gagal membuat transaksi
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Gagal membuat transaksi: ' . $e->getMessage()
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getBookedSchedules(Request $request) {
|
public function getBookedSchedules(Request $request) {
|
||||||
|
@ -54,6 +106,7 @@ public function getBookedSchedules(Request $request) {
|
||||||
$bookings = Booking::where('table_id', $request->table_id)
|
$bookings = Booking::where('table_id', $request->table_id)
|
||||||
->whereDate('start_time', $request->date)
|
->whereDate('start_time', $request->date)
|
||||||
->where('status', '!=', 'cancelled')
|
->where('status', '!=', 'cancelled')
|
||||||
|
->where('status', '!=', 'expired')
|
||||||
->select('start_time', 'end_time')
|
->select('start_time', 'end_time')
|
||||||
->get()
|
->get()
|
||||||
->map(function ($booking) {
|
->map(function ($booking) {
|
||||||
|
@ -65,4 +118,58 @@ public function getBookedSchedules(Request $request) {
|
||||||
|
|
||||||
return response()->json($bookings);
|
return response()->json($bookings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function handleNotification(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$notification = $request->all();
|
||||||
|
Log::info('Midtrans notification received:', $notification);
|
||||||
|
|
||||||
|
$transactionStatus = $notification['transaction_status'];
|
||||||
|
$orderId = $notification['order_id'];
|
||||||
|
$fraudStatus = $notification['fraud_status'];
|
||||||
|
|
||||||
|
// Get booking from order_id
|
||||||
|
$booking = Booking::where('order_id', $orderId)->first();
|
||||||
|
if (!$booking) {
|
||||||
|
Log::error('Booking not found for order_id: ' . $orderId);
|
||||||
|
return response()->json(['message' => 'Booking not found'], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update booking status based on transaction status
|
||||||
|
if ($transactionStatus == 'capture') {
|
||||||
|
if ($fraudStatus == 'challenge') {
|
||||||
|
$booking->status = 'challenge';
|
||||||
|
} else if ($fraudStatus == 'accept') {
|
||||||
|
$booking->status = 'paid';
|
||||||
|
// Update table status to booked
|
||||||
|
$booking->table->update(['status' => 'Booked']);
|
||||||
|
}
|
||||||
|
} else if ($transactionStatus == 'settlement') {
|
||||||
|
$booking->status = 'paid';
|
||||||
|
// Update table status to booked
|
||||||
|
$booking->table->update(['status' => 'Booked']);
|
||||||
|
} else if ($transactionStatus == 'cancel' || $transactionStatus == 'deny' || $transactionStatus == 'expire') {
|
||||||
|
$booking->status = 'cancelled';
|
||||||
|
// Reset table status to available if no other active bookings
|
||||||
|
$hasActiveBookings = $booking->table->bookings()
|
||||||
|
->where('status', 'paid')
|
||||||
|
->where('id', '!=', $booking->id)
|
||||||
|
->exists();
|
||||||
|
if (!$hasActiveBookings) {
|
||||||
|
$booking->table->update(['status' => 'Available']);
|
||||||
|
}
|
||||||
|
} else if ($transactionStatus == 'pending') {
|
||||||
|
$booking->status = 'pending';
|
||||||
|
}
|
||||||
|
|
||||||
|
$booking->save();
|
||||||
|
Log::info('Booking status updated:', ['booking_id' => $booking->id, 'status' => $booking->status]);
|
||||||
|
|
||||||
|
return response()->json(['message' => 'Notification processed successfully']);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error processing Midtrans notification: ' . $e->getMessage());
|
||||||
|
return response()->json(['message' => 'Error processing notification'], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,24 @@ class Booking extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
protected $fillable = ['table_id', 'user_id', 'start_time', 'end_time', 'status'];
|
protected $fillable = [
|
||||||
|
'table_id',
|
||||||
|
'user_id',
|
||||||
|
'start_time',
|
||||||
|
'end_time',
|
||||||
|
'status',
|
||||||
|
'payment_id',
|
||||||
|
'payment_method',
|
||||||
|
'total_amount',
|
||||||
|
'payment_expired_at'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'start_time' => 'datetime',
|
||||||
|
'end_time' => 'datetime',
|
||||||
|
'payment_expired_at' => 'datetime',
|
||||||
|
'total_amount' => 'decimal:2'
|
||||||
|
];
|
||||||
|
|
||||||
public function table()
|
public function table()
|
||||||
{
|
{
|
||||||
|
@ -20,4 +37,24 @@ public function user()
|
||||||
{
|
{
|
||||||
return $this->belongsTo(User::class);
|
return $this->belongsTo(User::class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isPending()
|
||||||
|
{
|
||||||
|
return $this->status === 'pending';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isPaid()
|
||||||
|
{
|
||||||
|
return $this->status === 'paid';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isExpired()
|
||||||
|
{
|
||||||
|
return $this->status === 'expired';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isCancelled()
|
||||||
|
{
|
||||||
|
return $this->status === 'cancelled';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,17 @@ class Table extends Model
|
||||||
{
|
{
|
||||||
use HasFactory;
|
use HasFactory;
|
||||||
|
|
||||||
protected $fillable = ['venue_id', 'name', 'brand', 'status'];
|
protected $fillable = [
|
||||||
|
'name',
|
||||||
|
'brand',
|
||||||
|
'status',
|
||||||
|
'venue_id',
|
||||||
|
'price_per_hour'
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'price_per_hour' => 'decimal:2'
|
||||||
|
];
|
||||||
|
|
||||||
public function venue()
|
public function venue()
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
namespace App\Providers;
|
namespace App\Providers;
|
||||||
|
|
||||||
use Illuminate\Support\ServiceProvider;
|
use Illuminate\Support\ServiceProvider;
|
||||||
|
use App\Services\MidtransService;
|
||||||
|
|
||||||
class AppServiceProvider extends ServiceProvider
|
class AppServiceProvider extends ServiceProvider
|
||||||
{
|
{
|
||||||
|
@ -11,7 +12,9 @@ class AppServiceProvider extends ServiceProvider
|
||||||
*/
|
*/
|
||||||
public function register(): void
|
public function register(): void
|
||||||
{
|
{
|
||||||
//
|
$this->app->singleton(MidtransService::class, function ($app) {
|
||||||
|
return new MidtransService();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Services;
|
||||||
|
|
||||||
|
use App\Models\Booking;
|
||||||
|
use Midtrans\Config;
|
||||||
|
use Midtrans\Snap;
|
||||||
|
use Illuminate\Support\Facades\Log;
|
||||||
|
|
||||||
|
class MidtransService
|
||||||
|
{
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$serverKey = config('midtrans.server_key');
|
||||||
|
$clientKey = config('midtrans.client_key');
|
||||||
|
$merchantId = config('midtrans.merchant_id');
|
||||||
|
$isProduction = config('midtrans.is_production', false);
|
||||||
|
|
||||||
|
// Log semua konfigurasi untuk debugging
|
||||||
|
Log::info('Midtrans Configuration:', [
|
||||||
|
'server_key' => $serverKey,
|
||||||
|
'client_key' => $clientKey,
|
||||||
|
'merchant_id' => $merchantId,
|
||||||
|
'is_production' => $isProduction
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (empty($serverKey)) {
|
||||||
|
throw new \Exception('Midtrans server key is not configured');
|
||||||
|
}
|
||||||
|
|
||||||
|
Config::$serverKey = $serverKey;
|
||||||
|
Config::$isProduction = $isProduction;
|
||||||
|
Config::$isSanitized = true;
|
||||||
|
Config::$is3ds = true;
|
||||||
|
|
||||||
|
// Log konfigurasi yang digunakan oleh Midtrans
|
||||||
|
Log::info('Midtrans Config:', [
|
||||||
|
'server_key' => Config::$serverKey,
|
||||||
|
'is_production' => Config::$isProduction,
|
||||||
|
'is_sanitized' => Config::$isSanitized,
|
||||||
|
'is_3ds' => Config::$is3ds
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createTransaction(Booking $booking)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (!$booking->user) {
|
||||||
|
throw new \Exception('User not found for booking');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($booking->total_amount) || $booking->total_amount <= 0) {
|
||||||
|
throw new \Exception('Invalid booking amount');
|
||||||
|
}
|
||||||
|
|
||||||
|
$params = [
|
||||||
|
'transaction_details' => [
|
||||||
|
'order_id' => 'BOOK-' . $booking->id,
|
||||||
|
'gross_amount' => (int) $booking->total_amount,
|
||||||
|
],
|
||||||
|
'customer_details' => [
|
||||||
|
'first_name' => $booking->user->name,
|
||||||
|
'email' => $booking->user->email,
|
||||||
|
],
|
||||||
|
'item_details' => [
|
||||||
|
[
|
||||||
|
'id' => $booking->table_id,
|
||||||
|
'price' => (int) $booking->total_amount,
|
||||||
|
'quantity' => 1,
|
||||||
|
'name' => 'Booking Meja ' . $booking->table->name,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
'expiry' => [
|
||||||
|
'start_time' => now()->format('Y-m-d H:i:s O'),
|
||||||
|
'unit' => 'hour',
|
||||||
|
'duration' => 24,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
||||||
|
Log::info('Creating Midtrans transaction:', [
|
||||||
|
'booking_id' => $booking->id,
|
||||||
|
'amount' => $booking->total_amount,
|
||||||
|
'params' => $params
|
||||||
|
]);
|
||||||
|
|
||||||
|
$snapToken = Snap::getSnapToken($params);
|
||||||
|
|
||||||
|
if (empty($snapToken)) {
|
||||||
|
throw new \Exception('Empty snap token received from Midtrans');
|
||||||
|
}
|
||||||
|
|
||||||
|
Log::info('Midtrans transaction created successfully:', [
|
||||||
|
'booking_id' => $booking->id,
|
||||||
|
'snap_token' => $snapToken
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $snapToken;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Midtrans transaction failed:', [
|
||||||
|
'booking_id' => $booking->id,
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
throw new \Exception('Failed to create Midtrans transaction: ' . $e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleNotification($notification)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$transaction = $notification->transaction_status;
|
||||||
|
$type = $notification->payment_type;
|
||||||
|
$orderId = $notification->order_id;
|
||||||
|
$fraud = $notification->fraud_status;
|
||||||
|
|
||||||
|
Log::info('Received Midtrans notification:', [
|
||||||
|
'transaction_status' => $transaction,
|
||||||
|
'payment_type' => $type,
|
||||||
|
'order_id' => $orderId,
|
||||||
|
'fraud_status' => $fraud
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Extract booking ID from order ID (format: BOOK-{id})
|
||||||
|
$bookingId = explode('-', $orderId)[1];
|
||||||
|
$booking = Booking::findOrFail($bookingId);
|
||||||
|
|
||||||
|
if ($transaction == 'capture') {
|
||||||
|
if ($type == 'credit_card') {
|
||||||
|
if ($fraud == 'challenge') {
|
||||||
|
$booking->status = 'pending';
|
||||||
|
} else {
|
||||||
|
$booking->status = 'paid';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ($transaction == 'settlement') {
|
||||||
|
$booking->status = 'paid';
|
||||||
|
} else if ($transaction == 'pending') {
|
||||||
|
$booking->status = 'pending';
|
||||||
|
} else if ($transaction == 'deny') {
|
||||||
|
$booking->status = 'cancelled';
|
||||||
|
} else if ($transaction == 'expire') {
|
||||||
|
$booking->status = 'expired';
|
||||||
|
} else if ($transaction == 'cancel') {
|
||||||
|
$booking->status = 'cancelled';
|
||||||
|
}
|
||||||
|
|
||||||
|
$booking->payment_id = $notification->transaction_id;
|
||||||
|
$booking->payment_method = $type;
|
||||||
|
$booking->save();
|
||||||
|
|
||||||
|
Log::info('Booking status updated:', [
|
||||||
|
'booking_id' => $booking->id,
|
||||||
|
'new_status' => $booking->status
|
||||||
|
]);
|
||||||
|
|
||||||
|
return $booking;
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Failed to handle Midtrans notification:', [
|
||||||
|
'error' => $e->getMessage(),
|
||||||
|
'trace' => $e->getTraceAsString()
|
||||||
|
]);
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,11 +6,13 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^8.1",
|
"php": "^8.1",
|
||||||
|
"doctrine/dbal": "^3.9",
|
||||||
"guzzlehttp/guzzle": "^7.2",
|
"guzzlehttp/guzzle": "^7.2",
|
||||||
"laravel/framework": "^10.10",
|
"laravel/framework": "^10.10",
|
||||||
"laravel/sanctum": "^3.3",
|
"laravel/sanctum": "^3.3",
|
||||||
"laravel/tinker": "^2.8",
|
"laravel/tinker": "^2.8",
|
||||||
"laravel/ui": "^4.6"
|
"laravel/ui": "^4.6",
|
||||||
|
"midtrans/midtrans-php": "^2.6"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"fakerphp/faker": "^1.9.1",
|
"fakerphp/faker": "^1.9.1",
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "dcbbd52cf3c38d0f1b88e12d39e47db7",
|
"content-hash": "edf30558ed2abcf5bae02cf31ec6ee71",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "brick/math",
|
"name": "brick/math",
|
||||||
|
@ -210,6 +210,349 @@
|
||||||
},
|
},
|
||||||
"time": "2024-07-08T12:26:09+00:00"
|
"time": "2024-07-08T12:26:09+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/cache",
|
||||||
|
"version": "2.2.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/cache.git",
|
||||||
|
"reference": "1ca8f21980e770095a31456042471a57bc4c68fb"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/cache/zipball/1ca8f21980e770095a31456042471a57bc4c68fb",
|
||||||
|
"reference": "1ca8f21980e770095a31456042471a57bc4c68fb",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "~7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"doctrine/common": ">2.2,<2.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"cache/integration-tests": "dev-master",
|
||||||
|
"doctrine/coding-standard": "^9",
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
||||||
|
"psr/cache": "^1.0 || ^2.0 || ^3.0",
|
||||||
|
"symfony/cache": "^4.4 || ^5.4 || ^6",
|
||||||
|
"symfony/var-exporter": "^4.4 || ^5.4 || ^6"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\Common\\Cache\\": "lib/Doctrine/Common/Cache"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Guilherme Blanco",
|
||||||
|
"email": "guilhermeblanco@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Roman Borschel",
|
||||||
|
"email": "roman@code-factory.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benjamin Eberlei",
|
||||||
|
"email": "kontakt@beberlei.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonathan Wage",
|
||||||
|
"email": "jonwage@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Johannes Schmitt",
|
||||||
|
"email": "schmittjoh@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP Doctrine Cache library is a popular cache implementation that supports many different drivers such as redis, memcache, apc, mongodb and others.",
|
||||||
|
"homepage": "https://www.doctrine-project.org/projects/cache.html",
|
||||||
|
"keywords": [
|
||||||
|
"abstraction",
|
||||||
|
"apcu",
|
||||||
|
"cache",
|
||||||
|
"caching",
|
||||||
|
"couchdb",
|
||||||
|
"memcached",
|
||||||
|
"php",
|
||||||
|
"redis",
|
||||||
|
"xcache"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/doctrine/cache/issues",
|
||||||
|
"source": "https://github.com/doctrine/cache/tree/2.2.0"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://www.patreon.com/phpdoctrine",
|
||||||
|
"type": "patreon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fcache",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2022-05-20T20:07:39+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/dbal",
|
||||||
|
"version": "3.9.4",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/dbal.git",
|
||||||
|
"reference": "ec16c82f20be1a7224e65ac67144a29199f87959"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/dbal/zipball/ec16c82f20be1a7224e65ac67144a29199f87959",
|
||||||
|
"reference": "ec16c82f20be1a7224e65ac67144a29199f87959",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"composer-runtime-api": "^2",
|
||||||
|
"doctrine/cache": "^1.11|^2.0",
|
||||||
|
"doctrine/deprecations": "^0.5.3|^1",
|
||||||
|
"doctrine/event-manager": "^1|^2",
|
||||||
|
"php": "^7.4 || ^8.0",
|
||||||
|
"psr/cache": "^1|^2|^3",
|
||||||
|
"psr/log": "^1|^2|^3"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/coding-standard": "12.0.0",
|
||||||
|
"fig/log-test": "^1",
|
||||||
|
"jetbrains/phpstorm-stubs": "2023.1",
|
||||||
|
"phpstan/phpstan": "2.1.1",
|
||||||
|
"phpstan/phpstan-strict-rules": "^2",
|
||||||
|
"phpunit/phpunit": "9.6.22",
|
||||||
|
"slevomat/coding-standard": "8.13.1",
|
||||||
|
"squizlabs/php_codesniffer": "3.10.2",
|
||||||
|
"symfony/cache": "^5.4|^6.0|^7.0",
|
||||||
|
"symfony/console": "^4.4|^5.4|^6.0|^7.0"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"symfony/console": "For helpful console commands such as SQL execution and import of files."
|
||||||
|
},
|
||||||
|
"bin": [
|
||||||
|
"bin/doctrine-dbal"
|
||||||
|
],
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\DBAL\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Guilherme Blanco",
|
||||||
|
"email": "guilhermeblanco@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Roman Borschel",
|
||||||
|
"email": "roman@code-factory.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benjamin Eberlei",
|
||||||
|
"email": "kontakt@beberlei.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonathan Wage",
|
||||||
|
"email": "jonwage@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.",
|
||||||
|
"homepage": "https://www.doctrine-project.org/projects/dbal.html",
|
||||||
|
"keywords": [
|
||||||
|
"abstraction",
|
||||||
|
"database",
|
||||||
|
"db2",
|
||||||
|
"dbal",
|
||||||
|
"mariadb",
|
||||||
|
"mssql",
|
||||||
|
"mysql",
|
||||||
|
"oci8",
|
||||||
|
"oracle",
|
||||||
|
"pdo",
|
||||||
|
"pgsql",
|
||||||
|
"postgresql",
|
||||||
|
"queryobject",
|
||||||
|
"sasql",
|
||||||
|
"sql",
|
||||||
|
"sqlite",
|
||||||
|
"sqlserver",
|
||||||
|
"sqlsrv"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/doctrine/dbal/issues",
|
||||||
|
"source": "https://github.com/doctrine/dbal/tree/3.9.4"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://www.patreon.com/phpdoctrine",
|
||||||
|
"type": "patreon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fdbal",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2025-01-16T08:28:55+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/deprecations",
|
||||||
|
"version": "1.1.5",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/deprecations.git",
|
||||||
|
"reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
|
||||||
|
"reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^7.1 || ^8.0"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"phpunit/phpunit": "<=7.5 || >=13"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/coding-standard": "^9 || ^12 || ^13",
|
||||||
|
"phpstan/phpstan": "1.4.10 || 2.1.11",
|
||||||
|
"phpstan/phpstan-phpunit": "^1.0 || ^2",
|
||||||
|
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12",
|
||||||
|
"psr/log": "^1 || ^2 || ^3"
|
||||||
|
},
|
||||||
|
"suggest": {
|
||||||
|
"psr/log": "Allows logging deprecations via PSR-3 logger implementation"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\Deprecations\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.",
|
||||||
|
"homepage": "https://www.doctrine-project.org/",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/doctrine/deprecations/issues",
|
||||||
|
"source": "https://github.com/doctrine/deprecations/tree/1.1.5"
|
||||||
|
},
|
||||||
|
"time": "2025-04-07T20:06:18+00:00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "doctrine/event-manager",
|
||||||
|
"version": "2.0.1",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/doctrine/event-manager.git",
|
||||||
|
"reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/doctrine/event-manager/zipball/b680156fa328f1dfd874fd48c7026c41570b9c6e",
|
||||||
|
"reference": "b680156fa328f1dfd874fd48c7026c41570b9c6e",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": "^8.1"
|
||||||
|
},
|
||||||
|
"conflict": {
|
||||||
|
"doctrine/common": "<2.9"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"doctrine/coding-standard": "^12",
|
||||||
|
"phpstan/phpstan": "^1.8.8",
|
||||||
|
"phpunit/phpunit": "^10.5",
|
||||||
|
"vimeo/psalm": "^5.24"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Doctrine\\Common\\": "src"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Guilherme Blanco",
|
||||||
|
"email": "guilhermeblanco@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Roman Borschel",
|
||||||
|
"email": "roman@code-factory.org"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Benjamin Eberlei",
|
||||||
|
"email": "kontakt@beberlei.de"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jonathan Wage",
|
||||||
|
"email": "jonwage@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Johannes Schmitt",
|
||||||
|
"email": "schmittjoh@gmail.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Marco Pivetta",
|
||||||
|
"email": "ocramius@gmail.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "The Doctrine Event Manager is a simple PHP event system that was built to be used with the various Doctrine projects.",
|
||||||
|
"homepage": "https://www.doctrine-project.org/projects/event-manager.html",
|
||||||
|
"keywords": [
|
||||||
|
"event",
|
||||||
|
"event dispatcher",
|
||||||
|
"event manager",
|
||||||
|
"event system",
|
||||||
|
"events"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/doctrine/event-manager/issues",
|
||||||
|
"source": "https://github.com/doctrine/event-manager/tree/2.0.1"
|
||||||
|
},
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"url": "https://www.doctrine-project.org/sponsorship.html",
|
||||||
|
"type": "custom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://www.patreon.com/phpdoctrine",
|
||||||
|
"type": "patreon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://tidelift.com/funding/github/packagist/doctrine%2Fevent-manager",
|
||||||
|
"type": "tidelift"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"time": "2024-05-22T20:47:39+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "doctrine/inflector",
|
"name": "doctrine/inflector",
|
||||||
"version": "2.0.10",
|
"version": "2.0.10",
|
||||||
|
@ -1947,6 +2290,67 @@
|
||||||
],
|
],
|
||||||
"time": "2024-09-21T08:32:55+00:00"
|
"time": "2024-09-21T08:32:55+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "midtrans/midtrans-php",
|
||||||
|
"version": "2.6.2",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/Midtrans/midtrans-php.git",
|
||||||
|
"reference": "8ed7fc58ff1ababe675da17acf8233f4028eb3be"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/Midtrans/midtrans-php/zipball/8ed7fc58ff1ababe675da17acf8233f4028eb3be",
|
||||||
|
"reference": "8ed7fc58ff1ababe675da17acf8233f4028eb3be",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"ext-curl": "*",
|
||||||
|
"ext-json": "*",
|
||||||
|
"ext-openssl": "*",
|
||||||
|
"php": ">=5.4"
|
||||||
|
},
|
||||||
|
"require-dev": {
|
||||||
|
"phpunit/phpunit": "5.7.*",
|
||||||
|
"psy/psysh": "0.4.*"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"SnapBi\\": "SnapBi/",
|
||||||
|
"Midtrans\\": "Midtrans/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Andri Setiawan",
|
||||||
|
"email": "andri.setiawan@veritrans.co.id"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Alvin Litani",
|
||||||
|
"email": "alvin.litani@veritrans.co.id"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ismail Faruqi",
|
||||||
|
"email": "ismail.faruqi@veritrans.co.id"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Muhammad Fauzi Masykur",
|
||||||
|
"email": "muhammad.masykur@gojek.com"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "PHP Wrapper for Midtrans Payment API.",
|
||||||
|
"homepage": "https://midtrans.com",
|
||||||
|
"support": {
|
||||||
|
"issues": "https://github.com/Midtrans/midtrans-php/issues",
|
||||||
|
"source": "https://github.com/Midtrans/midtrans-php/tree/v2.6.2"
|
||||||
|
},
|
||||||
|
"time": "2025-03-18T06:30:17+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "monolog/monolog",
|
"name": "monolog/monolog",
|
||||||
"version": "3.7.0",
|
"version": "3.7.0",
|
||||||
|
@ -2522,6 +2926,55 @@
|
||||||
],
|
],
|
||||||
"time": "2024-07-20T21:41:07+00:00"
|
"time": "2024-07-20T21:41:07+00:00"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "psr/cache",
|
||||||
|
"version": "3.0.0",
|
||||||
|
"source": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/php-fig/cache.git",
|
||||||
|
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf"
|
||||||
|
},
|
||||||
|
"dist": {
|
||||||
|
"type": "zip",
|
||||||
|
"url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
|
||||||
|
"reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf",
|
||||||
|
"shasum": ""
|
||||||
|
},
|
||||||
|
"require": {
|
||||||
|
"php": ">=8.0.0"
|
||||||
|
},
|
||||||
|
"type": "library",
|
||||||
|
"extra": {
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "1.0.x-dev"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoload": {
|
||||||
|
"psr-4": {
|
||||||
|
"Psr\\Cache\\": "src/"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notification-url": "https://packagist.org/downloads/",
|
||||||
|
"license": [
|
||||||
|
"MIT"
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "PHP-FIG",
|
||||||
|
"homepage": "https://www.php-fig.org/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "Common interface for caching libraries",
|
||||||
|
"keywords": [
|
||||||
|
"cache",
|
||||||
|
"psr",
|
||||||
|
"psr-6"
|
||||||
|
],
|
||||||
|
"support": {
|
||||||
|
"source": "https://github.com/php-fig/cache/tree/3.0.0"
|
||||||
|
},
|
||||||
|
"time": "2021-02-03T23:26:27+00:00"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "psr/clock",
|
"name": "psr/clock",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'merchant_id' => env('MIDTRANS_MERCHANT_ID', ''),
|
||||||
|
'client_key' => env('MIDTRANS_CLIENT_KEY', ''),
|
||||||
|
'server_key' => env('MIDTRANS_SERVER_KEY', ''),
|
||||||
|
'is_production' => env('MIDTRANS_IS_PRODUCTION', false),
|
||||||
|
'snap_url' => env('MIDTRANS_IS_PRODUCTION', false) ? 'https://app.midtrans.com/snap/snap.js' : 'https://app.sandbox.midtrans.com/snap/snap.js',
|
||||||
|
'notification_url' => env('APP_URL') . '/payment/notification',
|
||||||
|
'expiry_duration' => 24, // Durasi expired dalam jam
|
||||||
|
'expiry_unit' => 'hour',
|
||||||
|
];
|
|
@ -0,0 +1,39 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('bookings', function (Blueprint $table) {
|
||||||
|
$table->string('payment_id')->nullable();
|
||||||
|
$table->string('payment_method')->nullable();
|
||||||
|
$table->decimal('total_amount', 10, 2)->nullable();
|
||||||
|
$table->timestamp('payment_expired_at')->nullable();
|
||||||
|
|
||||||
|
// Update status column if it exists
|
||||||
|
if (Schema::hasColumn('bookings', 'status')) {
|
||||||
|
$table->string('status')->default('pending')->change();
|
||||||
|
} else {
|
||||||
|
$table->string('status')->default('pending');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('bookings', function (Blueprint $table) {
|
||||||
|
$table->dropColumn(['payment_id', 'payment_method', 'total_amount', 'payment_expired_at']);
|
||||||
|
// Don't drop status column as it might be used by other parts of the application
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('tables', function (Blueprint $table) {
|
||||||
|
$table->decimal('price_per_hour', 10, 2)->default(50000); // Default harga Rp 50.000 per jam
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('tables', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('price_per_hour');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
|
@ -16,7 +16,7 @@ public function run(): void
|
||||||
'name' => 'Capitano Billiard',
|
'name' => 'Capitano Billiard',
|
||||||
'location' => 'Genteng',
|
'location' => 'Genteng',
|
||||||
'address' => 'Jl. Hasanudin No.II, Dusun Krajan, Genteng Wetan, Kec. Genteng, Kabupaten Banyuwangi',
|
'address' => 'Jl. Hasanudin No.II, Dusun Krajan, Genteng Wetan, Kec. Genteng, Kabupaten Banyuwangi',
|
||||||
'price' => 30000,
|
'price' => 100000,
|
||||||
'image' => 'images/billiard2.jpg',
|
'image' => 'images/billiard2.jpg',
|
||||||
'tables' => [
|
'tables' => [
|
||||||
['name' => 'Table 1', 'brand' => 'Cosmic', 'status' => 'Available'],
|
['name' => 'Table 1', 'brand' => 'Cosmic', 'status' => 'Available'],
|
||||||
|
@ -31,7 +31,7 @@ public function run(): void
|
||||||
'name' => 'Osing Billiard Center',
|
'name' => 'Osing Billiard Center',
|
||||||
'location' => 'Lidah',
|
'location' => 'Lidah',
|
||||||
'address' => 'Dusun Krajan, Kalirejo, Kec. Kabat, Kabupaten Banyuwangi',
|
'address' => 'Dusun Krajan, Kalirejo, Kec. Kabat, Kabupaten Banyuwangi',
|
||||||
'price' => 25000,
|
'price' => 90000,
|
||||||
'image' => 'images/billiard3.jpg',
|
'image' => 'images/billiard3.jpg',
|
||||||
'tables' => [
|
'tables' => [
|
||||||
['name' => 'Table 1', 'brand' => 'Xingjue', 'status' => 'Booked'],
|
['name' => 'Table 1', 'brand' => 'Xingjue', 'status' => 'Booked'],
|
||||||
|
@ -47,7 +47,7 @@ public function run(): void
|
||||||
'name' => 'DAS Game & Billiard',
|
'name' => 'DAS Game & Billiard',
|
||||||
'location' => 'Jalen',
|
'location' => 'Jalen',
|
||||||
'address' => 'Jl. Samiran, Jalen Parungan, Setail, Kec. Genteng, Kabupaten Banyuwangi',
|
'address' => 'Jl. Samiran, Jalen Parungan, Setail, Kec. Genteng, Kabupaten Banyuwangi',
|
||||||
'price' => 20000,
|
'price' => 95000,
|
||||||
'image' => 'images/billiard4.jpg',
|
'image' => 'images/billiard4.jpg',
|
||||||
'tables' => [
|
'tables' => [
|
||||||
['name' => 'Table 1', 'brand' => 'Cosmic', 'status' => 'Available'],
|
['name' => 'Table 1', 'brand' => 'Cosmic', 'status' => 'Available'],
|
||||||
|
|
|
@ -80,6 +80,8 @@ class="flex items-center bg-[url('/public/images/map.jpg')] bg-cover bg-center p
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
|
||||||
|
<script src="https://app.sandbox.midtrans.com/snap/snap.js" data-client-key="{{ config('midtrans.client_key') }}"></script>
|
||||||
<script>
|
<script>
|
||||||
function updateClock() {
|
function updateClock() {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
@ -128,6 +130,7 @@ function updateClock() {
|
||||||
submitBooking(tableId, tableName) {
|
submitBooking(tableId, tableName) {
|
||||||
if (!this.isLoggedIn) {
|
if (!this.isLoggedIn) {
|
||||||
alert('Silahkan login terlebih dahulu untuk melakukan booking.');
|
alert('Silahkan login terlebih dahulu untuk melakukan booking.');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
const selectedTime = this.selectedTime;
|
const selectedTime = this.selectedTime;
|
||||||
const selectedDuration = this.selectedDuration;
|
const selectedDuration = this.selectedDuration;
|
||||||
|
@ -175,14 +178,37 @@ function updateClock() {
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (res.status === 409) throw new Error('Meja sudah dibooking.');
|
if (!res.ok) {
|
||||||
|
return res.json().then(err => {
|
||||||
|
throw new Error(err.message || 'Gagal membuat booking');
|
||||||
|
});
|
||||||
|
}
|
||||||
return res.json();
|
return res.json();
|
||||||
})
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
alert(`Booking ${tableName} berhasil! Meja akan diblokir dari ${selectedTime} hingga ${endTimeFormatted}`);
|
if (!data.snap_token) {
|
||||||
location.reload(); // Reload untuk update status meja
|
throw new Error('Snap token tidak ditemukan');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buka Snap Midtrans
|
||||||
|
window.snap.pay(data.snap_token, {
|
||||||
|
onSuccess: function(result) {
|
||||||
|
alert('Pembayaran berhasil!');
|
||||||
|
location.reload();
|
||||||
|
},
|
||||||
|
onPending: function(result) {
|
||||||
|
alert('Pembayaran pending, silahkan selesaikan pembayaran');
|
||||||
|
},
|
||||||
|
onError: function(result) {
|
||||||
|
alert('Pembayaran gagal');
|
||||||
|
},
|
||||||
|
onClose: function() {
|
||||||
|
alert('Anda menutup popup tanpa menyelesaikan pembayaran');
|
||||||
|
}
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
|
console.error('Booking error:', err);
|
||||||
alert('Gagal booking: ' + err.message);
|
alert('Gagal booking: ' + err.message);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
@ -192,7 +218,4 @@ function updateClock() {
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<script src="https://unpkg.com/alpinejs@3.x.x/dist/cdn.min.js" defer></script>
|
|
||||||
@endsection
|
@endsection
|
|
@ -14,6 +14,9 @@
|
||||||
Route::get('/venue/{venueName}', [VenueController::class, "venue"])->name('venue');
|
Route::get('/venue/{venueName}', [VenueController::class, "venue"])->name('venue');
|
||||||
Route::post('/booking', [BookingController::class, 'store'])->name('booking.store');
|
Route::post('/booking', [BookingController::class, 'store'])->name('booking.store');
|
||||||
Route::get('/booking/schedules', [BookingController::class, 'getBookedSchedules'])->name('booking.schedules');
|
Route::get('/booking/schedules', [BookingController::class, 'getBookedSchedules'])->name('booking.schedules');
|
||||||
|
Route::post('/booking/payment', [BookingController::class, 'processPayment'])->name('booking.payment');
|
||||||
|
Route::get('/booking/payment/{bookingId}', [BookingController::class, 'checkPaymentStatus'])->name('booking.payment.status');
|
||||||
|
Route::post('/payment/notification', [BookingController::class, 'handleNotification'])->name('payment.notification');
|
||||||
Route::middleware(['auth', 'is_admin'])->prefix('admin')->group(function () {
|
Route::middleware(['auth', 'is_admin'])->prefix('admin')->group(function () {
|
||||||
Route::get('/', [AdminController::class, 'index'])->name('admin.dashboard');
|
Route::get('/', [AdminController::class, 'index'])->name('admin.dashboard');
|
||||||
Route::get('/bookings', [BookingsController::class, 'index'])->name('admin.bookings.index');
|
Route::get('/bookings', [BookingsController::class, 'index'])->name('admin.bookings.index');
|
||||||
|
|
Loading…
Reference in New Issue