ifnex/04_Laravel/tests/Feature/Api/DiscountCodeControllerTest.php
Kazem Alghasi b9ede16613 refactor(core): harden production environment and fix discount logic
Implement critical security hardening and resolve a P0 bug in the
discount code consumption flow. This update transitions the system
from a development-heavy configuration to a production-ready state.

Key changes:
- Fix P0 bug where `consumeDiscountCode()` was missing, breaking order
  registration; replaced with a robust `DiscountCodeService` using
  `discount_code_usages` for audit trails and idempotency.
- Implement strict production guards for the Zarinpal payment gateway
  to prevent accidental mock processing in live environments.
- Refactor WordPress bridge asset management to use `filemtime` based
  versioning instead of `time()` to prevent unnecessary cache busting.
- Remove debug-only hacks (`opcache_reset`, `header` cache control)
  from the WordPress plugin.
- Enhance file upload security by enforcing strict `mimetypes` validation.
- Update `.gitignore` to exclude sensitive WordPress configuration
  files and local PHPUnit caches.
- Add comprehensive documentation for production deployment, including
  security checklists and key rotation procedures.
- Update test suite to reflect new architecture and ensure 100%
  coverage of the discount service.
2026-10-31 19:18:58 +03:30

171 lines
4.4 KiB
PHP

<?php
namespace Tests\Feature\Api;
use App\Models\DiscountCode;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;
use PHPUnit\Framework\Attributes\Test;
use Tests\TestCase;
class DiscountCodeControllerTest extends TestCase
{
use RefreshDatabase;
private User $user;
protected function setUp(): void
{
parent::setUp();
// روت‌های کد تخفیف داخل گروه auth:sanctum هستند (سخت‌سازی Production)
$this->user = User::factory()->create();
Sanctum::actingAs($this->user);
}
#[Test]
public function it_returns_active_discount_codes()
{
DiscountCode::create([
'code' => 'TEST10',
'type' => 'percentage',
'value' => 10,
'min_order_amount' => 100000,
'is_active' => true,
]);
DiscountCode::create([
'code' => 'INACTIVE',
'type' => 'fixed',
'value' => 50000,
'is_active' => false,
]);
$response = $this->get('/api/v1/discount-codes');
$response->assertStatus(200)
->assertJson([
'codes' => [
[
'code' => 'TEST10',
'type' => 'percentage',
'value' => 10,
],
],
])
->assertJsonCount(1, 'codes');
}
#[Test]
public function it_validates_discount_code_successfully()
{
DiscountCode::create([
'code' => 'PERCENT10',
'type' => 'percentage',
'value' => 10,
'min_order_amount' => 100000,
'is_active' => true,
]);
$response = $this->post('/api/v1/discount-codes/validate', [
'code' => 'PERCENT10',
'total_price' => 500000,
]);
$response->assertStatus(200)
->assertJson([
'valid' => true,
'type' => 'percentage',
'value' => 10,
'discount_amount' => 50000,
'final_price' => 450000,
]);
}
#[Test]
public function it_rejects_invalid_discount_code()
{
$response = $this->post('/api/v1/discount-codes/validate', [
'code' => 'INVALID',
'total_price' => 500000,
]);
$response->assertStatus(200)
->assertJson([
'valid' => false,
'message' => 'کد تخفیف نامعتبر است.',
]);
}
#[Test]
public function it_rejects_expired_discount_code()
{
DiscountCode::create([
'code' => 'EXPIRED',
'type' => 'fixed',
'value' => 50000,
'is_active' => true,
'expires_at' => now()->subDay(),
]);
$response = $this->post('/api/v1/discount-codes/validate', [
'code' => 'EXPIRED',
'total_price' => 500000,
]);
$response->assertStatus(200)
->assertJson([
'valid' => false,
'message' => 'این کد تخفیف منقضی شده است.',
]);
}
#[Test]
public function it_rejects_code_below_minimum_order_amount()
{
DiscountCode::create([
'code' => 'MIN500',
'type' => 'fixed',
'value' => 50000,
'min_order_amount' => 500000,
'is_active' => true,
]);
$response = $this->post('/api/v1/discount-codes/validate', [
'code' => 'MIN500',
'total_price' => 100000,
]);
$response->assertStatus(200)
->assertJson([
'valid' => false,
])
->assertJsonStructure(['message']);
}
#[Test]
public function it_calculates_fixed_discount_correctly()
{
DiscountCode::create([
'code' => 'FIXED50',
'type' => 'fixed',
'value' => 50000,
'min_order_amount' => 100000,
'is_active' => true,
]);
$response = $this->post('/api/v1/discount-codes/validate', [
'code' => 'FIXED50',
'total_price' => 500000,
]);
$response->assertStatus(200)
->assertJson([
'valid' => true,
'discount_amount' => 50000,
'final_price' => 450000,
]);
}
}