- Add UserManagementController@store for creating users - Add POST /api/admin/users endpoint - Support user types: Free, Pro, Admin - Auto-create 100-year subscription for Pro/Admin users - Add user creation modal to Users.jsx - Complete SaaS limit testing: - Free user limits: 1 account, 10 categories, 3 budgets, 100 tx - Middleware blocks correctly at limits - Error messages are user-friendly - Usage stats API working correctly - Update SAAS_STATUS.md with test results - Bump version to 1.51.0
107 lines
3.3 KiB
PHP
107 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Middleware;
|
|
|
|
use Closure;
|
|
use Illuminate\Http\Request;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
class CheckPlanLimits
|
|
{
|
|
/**
|
|
* Resource type to limit mapping
|
|
*/
|
|
protected array $resourceLimits = [
|
|
'accounts' => 'accounts',
|
|
'categories' => 'categories',
|
|
'budgets' => 'budgets',
|
|
'transactions' => 'transactions',
|
|
'goals' => 'goals',
|
|
];
|
|
|
|
/**
|
|
* Handle an incoming request.
|
|
*/
|
|
public function handle(Request $request, Closure $next, string $resource): Response
|
|
{
|
|
// Only check on store (create) requests
|
|
if (!in_array($request->method(), ['POST'])) {
|
|
return $next($request);
|
|
}
|
|
|
|
$user = $request->user();
|
|
if (!$user) {
|
|
return $next($request);
|
|
}
|
|
|
|
$plan = $user->currentPlan();
|
|
if (!$plan) {
|
|
return $next($request);
|
|
}
|
|
|
|
$limits = $plan->limits ?? [];
|
|
$limitKey = $this->resourceLimits[$resource] ?? null;
|
|
|
|
if (!$limitKey || !isset($limits[$limitKey])) {
|
|
return $next($request);
|
|
}
|
|
|
|
$limit = $limits[$limitKey];
|
|
|
|
// null means unlimited
|
|
if ($limit === null) {
|
|
return $next($request);
|
|
}
|
|
|
|
$currentCount = $this->getCurrentCount($user, $resource);
|
|
|
|
if ($currentCount >= $limit) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => $this->getLimitMessage($resource, $limit),
|
|
'error' => 'plan_limit_exceeded',
|
|
'data' => [
|
|
'resource' => $resource,
|
|
'current' => $currentCount,
|
|
'limit' => $limit,
|
|
'plan' => $plan->name,
|
|
'upgrade_url' => '/pricing',
|
|
],
|
|
], 403);
|
|
}
|
|
|
|
return $next($request);
|
|
}
|
|
|
|
/**
|
|
* Get current count for a resource
|
|
*/
|
|
protected function getCurrentCount($user, string $resource): int
|
|
{
|
|
return match ($resource) {
|
|
'accounts' => $user->accounts()->count(),
|
|
'categories' => $user->categories()->count(),
|
|
'budgets' => $user->budgets()->count(),
|
|
'transactions' => $user->transactions()->count(),
|
|
'goals' => $user->goals()->count(),
|
|
default => 0,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Get user-friendly limit message
|
|
*/
|
|
protected function getLimitMessage(string $resource, int $limit): string
|
|
{
|
|
$messages = [
|
|
'accounts' => "Has alcanzado el límite de {$limit} cuenta(s) de tu plan. Actualiza a Pro para cuentas ilimitadas.",
|
|
'categories' => "Has alcanzado el límite de {$limit} categorías de tu plan. Actualiza a Pro para categorías ilimitadas.",
|
|
'budgets' => "Has alcanzado el límite de {$limit} presupuesto(s) de tu plan. Actualiza a Pro para presupuestos ilimitados.",
|
|
'transactions' => "Has alcanzado el límite de {$limit} transacciones de tu plan. Actualiza a Pro para transacciones ilimitadas.",
|
|
'goals' => "Has alcanzado el límite de {$limit} meta(s) de tu plan. Actualiza a Pro para metas ilimitadas.",
|
|
];
|
|
|
|
return $messages[$resource] ?? "Has alcanzado el límite de tu plan para este recurso.";
|
|
}
|
|
}
|