diff --git a/routes/api.php b/routes/api.php index 53a1d1b..56bab66 100644 --- a/routes/api.php +++ b/routes/api.php @@ -41,7 +41,7 @@ use Illuminate\Support\Facades\Route; Route::prefix('v1')->name('api.v1.')->group(function () { Route::prefix('marketing')->name('marketing.')->group(function () { Route::post('/coupons/preview', CouponPreviewController::class) - ->middleware('throttle:coupon-preview') + ->middleware([EncryptCookies::class, AddQueuedCookiesToResponse::class, StartSession::class, 'throttle:coupon-preview']) ->name('coupons.preview'); Route::post('/gift-vouchers/checkout', [\App\Http\Controllers\Api\Marketing\GiftVoucherCheckoutController::class, 'store']) ->middleware('throttle:60,1') diff --git a/tests/Feature/Api/Marketing/CouponPreviewTest.php b/tests/Feature/Api/Marketing/CouponPreviewTest.php index c2a7988..28d4215 100644 --- a/tests/Feature/Api/Marketing/CouponPreviewTest.php +++ b/tests/Feature/Api/Marketing/CouponPreviewTest.php @@ -4,6 +4,8 @@ namespace Tests\Feature\Api\Marketing; use App\Models\Coupon; use App\Models\Package; +use App\Models\Tenant; +use App\Models\User; use App\Services\Paddle\PaddleDiscountService; use Illuminate\Foundation\Testing\RefreshDatabase; use Mockery; @@ -69,4 +71,73 @@ class CouponPreviewTest extends TestCase ])->assertUnprocessable() ->assertJsonValidationErrors('code'); } + + public function test_coupon_with_per_customer_limit_requires_login(): void + { + $package = Package::factory()->create([ + 'paddle_price_id' => 'pri_test_login', + ]); + + $coupon = Coupon::factory()->create([ + 'code' => 'LIMITED', + 'paddle_discount_id' => 'dsc_login', + 'per_customer_limit' => 1, + ]); + $coupon->packages()->attach($package); + + $response = $this->postJson(route('api.v1.marketing.coupons.preview'), [ + 'package_id' => $package->id, + 'code' => 'LIMITED', + ]); + + $response->assertUnprocessable() + ->assertJsonValidationErrors('code'); + + $this->assertSame( + __('marketing.coupon.errors.login_required'), + $response->json('errors.code.0') + ); + } + + public function test_coupon_with_per_customer_limit_allows_logged_in_tenant(): void + { + $tenant = Tenant::factory()->create(); + $user = User::factory()->create([ + 'tenant_id' => $tenant->id, + ]); + + $package = Package::factory()->create([ + 'paddle_price_id' => 'pri_test_logged_in', + 'price' => 120, + ]); + + $coupon = Coupon::factory()->create([ + 'code' => 'LIMITEDTENANT', + 'paddle_discount_id' => 'dsc_logged_in', + 'per_customer_limit' => 1, + ]); + $coupon->packages()->attach($package); + + $this->instance(PaddleDiscountService::class, Mockery::mock(PaddleDiscountService::class, function ($mock) { + $mock->shouldReceive('previewDiscount')->andReturn([ + 'totals' => [ + 'currency_code' => 'EUR', + 'subtotal' => 12000, + 'discount' => 2000, + 'tax' => 0, + 'total' => 10000, + ], + ]); + })); + + $response = $this->actingAs($user)->postJson(route('api.v1.marketing.coupons.preview'), [ + 'package_id' => $package->id, + 'code' => 'limitedtenant', + ]); + + $response->assertOk() + ->assertJsonPath('coupon.code', 'LIMITEDTENANT'); + + $this->assertEquals(100.0, (float) $response->json('pricing.total')); + } }