132 lines
4.7 KiB
PHP
132 lines
4.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Feature\Api\Client;
|
|
|
|
use App\Enums\Invoice\InvoiceStatus;
|
|
use App\Models\Customer;
|
|
use App\Models\Invoice;
|
|
use App\Models\InvoiceItem;
|
|
use App\Support\InvoiceBuyer;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
class InvoiceLookupTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private Invoice $invoice;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$customer = Customer::factory()->create([
|
|
'fullname' => 'Nguyen Van A',
|
|
'address' => '1 Le Loi',
|
|
'invoice_company' => 'Cong ty ABC',
|
|
'tax_code' => '0312345678',
|
|
'invoice_address' => '99 Nguyen Hue',
|
|
]);
|
|
|
|
$this->invoice = Invoice::create([
|
|
'invoice_number' => 'INV-LOOKUP-1',
|
|
'customer_id' => $customer->id,
|
|
'invoice_type' => 1,
|
|
'sub_total' => 100_000,
|
|
'tax' => 10_000,
|
|
'total' => 110_000,
|
|
'status' => InvoiceStatus::PAID->value,
|
|
]);
|
|
InvoiceItem::create([
|
|
'invoice_id' => $this->invoice->id,
|
|
'type' => 'service',
|
|
'description' => 'VPS 1 thang',
|
|
'months' => 1,
|
|
'quantity' => 1,
|
|
'unit_price' => 100_000,
|
|
'total_price' => 100_000,
|
|
]);
|
|
}
|
|
|
|
private function lookup(string $uri, array $body)
|
|
{
|
|
return $this->withHeaders(['x-access-token' => $this->buildClientAccessToken()])->postJson($uri, $body);
|
|
}
|
|
|
|
public function test_lookup_code_is_generated_on_create(): void
|
|
{
|
|
$this->assertMatchesRegularExpression('/^[A-Z0-9]{10}$/', $this->invoice->lookup_code);
|
|
}
|
|
|
|
public function test_correct_code_returns_limited_payload(): void
|
|
{
|
|
$response = $this->lookup('/v1/invoice-lookup', [
|
|
'invoice_number' => 'INV-LOOKUP-1',
|
|
'lookup_code' => strtolower($this->invoice->lookup_code),
|
|
])->assertOk();
|
|
|
|
$response->assertJsonPath('data.total', 110_000)
|
|
->assertJsonPath('data.buyer.tax_code', '0312345678')
|
|
->assertJsonPath('data.buyer.company', 'Cong ty ABC');
|
|
|
|
$body = json_encode($response->json());
|
|
$this->assertStringNotContainsString('Nguyen Van A', $body);
|
|
$this->assertStringNotContainsString('99 Nguyen Hue', $body);
|
|
$this->assertStringNotContainsString($this->invoice->lookup_code, $body);
|
|
}
|
|
|
|
public function test_wrong_code_or_unknown_number_is_404(): void
|
|
{
|
|
$this->lookup('/v1/invoice-lookup', ['invoice_number' => 'INV-LOOKUP-1', 'lookup_code' => 'WRONGCODE1'])->assertNotFound();
|
|
$this->lookup('/v1/invoice-lookup', ['invoice_number' => 'INV-NOPE', 'lookup_code' => $this->invoice->lookup_code])->assertNotFound();
|
|
$this->lookup('/v1/invoice-lookup/pdf', ['invoice_number' => 'INV-LOOKUP-1', 'lookup_code' => 'WRONGCODE1'])->assertNotFound();
|
|
}
|
|
|
|
public function test_cancelled_invoice_is_not_found(): void
|
|
{
|
|
$this->invoice->update(['status' => InvoiceStatus::CANCELLED->value]);
|
|
|
|
$this->lookup('/v1/invoice-lookup', [
|
|
'invoice_number' => 'INV-LOOKUP-1',
|
|
'lookup_code' => $this->invoice->lookup_code,
|
|
])->assertNotFound();
|
|
}
|
|
|
|
public function test_pdf_is_returned_for_correct_code(): void
|
|
{
|
|
$response = $this->lookup('/v1/invoice-lookup/pdf', [
|
|
'invoice_number' => 'INV-LOOKUP-1',
|
|
'lookup_code' => $this->invoice->lookup_code,
|
|
])->assertOk();
|
|
|
|
$this->assertSame('application/pdf', $response->headers->get('Content-Type'));
|
|
$this->assertStringStartsWith('%PDF', $response->getContent());
|
|
}
|
|
|
|
public function test_requires_client_access_token(): void
|
|
{
|
|
$this->postJson('/v1/invoice-lookup', ['invoice_number' => 'INV-LOOKUP-1', 'lookup_code' => $this->invoice->lookup_code])
|
|
->assertForbidden();
|
|
}
|
|
|
|
public function test_throttles_repeated_guesses_for_one_invoice(): void
|
|
{
|
|
for ($i = 0; $i < 10; $i++) {
|
|
$this->lookup('/v1/invoice-lookup', ['invoice_number' => 'INV-LOOKUP-1', 'lookup_code' => 'GUESS' . $i])->assertNotFound();
|
|
}
|
|
|
|
$this->lookup('/v1/invoice-lookup', ['invoice_number' => 'INV-LOOKUP-1', 'lookup_code' => $this->invoice->lookup_code])
|
|
->assertStatus(429);
|
|
}
|
|
|
|
public function test_buyer_snapshot_freezes_buyer_after_vat_is_recorded(): void
|
|
{
|
|
$this->invoice->update(['buyer_snapshot' => InvoiceBuyer::fromCustomer($this->invoice->customer)]);
|
|
$this->invoice->customer->update(['tax_code' => '0999999999']);
|
|
|
|
$this->assertSame('0312345678', InvoiceBuyer::forInvoice($this->invoice->fresh())['tax_code']);
|
|
}
|
|
}
|