initial: bootstrap from BukidBountyApp base
This commit is contained in:
201
app/Http/Controllers/Subscription/SubscriptionController.php
Normal file
201
app/Http/Controllers/Subscription/SubscriptionController.php
Normal file
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\Subscription;
|
||||
|
||||
use Hypervel\Http\Request;
|
||||
use Hypervel\Support\Facades\Auth;
|
||||
use Hypervel\Support\Facades\Response;
|
||||
use App\Models\User;
|
||||
use App\Models\Subscription\SubscriptionPlan;
|
||||
use App\Models\Subscription\Subscription;
|
||||
use App\Models\Subscription\SubscriptionInvoice;
|
||||
use App\Enums\UserTypes;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class SubscriptionController
|
||||
{
|
||||
// ── User: list available plans (active only) ───────────────────────────
|
||||
public function listAvailablePlans()
|
||||
{
|
||||
$plans = SubscriptionPlan::where('active', true)
|
||||
->orderBy('price')
|
||||
->get()
|
||||
->map(fn($p) => [
|
||||
'hashkey' => $p->hashkey,
|
||||
'name' => $p->name,
|
||||
'description' => $p->description,
|
||||
'price' => $p->price,
|
||||
'duration_days' => $p->duration_days,
|
||||
'expiry_action' => $p->expiry_action,
|
||||
]);
|
||||
|
||||
return Response::json($plans);
|
||||
}
|
||||
|
||||
// ── User: get my current subscription ─────────────────────────────────
|
||||
public function mySubscription()
|
||||
{
|
||||
$user = User::findOrFail(Auth::id());
|
||||
$sub = self::getActiveSubscription($user->id);
|
||||
|
||||
if (!$sub) {
|
||||
return Response::json([
|
||||
'has_subscription' => false,
|
||||
'balance' => $user->total_balance,
|
||||
]);
|
||||
}
|
||||
|
||||
return Response::json([
|
||||
'has_subscription' => true,
|
||||
'subscription' => self::formatUserSubscription($sub),
|
||||
'balance' => $user->total_balance,
|
||||
]);
|
||||
}
|
||||
|
||||
// ── User: pay for a subscription via wallet ────────────────────────────
|
||||
public function payWithWallet(Request $request)
|
||||
{
|
||||
$planHashkey = $request->input('plan_hashkey');
|
||||
if (!$planHashkey) {
|
||||
return Response::json('Plan is required.', 422);
|
||||
}
|
||||
|
||||
$plan = SubscriptionPlan::where('hashkey', $planHashkey)
|
||||
->where('active', true)
|
||||
->first();
|
||||
|
||||
if (!$plan) {
|
||||
return Response::json('Plan not found or no longer available.', 404);
|
||||
}
|
||||
|
||||
$user = User::findOrFail(Auth::id());
|
||||
|
||||
if ($user->total_balance < $plan->price) {
|
||||
return Response::json('Insufficient wallet balance.', 402);
|
||||
}
|
||||
|
||||
$admin = User::where('acct_type', UserTypes::ULTIMATE->value)->first();
|
||||
if (!$admin) {
|
||||
return Response::json('Payment recipient not configured.', 500);
|
||||
}
|
||||
|
||||
try {
|
||||
// Deduct from user, credit admin
|
||||
$user->total_balance -= $plan->price;
|
||||
$user->save();
|
||||
|
||||
$admin->total_balance += $plan->price;
|
||||
$admin->save();
|
||||
|
||||
// Create or extend subscription
|
||||
$now = Carbon::now();
|
||||
$expiry = $now->copy()->addDays($plan->duration_days);
|
||||
|
||||
$existing = self::getActiveSubscription($user->id);
|
||||
|
||||
if ($existing) {
|
||||
// Extend from current expiry if still active, otherwise from now
|
||||
$base = $existing->expires_at && $existing->expires_at->isFuture()
|
||||
? $existing->expires_at
|
||||
: $now;
|
||||
$expiry = $base->copy()->addDays($plan->duration_days);
|
||||
|
||||
$existing->expires_at = $expiry;
|
||||
$existing->status = 'active';
|
||||
$existing->payment_method = 'wallet';
|
||||
$existing->save();
|
||||
|
||||
$subscription = $existing;
|
||||
} else {
|
||||
$subscription = Subscription::create([
|
||||
'user_id' => $user->id,
|
||||
'plan_id' => $plan->id,
|
||||
'status' => 'active',
|
||||
'starts_at' => $now,
|
||||
'expires_at' => $expiry,
|
||||
'payment_method' => 'wallet',
|
||||
]);
|
||||
}
|
||||
|
||||
// Record invoice
|
||||
SubscriptionInvoice::create([
|
||||
'subscription_id' => $subscription->id,
|
||||
'user_id' => $user->id,
|
||||
'amount' => $plan->price,
|
||||
'status' => 'paid',
|
||||
'paid_at' => $now,
|
||||
'payment_method' => 'wallet',
|
||||
'payment_reference' => null,
|
||||
'additional_details' => [
|
||||
'plan_name' => $plan->name,
|
||||
'plan_hashkey' => $plan->hashkey,
|
||||
'admin_id' => $admin->id,
|
||||
],
|
||||
]);
|
||||
|
||||
return Response::json([
|
||||
'success' => true,
|
||||
'expires_at' => $expiry,
|
||||
'balance' => $user->total_balance,
|
||||
]);
|
||||
} catch (\Throwable $th) {
|
||||
return Response::json($th->getMessage(), 500);
|
||||
}
|
||||
}
|
||||
|
||||
// ── User: my invoice history ───────────────────────────────────────────
|
||||
public function myInvoices()
|
||||
{
|
||||
$invoices = SubscriptionInvoice::where('user_id', Auth::id())
|
||||
->orderByDesc('created_at')
|
||||
->get()
|
||||
->map(fn($inv) => [
|
||||
'hashkey' => $inv->hashkey,
|
||||
'amount' => $inv->amount,
|
||||
'status' => $inv->status,
|
||||
'payment_method' => $inv->payment_method,
|
||||
'payment_reference' => $inv->payment_reference,
|
||||
'paid_at' => $inv->paid_at,
|
||||
'plan_name' => $inv->additional_details['plan_name'] ?? '',
|
||||
'created_at' => $inv->created_at,
|
||||
]);
|
||||
|
||||
return Response::json($invoices);
|
||||
}
|
||||
|
||||
// ── Helper: get user's latest active subscription ─────────────────────
|
||||
private static function getActiveSubscription(int $userId): ?Subscription
|
||||
{
|
||||
return Subscription::where('user_id', $userId)
|
||||
->where('status', 'active')
|
||||
->where('expires_at', '>', Carbon::now())
|
||||
->with('plan')
|
||||
->orderByDesc('expires_at')
|
||||
->first();
|
||||
}
|
||||
|
||||
private static function formatUserSubscription(Subscription $sub): array
|
||||
{
|
||||
$plan = $sub->plan;
|
||||
$expiresAt = $sub->expires_at;
|
||||
$daysRemaining = $expiresAt ? (int) now()->diffInDays($expiresAt, false) : 0;
|
||||
|
||||
return [
|
||||
'hashkey' => $sub->hashkey,
|
||||
'status' => $sub->status,
|
||||
'starts_at' => $sub->starts_at,
|
||||
'expires_at' => $expiresAt,
|
||||
'days_remaining' => max(0, $daysRemaining),
|
||||
'payment_method' => $sub->payment_method,
|
||||
'plan' => $plan ? [
|
||||
'hashkey' => $plan->hashkey,
|
||||
'name' => $plan->name,
|
||||
'price' => $plan->price,
|
||||
'duration_days' => $plan->duration_days,
|
||||
'expiry_action' => $plan->expiry_action,
|
||||
] : null,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user