- Nạp tiền: mã thanh toán sống 30 phút (ManualDepositDraft), khôi phục/huỷ mã, lệnh dọn mã hết hạn; total_pending chỉ tính giao dịch đã nộp chứng từ, admin duyệt/từ chối/xoá giao dịch - Gia hạn dịch vụ: phát hành invoice gia hạn trên order gốc và trừ số dư ngay - Đồng bộ domain từ Plesk theo server, ServiceOrderRecorder tạo order/invoice cho dịch vụ admin dựng - Danh sách dịch vụ trả field theo loại (service_plan, dns_records_count), đếm dịch vụ theo loại Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
94 lines
3.8 KiB
PHP
94 lines
3.8 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Feature\Payment;
|
|
|
|
use App\Enums\TransactionStatus;
|
|
use App\Http\Controllers\Api\Admin\Transaction\AdminTransactionController;
|
|
use App\Models\Customer;
|
|
use App\Models\Transaction;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Mail;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Str;
|
|
use Tests\TestCase;
|
|
|
|
class AdminManualDepositActionsTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private function deposit(Customer $customer, int $amount, ?string $proof, TransactionStatus $status = TransactionStatus::PENDING): Transaction
|
|
{
|
|
return Transaction::create([
|
|
'uuid' => (string) Str::uuid(),
|
|
'trans' => 'MANTEST' . Str::random(6),
|
|
'amount' => $amount,
|
|
'customer_id' => $customer->id,
|
|
'type' => 'manual',
|
|
'status' => $status->value,
|
|
'proof_image' => $proof,
|
|
]);
|
|
}
|
|
|
|
public function test_draft_without_proof_can_be_rejected_and_approved_without_touching_pending(): void
|
|
{
|
|
Mail::fake();
|
|
$customer = Customer::factory()->create(['total' => 0, 'total_pending' => 300_000]);
|
|
$controller = app(AdminTransactionController::class);
|
|
|
|
$rejected = $this->deposit($customer, 5_000_000, null);
|
|
$this->assertSame(200, $controller->reject($rejected->uuid)->getStatusCode());
|
|
$this->assertSame(TransactionStatus::FAILED->value, (int) $rejected->fresh()->status);
|
|
|
|
$approved = $this->deposit($customer, 1_000_000, null);
|
|
$this->assertSame(200, $controller->approve(new Request(), $approved->uuid)->getStatusCode());
|
|
|
|
$customer->refresh();
|
|
$this->assertSame(300_000, (int) $customer->total_pending);
|
|
$this->assertSame(1_000_000, (int) $customer->total);
|
|
}
|
|
|
|
public function test_signed_proof_image_url_serves_the_file(): void
|
|
{
|
|
Storage::fake('local');
|
|
$customer = Customer::factory()->create();
|
|
$path = UploadedFile::fake()->image('proof.png')->store('deposit-proofs/' . $customer->id, 'local');
|
|
$transaction = $this->deposit($customer, 300_000, $path);
|
|
|
|
$this->get($transaction->proof_image_urls[0])->assertOk();
|
|
$this->get(strtok($transaction->proof_image_urls[0], '?'))->assertForbidden();
|
|
}
|
|
|
|
public function test_deleting_submitted_pending_deposit_releases_pending_amount(): void
|
|
{
|
|
$customer = Customer::factory()->create(['total' => 0, 'total_pending' => 300_000]);
|
|
$transaction = $this->deposit($customer, 300_000, 'deposit-proofs/a.jpg');
|
|
|
|
$response = app(AdminTransactionController::class)->destroy($transaction->uuid);
|
|
|
|
$this->assertSame(200, $response->getStatusCode());
|
|
$this->assertSoftDeleted($transaction);
|
|
$this->assertSame(0, (int) $customer->fresh()->total_pending);
|
|
}
|
|
|
|
public function test_deleting_draft_or_completed_deposit_keeps_balances(): void
|
|
{
|
|
$customer = Customer::factory()->create(['total' => 2_000_000, 'total_pending' => 300_000]);
|
|
$controller = app(AdminTransactionController::class);
|
|
|
|
$draft = $this->deposit($customer, 500_000, null);
|
|
$completed = $this->deposit($customer, 2_000_000, 'deposit-proofs/b.jpg', TransactionStatus::COMPLETED);
|
|
|
|
$this->assertSame(200, $controller->destroy($draft->uuid)->getStatusCode());
|
|
$this->assertSame(200, $controller->destroy($completed->uuid)->getStatusCode());
|
|
$this->assertSame(404, $controller->destroy($completed->uuid)->getStatusCode());
|
|
|
|
$customer->refresh();
|
|
$this->assertSame(300_000, (int) $customer->total_pending);
|
|
$this->assertSame(2_000_000, (int) $customer->total);
|
|
}
|
|
}
|