PXG_2026_API/app/Http/Controllers/Api/V1/WebhookController.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]);
}
}