145 lines
5.0 KiB
PHP
145 lines
5.0 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature\Api\V1\Store;
|
|
|
|
use App\Models\PartnerStore;
|
|
use App\Models\QrCode;
|
|
use App\Models\QrCodeBatch;
|
|
use App\Models\StoreSale;
|
|
use App\Models\Tenant;
|
|
use App\Models\User;
|
|
use App\Services\Store\StoreOperations;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
class PartnerStoreSettlementTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected User $admin;
|
|
protected PartnerStore $store;
|
|
protected StoreOperations $ops;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
// $this->defaultTenant is already created and set in parent::setUp()
|
|
$this->admin = User::factory()->create(['tenant_id' => $this->defaultTenant->id, 'role' => 'admin']);
|
|
$owner = User::factory()->create(['tenant_id' => $this->defaultTenant->id, 'role' => 'store_partner']);
|
|
$this->store = PartnerStore::factory()->create([
|
|
'tenant_id' => $this->defaultTenant->id,
|
|
'owner_user_id' => $owner->id,
|
|
'commission_rate_percent' => 10,
|
|
'status' => 'active',
|
|
]);
|
|
$this->ops = app(StoreOperations::class);
|
|
}
|
|
|
|
public function test_calculate_balance_due_consignment_model()
|
|
{
|
|
// 1. Issue inventory (already in setup)
|
|
|
|
// 2. Record sales (Retail Price 100, Commission 10%)
|
|
// Total Sold: 2 codes @ 100 each = 200 Gross
|
|
// Commission: 10% of 200 = 20
|
|
// Net Owed to City: 200 - 20 = 180
|
|
StoreSale::factory()->count(2)->create([
|
|
'store_id' => $this->store->id,
|
|
'retail_price_centavos' => 10000,
|
|
'commission_centavos' => 1000
|
|
]);
|
|
|
|
$balance = $this->ops->calculateBalanceDue($this->store);
|
|
$this->assertEquals(18000, $balance); // 180.00 in centavos
|
|
|
|
// 3. Record payment
|
|
$response = $this->actingAs($this->admin)
|
|
->postJson("/api/v1/admin/partner-stores/{$this->store->uuid}/settle", [
|
|
'amount_pesos' => 100,
|
|
'payment_method' => 'cash',
|
|
'reference_number' => 'REF123'
|
|
]);
|
|
$response->assertSuccessful();
|
|
|
|
// 4. Check new balance: 180 - 100 = 80
|
|
$newBalance = $this->ops->calculateBalanceDue($this->store);
|
|
$this->assertEquals(8000, $newBalance);
|
|
}
|
|
|
|
public function test_report_defective_with_replacement()
|
|
{
|
|
// Setup: Issue a specific code
|
|
$qr = QrCode::factory()->create([
|
|
'tenant_id' => $this->defaultTenant->id,
|
|
'assigned_to_store_id' => $this->store->id,
|
|
'status' => 'allocated'
|
|
]);
|
|
|
|
\App\Models\StoreInventory::create([
|
|
'store_id' => $this->store->id,
|
|
'current_code_balance' => 1,
|
|
'prepaid_balance' => 0
|
|
]);
|
|
|
|
$this->actingAs($this->admin)
|
|
->postJson("/api/v1/admin/partner-stores/{$this->store->uuid}/report-issue", [
|
|
'serial' => $qr->serial,
|
|
'reason' => 'Defective Adhesive'
|
|
])
|
|
->assertSuccessful();
|
|
|
|
// Original should be voided
|
|
$qr->refresh();
|
|
$this->assertEquals('voided', $qr->status);
|
|
|
|
// A new replacement QR should exist
|
|
$replacement = QrCode::where('replacement_for_id', $qr->id)->first();
|
|
$this->assertNotNull($replacement);
|
|
$this->assertEquals('allocated', $replacement->status);
|
|
$this->assertEquals($this->store->id, $replacement->assigned_to_store_id);
|
|
|
|
// Inventory balance should be 1 (started at 1, -1 for defective, +1 for replacement)
|
|
$this->store->refresh()->load('inventory');
|
|
$this->assertEquals(1, $this->store->inventory?->current_code_balance ?? 0);
|
|
}
|
|
|
|
public function test_print_replacement_endpoint()
|
|
{
|
|
$qr = QrCode::factory()->create([
|
|
'tenant_id' => $this->defaultTenant->id,
|
|
'assigned_to_store_id' => $this->store->id,
|
|
'status' => 'voided'
|
|
]);
|
|
|
|
$replacement = QrCode::factory()->create([
|
|
'tenant_id' => $this->defaultTenant->id,
|
|
'assigned_to_store_id' => $this->store->id,
|
|
'status' => 'allocated',
|
|
'replacement_for_id' => $qr->id
|
|
]);
|
|
|
|
$this->actingAs($this->admin)
|
|
->getJson("/api/v1/admin/partner-stores/{$this->store->uuid}/qr-codes/{$replacement->serial}/print")
|
|
->assertSuccessful()
|
|
->assertJsonStructure(['data' => ['qr_data', 'serial']]);
|
|
}
|
|
|
|
public function test_analytics_includes_financials()
|
|
{
|
|
// 1 sale: 100 retail, 10 comm -> 90 owed
|
|
StoreSale::factory()->create([
|
|
'store_id' => $this->store->id,
|
|
'retail_price_centavos' => 10000,
|
|
'commission_centavos' => 1000
|
|
]);
|
|
|
|
$this->actingAs($this->admin)
|
|
->getJson("/api/v1/admin/partner-stores/{$this->store->uuid}/analytics")
|
|
->assertSuccessful()
|
|
->assertJsonFragment([
|
|
'balance_due_pesos' => '90.00',
|
|
'total_settled_pesos' => '0.00'
|
|
]);
|
|
}
|
|
}
|