Files
Gnuboard7/modules/_bundled/sirsoft-ecommerce/tests/Unit/Resources/MileageTransactionResourceTest.php
T
2026-07-01 10:30:32 +09:00

155 lines
6.0 KiB
PHP

<?php
namespace Modules\Sirsoft\Ecommerce\Tests\Unit\Resources;
use App\Models\User;
use Illuminate\Http\Request;
use Modules\Sirsoft\Ecommerce\Http\Resources\MileageTransactionCollection;
use Modules\Sirsoft\Ecommerce\Http\Resources\MileageTransactionResource;
use Modules\Sirsoft\Ecommerce\Models\MileageTransaction;
use Modules\Sirsoft\Ecommerce\Tests\ModuleTestCase;
/**
* MileageTransaction Resource / Collection 테스트 (§18.2-G)
*/
class MileageTransactionResourceTest extends ModuleTestCase
{
private function makeTx(string $type = 'purchase_earn'): MileageTransaction
{
$user = User::factory()->create();
return MileageTransaction::create([
'user_id' => $user->id, 'currency' => 'KRW', 'type' => $type,
'amount' => 1000, 'remaining_amount' => 1000, 'balance_after' => 1000,
'expires_at' => now()->addDays(30),
]);
}
/**
* Resource: type_label / 배지 그룹 / 표시분류 + *_formatted 동반.
*/
public function test_resource_exposes_badge_and_display_category(): void
{
$tx = $this->makeTx('refund_restore');
$array = (new MileageTransactionResource($tx))->toArray(Request::create('/'));
$this->assertSame('refund_restore', $array['type']);
$this->assertSame('teal', $array['admin_badge_group']); // 복원계
$this->assertSame('adjust', $array['user_display_category']); // 사용자 4분류
$this->assertNotEmpty($array['type_label']);
// *_at 원시 + *_formatted 사용자 타임존 동반
$this->assertArrayHasKey('expires_at', $array);
$this->assertArrayHasKey('expires_at_formatted', $array);
$this->assertArrayHasKey('created_at_formatted', $array);
}
/**
* Resource: 금액 필드는 float.
*/
public function test_resource_amounts_are_float(): void
{
$tx = $this->makeTx();
$array = (new MileageTransactionResource($tx))->toArray(Request::create('/'));
$this->assertIsFloat($array['amount']);
$this->assertIsFloat($array['remaining_amount']);
$this->assertSame(1000.0, $array['amount']);
}
/**
* Collection: data + abilities(can_manage) 구조.
*/
public function test_collection_structure_with_abilities(): void
{
$this->makeTx();
$this->makeTx('admin_deduct');
$collection = MileageTransaction::query()->paginate(20);
$array = (new MileageTransactionCollection($collection))->toArray(Request::create('/'));
$this->assertArrayHasKey('data', $array);
$this->assertArrayHasKey('abilities', $array);
$this->assertArrayHasKey('can_manage', $array['abilities']);
$this->assertCount(2, $array['data']);
}
/**
* 적립계 + 소멸 집계(expired_amount) 기준 expiry_state 계산: active/partial/fully.
*/
public function test_resource_expiry_state_by_expired_amount(): void
{
// 미소멸 적립 → active
$active = $this->makeTx('purchase_earn');
$activeArr = (new MileageTransactionResource($active))->toArray(Request::create('/'));
$this->assertSame('active', $activeArr['expiry_state']);
$this->assertSame(0.0, $activeArr['expired_amount']);
// 부분 소멸: 적립 1000, 소멸 집계 400 → partial_expired (서브쿼리 주입값 모사)
$partial = $this->makeTx('purchase_earn');
$partial->expired_amount = 400;
$partialArr = (new MileageTransactionResource($partial))->toArray(Request::create('/'));
$this->assertSame('partial_expired', $partialArr['expiry_state']);
$this->assertSame(400.0, $partialArr['expired_amount']);
// 전체 소멸: 적립 1000, 소멸 집계 1000 → fully_expired
$full = $this->makeTx('purchase_earn');
$full->expired_amount = 1000;
$fullArr = (new MileageTransactionResource($full))->toArray(Request::create('/'));
$this->assertSame('fully_expired', $fullArr['expiry_state']);
}
/**
* 비적립계(사용)는 소멸 집계가 있어도 expiry_state=active (적립계만 의미).
*/
public function test_resource_non_earning_expiry_state_is_active(): void
{
$use = $this->makeTx('order_use');
$use->expired_amount = 100; // 비정상 값이 들어와도 비적립계는 active 고정
$arr = (new MileageTransactionResource($use))->toArray(Request::create('/'));
$this->assertFalse($arr['is_earning']);
$this->assertSame('active', $arr['expiry_state']);
}
/**
* can_edit_expiry: 적립계 + 미소멸 + 잔여>0 일 때만 true.
*/
public function test_resource_can_edit_expiry_flag(): void
{
// 적립계 + 잔여 + 미소멸 → true
$editable = $this->makeTx('purchase_earn');
$this->assertTrue((new MileageTransactionResource($editable))->toArray(Request::create('/'))['can_edit_expiry']);
// 소멸됨 → false
$expired = $this->makeTx('purchase_earn');
$expired->expired_at = now();
$expired->remaining_amount = 0;
$this->assertFalse((new MileageTransactionResource($expired))->toArray(Request::create('/'))['can_edit_expiry']);
// 비적립계 → false
$use = $this->makeTx('order_use');
$this->assertFalse((new MileageTransactionResource($use))->toArray(Request::create('/'))['can_edit_expiry']);
}
/**
* adminBadgeGroup 5색 매핑이 Resource 에 정확히 노출.
*/
public function test_resource_badge_group_for_each_type(): void
{
$map = [
'purchase_earn' => 'green',
'order_use' => 'blue',
'expired' => 'gray',
'order_cancel_restore' => 'teal',
'admin_earn' => 'amber',
];
foreach ($map as $type => $expected) {
$tx = $this->makeTx($type);
$array = (new MileageTransactionResource($tx))->toArray(Request::create('/'));
$this->assertSame($expected, $array['admin_badge_group'], "{$type} 배지 그룹");
}
}
}