107 lines
3.7 KiB
PHP
107 lines
3.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace Tests\Feature\Console;
|
|
|
|
use App\Enums\Invoice\InvoiceStatus;
|
|
use App\Enums\Order\OrderStatus;
|
|
use App\Models\Customer;
|
|
use App\Models\Invoice;
|
|
use App\Models\Order;
|
|
use App\Services\InvoiceReminderService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Facades\Queue;
|
|
use Tests\TestCase;
|
|
|
|
class InvoiceReminderTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
// EmailTemplateService::send() đẩy qua SendTemplateEmailJob — fake queue để test
|
|
// không phụ thuộc template có trong DB hay không.
|
|
Queue::fake();
|
|
config(['billing.reminder_offsets' => [-7, -3, 0, 3]]);
|
|
}
|
|
|
|
public function test_no_reminder_is_sent_before_the_first_offset(): void
|
|
{
|
|
$invoice = $this->makeInvoice(now()->addDays(30));
|
|
|
|
$this->artisan('invoices:send-reminders')->assertExitCode(0);
|
|
|
|
$this->assertSame(0, (int) $invoice->fresh()->reminder_step);
|
|
}
|
|
|
|
public function test_reminder_step_advances_once_per_offset_reached(): void
|
|
{
|
|
// Hạn còn 5 ngày → đã qua mốc -7, chưa tới mốc -3.
|
|
$invoice = $this->makeInvoice(now()->addDays(5));
|
|
|
|
$this->artisan('invoices:send-reminders')->assertExitCode(0);
|
|
$this->assertSame(1, (int) $invoice->fresh()->reminder_step);
|
|
|
|
// Chạy lại trong ngày không được gửi trùng.
|
|
$this->artisan('invoices:send-reminders')->assertExitCode(0);
|
|
$this->assertSame(1, (int) $invoice->fresh()->reminder_step);
|
|
}
|
|
|
|
public function test_an_overdue_invoice_reaches_the_later_offsets(): void
|
|
{
|
|
$invoice = $this->makeInvoice(now()->subDays(4), InvoiceStatus::OVERDUE->value);
|
|
|
|
$this->artisan('invoices:send-reminders')->assertExitCode(0);
|
|
|
|
// Đã qua cả 4 mốc: -7, -3, 0, +3.
|
|
$this->assertSame(4, (int) $invoice->fresh()->reminder_step);
|
|
}
|
|
|
|
public function test_a_paid_invoice_is_never_reminded(): void
|
|
{
|
|
$invoice = $this->makeInvoice(now()->subDays(10), InvoiceStatus::PAID->value);
|
|
|
|
$this->artisan('invoices:send-reminders')->assertExitCode(0);
|
|
|
|
$this->assertSame(0, (int) $invoice->fresh()->reminder_step);
|
|
$this->assertFalse(app(InvoiceReminderService::class)->isRemindable($invoice->fresh()));
|
|
}
|
|
|
|
/** Nút nhắc thủ công của kế toán gửi được kể cả khi mốc đó đã gửi rồi. */
|
|
public function test_manual_reminder_sends_even_when_the_offset_was_already_used(): void
|
|
{
|
|
$invoice = $this->makeInvoice(now()->addDays(5));
|
|
$reminders = app(InvoiceReminderService::class);
|
|
|
|
$this->assertTrue($reminders->remind($invoice));
|
|
$this->assertFalse($reminders->remind($invoice->fresh()));
|
|
$this->assertTrue($reminders->remind($invoice->fresh(), force: true));
|
|
}
|
|
|
|
private function makeInvoice(\Carbon\Carbon $dueDate, int $status = InvoiceStatus::UNPAID->value): Invoice
|
|
{
|
|
$customer = Customer::factory()->create();
|
|
$order = Order::create([
|
|
'order_num' => 'ORD-' . uniqid(),
|
|
'customer_id' => $customer->id,
|
|
'sub_total' => 100_000,
|
|
'total' => 100_000,
|
|
'status' => OrderStatus::PENDING->value,
|
|
]);
|
|
|
|
return Invoice::create([
|
|
'invoice_number' => 'INV-' . uniqid(),
|
|
'customer_id' => $customer->id,
|
|
'order_id' => $order->id,
|
|
'invoice_type' => 1,
|
|
'sub_total' => 100_000,
|
|
'tax' => 0,
|
|
'total' => 100_000,
|
|
'status' => $status,
|
|
'due_date' => $dueDate->toDateString(),
|
|
]);
|
|
}
|
|
}
|