Initial commit: API Wipay dengan fix CORS untuk GET request
This commit is contained in:
644
src/Controllers/PembayaranController.php
Normal file
644
src/Controllers/PembayaranController.php
Normal file
@@ -0,0 +1,644 @@
|
||||
<?php
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Helpers\HttpHelper;
|
||||
use App\Helpers\KodeHelper;
|
||||
use App\Helpers\QrisHelper;
|
||||
use App\Helpers\ResponseHelper;
|
||||
use App\Helpers\TelegramHelper;
|
||||
use App\Helpers\WhatsAppHelper;
|
||||
use App\Config\Database;
|
||||
use App\Models\PembayaranModel;
|
||||
use App\Models\UserModel;
|
||||
use Psr\Http\Message\ResponseInterface as Response;
|
||||
use Psr\Http\Message\ServerRequestInterface as Request;
|
||||
|
||||
class PembayaranController
|
||||
{
|
||||
private $pembayaranModel;
|
||||
private $userModel;
|
||||
private $db;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->pembayaranModel = new PembayaranModel();
|
||||
$this->userModel = new UserModel();
|
||||
$this->db = Database::getInstance();
|
||||
}
|
||||
|
||||
public function requestPembayaran(Request $request, Response $response): Response
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$token = $data['token'] ?? '';
|
||||
$no_sl = $data['no_sl'] ?? '';
|
||||
$nama_bank = $data['nama_bank'] ?? '';
|
||||
$no_rek = $data['no_rek'] ?? '';
|
||||
$payment_method = $data['payment_method'] ?? 'transfer'; // transfer, qris
|
||||
|
||||
// Format response awal sama dengan API lama
|
||||
$responseData = [
|
||||
'status' => 404,
|
||||
'pesan' => 'Gagal mendapatkan detail Tagihan anda, silahkan coba beberapa saat lagi'
|
||||
];
|
||||
|
||||
if (empty($token) || empty($no_sl)) {
|
||||
$responseData['pesan'] = 'Token dan nomor SL harus diisi';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
$pengguna = $this->userModel->findById($token);
|
||||
if (!$pengguna) {
|
||||
$responseData['pesan'] = 'Token tidak Valid. Silahkan Login dan Ulangi transaksi. Terima kasih';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
// Cek apakah ada pembayaran yang masih aktif
|
||||
$cek_pembayaran = $this->pembayaranModel->findByTokenAndSL($token, $no_sl, 'DIBUAT');
|
||||
if ($cek_pembayaran && strtotime($cek_pembayaran->waktu_expired) > time()) {
|
||||
$responseData = [
|
||||
'status' => 200,
|
||||
'pesan' => '',
|
||||
'data' => $cek_pembayaran
|
||||
];
|
||||
return ResponseHelper::custom($response, $responseData, 200);
|
||||
}
|
||||
|
||||
// Jika ada pembayaran yang expired, update status
|
||||
if ($cek_pembayaran) {
|
||||
$this->pembayaranModel->update($cek_pembayaran->id_pembayaran, ['status_bayar' => 'EXPIRED']);
|
||||
}
|
||||
|
||||
// Buat pembayaran baru
|
||||
$biaya_admin = 0;
|
||||
$promo = 0;
|
||||
$jumlah_unik = 0; // QRIS tidak pakai kode unik
|
||||
|
||||
// Cek tagihan dari API TIMO
|
||||
$respon = HttpHelper::doCurl('https://timo.tirtaintan.co.id/enquiry/' . $no_sl);
|
||||
|
||||
if (!$respon || $respon->errno != 0) {
|
||||
$responseData['pesan'] = 'Gagal mendapatkan data tagihan dari server';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
if (count($respon->data) > 0) {
|
||||
$total_tagihan = 0;
|
||||
foreach ($respon->data as $d) {
|
||||
$total_tagihan += $d->rek_total;
|
||||
$biaya_admin += $pengguna->biaya_admin;
|
||||
}
|
||||
|
||||
$total_pembayaran = $total_tagihan + $biaya_admin;
|
||||
|
||||
// Validasi QRIS: hanya untuk transaksi < 70 ribu
|
||||
if ($payment_method === 'qris') {
|
||||
if ($total_pembayaran > 70000) {
|
||||
$responseData['pesan'] = 'QRIS hanya tersedia untuk transaksi di bawah Rp 70.000';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
// QRIS tidak pakai kode unik
|
||||
$jumlah_unik = 0;
|
||||
} else {
|
||||
// BRI/Manual pakai kode unik
|
||||
$jumlah_unik = KodeHelper::generateKodeUnikPrioritas();
|
||||
}
|
||||
|
||||
$ins = [
|
||||
'no_trx' => '#TIMO' . $respon->token,
|
||||
'token' => $token,
|
||||
'no_sl' => $no_sl,
|
||||
'nama_bank' => $payment_method === 'qris' ? 'QRIS' : $nama_bank,
|
||||
'no_rekening' => $no_rek,
|
||||
'jumlah_tagihan' => (string)$total_tagihan,
|
||||
'biaya_admin' => (string)$biaya_admin,
|
||||
'jumlah_unik' => (string)$jumlah_unik,
|
||||
'promo' => (string)$promo,
|
||||
'raw_data' => json_encode($respon->data),
|
||||
'waktu_expired' => date('Y-m-d H:i:s', strtotime('+1 days')),
|
||||
'status_bayar' => 'DIBUAT',
|
||||
'tanggal_bayar' => '0000-00-00 00:00:00',
|
||||
'jumlah_bayar' => '0',
|
||||
'bukti_transfer' => '',
|
||||
'tanggal_request' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
|
||||
$pembayaranId = $this->pembayaranModel->create($ins);
|
||||
|
||||
// Jika QRIS, generate QR code
|
||||
if ($payment_method === 'qris' && $pembayaranId) {
|
||||
$qrisResponse = QrisHelper::createInvoice($ins['no_trx'], (int)$total_pembayaran, false);
|
||||
|
||||
if ($qrisResponse && isset($qrisResponse['data'])) {
|
||||
$qrisData = $qrisResponse['data'];
|
||||
$qrisRequestDate = date('Y-m-d H:i:s');
|
||||
$expiredMinutes = QrisHelper::getExpiredMinutes();
|
||||
$expiredAt = date('Y-m-d H:i:s', strtotime("+{$expiredMinutes} minutes"));
|
||||
|
||||
// Update pembayaran dengan data QRIS
|
||||
$this->db->update('pembayaran', [
|
||||
'qris_qr_code' => $qrisData['qris_content'] ?? '',
|
||||
'qris_invoiceid' => $qrisData['qris_invoiceid'] ?? '',
|
||||
'qris_nmid' => $qrisData['qris_nmid'] ?? QrisHelper::getNmid(),
|
||||
'qris_request_date' => $qrisRequestDate,
|
||||
'qris_expired_at' => $expiredAt,
|
||||
'qris_check_count' => 0,
|
||||
'qris_last_check_at' => null,
|
||||
'qris_status' => 'unpaid' // Initial status
|
||||
], 'id_pembayaran = :id', ['id' => $pembayaranId]);
|
||||
|
||||
$ins['qris_qr_code'] = $qrisData['qris_content'] ?? '';
|
||||
$ins['qris_invoiceid'] = $qrisData['qris_invoiceid'] ?? '';
|
||||
$ins['qris_nmid'] = $qrisData['qris_nmid'] ?? QrisHelper::getNmid();
|
||||
$ins['qris_request_date'] = $qrisRequestDate;
|
||||
$ins['qris_expired_at'] = $expiredAt;
|
||||
$ins['qris_status'] = 'unpaid';
|
||||
} else {
|
||||
$responseData['pesan'] = 'Gagal generate QRIS, silahkan coba lagi';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
}
|
||||
|
||||
if ($total_tagihan > 0) {
|
||||
$responseData = [
|
||||
'status' => 200,
|
||||
'pesan' => '',
|
||||
'data' => $ins
|
||||
];
|
||||
} else {
|
||||
$responseData['pesan'] = "Tidak ada tagihan untuk no SL $no_sl";
|
||||
}
|
||||
} else {
|
||||
$responseData['pesan'] = "Tidak ada tagihan untuk no SL $no_sl";
|
||||
}
|
||||
|
||||
return ResponseHelper::custom($response, $responseData, $responseData['status']);
|
||||
}
|
||||
|
||||
public function cekPembayaran(Request $request, Response $response): Response
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$token = $data['token'] ?? '';
|
||||
$no_sl = $data['no_sl'] ?? '';
|
||||
|
||||
// Format response awal sama dengan API lama
|
||||
$responseData = [
|
||||
'status' => 404,
|
||||
'pesan' => 'Gagal mendapatkan detail Tagihan anda, silahkan coba beberapa saat lagi'
|
||||
];
|
||||
|
||||
if (empty($token) || empty($no_sl)) {
|
||||
$responseData['pesan'] = 'Token dan nomor SL harus diisi';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
$pengguna = $this->userModel->findById($token);
|
||||
if (!$pengguna) {
|
||||
$responseData['pesan'] = 'Token tidak Valid. Silahkan Login dan Ulangi transaksi. Terima kasih';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
// Cek pembayaran dengan status DIBUAT atau MENUNGGU VERIFIKASI
|
||||
$cek_pembayaran = $this->pembayaranModel->findByTokenAndSL($token, $no_sl, ['DIBUAT', 'MENUNGGU VERIFIKASI']);
|
||||
|
||||
if ($cek_pembayaran && strtotime($cek_pembayaran->waktu_expired) > time()) {
|
||||
$responseData = [
|
||||
'status' => 200,
|
||||
'pesan' => '',
|
||||
'data' => $cek_pembayaran
|
||||
];
|
||||
}
|
||||
|
||||
return ResponseHelper::custom($response, $responseData, $responseData['status']);
|
||||
}
|
||||
|
||||
public function cekTransfer(Request $request, Response $response): Response
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$token = $data['token'] ?? '';
|
||||
$no_rek = $data['no_rek'] ?? '';
|
||||
|
||||
// Format response awal sama dengan API lama
|
||||
$responseData = [
|
||||
'status' => 404,
|
||||
'pesan' => 'Gagal membatalkan pembayaran, silahkan coba beberapa saat lagi'
|
||||
];
|
||||
|
||||
if (empty($token) || empty($no_rek)) {
|
||||
$responseData['pesan'] = 'Token dan nomor rekening harus diisi';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
$pengguna = $this->userModel->findById($token);
|
||||
if (!$pengguna) {
|
||||
$responseData['pesan'] = 'Token tidak Valid. Silahkan Login dan Ulangi transaksi. Terima kasih';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
$cek_pembayaran = $this->pembayaranModel->findByNoTrx($token, $no_rek);
|
||||
if ($cek_pembayaran) {
|
||||
$responseData = [
|
||||
'status' => 200,
|
||||
'pesan' => '',
|
||||
'data' => $cek_pembayaran
|
||||
];
|
||||
}
|
||||
|
||||
return ResponseHelper::custom($response, $responseData, $responseData['status']);
|
||||
}
|
||||
|
||||
public function batalPembayaran(Request $request, Response $response): Response
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$token = $data['token'] ?? '';
|
||||
$no_rek = $data['no_rek'] ?? '';
|
||||
|
||||
// Format response awal sama dengan API lama
|
||||
$responseData = [
|
||||
'status' => 404,
|
||||
'pesan' => 'Gagal membatalkan pembayaran, silahkan coba beberapa saat lagi'
|
||||
];
|
||||
|
||||
if (empty($token) || empty($no_rek)) {
|
||||
$responseData['pesan'] = 'Token dan nomor rekening harus diisi';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
$pengguna = $this->userModel->findById($token);
|
||||
if (!$pengguna) {
|
||||
$responseData['pesan'] = 'Token tidak Valid. Silahkan Login dan Ulangi transaksi. Terima kasih';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
$cek_pembayaran = $this->pembayaranModel->findByNoTrx($token, $no_rek);
|
||||
if ($cek_pembayaran) {
|
||||
$this->pembayaranModel->update($cek_pembayaran->id_pembayaran, ['status_bayar' => 'DIBATALKAN']);
|
||||
// Format response sama dengan API lama: status 200, pesan tetap ada (tidak diubah)
|
||||
$responseData['status'] = 200;
|
||||
// Pesan tetap dengan nilai default, tidak diubah (sesuai API lama)
|
||||
} else {
|
||||
$responseData['pesan'] = 'Tidak ada data dengan no SL $';
|
||||
}
|
||||
|
||||
return ResponseHelper::custom($response, $responseData, $responseData['status']);
|
||||
}
|
||||
|
||||
public function confirmPembayaran(Request $request, Response $response): Response
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$token = $data['token'] ?? '';
|
||||
$no_rek = $data['no_rek'] ?? ''; // API lama menggunakan no_rek (no_trx)
|
||||
|
||||
// Format response awal sama dengan API lama
|
||||
$responseData = [
|
||||
'status' => 404,
|
||||
'pesan' => 'Gagal membatalkan pembayaran, silahkan coba beberapa saat lagi'
|
||||
];
|
||||
|
||||
if (empty($token) || empty($no_rek)) {
|
||||
$responseData['pesan'] = 'Token dan nomor rekening harus diisi';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
$pengguna = $this->userModel->findById($token);
|
||||
if (!$pengguna) {
|
||||
$responseData['pesan'] = 'Token tidak Valid. Silahkan Login dan Ulangi transaksi. Terima kasih';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
// Cari pembayaran berdasarkan no_trx (no_rek)
|
||||
$cek_pembayaran = $this->pembayaranModel->findByNoTrx($token, $no_rek);
|
||||
if ($cek_pembayaran) {
|
||||
// Update status ke MENUNGGU VERIFIKASI
|
||||
$this->pembayaranModel->update($cek_pembayaran->id_pembayaran, [
|
||||
'status_bayar' => 'MENUNGGU VERIFIKASI'
|
||||
]);
|
||||
|
||||
// Kirim notifikasi Telegram
|
||||
$pesan = "🔔 *TRANSAKSI BARU*\n\n"
|
||||
. "No. Transaksi: " . $cek_pembayaran->no_trx . "\n"
|
||||
. "No. SL: " . $cek_pembayaran->no_sl . "\n"
|
||||
. "Jumlah: Rp " . number_format($cek_pembayaran->jumlah_tagihan + $cek_pembayaran->biaya_admin, 0, ',', '.') . "\n"
|
||||
. "Status: MENUNGGU VERIFIKASI\n\n"
|
||||
. "Silahkan verifikasi pembayaran.";
|
||||
TelegramHelper::sendToTransactionAdmin($pesan);
|
||||
|
||||
// Update respon_wa field
|
||||
$this->pembayaranModel->update($cek_pembayaran->id_pembayaran, [
|
||||
'respon_wa' => 'TELEGRAM_SENT_' . date('Y-m-d H:i:s') . ' | SUCCESS'
|
||||
]);
|
||||
|
||||
// Format response sama dengan API lama: status 200, pesan tetap ada (tidak diubah)
|
||||
$responseData['status'] = 200;
|
||||
// Pesan tetap dengan nilai default, tidak diubah (sesuai API lama)
|
||||
}
|
||||
|
||||
return ResponseHelper::custom($response, $responseData, $responseData['status']);
|
||||
}
|
||||
|
||||
public function historyBayar(Request $request, Response $response): Response
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$token = $data['token'] ?? '';
|
||||
|
||||
// Format response awal sama dengan API lama
|
||||
$responseData = [
|
||||
'status' => 404,
|
||||
'pesan' => '-'
|
||||
];
|
||||
|
||||
if (empty($token)) {
|
||||
$responseData['pesan'] = 'Token harus diisi';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
$pengguna = $this->userModel->findById($token);
|
||||
if (!$pengguna) {
|
||||
$responseData['pesan'] = 'Token tidak Valid';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
// History bayar hanya menampilkan yang status DIBAYAR (sama dengan API lama)
|
||||
$history = $this->pembayaranModel->getHistoryByToken($token, 'DIBAYAR', 20);
|
||||
|
||||
$responseData = [
|
||||
'status' => 200,
|
||||
'pesan' => '',
|
||||
'data' => $history
|
||||
];
|
||||
|
||||
return ResponseHelper::custom($response, $responseData, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* POST /timo/cek_status_qris
|
||||
* Check QRIS payment status (user-triggered)
|
||||
*/
|
||||
public function cekStatusQris(Request $request, Response $response): Response
|
||||
{
|
||||
$data = $request->getParsedBody();
|
||||
|
||||
$token = $data['token'] ?? '';
|
||||
$no_sl = $data['no_sl'] ?? '';
|
||||
|
||||
$responseData = [
|
||||
'status' => 404,
|
||||
'pesan' => 'Gagal cek status QRIS'
|
||||
];
|
||||
|
||||
if (empty($token) || empty($no_sl)) {
|
||||
$responseData['pesan'] = 'Token dan nomor SL harus diisi';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
$pengguna = $this->userModel->findById($token);
|
||||
if (!$pengguna) {
|
||||
$responseData['pesan'] = 'Token tidak Valid';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
// Cari pembayaran QRIS dengan status DIBUAT
|
||||
$pembayaran = $this->db->fetchOne(
|
||||
"SELECT * FROM pembayaran
|
||||
WHERE token = :token AND no_sl = :no_sl
|
||||
AND nama_bank = 'QRIS'
|
||||
AND status_bayar = 'DIBUAT'
|
||||
AND qris_invoiceid IS NOT NULL
|
||||
ORDER BY id_pembayaran DESC LIMIT 1",
|
||||
['token' => $token, 'no_sl' => $no_sl]
|
||||
);
|
||||
|
||||
if (!$pembayaran) {
|
||||
$responseData['pesan'] = 'Pembayaran QRIS tidak ditemukan';
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
// Cek apakah sudah expired
|
||||
if ($pembayaran->qris_expired_at && strtotime($pembayaran->qris_expired_at) < time()) {
|
||||
// Update status ke expired
|
||||
$this->db->update('pembayaran', [
|
||||
'qris_status' => 'expired'
|
||||
], 'id_pembayaran = :id', ['id' => $pembayaran->id_pembayaran]);
|
||||
|
||||
$responseData['pesan'] = 'QRIS sudah expired';
|
||||
$responseData['data'] = [
|
||||
'status' => 'expired',
|
||||
'message' => 'QRIS sudah expired. Silahkan buat pembayaran baru.'
|
||||
];
|
||||
return ResponseHelper::custom($response, $responseData, 404);
|
||||
}
|
||||
|
||||
// Cek apakah sudah mencapai max attempts (3)
|
||||
$checkCount = ($pembayaran->qris_check_count ?? 0);
|
||||
if ($checkCount >= 3) {
|
||||
$responseData = [
|
||||
'status' => 200,
|
||||
'pesan' => 'Silahkan upload bukti pembayaran atau hubungi customer service',
|
||||
'data' => [
|
||||
'status' => 'pending_verification',
|
||||
'check_count' => $checkCount,
|
||||
'message' => 'Pembayaran belum terdeteksi. Silahkan upload bukti pembayaran atau hubungi CS.',
|
||||
'show_upload_proof' => true,
|
||||
'show_contact_cs' => true
|
||||
]
|
||||
];
|
||||
return ResponseHelper::custom($response, $responseData, 200);
|
||||
}
|
||||
|
||||
// Cek status dari QRIS API dengan retry mechanism
|
||||
$totalBayar = (int)$pembayaran->jumlah_tagihan + (int)$pembayaran->biaya_admin;
|
||||
$transactionDate = $pembayaran->qris_request_date ?? $pembayaran->tanggal_request;
|
||||
$transactionDate = date('Y-m-d', strtotime($transactionDate)); // Format: YYYY-MM-DD
|
||||
|
||||
// Gunakan checkStatusWithRetry (max 3 attempts, 15 seconds interval)
|
||||
$qrisStatus = QrisHelper::checkStatusWithRetry(
|
||||
(int)$pembayaran->qris_invoiceid,
|
||||
$totalBayar,
|
||||
$transactionDate
|
||||
);
|
||||
|
||||
// Update check count
|
||||
$checkCount = $checkCount + 1;
|
||||
$this->db->update('pembayaran', [
|
||||
'qris_check_count' => $checkCount,
|
||||
'qris_last_check_at' => date('Y-m-d H:i:s')
|
||||
], 'id_pembayaran = :id', ['id' => $pembayaran->id_pembayaran]);
|
||||
|
||||
// Check response
|
||||
if ($qrisStatus && isset($qrisStatus['status']) && $qrisStatus['status'] == 'success') {
|
||||
$qrisData = $qrisStatus['data'] ?? [];
|
||||
$paymentStatus = $qrisData['qris_status'] ?? 'unpaid';
|
||||
|
||||
if ($paymentStatus == 'paid') {
|
||||
// Payment sudah dibayar, auto approve
|
||||
$this->autoApproveQris($pembayaran->id_pembayaran, $qrisData);
|
||||
|
||||
$responseData = [
|
||||
'status' => 200,
|
||||
'pesan' => 'Pembayaran berhasil',
|
||||
'data' => [
|
||||
'status' => 'paid',
|
||||
'message' => 'Pembayaran QRIS berhasil diverifikasi',
|
||||
'payment_method' => $qrisData['qris_payment_methodby'] ?? '',
|
||||
'customer_name' => $qrisData['qris_payment_customername'] ?? ''
|
||||
]
|
||||
];
|
||||
} else {
|
||||
// Masih unpaid
|
||||
if ($checkCount >= 3) {
|
||||
$responseData = [
|
||||
'status' => 200,
|
||||
'pesan' => 'Silahkan upload bukti pembayaran atau hubungi customer service',
|
||||
'data' => [
|
||||
'status' => 'pending_verification',
|
||||
'check_count' => $checkCount,
|
||||
'message' => 'Pembayaran belum terdeteksi setelah 3x pengecekan. Silahkan upload bukti pembayaran.',
|
||||
'show_upload_proof' => true,
|
||||
'show_contact_cs' => true
|
||||
]
|
||||
];
|
||||
} else {
|
||||
$responseData = [
|
||||
'status' => 200,
|
||||
'pesan' => 'Menunggu pembayaran',
|
||||
'data' => [
|
||||
'status' => 'unpaid',
|
||||
'check_count' => $checkCount,
|
||||
'remaining_attempts' => 3 - $checkCount,
|
||||
'message' => 'Silahkan scan QR code dan lakukan pembayaran'
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Request gagal atau response tidak valid
|
||||
if ($checkCount >= 3) {
|
||||
$responseData = [
|
||||
'status' => 200,
|
||||
'pesan' => 'Silahkan upload bukti pembayaran atau hubungi customer service',
|
||||
'data' => [
|
||||
'status' => 'pending_verification',
|
||||
'check_count' => $checkCount,
|
||||
'message' => 'Gagal mengecek status pembayaran. Silahkan upload bukti pembayaran.',
|
||||
'show_upload_proof' => true,
|
||||
'show_contact_cs' => true
|
||||
]
|
||||
];
|
||||
} else {
|
||||
$responseData = [
|
||||
'status' => 200,
|
||||
'pesan' => 'Menunggu pembayaran',
|
||||
'data' => [
|
||||
'status' => 'unpaid',
|
||||
'check_count' => $checkCount,
|
||||
'remaining_attempts' => 3 - $checkCount,
|
||||
'message' => 'Silahkan scan QR code dan lakukan pembayaran'
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return ResponseHelper::custom($response, $responseData, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto approve QRIS payment setelah verified paid
|
||||
*
|
||||
* @param int $pembayaranId ID pembayaran
|
||||
* @param array $qrisData Data dari QRIS API response
|
||||
*/
|
||||
private function autoApproveQris($pembayaranId, $qrisData = [])
|
||||
{
|
||||
try {
|
||||
$pembayaran = $this->db->fetchOne(
|
||||
"SELECT * FROM pembayaran WHERE id_pembayaran = :id LIMIT 1",
|
||||
['id' => $pembayaranId]
|
||||
);
|
||||
|
||||
if (!$pembayaran || $pembayaran->status_bayar !== 'DIBUAT') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update status ke MENUNGGU VERIFIKASI (sementara)
|
||||
$this->db->update('pembayaran', [
|
||||
'status_bayar' => 'MENUNGGU VERIFIKASI',
|
||||
'qris_status' => 'paid',
|
||||
'qris_payment_method' => $qrisData['qris_payment_methodby'] ?? '',
|
||||
'qris_payment_customer_name' => $qrisData['qris_payment_customername'] ?? ''
|
||||
], 'id_pembayaran = :id', ['id' => $pembayaranId]);
|
||||
|
||||
// Approve ke PDAM (sama seperti SiteController::approve)
|
||||
$token = str_replace('#TIMO', '', $pembayaran->no_trx);
|
||||
$url = "https://timo.tirtaintan.co.id/payment/$token";
|
||||
|
||||
$data = [];
|
||||
$rincian = json_decode($pembayaran->raw_data);
|
||||
|
||||
if (is_array($rincian) && count($rincian) > 0) {
|
||||
foreach ($rincian as $r) {
|
||||
$data[] = [
|
||||
'rek_nomor' => $r->rek_nomor ?? $r->rek_no ?? '',
|
||||
'rek_total' => $r->rek_total ?? 0,
|
||||
'serial' => '#TM' . time(),
|
||||
'byr_tgl' => date('YmdHis'),
|
||||
'loket' => 'TIMO',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$post = [
|
||||
'token' => $token,
|
||||
'data' => $data
|
||||
];
|
||||
|
||||
$headers = [
|
||||
'Content-Type: application/json',
|
||||
'Accept-Encoding: gzip, deflate',
|
||||
'Cache-Control: max-age=0',
|
||||
'Connection: keep-alive',
|
||||
'Accept-Language: en-US,en;q=0.8,id;q=0.6'
|
||||
];
|
||||
|
||||
$paymentResponse = HttpHelper::doCurl($url, 'POST', $post, true, $headers);
|
||||
|
||||
if ($paymentResponse && isset($paymentResponse->errno) && $paymentResponse->errno == 0) {
|
||||
$totalBayar = (int)$pembayaran->jumlah_tagihan + (int)$pembayaran->biaya_admin;
|
||||
$paidAt = date('Y-m-d H:i:s');
|
||||
|
||||
$this->db->update('pembayaran', [
|
||||
'status_bayar' => 'DIBAYAR',
|
||||
'tanggal_bayar' => $paidAt,
|
||||
'jumlah_bayar' => (string)$totalBayar,
|
||||
'raw_bayar' => json_encode($paymentResponse),
|
||||
'qris_paid_at' => $paidAt
|
||||
], 'id_pembayaran = :id', ['id' => $pembayaranId]);
|
||||
|
||||
// Kirim notifikasi WhatsApp ke user
|
||||
$user = $this->userModel->findById($pembayaran->token);
|
||||
if ($user && $user->no_hp) {
|
||||
$pesan = "✅ *Pembayaran Berhasil*\n\n"
|
||||
. "No. Transaksi: " . $pembayaran->no_trx . "\n"
|
||||
. "No. SL: " . $pembayaran->no_sl . "\n"
|
||||
. "Jumlah: Rp " . number_format($totalBayar, 0, ',', '.') . "\n"
|
||||
. "Metode: QRIS\n"
|
||||
. "E-Wallet: " . ($qrisData['qris_payment_methodby'] ?? '-') . "\n\n"
|
||||
. "Terima kasih telah melakukan pembayaran.";
|
||||
WhatsAppHelper::sendWa($user->no_hp, $pesan);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (\Exception $e) {
|
||||
error_log("Error in autoApproveQris: " . $e->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user