Fix reseller package selection when older batches are exhausted
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
tests / ui (push) Has been cancelled

This commit is contained in:
Codex Agent
2026-02-06 12:01:43 +01:00
parent 61d1bbc707
commit fa114ac0dc
5 changed files with 45 additions and 7 deletions

View File

@@ -247,11 +247,13 @@ class EventController extends Controller
$tenant->refresh(); $tenant->refresh();
$event->load(['eventType', 'tenant', 'eventPackages.package', 'eventPackages.addons']); $event->load(['eventType', 'tenant', 'eventPackages.package', 'eventPackages.addons']);
$activeResellerPackage = $tenant->getActiveResellerPackage();
return response()->json([ return response()->json([
'message' => 'Event created successfully', 'message' => 'Event created successfully',
'data' => new EventResource($event), 'data' => new EventResource($event),
'package' => $event->eventPackage ? $event->eventPackage->package->name : 'None', 'package' => $event->eventPackage ? $event->eventPackage->package->name : 'None',
'remaining_events' => $tenant->activeResellerPackage ? $tenant->activeResellerPackage->remaining_events : 0, 'remaining_events' => $activeResellerPackage?->remaining_events ?? 0,
], 201); ], 201);
} }

View File

@@ -119,8 +119,6 @@ class TenantAdminTokenController extends Controller
], 404); ], 404);
} }
$tenant->loadMissing('activeResellerPackage');
$user = $request->user(); $user = $request->user();
$abilities = $user?->currentAccessToken()?->abilities ?? []; $abilities = $user?->currentAccessToken()?->abilities ?? [];
@@ -131,7 +129,7 @@ class TenantAdminTokenController extends Controller
$fullName = trim($first.' '.$last) ?: null; $fullName = trim($first.' '.$last) ?: null;
} }
$activePackage = $tenant->activeResellerPackage; $activePackage = $tenant->getActiveResellerPackage();
return response()->json([ return response()->json([
'id' => $tenant->id, 'id' => $tenant->id,

View File

@@ -37,7 +37,7 @@ class TenantPackageController extends Controller
$this->hydratePackageSnapshot($package, $eventPackage); $this->hydratePackageSnapshot($package, $eventPackage);
}); });
$activePackage = $tenant->activeResellerPackage?->load('package'); $activePackage = $tenant->getActiveResellerPackage();
if (! ($activePackage instanceof TenantPackage)) { if (! ($activePackage instanceof TenantPackage)) {
$activePackage = $packages->firstWhere('active', true); $activePackage = $packages->firstWhere('active', true);

View File

@@ -233,10 +233,18 @@ class Tenant extends Model
public function getActiveResellerPackage(): ?TenantPackage public function getActiveResellerPackage(): ?TenantPackage
{ {
return $this->activeResellerPackage()->with('package')->first(); return $this->getActiveResellerPackageFor(null);
} }
public function getActiveResellerPackageFor(?string $includedPackageSlug): ?TenantPackage public function getActiveResellerPackageFor(?string $includedPackageSlug): ?TenantPackage
{
$candidates = $this->activeResellerPackagesQuery($includedPackageSlug)->get();
return $candidates->first(fn (TenantPackage $package) => $package->canCreateEvent())
?? $candidates->first();
}
private function activeResellerPackagesQuery(?string $includedPackageSlug): HasMany
{ {
$query = $this->tenantPackages() $query = $this->tenantPackages()
->with('package') ->with('package')
@@ -258,7 +266,7 @@ class Tenant extends Model
}); });
} }
return $query->first(); return $query;
} }
public function activeSubscription(): Attribute public function activeSubscription(): Attribute

View File

@@ -181,4 +181,34 @@ class TenantModelTest extends TestCase
$this->assertFalse($tenant->consumeEventAllowance()); $this->assertFalse($tenant->consumeEventAllowance());
} }
public function test_get_active_reseller_package_skips_exhausted_legacy_batches(): void
{
$tenant = Tenant::factory()->create();
$package = Package::factory()->reseller()->create([
'max_events_per_year' => 1,
]);
$exhaustedBatch = TenantPackage::factory()->for($tenant)->for($package)->create([
'used_events' => 1,
'active' => true,
'expires_at' => null,
'purchased_at' => now()->subDay(),
]);
$availableBatch = TenantPackage::factory()->for($tenant)->for($package)->create([
'used_events' => 0,
'active' => true,
'expires_at' => null,
'purchased_at' => now(),
]);
$resolved = $tenant->getActiveResellerPackage();
$this->assertNotNull($resolved);
$this->assertSame($availableBatch->id, $resolved?->id);
$this->assertNotSame($exhaustedBatch->id, $resolved?->id);
$this->assertTrue($tenant->hasEventAllowance());
}
} }