First Commit
This commit is contained in:
+153
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Http\Controllers\SuperAdmin;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Invoice;
|
||||
use App\Models\SubscriptionPlan;
|
||||
use App\Models\User;
|
||||
use App\Models\UserNotification;
|
||||
use App\Models\UserSubscription;
|
||||
use Barryvdh\DomPDF\Facade\Pdf;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class BillingController extends Controller
|
||||
{
|
||||
public function index(): View
|
||||
{
|
||||
$stats = [
|
||||
'total_plans' => SubscriptionPlan::count(),
|
||||
'active_plans' => SubscriptionPlan::where('is_active', true)->count(),
|
||||
'active_subscriptions' => UserSubscription::where('status', 'active')->count(),
|
||||
'total_revenue' => Invoice::where('status', 'paid')->sum('amount'),
|
||||
'pending_invoices' => Invoice::where('status', 'pending')->count(),
|
||||
'expiring_soon' => UserSubscription::where('status', 'active')
|
||||
->where('end_date', '<=', now()->addDays(7))
|
||||
->count(),
|
||||
];
|
||||
|
||||
$plans = SubscriptionPlan::withCount('userSubscriptions')->get();
|
||||
$subscriptions = UserSubscription::with(['user', 'plan'])
|
||||
->orderByDesc('created_at')
|
||||
->paginate(20);
|
||||
|
||||
return view('superadmin.billing.index', compact('stats', 'plans', 'subscriptions'));
|
||||
}
|
||||
|
||||
public function storePlan(Request $request): RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'description' => ['nullable', 'string'],
|
||||
'price' => ['required', 'numeric', 'min:0'],
|
||||
'currency' => ['required', 'string', 'size:3'],
|
||||
'duration_days' => ['required', 'integer', 'min:1'],
|
||||
'token_limit' => ['nullable', 'integer', 'min:0'],
|
||||
]);
|
||||
|
||||
SubscriptionPlan::create($validated + ['is_active' => true]);
|
||||
|
||||
return back()->with('success', __('Plan created successfully.'));
|
||||
}
|
||||
|
||||
public function updatePlan(Request $request, SubscriptionPlan $plan): RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'name' => ['required', 'string', 'max:255'],
|
||||
'description' => ['nullable', 'string'],
|
||||
'price' => ['required', 'numeric', 'min:0'],
|
||||
'currency' => ['required', 'string', 'size:3'],
|
||||
'duration_days' => ['required', 'integer', 'min:1'],
|
||||
'token_limit' => ['nullable', 'integer', 'min:0'],
|
||||
'is_active' => ['boolean'],
|
||||
]);
|
||||
|
||||
$plan->update($validated);
|
||||
|
||||
return back()->with('success', __('Plan updated successfully.'));
|
||||
}
|
||||
|
||||
public function approvePayment(UserSubscription $subscription): RedirectResponse
|
||||
{
|
||||
$subscription->update(['payment_approved' => true, 'status' => 'active']);
|
||||
|
||||
// Create invoice
|
||||
$lastInvoice = Invoice::orderByDesc('id')->first();
|
||||
$nextNumber = $lastInvoice ? (int)filter_var($lastInvoice->invoice_number, FILTER_SANITIZE_NUMBER_INT) + 1 : 1001;
|
||||
|
||||
$invoice = Invoice::create([
|
||||
'user_id' => $subscription->user_id,
|
||||
'user_subscription_id' => $subscription->id,
|
||||
'invoice_number' => 'INV-' . $nextNumber . '/' . now()->year,
|
||||
'amount' => $subscription->plan->price,
|
||||
'currency' => $subscription->plan->currency,
|
||||
'status' => 'paid',
|
||||
'payment_method' => 'manual',
|
||||
'paid_at' => now(),
|
||||
]);
|
||||
|
||||
// Generate PDF
|
||||
$this->generateInvoicePdf($invoice);
|
||||
|
||||
// Notify user
|
||||
UserNotification::create([
|
||||
'user_id' => $subscription->user_id,
|
||||
'type' => 'payment_received',
|
||||
'title' => __('Payment Approved'),
|
||||
'message' => __('Your payment of :amount has been approved. Your subscription is active until :date.', [
|
||||
'amount' => 'R$ ' . number_format($subscription->plan->price, 2, ',', '.'),
|
||||
'date' => $subscription->end_date->format('d/m/Y'),
|
||||
]),
|
||||
]);
|
||||
|
||||
return back()->with('success', __('Payment approved. Invoice generated and user notified.'));
|
||||
}
|
||||
|
||||
public function cancelSubscription(UserSubscription $subscription): RedirectResponse
|
||||
{
|
||||
$subscription->update(['status' => 'cancelled', 'cancelled_at' => now()]);
|
||||
|
||||
UserNotification::create([
|
||||
'user_id' => $subscription->user_id,
|
||||
'type' => 'admin_message',
|
||||
'title' => __('Subscription Cancelled'),
|
||||
'message' => __('Your subscription has been cancelled by the administrator.'),
|
||||
]);
|
||||
|
||||
return back()->with('success', __('Subscription cancelled.'));
|
||||
}
|
||||
|
||||
public function invoices(): View
|
||||
{
|
||||
$invoices = Invoice::with(['user', 'subscription.plan'])
|
||||
->orderByDesc('created_at')
|
||||
->paginate(20);
|
||||
|
||||
return view('superadmin.billing.invoices', compact('invoices'));
|
||||
}
|
||||
|
||||
public function downloadInvoice(Invoice $invoice)
|
||||
{
|
||||
if ($invoice->pdf_path && Storage::exists($invoice->pdf_path)) {
|
||||
return Storage::download($invoice->pdf_path, "invoice-{$invoice->invoice_number}.pdf");
|
||||
}
|
||||
|
||||
// Generate on the fly
|
||||
$this->generateInvoicePdf($invoice);
|
||||
|
||||
return Storage::download($invoice->pdf_path, "invoice-{$invoice->invoice_number}.pdf");
|
||||
}
|
||||
|
||||
private function generateInvoicePdf(Invoice $invoice): void
|
||||
{
|
||||
$pdf = Pdf::loadView('pdf.invoice', compact('invoice'));
|
||||
$path = "invoices/invoice-{$invoice->invoice_number}.pdf";
|
||||
Storage::put($path, $pdf->output());
|
||||
$invoice->update(['pdf_path' => $path]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user