coupon code system eingeführt. coupons werden vom super admin gemanaged. coupons werden mit paddle synchronisiert und dort validiert. plus: einige mobil-optimierungen im tenant admin pwa.

This commit is contained in:
Codex Agent
2025-11-09 20:26:50 +01:00
parent f3c44be76d
commit 082b78cd43
80 changed files with 4855 additions and 435 deletions

64
tests/Unit/CouponTest.php Normal file
View File

@@ -0,0 +1,64 @@
<?php
namespace Tests\Unit;
use App\Models\Coupon;
use App\Models\Package;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class CouponTest extends TestCase
{
use RefreshDatabase;
public function test_it_evaluates_active_state(): void
{
$coupon = Coupon::factory()->create([
'starts_at' => now()->subDay(),
'ends_at' => now()->addDay(),
'usage_limit' => 1,
'redemptions_count' => 0,
]);
$this->assertTrue($coupon->isCurrentlyActive());
$coupon->update(['redemptions_count' => 1]);
$this->assertFalse($coupon->refresh()->isCurrentlyActive());
$coupon->update([
'usage_limit' => null,
'starts_at' => now()->addDay(),
'redemptions_count' => 0,
]);
$this->assertFalse($coupon->fresh()->isCurrentlyActive());
}
public function test_it_checks_package_applicability(): void
{
$coupon = Coupon::factory()->create();
$packageA = Package::factory()->create();
$packageB = Package::factory()->create();
$this->assertTrue($coupon->appliesToPackage($packageA));
$coupon->packages()->sync([$packageA->getKey()]);
$this->assertTrue($coupon->fresh()->appliesToPackage($packageA));
$this->assertFalse($coupon->appliesToPackage($packageB));
}
public function test_remaining_usage_calculation(): void
{
$coupon = Coupon::factory()->create([
'usage_limit' => 10,
'per_customer_limit' => 2,
'redemptions_count' => 4,
]);
$this->assertSame(6, $coupon->remainingUsages());
$this->assertSame(2, $coupon->remainingUsages(0));
$this->assertSame(1, $coupon->remainingUsages(1));
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace Tests\Unit;
use App\Models\Tenant;
use App\Support\TenantRequestResolver;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\Request;
use Tests\TestCase;
class TenantRequestResolverTest extends TestCase
{
use RefreshDatabase;
public function test_it_returns_tenant_from_request_attribute(): void
{
$tenant = Tenant::factory()->make();
$request = Request::create('/api/tenant/test', 'GET');
$request->attributes->set('tenant', $tenant);
$resolved = TenantRequestResolver::resolve($request);
$this->assertSame($tenant, $resolved);
}
public function test_it_finds_tenant_using_identifier(): void
{
$tenant = Tenant::factory()->create();
$request = Request::create('/api/tenant/test', 'GET');
$request->attributes->set('tenant_id', $tenant->id);
$resolved = TenantRequestResolver::resolve($request);
$this->assertTrue($tenant->is($resolved));
}
public function test_it_throws_when_tenant_cannot_be_resolved(): void
{
$this->expectException(HttpResponseException::class);
$request = Request::create('/api/tenant/test', 'GET');
TenantRequestResolver::resolve($request);
}
}