From 791ca8dd842cb38c22432d647323f7352b9444e5 Mon Sep 17 00:00:00 2001 From: BTMS2 Date: Tue, 6 May 2025 10:12:20 +0800 Subject: [PATCH 1/2] tambah function semakan billplz --- app/Console/Commands/CheckBillplzPayments.php | 112 +++++++++++ app/Http/Controllers/ApiController.php | 62 ++++++ app/Http/Controllers/PembidaController.php | 170 ++++++++++++++++- app/Services/BillplzService.php | 49 +++++ config/services.php | 5 + .../views/pembida/semakanbillplz.blade.php | 178 ++++++++++++++++++ .../views/pembida/statuspembayaran2.blade.php | 2 + routes/web.php | 3 + 8 files changed, 580 insertions(+), 1 deletion(-) create mode 100644 app/Console/Commands/CheckBillplzPayments.php create mode 100644 app/Services/BillplzService.php create mode 100644 resources/views/pembida/semakanbillplz.blade.php diff --git a/app/Console/Commands/CheckBillplzPayments.php b/app/Console/Commands/CheckBillplzPayments.php new file mode 100644 index 00000000..53133b74 --- /dev/null +++ b/app/Console/Commands/CheckBillplzPayments.php @@ -0,0 +1,112 @@ +billplzService = $billplzService; + } + + public function handle() +{ + $date = $this->option('date') ?? now()->toDateString(); + $preview = $this->option('preview'); + + // Validate date + try { + $dateObj = Carbon::createFromFormat('Y-m-d', $date); + } catch (\Exception $e) { + $this->error("Invalid date format. Use YYYY-MM-DD."); + return 1; + } + + $this->info("Retrying Billplz check for date: {$dateObj->toDateString()}"); + + $date = $dateObj->toDateString(); + + $pendingResits = DB::table('resit as r') + ->join('payment as p', 'p.resit_id', '=', 'r.id') + ->join(DB::raw('( + SELECT user_id, total_payment, MIN(id) AS min_id + FROM payment + GROUP BY user_id, total_payment + ) as unique_payment'), 'p.id', '=', 'unique_payment.min_id') + ->whereNull('r.status') + ->where('p.status', 0) + ->whereNotNull('r.billplz_id') + ->whereDate('r.created_at', $date) + ->where('r.billplz_id', 'NOT LIKE', '%CDM%') + ->select('r.*', 'p.id as payment_id', 'p.total_payment') + ->distinct() + ->get(); + + if ($pendingResits->isEmpty()) { + $this->info('Tiada Resit belum dibayar ditemui.'); + return 0; + } + + if ($preview) { + $this->info("Preview mode aktif. Senarai Resit:"); + foreach ($pendingResits as $resit) { + $this->line("Resit ID: {$resit->id} | Billplz ID: {$resit->billplz_id} | Jumlah: RM{$resit->total_payment}"); + } + return 0; + } + + foreach ($pendingResits as $resit) { + $this->info("Semak Resit ID: {$resit->id}"); + + $billData = $this->billplzService->testGetBill($resit->billplz_id); + + if (isset($billData['error'])) { + $this->error("❌ Gagal semak Billplz untuk Resit {$resit->id}: {$billData['details']}"); + continue; + } + + if (isset($billData['paid']) && $billData['paid'] === true) { + // Simulate Request object + $data = [ + 'billplz' => [ + 'id' => $resit->billplz_id, + 'paid' => 'true', + 'paid_at' => $billData['paid_at'] ?? now()->toDateTimeString(), + ] + ]; + // dd($data); + + $apiController = App::make(ApiController::class); + $apiController->processPaidResit($data); + // dd($fakeRequest); + + + $this->info("✅ Resit ID {$resit->id} handled via processPaidResit."); + }else { + $this->info("ℹ️ Resit ID {$resit->id} masih belum dibayar."); + } + } + + $this->info('Semakan semula Billplz selesai.'); +} + + +} diff --git a/app/Http/Controllers/ApiController.php b/app/Http/Controllers/ApiController.php index e0da97b0..c3a641dc 100644 --- a/app/Http/Controllers/ApiController.php +++ b/app/Http/Controllers/ApiController.php @@ -39,6 +39,7 @@ use Billplz\Client; use Http\Client\Common\HttpMethodsClient; use Http\Adapter\Guzzle7\Client as GuzzleHttpClient; use Http\Message\MessageFactory\GuzzleMessageFactory; +use App\Models\LogUser; class ApiController extends Controller { @@ -644,5 +645,66 @@ class ApiController extends Controller return view('pembida.feePaymentResult', compact('data', 'result', 'success')); } } + + + // BillplzService.php atau ApiController.php +public function processPaidResit(array $data) +{ + $currentdate = Carbon::now(); + $currentdate = $currentdate->toDateTimeString(); + $loguser = new LogUser; + $loguser->user_id = User::where('name','System')->first()->id; + $loguser->date = $currentdate; + $loguser->username = 'System'; + $loguser->nama_user = 'System'; + $loguser->norujukan = $data['billplz']['id']; + $loguser->nota = 'Callback Resit Billplz Telah Bayar : Billplz_id -'.$data['billplz']['id']; + $loguser->save(); + + $resit = Resit::where('billplz_id', '=', $data['billplz']['id'])->first(); + + if (!$resit) { + return false; + } + + $resit->status = 'PAID'; + $resit->paid_at = $data['billplz']['paid_at']; + $resit->save(); + + $resitoriginal = Resit::where('user_id', $resit->user_id) + ->where('lelong_id', $resit->lelong_id) + ->where('resit_type', 2) + ->first(); + + $payment = Payment::where('lelong_id', $resit->lelong_id) + ->where('user_id', $resit->user_id) + ->where('resit_id', $resit->id) + ->get(); + + foreach ($payment as $index) { + $index->status = 2; + $index->remark = "BERJAYA BAYARAN ONLINE"; + $index->update(); + + $updateTagBid = LelongBid::where('norujukan', $index->norujukan)->first(); + if ($updateTagBid) { + $updateTagBid->status_payment = 2; + $updateTagBid->save(); + + $updateTagBidder = LelongBidder::where('lelongbid_id', $updateTagBid->id) + ->where('user_id', $resit->user_id)->first(); + if ($updateTagBidder) { + $updateTagBidder->status_payment = 2; + $updateTagBidder->payment_id = $index->id; + $updateTagBidder->save(); + } + } + } + + event(new PaymentNotify('PAID', $resit->user_id, $payment)); + + return true; +} + } \ No newline at end of file diff --git a/app/Http/Controllers/PembidaController.php b/app/Http/Controllers/PembidaController.php index 597b7b45..57fab8a2 100644 --- a/app/Http/Controllers/PembidaController.php +++ b/app/Http/Controllers/PembidaController.php @@ -24,19 +24,26 @@ use App\Models\Invoice; use App\Models\ScanJual; use App\Services\ResitPhotoService; use Symfony\Component\Console\Descriptor\Descriptor; +use Illuminate\Support\Facades\DB; +use App\Services\BillplzService; +use App\Http\Controllers\ApiController; + class PembidaController extends Controller { private $resitPhotoService; + protected $billplzService; + protected $ResitSemakanService; /** * Create a new controller instance. * * @return void */ - public function __construct(ResitPhotoService $resitPhotoService) + public function __construct(ResitPhotoService $resitPhotoService,BillplzService $billplzService) { $this->middleware('auth'); $this->resitPhotoService = $resitPhotoService; + $this->billplzService = $billplzService; } /** @@ -1371,5 +1378,166 @@ class PembidaController extends Controller //return view('pembida.statusserahanbypembida',compact('listwinner','lelong','arrayinfo','cawanganbidder')); return view('pembida.statusserahanbypembida',compact('arraysms','arraysls','listwinner','lelong','cawanganbidder')); } + + public function semakanBillplz(Request $request, BillplzService $billplzService) + { + $date = $request->input('date') ?? now()->toDateString(); + + try { + $dateObj = Carbon::createFromFormat('Y-m-d', $date); + } catch (\Exception $e) { + return back()->with('error', 'Tarikh tidak sah. Guna format YYYY-MM-DD.'); + } + + $date = $dateObj->toDateString(); + + $allPendingResits = DB::table('resit as r') + ->join('payment as p', 'p.resit_id', '=', 'r.id') + ->join(DB::raw('( + SELECT user_id, total_payment, MIN(id) AS min_id + FROM payment + GROUP BY user_id, total_payment + ) as unique_payment'), 'p.id', '=', 'unique_payment.min_id') + ->join('users as u', 'p.user_id', '=', 'u.id') + ->join('cawangan as c', 'p.kodcaw', '=', 'c.caw_code') // JOIN ikut kodcaw + // Elakkan resit yang ada CDM payment pada hari yang sama + ->whereNotExists(function ($query) use ($date) { + $query->select(DB::raw(1)) + ->from('resit as r2') + ->join('payment as p2', 'p2.resit_id', '=', 'r2.id') + ->whereRaw('p2.user_id = p.user_id') + ->whereRaw('p2.total_payment = p.total_payment') + ->whereDate('r2.created_at', $date) + ->where('r2.billplz_id', 'LIKE', '%CDM%'); + }) + ->whereNull('r.status') + ->where('p.status', 0) + ->whereNotNull('r.billplz_id') + ->where('r.billplz_id', 'NOT LIKE', '%CDM%') + ->whereDate('r.created_at', $date) + ->select( + 'r.*', + 'p.id as payment_id', + 'p.total_payment', + 'p.user_id', + 'u.name as payer_name', + 'c.caw_name as cawangan_nama' // Tambah nama cawangan + ) + ->distinct() + ->get(); + + // Kumpul mengikut billplz_id dan user_id + $groupedResitsUnpaid = $allPendingResits + ->groupBy('billplz_id') // Group mengikut billplz_id + ->map(function ($items) { + return (object) [ + 'billplz_id' => $items->first()->billplz_id, + 'jumlah_bayaran' => $items->sum('total_payment'), + 'payer_name' => $items->first()->payer_name, + 'cawangan_nama' => $items->first()->cawangan_nama, + 'resit_id' => $items->first()->id, + 'created_at' => $items->first()->created_at, + 'user_id' => $items->first()->user_id, + ]; + }) + ->values(); // Reset index + + + $billplzWithCdmResits = DB::table('resit as r') + ->join('payment as p', 'p.resit_id', '=', 'r.id') + ->join(DB::raw('( + SELECT user_id, total_payment, MIN(id) AS min_id + FROM payment + GROUP BY user_id, total_payment + ) as unique_payment'), 'p.id', '=', 'unique_payment.min_id') + ->join('users as u', 'p.user_id', '=', 'u.id') + ->join('cawangan as c', 'p.kodcaw', '=', 'c.caw_code') + ->whereNull('r.status') + ->where('p.status', 0) + ->whereNotNull('r.billplz_id') + ->where('r.billplz_id', 'NOT LIKE', '%CDM%') + ->whereDate('r.created_at', $date) + ->whereExists(function ($query) use ($date) { + $query->select(DB::raw(1)) + ->from('resit as r2') + ->join('payment as p2', 'p2.resit_id', '=', 'r2.id') + ->join('users as u2', 'p2.user_id', '=', 'u2.id') + ->whereRaw('u2.name = u.name') // banding nama + ->whereRaw('p2.total_payment = p.total_payment') // dan jumlah + ->whereDate('r2.created_at', $date) + ->where('r2.billplz_id', 'LIKE', '%CDM%'); + }) + ->select('r.*', 'p.id as payment_id', 'p.total_payment', 'u.name as payer_name', 'c.caw_name as cawangan_nama') + ->distinct() + ->get(); + + $groupedResits = $billplzWithCdmResits + ->groupBy('billplz_id') + ->map(function ($items) { + return (object) [ + 'billplz_id' => $items->first()->billplz_id, + 'jumlah_bayaran' => $items->sum('total_payment'), + 'payer_name' => $items->first()->payer_name, + 'cawangan_nama' => $items->first()->cawangan_nama, + 'resit_id' => $items->first()->id, + 'created_at' => $items->first()->created_at, + 'user_id' => $items->first()->user_id, + ]; + })->values(); + + + + + + // Semak status Billplz untuk setiap resit + $paidResits = collect(); + $unpaidResits = collect(); + $processingResits = collect(); + + foreach ($allPendingResits as $resit) { + $billData = $billplzService->testGetBill($resit->billplz_id); + + $isPaid = isset($billData['paid']) && $billData['paid'] === true; + $isProcessing = isset($billData['state']) && in_array($billData['state'], ['pending', 'processing']) && isset($billData['paid_at']); + + if ($isPaid) { + $resit->paid_at = $billData['paid_at'] ?? now(); + $paidResits->push($resit); + } elseif ($isProcessing) { + $resit->paid_at = $billData['paid_at']; + $resit->state = $billData['state']; + $processingResits->push($resit); + } else { + $unpaidResits->push($resit); + } + } + + return view('pembida.semakanbillplz', compact( + 'paidResits', + 'unpaidResits', + 'billplzWithCdmResits', + 'processingResits', + 'groupedResits', + 'groupedResitsUnpaid', + 'date' + )); + } + + public function prosesBillplz(Request $request) + { + $data = [ + 'billplz' => [ + 'id' => $request->billplz_id, + 'paid' => 'true', + 'paid_at' => $request->paid_at ?? now()->toDateTimeString(), + ] + ]; + + $apiController = app(ApiController::class); + $apiController->processPaidResit($data); + + return redirect()->back()->with('success', 'Resit telah diproses.'); + } + } \ No newline at end of file diff --git a/app/Services/BillplzService.php b/app/Services/BillplzService.php new file mode 100644 index 00000000..f279144f --- /dev/null +++ b/app/Services/BillplzService.php @@ -0,0 +1,49 @@ +client = new BillplzClient($http, $apiKey, $baseUrl); + } + + public function testGetBill(string $billId) + { + try { + // Minta details bill berdasarkan ID + $response = $this->client->bill()->get($billId); + + // Pastikan respons berjaya + if ($response->isSuccessful()) { + return $response->toArray(); // Kembalikan hasil dalam bentuk array + } + + return ['error' => 'Request failed', 'details' => $response->toArray()]; + } catch (NotFoundException $e) { + return ['error' => 'Bill not found', 'details' => $e->getMessage()]; + } catch (\Throwable $e) { + return ['error' => 'Unexpected error', 'details' => $e->getMessage()]; + } + } +} diff --git a/config/services.php b/config/services.php index 2a1d616c..91dedce4 100644 --- a/config/services.php +++ b/config/services.php @@ -30,4 +30,9 @@ return [ 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), ], + 'billplz' => [ + 'key' => env('BILLPLZ_API_KEY'), + 'sandbox' => env('BILLPLZ_SANDBOX', false), + ], + ]; diff --git a/resources/views/pembida/semakanbillplz.blade.php b/resources/views/pembida/semakanbillplz.blade.php new file mode 100644 index 00000000..daa85675 --- /dev/null +++ b/resources/views/pembida/semakanbillplz.blade.php @@ -0,0 +1,178 @@ +@extends('layouts.app') +@section('content') +
+
+
+
+
+ + + +
+ Semakan Billplz FPX +
+
+
+ @if ($message = Session::get('success')) +
+

{{ $message }}

+
+ @endif + +
+
+ + + +
+
+ + +
+ +

✅ Resit Telah Dibayar (PAID)

+@if($paidResits->isEmpty()) +

Tiada resit yang telah dibayar.

+@else + + + + + + + + + + + + + + + @foreach($paidResits as $resit) + + + + + + + + + + + @endforeach + +
Nama PembayarID PembayarCawanganResit IDBillplz IDJumlah (RM)Dibayar PadaTindakan
{{ $resit->payer_name ?? '-' }}{{ $resit->user_id }}{{ $resit->cawangan_nama ?? '-' }}{{ $resit->id }}{{ $resit->billplz_id }}{{ number_format($resit->total_payment, 2) }}{{ \Carbon\Carbon::parse($resit->paid_at)->format('d/m/Y H:i') }} +
+ @csrf + + + +
+
+@endif + +
+ +

❌ Resit Belum Dibayar (UNPAID)

+@if($unpaidResits->isEmpty()) +

Semua resit telah dibayar.

+@else + + + + + + + + + + + + + + @foreach ($groupedResitsUnpaid as $resit) + + + + + + + + + + @endforeach + +
Nama PembayarID PembayarCawanganResit IDBillplz IDJumlah (RM)Tarikh Dicipta
{{ $resit->payer_name ?? '-' }}{{ $resit->user_id }}{{ $resit->cawangan_nama ?? '-' }}{{ $resit->resit_id }}{{ $resit->billplz_id }}{{ number_format($resit->jumlah_bayaran, 2) }}{{ \Carbon\Carbon::parse($resit->created_at)->format('d/m/Y H:i') }}
+@endif + +
+

🔄 Resit Billplz yang Telah Dibayar Semula Melalui CDM

+@if($billplzWithCdmResits->isEmpty()) +

Tiada bayaran semula melalui CDM ditemui.

+@else + + + + + + + + + + + + + + @foreach ($groupedResits as $resit) + + + + + + + + + + @endforeach + +
Nama PembayarID PembayarCawanganJumlah (RM)Resit IDBillplz IDTarikh Dicipta
{{ $resit->payer_name }}{{ $resit->user_id }}{{ $resit->cawangan_nama }}{{ number_format($resit->jumlah_bayaran, 2) }}{{ $resit->resit_id }}{{ $resit->billplz_id }}{{ \Carbon\Carbon::parse($resit->created_at)->format('Y-m-d') }}
+@endif + +
+

🕒 Resit Telah Dibayar Tetapi Dalam Proses (PENDING)

+@if($processingResits->isEmpty()) +

Tiada resit yang belum direlease.

+@else + + + + + + + + + + + + + + @foreach($processingResits as $resit) + + + + + + + + + + @endforeach + +
Nama PembayarID PembayarCawanganResit IDBillplz IDJumlah (RM)Tarikh Dibayar
{{ $resit->payer_name }}{{ $resit->user_id }}{{ $resit->cawangan_nama ?? '-' }}{{ $resit->id }}{{ $resit->billplz_id }}{{ number_format($resit->total_payment, 2) }}{{ \Carbon\Carbon::parse($resit->paid_at)->format('d/m/Y H:i') }}
+@endif + + + + + +@endsection \ No newline at end of file diff --git a/resources/views/pembida/statuspembayaran2.blade.php b/resources/views/pembida/statuspembayaran2.blade.php index 6343a8e4..b5086619 100644 --- a/resources/views/pembida/statuspembayaran2.blade.php +++ b/resources/views/pembida/statuspembayaran2.blade.php @@ -13,6 +13,8 @@
@hasrole('operasi') Status Pembayaran Mengikut Nama Pembida + Semakan BILLPLZ + @endhasrole @hasrole('account') Status Pembayaran Mengikut Nama Pembida diff --git a/routes/web.php b/routes/web.php index ada42e86..1e4b41ff 100644 --- a/routes/web.php +++ b/routes/web.php @@ -364,6 +364,9 @@ Route::group(['middleware' => ['permission:pengesahanpembida'],'prefix'=>'pembid Route::get('/statuspembayaranbypembida',['as'=>'pembida.statuspembayaranbypembida','uses'=>'PembidaController@statuspembayaranbypembida']); Route::get('/statusserahanbidaan',['as'=>'pembida.statusserahanbidaan','uses'=>'PembidaController@statusserahanbidaan']); Route::get('/statusserahanbypembida',['as'=>'pembida.statusserahanbypembida','uses'=>'PembidaController@statusserahanbypembida']); + Route::get('/semakanbillplz',['as'=>'pembida.semakanbillplz','uses'=>'PembidaController@semakanbillplz']); + Route::post('/semakanbillplz/proses',['as'=>'pembida.prosesBillplz','uses'=>'PembidaController@prosesBillplz']); + // Route::get('/pemenangkedua',['as'=>'pembida.pemenangkedua','uses'=>'PembidaController@pemenangkedua']); // Route::get('/senaraipemenangkedua/{lelong_id}/{kodcaw}',['as'=>'pembida.senaraipemenangkedua','uses'=>'PembidaController@senaraipemenangkedua']); From 2c579e43278b7ce514263c000d42b74b59f0362a Mon Sep 17 00:00:00 2001 From: BTMS2 Date: Tue, 6 May 2025 16:13:34 +0800 Subject: [PATCH 2/2] tambah notifikasi wasap pembida billplz paid --- app/Http/Controllers/ApiController.php | 99 +++--- app/Http/Controllers/PembidaController.php | 1 + app/Jobs/WhatsappPembidaFPXPaid.php | 59 ++++ .../views/pembida/semakanbillplz.blade.php | 330 +++++++++--------- 4 files changed, 276 insertions(+), 213 deletions(-) create mode 100644 app/Jobs/WhatsappPembidaFPXPaid.php diff --git a/app/Http/Controllers/ApiController.php b/app/Http/Controllers/ApiController.php index c3a641dc..2a6a4ce9 100644 --- a/app/Http/Controllers/ApiController.php +++ b/app/Http/Controllers/ApiController.php @@ -40,6 +40,7 @@ use Http\Client\Common\HttpMethodsClient; use Http\Adapter\Guzzle7\Client as GuzzleHttpClient; use Http\Message\MessageFactory\GuzzleMessageFactory; use App\Models\LogUser; +use App\Jobs\WhatsappPembidaFPXPaid; class ApiController extends Controller { @@ -648,63 +649,67 @@ class ApiController extends Controller // BillplzService.php atau ApiController.php -public function processPaidResit(array $data) -{ - $currentdate = Carbon::now(); - $currentdate = $currentdate->toDateTimeString(); - $loguser = new LogUser; - $loguser->user_id = User::where('name','System')->first()->id; - $loguser->date = $currentdate; - $loguser->username = 'System'; - $loguser->nama_user = 'System'; - $loguser->norujukan = $data['billplz']['id']; - $loguser->nota = 'Callback Resit Billplz Telah Bayar : Billplz_id -'.$data['billplz']['id']; - $loguser->save(); - - $resit = Resit::where('billplz_id', '=', $data['billplz']['id'])->first(); + public function processPaidResit(array $data) + { + $currentdate = Carbon::now(); + $currentdate = $currentdate->toDateTimeString(); + $loguser = new LogUser; + $loguser->user_id = User::where('name','System')->first()->id; + $loguser->date = $currentdate; + $loguser->username = 'System'; + $loguser->nama_user = 'System'; + $loguser->norujukan = $data['billplz']['id']; + $loguser->nota = 'Callback Resit Billplz Telah Bayar : Billplz_id -'.$data['billplz']['id']; + $loguser->save(); + + $resit = Resit::where('billplz_id', '=', $data['billplz']['id'])->first(); - if (!$resit) { - return false; - } + if (!$resit) { + return false; + } - $resit->status = 'PAID'; - $resit->paid_at = $data['billplz']['paid_at']; - $resit->save(); + $resit->status = 'PAID'; + $resit->paid_at = $data['billplz']['paid_at']; + $resit->save(); - $resitoriginal = Resit::where('user_id', $resit->user_id) - ->where('lelong_id', $resit->lelong_id) - ->where('resit_type', 2) - ->first(); + $resitoriginal = Resit::where('user_id', $resit->user_id) + ->where('lelong_id', $resit->lelong_id) + ->where('resit_type', 2) + ->first(); - $payment = Payment::where('lelong_id', $resit->lelong_id) - ->where('user_id', $resit->user_id) - ->where('resit_id', $resit->id) - ->get(); + $payment = Payment::where('lelong_id', $resit->lelong_id) + ->where('user_id', $resit->user_id) + ->where('resit_id', $resit->id) + ->get(); - foreach ($payment as $index) { - $index->status = 2; - $index->remark = "BERJAYA BAYARAN ONLINE"; - $index->update(); + foreach ($payment as $index) { + $index->status = 2; + $index->remark = "BERJAYA BAYARAN ONLINE"; + $index->update(); - $updateTagBid = LelongBid::where('norujukan', $index->norujukan)->first(); - if ($updateTagBid) { - $updateTagBid->status_payment = 2; - $updateTagBid->save(); + $updateTagBid = LelongBid::where('norujukan', $index->norujukan)->first(); + if ($updateTagBid) { + $updateTagBid->status_payment = 2; + $updateTagBid->save(); - $updateTagBidder = LelongBidder::where('lelongbid_id', $updateTagBid->id) - ->where('user_id', $resit->user_id)->first(); - if ($updateTagBidder) { - $updateTagBidder->status_payment = 2; - $updateTagBidder->payment_id = $index->id; - $updateTagBidder->save(); + $updateTagBidder = LelongBidder::where('lelongbid_id', $updateTagBid->id) + ->where('user_id', $resit->user_id)->first(); + if ($updateTagBidder) { + $updateTagBidder->status_payment = 2; + $updateTagBidder->payment_id = $index->id; + $updateTagBidder->save(); + } } } + + event(new PaymentNotify('PAID', $resit->user_id, $payment)); + //notifikasi wasap kepada pembida// + WhatsappPembidaFPXPaid::dispatch($resit->user_id, + $resit->id, + $resit->total_payment); + + return true; } - event(new PaymentNotify('PAID', $resit->user_id, $payment)); - - return true; -} - } \ No newline at end of file diff --git a/app/Http/Controllers/PembidaController.php b/app/Http/Controllers/PembidaController.php index 57fab8a2..d76d8240 100644 --- a/app/Http/Controllers/PembidaController.php +++ b/app/Http/Controllers/PembidaController.php @@ -1528,6 +1528,7 @@ class PembidaController extends Controller $data = [ 'billplz' => [ 'id' => $request->billplz_id, + 'resit_id' => $request->resit_id, 'paid' => 'true', 'paid_at' => $request->paid_at ?? now()->toDateTimeString(), ] diff --git a/app/Jobs/WhatsappPembidaFPXPaid.php b/app/Jobs/WhatsappPembidaFPXPaid.php new file mode 100644 index 00000000..4ba3ce9d --- /dev/null +++ b/app/Jobs/WhatsappPembidaFPXPaid.php @@ -0,0 +1,59 @@ +userId = $userId; + $this->resitId = $resitId; + $this->amount = $amount; + } + + public function handle(): void + { + $dt = Carbon::now(); + $user = User::find($this->userId); + if (!$user || !$user->notelbimbit) return; + + $message = "Assalamualaikum {$user->name}, bayaran FPX anda sebanyak RM " . number_format($this->amount, 2) . " telah berjaya direkodkan. Resit ID: {$this->resitId}. Terima kasih."; + + $mobile_no = '6' . $user->notelbimbit; + if (config('app.env') != 'production') { + $mobile_no = config('app.admin_phone_number'); + } + + $response = Http::get(config('app.wabot_api'), [ + 'number' => $mobile_no, + 'type' => 'text', + 'message' => $message, + 'instance_id' => config('app.wabot_instances_id'), + 'access_token' => config('app.wabot_token_keys') + ]); + + $loguser = new LogUser; + $loguser->date = $dt; + $loguser->username = 'Operasi'; + $loguser->nama_user = 'System'; + $loguser->nota = 'Notifikasi Pembayaran Billplz Berjaya'; + $loguser->save(); + + Log::info("Notifikasi Pembayaran Billplz Berjaya: " . $response); + } +} diff --git a/resources/views/pembida/semakanbillplz.blade.php b/resources/views/pembida/semakanbillplz.blade.php index daa85675..4b3133ee 100644 --- a/resources/views/pembida/semakanbillplz.blade.php +++ b/resources/views/pembida/semakanbillplz.blade.php @@ -5,174 +5,172 @@
- - - -
- Semakan Billplz FPX -
+ + + +
Semakan Billplz FPX
+
- @if ($message = Session::get('success')) -
-

{{ $message }}

+ @if ($message = Session::get('success')) +
+

{{ $message }}

+
+ @endif + +
+
+ + + +
+
+ +
+

✅ Resit Telah Dibayar (PAID)

+ @if($paidResits->isEmpty()) +

Tiada resit yang telah dibayar.

+ @else + + + + + + + + + + + + + + + @foreach($paidResits as $resit) + + + + + + + + + + + @endforeach + +
Nama PembayarID PembayarCawanganResit IDBillplz IDJumlah (RM)Dibayar PadaTindakan
{{ $resit->payer_name ?? '-' }}{{ $resit->user_id }}{{ $resit->cawangan_nama ?? '-' }}{{ $resit->id }}{{ $resit->billplz_id }}{{ number_format($resit->total_payment, 2) }}{{ \Carbon\Carbon::parse($resit->paid_at)->format('d/m/Y H:i') }} +
+ @csrf + + + +
+
+ @endif + +
+ +

❌ Resit Belum Dibayar (UNPAID)

+ @if($unpaidResits->isEmpty()) +

Semua resit telah dibayar.

+ @else + + + + + + + + + + + + + + @foreach ($groupedResitsUnpaid as $resit) + + + + + + + + + + @endforeach + +
Nama PembayarID PembayarCawanganResit IDBillplz IDJumlah (RM)Tarikh Dicipta
{{ $resit->payer_name ?? '-' }}{{ $resit->user_id }}{{ $resit->cawangan_nama ?? '-' }}{{ $resit->resit_id }}{{ $resit->billplz_id }}{{ number_format($resit->jumlah_bayaran, 2) }}{{ \Carbon\Carbon::parse($resit->created_at)->format('d/m/Y H:i') }}
+ @endif + +
+

🔄 Resit Billplz yang Telah Dibayar Semula Melalui CDM

+ @if($billplzWithCdmResits->isEmpty()) +

Tiada bayaran semula melalui CDM ditemui.

+ @else + + + + + + + + + + + + + + @foreach ($groupedResits as $resit) + + + + + + + + + + @endforeach + +
Nama PembayarID PembayarCawanganResit IDBillplz IDJumlah (RM)Tarikh Dicipta
{{ $resit->payer_name }}{{ $resit->user_id }}{{ $resit->cawangan_nama }}{{ $resit->resit_id }}{{ $resit->billplz_id }}{{ number_format($resit->jumlah_bayaran, 2) }}{{ \Carbon\Carbon::parse($resit->created_at)->format('d/m/Y H:i') }}
+ @endif + +
+

🕒 Resit Telah Dibayar Tetapi Dalam Proses (PENDING)

+ @if($processingResits->isEmpty()) +

Tiada resit yang belum direlease.

+ @else + + + + + + + + + + + + + + @foreach($processingResits as $resit) + + + + + + + + + + @endforeach + +
Nama PembayarID PembayarCawanganResit IDBillplz IDJumlah (RM)Tarikh Dibayar
{{ $resit->payer_name }}{{ $resit->user_id }}{{ $resit->cawangan_nama ?? '-' }}{{ $resit->id }}{{ $resit->billplz_id }}{{ number_format($resit->total_payment, 2) }}{{ \Carbon\Carbon::parse($resit->paid_at)->format('d/m/Y H:i') }}
+ @endif +
- @endif - -
-
- - - +
+
- - - -
- -

✅ Resit Telah Dibayar (PAID)

-@if($paidResits->isEmpty()) -

Tiada resit yang telah dibayar.

-@else - - - - - - - - - - - - - - - @foreach($paidResits as $resit) - - - - - - - - - - - @endforeach - -
Nama PembayarID PembayarCawanganResit IDBillplz IDJumlah (RM)Dibayar PadaTindakan
{{ $resit->payer_name ?? '-' }}{{ $resit->user_id }}{{ $resit->cawangan_nama ?? '-' }}{{ $resit->id }}{{ $resit->billplz_id }}{{ number_format($resit->total_payment, 2) }}{{ \Carbon\Carbon::parse($resit->paid_at)->format('d/m/Y H:i') }} -
- @csrf - - - -
-
-@endif - -
- -

❌ Resit Belum Dibayar (UNPAID)

-@if($unpaidResits->isEmpty()) -

Semua resit telah dibayar.

-@else - - - - - - - - - - - - - - @foreach ($groupedResitsUnpaid as $resit) - - - - - - - - - - @endforeach - -
Nama PembayarID PembayarCawanganResit IDBillplz IDJumlah (RM)Tarikh Dicipta
{{ $resit->payer_name ?? '-' }}{{ $resit->user_id }}{{ $resit->cawangan_nama ?? '-' }}{{ $resit->resit_id }}{{ $resit->billplz_id }}{{ number_format($resit->jumlah_bayaran, 2) }}{{ \Carbon\Carbon::parse($resit->created_at)->format('d/m/Y H:i') }}
-@endif - -
-

🔄 Resit Billplz yang Telah Dibayar Semula Melalui CDM

-@if($billplzWithCdmResits->isEmpty()) -

Tiada bayaran semula melalui CDM ditemui.

-@else - - - - - - - - - - - - - - @foreach ($groupedResits as $resit) - - - - - - - - - - @endforeach - -
Nama PembayarID PembayarCawanganJumlah (RM)Resit IDBillplz IDTarikh Dicipta
{{ $resit->payer_name }}{{ $resit->user_id }}{{ $resit->cawangan_nama }}{{ number_format($resit->jumlah_bayaran, 2) }}{{ $resit->resit_id }}{{ $resit->billplz_id }}{{ \Carbon\Carbon::parse($resit->created_at)->format('Y-m-d') }}
-@endif - -
-

🕒 Resit Telah Dibayar Tetapi Dalam Proses (PENDING)

-@if($processingResits->isEmpty()) -

Tiada resit yang belum direlease.

-@else - - - - - - - - - - - - - - @foreach($processingResits as $resit) - - - - - - - - - - @endforeach - -
Nama PembayarID PembayarCawanganResit IDBillplz IDJumlah (RM)Tarikh Dibayar
{{ $resit->payer_name }}{{ $resit->user_id }}{{ $resit->cawangan_nama ?? '-' }}{{ $resit->id }}{{ $resit->billplz_id }}{{ number_format($resit->total_payment, 2) }}{{ \Carbon\Carbon::parse($resit->paid_at)->format('d/m/Y H:i') }}
-@endif - - - - - +
@endsection \ No newline at end of file