331 lines
14 KiB
PHP
331 lines
14 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
use App\Models\Booking;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Midtrans\Config;
|
|
use Midtrans\Snap;
|
|
use Midtrans\Notification;
|
|
use Midtrans\Transaction;
|
|
use App\Models\Wallet;
|
|
|
|
class MidtransController extends BaseController
|
|
{
|
|
public function __construct()
|
|
{
|
|
// Konfigurasi Midtrans
|
|
Config::$serverKey = env('MIDTRANS_SERVER_KEY', 'SB-Mid-server-m_cMr-8mOqJoaorKXpXoWBoQ');
|
|
Config::$isProduction = env('MIDTRANS_IS_PRODUCTION', false);
|
|
Config::$isSanitized = true;
|
|
Config::$is3ds = true;
|
|
}
|
|
|
|
/**
|
|
* Inisiasi pembayaran dengan Midtrans
|
|
*/
|
|
public function initiatePayment(Request $request, Booking $booking)
|
|
{
|
|
try {
|
|
// Periksa otentikasi dan otorisasi
|
|
if (Auth::id() !== $booking->customer_id) {
|
|
return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk melakukan pembayaran ini'], 403);
|
|
}
|
|
|
|
// Periksa status booking
|
|
if (!in_array($booking->status, ['reservasi', 'diproses', 'selesai'])) {
|
|
return $this->sendError('Invalid status', ['error' => 'Pesanan tidak dapat dibayar dengan status saat ini'], 422);
|
|
}
|
|
|
|
// Periksa jika pembayaran sudah dilakukan
|
|
if (in_array($booking->payment_status, ['paid', 'success'])) {
|
|
return $this->sendError('Already paid', ['error' => 'Pesanan ini sudah dibayar'], 422);
|
|
}
|
|
|
|
// Pastikan harga telah diatur
|
|
if (!$booking->total_price) {
|
|
return $this->sendError('Invalid price', ['error' => 'Harga belum ditetapkan oleh penjahit'], 422);
|
|
}
|
|
|
|
// Set up parameter untuk Midtrans
|
|
$params = [
|
|
'transaction_details' => [
|
|
'order_id' => $booking->transaction_code, // Gunakan transaction_code yang sudah ada
|
|
'gross_amount' => (int) ($booking->total_price + 4000), // Tambahkan biaya admin
|
|
],
|
|
'customer_details' => [
|
|
'first_name' => $booking->customer->name,
|
|
'email' => $booking->customer->email,
|
|
'phone' => $booking->customer->phone_number ?? '',
|
|
],
|
|
'item_details' => [
|
|
[
|
|
'id' => 'BOOKING-' . $booking->id,
|
|
'price' => (int) $booking->total_price,
|
|
'quantity' => 1,
|
|
'name' => 'Booking ' . $booking->service_type . ' - ' . $booking->category,
|
|
],
|
|
[
|
|
'id' => 'ADMIN-FEE',
|
|
'price' => 4000,
|
|
'quantity' => 1,
|
|
'name' => 'Biaya Admin (Payment Gateway + TailorHub)',
|
|
]
|
|
],
|
|
// CATATAN PENTING: Jangan aktifkan baris di bawah ini jika ingin menampilkan semua metode pembayaran
|
|
// Jika ingin membatasi metode pembayaran tertentu, uncomment baris di bawah ini
|
|
// 'enabled_payments' => ['bank_transfer'],
|
|
];
|
|
|
|
// Buat token transaksi Snap
|
|
$snapToken = Snap::getSnapToken($params);
|
|
|
|
// Simpan informasi pembayaran
|
|
$booking->update([
|
|
'payment_method' => 'transfer_bank_midtrans',
|
|
'midtrans_snap_token' => $snapToken
|
|
]);
|
|
|
|
return $this->sendResponse([
|
|
'snap_token' => $snapToken,
|
|
'redirect_url' => 'https://app.sandbox.midtrans.com/snap/v2/vtweb/' . $snapToken,
|
|
'booking' => [
|
|
'id' => $booking->id,
|
|
'transaction_code' => $booking->transaction_code,
|
|
'total_price' => $booking->total_price,
|
|
'status' => $booking->status,
|
|
]
|
|
], 'Token pembayaran berhasil dibuat');
|
|
|
|
} catch (\Exception $e) {
|
|
\Log::error('Error initiating Midtrans payment: ' . $e->getMessage());
|
|
return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat memulai pembayaran: ' . $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Callback notification handler dari Midtrans
|
|
*/
|
|
public function notificationHandler(Request $request)
|
|
{
|
|
try {
|
|
$notificationBody = $request->all();
|
|
\Log::info('Midtrans Notification Received', $notificationBody);
|
|
|
|
// Verifikasi signature menggunakan server key untuk keamanan
|
|
$notification = new Notification();
|
|
|
|
$transactionStatus = $notification->transaction_status;
|
|
$type = $notification->payment_type;
|
|
$orderId = $notification->order_id;
|
|
$fraud = $notification->fraud_status;
|
|
|
|
// Cari booking berdasarkan transaction_code (order_id)
|
|
$booking = Booking::where('transaction_code', $orderId)->first();
|
|
|
|
if (!$booking) {
|
|
return response()->json(['status' => 'error', 'message' => 'Booking tidak ditemukan'], 404);
|
|
}
|
|
|
|
// Proses berdasarkan status transaksi
|
|
if ($transactionStatus == 'capture') {
|
|
if ($type == 'credit_card'){
|
|
if($fraud == 'challenge'){
|
|
$booking->payment_status = 'pending';
|
|
} else {
|
|
$booking->payment_status = 'paid';
|
|
// Tambahkan dana ke wallet penjahit
|
|
$tailorWallet = $booking->tailor->wallet;
|
|
if (!$tailorWallet) {
|
|
$tailorWallet = Wallet::create([
|
|
'user_id' => $booking->tailor_id,
|
|
'balance' => 0
|
|
]);
|
|
}
|
|
$tailorWallet->addBalance(
|
|
$booking->total_price,
|
|
'Pembayaran booking #' . $booking->transaction_code,
|
|
$booking
|
|
);
|
|
}
|
|
}
|
|
}
|
|
else if ($transactionStatus == 'settlement') {
|
|
$booking->payment_status = 'paid';
|
|
// Tambahkan dana ke wallet penjahit
|
|
$tailorWallet = $booking->tailor->wallet;
|
|
if (!$tailorWallet) {
|
|
$tailorWallet = Wallet::create([
|
|
'user_id' => $booking->tailor_id,
|
|
'balance' => 0
|
|
]);
|
|
}
|
|
$tailorWallet->addBalance(
|
|
$booking->total_price,
|
|
'Pembayaran booking #' . $booking->transaction_code,
|
|
$booking
|
|
);
|
|
}
|
|
else if ($transactionStatus == 'pending') {
|
|
$booking->payment_status = 'pending';
|
|
}
|
|
else if ($transactionStatus == 'deny') {
|
|
$booking->payment_status = 'failed';
|
|
}
|
|
else if ($transactionStatus == 'expire') {
|
|
$booking->payment_status = 'expired';
|
|
}
|
|
else if ($transactionStatus == 'cancel') {
|
|
$booking->payment_status = 'cancelled';
|
|
}
|
|
|
|
// Simpan perubahan
|
|
$booking->save();
|
|
|
|
\Log::info('Payment status updated: ' . $booking->payment_status);
|
|
|
|
return response()->json(['status' => 'success', 'message' => 'Notification processed']);
|
|
|
|
} catch (\Exception $e) {
|
|
\Log::error('Error processing Midtrans notification: ' . $e->getMessage());
|
|
return response()->json(['status' => 'error', 'message' => $e->getMessage()], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Memeriksa status pembayaran
|
|
*/
|
|
public function checkPaymentStatus(Booking $booking)
|
|
{
|
|
try {
|
|
// Periksa otentikasi dan otorisasi
|
|
if (Auth::id() !== $booking->customer_id && Auth::id() !== $booking->tailor_id) {
|
|
return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk melihat status pembayaran ini'], 403);
|
|
}
|
|
|
|
return $this->sendResponse([
|
|
'booking_id' => $booking->id,
|
|
'transaction_code' => $booking->transaction_code,
|
|
'payment_status' => $booking->payment_status,
|
|
'payment_method' => $booking->payment_method,
|
|
'total_price' => $booking->total_price,
|
|
'status' => $booking->status,
|
|
'midtrans_snap_token' => $booking->midtrans_snap_token
|
|
], 'Status pembayaran berhasil diambil');
|
|
|
|
} catch (\Exception $e) {
|
|
\Log::error('Error checking payment status: ' . $e->getMessage());
|
|
return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat memeriksa status pembayaran'], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Memeriksa dan memperbarui status pembayaran secara manual
|
|
* Dapat digunakan sebagai alternatif notification handler Midtrans
|
|
*/
|
|
public function manualCheckStatus(Booking $booking)
|
|
{
|
|
try {
|
|
// Periksa otentikasi dan otorisasi
|
|
// User harus customer atau penjahit terkait atau admin
|
|
$user = Auth::user();
|
|
if ($user->id !== $booking->customer_id && $user->id !== $booking->tailor_id && !$user->hasRole('admin')) {
|
|
return $this->sendError('Unauthorized.', ['error' => 'Anda tidak memiliki akses untuk memeriksa status pembayaran ini'], 403);
|
|
}
|
|
|
|
// Periksa apakah booking memiliki transaction_code
|
|
if (!$booking->transaction_code) {
|
|
return $this->sendError('Invalid order', ['error' => 'Booking ini tidak memiliki kode transaksi'], 422);
|
|
}
|
|
|
|
// Periksa status transaksi di Midtrans
|
|
$statusResponse = Transaction::status($booking->transaction_code);
|
|
|
|
\Log::info('Midtrans Status Check Response', (array) $statusResponse);
|
|
|
|
$transactionStatus = $statusResponse->transaction_status ?? null;
|
|
$fraudStatus = $statusResponse->fraud_status ?? null;
|
|
$paymentType = $statusResponse->payment_type ?? null;
|
|
|
|
// Jika status sudah paid, tidak perlu update lagi
|
|
if (in_array($booking->payment_status, ['paid', 'success']) && $transactionStatus == 'settlement') {
|
|
return $this->sendResponse([
|
|
'booking_id' => $booking->id,
|
|
'transaction_code' => $booking->transaction_code,
|
|
'payment_status' => $booking->payment_status,
|
|
'payment_method' => $booking->payment_method,
|
|
'midtrans_status' => $transactionStatus,
|
|
], 'Pembayaran sudah berhasil');
|
|
}
|
|
|
|
// Update status pembayaran berdasarkan response
|
|
$statusUpdated = false;
|
|
|
|
if ($transactionStatus == 'capture') {
|
|
if ($paymentType == 'credit_card') {
|
|
if ($fraudStatus == 'challenge') {
|
|
$booking->payment_status = 'pending';
|
|
} else {
|
|
$booking->payment_status = 'paid';
|
|
$statusUpdated = true;
|
|
}
|
|
}
|
|
}
|
|
else if ($transactionStatus == 'settlement') {
|
|
$booking->payment_status = 'paid';
|
|
$statusUpdated = true;
|
|
}
|
|
else if ($transactionStatus == 'pending') {
|
|
$booking->payment_status = 'pending';
|
|
}
|
|
else if ($transactionStatus == 'deny') {
|
|
$booking->payment_status = 'failed';
|
|
}
|
|
else if ($transactionStatus == 'expire') {
|
|
$booking->payment_status = 'expired';
|
|
}
|
|
else if ($transactionStatus == 'cancel') {
|
|
$booking->payment_status = 'cancelled';
|
|
}
|
|
|
|
// Jika status berubah menjadi paid, tambahkan dana ke wallet penjahit
|
|
if ($statusUpdated && $booking->payment_status == 'paid') {
|
|
$tailorWallet = $booking->tailor->wallet;
|
|
if (!$tailorWallet) {
|
|
$tailorWallet = Wallet::create([
|
|
'user_id' => $booking->tailor_id,
|
|
'balance' => 0
|
|
]);
|
|
}
|
|
$tailorWallet->addBalance(
|
|
$booking->total_price,
|
|
'Pembayaran booking #' . $booking->transaction_code,
|
|
$booking
|
|
);
|
|
}
|
|
|
|
// Simpan perubahan
|
|
$booking->save();
|
|
|
|
\Log::info('Payment status manually updated: ' . $booking->payment_status);
|
|
|
|
return $this->sendResponse([
|
|
'booking_id' => $booking->id,
|
|
'transaction_code' => $booking->transaction_code,
|
|
'payment_status' => $booking->payment_status,
|
|
'payment_method' => $booking->payment_method,
|
|
'total_price' => $booking->total_price,
|
|
'status' => $booking->status,
|
|
'midtrans_status' => $transactionStatus,
|
|
'midtrans_snap_token' => $booking->midtrans_snap_token
|
|
], 'Status pembayaran berhasil diperbarui');
|
|
|
|
} catch (\Exception $e) {
|
|
\Log::error('Error checking payment status manually: ' . $e->getMessage());
|
|
return $this->sendError('Error.', ['error' => 'Terjadi kesalahan saat memeriksa status pembayaran: ' . $e->getMessage()], 500);
|
|
}
|
|
}
|
|
}
|