Add coupon fraud context and analytics tracking
This commit is contained in:
101
tests/Unit/CouponRedemptionServiceTest.php
Normal file
101
tests/Unit/CouponRedemptionServiceTest.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Models\CheckoutSession;
|
||||
use App\Models\Coupon;
|
||||
use App\Models\CouponRedemption;
|
||||
use App\Models\Package;
|
||||
use App\Models\Tenant;
|
||||
use App\Models\User;
|
||||
use App\Services\Coupons\CouponRedemptionService;
|
||||
use App\Services\GiftVouchers\GiftVoucherService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Str;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CouponRedemptionServiceTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_records_request_context_and_fraud_snapshot(): void
|
||||
{
|
||||
config()->set('checkout.fraud.window_hours', 12);
|
||||
|
||||
$tenant = Tenant::factory()->create();
|
||||
$user = User::factory()->for($tenant)->create();
|
||||
$package = Package::factory()->create([
|
||||
'price' => 120,
|
||||
]);
|
||||
$coupon = Coupon::factory()->create([
|
||||
'code' => 'SAVE10',
|
||||
'paddle_discount_id' => 'dsc_123',
|
||||
]);
|
||||
$coupon->packages()->attach($package);
|
||||
|
||||
$session = CheckoutSession::create([
|
||||
'id' => (string) Str::uuid(),
|
||||
'user_id' => $user->id,
|
||||
'tenant_id' => $tenant->id,
|
||||
'package_id' => $package->id,
|
||||
'package_snapshot' => [
|
||||
'id' => $package->id,
|
||||
'name' => $package->name,
|
||||
'type' => $package->type,
|
||||
'price' => (float) $package->price,
|
||||
'currency' => $package->currency ?? 'EUR',
|
||||
'features' => $package->features,
|
||||
'limits' => $package->limits,
|
||||
],
|
||||
'coupon_id' => $coupon->id,
|
||||
'coupon_code' => $coupon->code,
|
||||
'coupon_snapshot' => [
|
||||
'coupon' => [
|
||||
'id' => $coupon->id,
|
||||
'code' => $coupon->code,
|
||||
'type' => $coupon->type?->value,
|
||||
],
|
||||
'pricing' => [
|
||||
'subtotal' => 120,
|
||||
'discount' => 12,
|
||||
'total' => 108,
|
||||
],
|
||||
],
|
||||
'status' => CheckoutSession::STATUS_PROCESSING,
|
||||
'provider' => CheckoutSession::PROVIDER_PADDLE,
|
||||
'currency' => 'EUR',
|
||||
'amount_subtotal' => 120,
|
||||
'amount_total' => 108,
|
||||
'amount_discount' => 12,
|
||||
'ip_address' => '203.0.113.10',
|
||||
'device_id' => 'device-123',
|
||||
'user_agent' => 'Mozilla/5.0',
|
||||
]);
|
||||
|
||||
$giftVouchers = $this->createMock(GiftVoucherService::class);
|
||||
$giftVouchers->expects($this->once())
|
||||
->method('markRedeemed')
|
||||
->with($this->callback(fn (Coupon $provided) => $provided->is($coupon)), 'txn_123');
|
||||
|
||||
$service = new CouponRedemptionService($giftVouchers);
|
||||
$service->recordSuccess($session, ['id' => 'txn_123']);
|
||||
|
||||
$this->assertDatabaseHas('coupon_redemptions', [
|
||||
'coupon_id' => $coupon->id,
|
||||
'checkout_session_id' => $session->id,
|
||||
'ip_address' => '203.0.113.10',
|
||||
'device_id' => 'device-123',
|
||||
'user_agent' => 'Mozilla/5.0',
|
||||
'status' => CouponRedemption::STATUS_SUCCESS,
|
||||
]);
|
||||
|
||||
$redemption = CouponRedemption::query()
|
||||
->where('checkout_session_id', $session->id)
|
||||
->first();
|
||||
|
||||
$this->assertNotNull($redemption);
|
||||
$this->assertSame(12, $redemption->metadata['fraud']['window_hours'] ?? null);
|
||||
$this->assertSame('203.0.113.10', $redemption->metadata['fraud']['ip']['value'] ?? null);
|
||||
$this->assertSame('device-123', $redemption->metadata['fraud']['device']['value'] ?? null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user