64 lines
2.0 KiB
PHP
64 lines
2.0 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\V1;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\PaymentIntent;
|
|
use App\Models\Registration;
|
|
use App\Services\XenditService;
|
|
use Illuminate\Http\Request;
|
|
|
|
class WebhookController extends Controller
|
|
{
|
|
public function xendit(Request $request, XenditService $xendit)
|
|
{
|
|
if (!$xendit->verifyWebhook($request)) {
|
|
return response()->json(['message' => 'Invalid webhook signature'], 401);
|
|
}
|
|
|
|
$payload = $request->all();
|
|
|
|
// NOTE: Map this based on the actual Xendit product you use.
|
|
// For Invoice webhook, you typically get invoice id + status.
|
|
$providerRefId = $payload['id'] ?? $payload['data']['id'] ?? null;
|
|
$status = strtoupper($payload['status'] ?? $payload['data']['status'] ?? '');
|
|
|
|
if (!$providerRefId) {
|
|
return response()->json(['message' => 'Missing provider_ref_id'], 422);
|
|
}
|
|
|
|
$intent = PaymentIntent::where('provider_ref_id', $providerRefId)->first();
|
|
if (!$intent) {
|
|
// idempotent: ignore unknown references
|
|
return response()->json(['ok' => true]);
|
|
}
|
|
|
|
// Convert Xendit statuses to our statuses
|
|
$mapped = match ($status) {
|
|
'PAID', 'SETTLED' => 'PAID',
|
|
'EXPIRED' => 'EXPIRED',
|
|
'FAILED' => 'FAILED',
|
|
'CANCELED', 'CANCELLED' => 'CANCELLED',
|
|
default => 'PENDING',
|
|
};
|
|
|
|
$intent->status = $mapped;
|
|
$intent->raw_payload = $payload;
|
|
if ($mapped === 'PAID') {
|
|
$intent->paid_at = now();
|
|
}
|
|
$intent->save();
|
|
|
|
if ($mapped === 'PAID') {
|
|
$reg = Registration::find($intent->registration_id);
|
|
if ($reg && $reg->status !== 'CONFIRMED') {
|
|
$reg->status = 'CONFIRMED';
|
|
$reg->save();
|
|
}
|
|
dispatch(new \App\Jobs\AssignPairingJob((int)$reg->event_id));
|
|
}
|
|
|
|
return response()->json(['ok' => true]);
|
|
}
|
|
}
|