feat: implement tenant OAuth flow and guest achievements
This commit is contained in:
@@ -8,18 +8,15 @@ use App\Http\Resources\Tenant\EventPurchaseResource;
|
||||
use App\Models\EventCreditsLedger;
|
||||
use App\Models\EventPurchase;
|
||||
use App\Models\Tenant;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
|
||||
class CreditController extends Controller
|
||||
{
|
||||
public function balance(Request $request)
|
||||
public function balance(Request $request): JsonResponse
|
||||
{
|
||||
$user = $request->user();
|
||||
if (!$user) {
|
||||
return response()->json(['message' => 'Unauthenticated'], 401);
|
||||
}
|
||||
|
||||
$tenant = Tenant::findOrFail($user->tenant_id);
|
||||
$tenant = $this->resolveTenant($request);
|
||||
|
||||
return response()->json([
|
||||
'balance' => $tenant->event_credits_balance,
|
||||
@@ -29,14 +26,10 @@ class CreditController extends Controller
|
||||
|
||||
public function ledger(Request $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
if (!$user) {
|
||||
return response()->json(['message' => 'Unauthenticated'], 401);
|
||||
}
|
||||
$tenant = $this->resolveTenant($request);
|
||||
|
||||
$tenant = Tenant::findOrFail($user->tenant_id);
|
||||
$ledgers = EventCreditsLedger::where('tenant_id', $tenant->id)
|
||||
->orderBy('created_at', 'desc')
|
||||
->orderByDesc('created_at')
|
||||
->paginate(20);
|
||||
|
||||
return CreditLedgerResource::collection($ledgers);
|
||||
@@ -44,16 +37,100 @@ class CreditController extends Controller
|
||||
|
||||
public function history(Request $request)
|
||||
{
|
||||
$user = $request->user();
|
||||
if (!$user) {
|
||||
return response()->json(['message' => 'Unauthenticated'], 401);
|
||||
}
|
||||
$tenant = $this->resolveTenant($request);
|
||||
|
||||
$tenant = Tenant::findOrFail($user->tenant_id);
|
||||
$purchases = EventPurchase::where('tenant_id', $tenant->id)
|
||||
->orderBy('purchased_at', 'desc')
|
||||
->orderByDesc('purchased_at')
|
||||
->paginate(20);
|
||||
|
||||
return EventPurchaseResource::collection($purchases);
|
||||
}
|
||||
}
|
||||
|
||||
public function purchase(Request $request): JsonResponse
|
||||
{
|
||||
$tenant = $this->resolveTenant($request);
|
||||
|
||||
$data = $request->validate([
|
||||
'package_id' => ['required', 'string', 'max:255'],
|
||||
'credits_added' => ['required', 'integer', 'min:1'],
|
||||
'platform' => ['nullable', 'string', 'max:32'],
|
||||
'transaction_id' => ['nullable', 'string', 'max:255'],
|
||||
'subscription_active' => ['sometimes', 'boolean'],
|
||||
]);
|
||||
|
||||
$purchase = EventPurchase::create([
|
||||
'tenant_id' => $tenant->id,
|
||||
'events_purchased' => $data['credits_added'],
|
||||
'amount' => 0,
|
||||
'currency' => 'EUR',
|
||||
'provider' => $data['platform'] ?? 'tenant-app',
|
||||
'external_receipt_id' => $data['transaction_id'] ?? null,
|
||||
'status' => 'completed',
|
||||
'purchased_at' => now(),
|
||||
]);
|
||||
|
||||
$note = 'Package: '.$data['package_id'];
|
||||
$incremented = $tenant->incrementCredits($data['credits_added'], 'purchase', $note, $purchase->id);
|
||||
|
||||
if (! $incremented) {
|
||||
throw new HttpException(500, 'Unable to record credit purchase');
|
||||
}
|
||||
|
||||
if (array_key_exists('subscription_active', $data)) {
|
||||
$tenant->update([
|
||||
'subscription_tier' => $data['subscription_active'] ? 'pro' : $tenant->subscription_tier,
|
||||
]);
|
||||
}
|
||||
|
||||
$tenant->refresh();
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Purchase recorded',
|
||||
'balance' => $tenant->event_credits_balance,
|
||||
'subscription_active' => (bool) ($data['subscription_active'] ?? false),
|
||||
], 201);
|
||||
}
|
||||
|
||||
public function sync(Request $request): JsonResponse
|
||||
{
|
||||
$tenant = $this->resolveTenant($request);
|
||||
|
||||
$data = $request->validate([
|
||||
'balance' => ['nullable', 'integer', 'min:0'],
|
||||
'subscription_active' => ['sometimes', 'boolean'],
|
||||
'last_sync' => ['nullable', 'date'],
|
||||
]);
|
||||
|
||||
if (array_key_exists('subscription_active', $data)) {
|
||||
$tenant->update([
|
||||
'subscription_tier' => $data['subscription_active'] ? 'pro' : ($tenant->subscription_tier ?? 'free'),
|
||||
]);
|
||||
}
|
||||
|
||||
// Server remains source of truth for balance; echo current state back to client
|
||||
return response()->json([
|
||||
'balance' => $tenant->event_credits_balance,
|
||||
'subscription_active' => (bool) ($tenant->active_subscription ?? false),
|
||||
'server_time' => now()->toIso8601String(),
|
||||
]);
|
||||
}
|
||||
|
||||
private function resolveTenant(Request $request): Tenant
|
||||
{
|
||||
$user = $request->user();
|
||||
if ($user && isset($user->tenant) && $user->tenant instanceof Tenant) {
|
||||
return $user->tenant;
|
||||
}
|
||||
|
||||
$tenantId = $request->attributes->get('tenant_id');
|
||||
if (! $tenantId && $user && isset($user->tenant_id)) {
|
||||
$tenantId = $user->tenant_id;
|
||||
}
|
||||
|
||||
if (! $tenantId) {
|
||||
throw new HttpException(401, 'Unauthenticated');
|
||||
}
|
||||
|
||||
return Tenant::findOrFail($tenantId);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user