d1e0695930
- SetLocale middleware (ro/ru/en, session-first, user-persisted)
- Lang switcher in topbar (Filament render hook USER_MENU_BEFORE)
- POST /locale/{lang} route persists to user.locale + session
- Database notifications enabled on tenant panel (30s polling)
- GlobalSearch (Cmd+K / Ctrl+K) on Client, Vehicle, WorkOrder, Lead, Part
- Tests: TenantIsolation (4), AuthFlow (2), WorkOrderCalc (3), MarkupRule (3)
104 lines
2.8 KiB
PHP
104 lines
2.8 KiB
PHP
<?php
|
|
|
|
namespace Tests\Unit;
|
|
|
|
use App\Models\Central\Company;
|
|
use App\Models\Central\Plan;
|
|
use App\Models\Tenant\MarkupRule;
|
|
use App\Models\Tenant\Part;
|
|
use App\Tenancy\TenantManager;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
class MarkupRuleTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
public function test_category_rule_applies_to_part(): void
|
|
{
|
|
$this->setupTenant();
|
|
|
|
$part = Part::create([
|
|
'name' => 'Plăcuțe frână',
|
|
'category' => 'Frâne',
|
|
'buy_price' => 100,
|
|
'sell_price' => 100,
|
|
'stock' => 10,
|
|
'is_active' => true,
|
|
]);
|
|
|
|
MarkupRule::create([
|
|
'type' => 'category',
|
|
'key' => 'Frâne',
|
|
'markup_pct' => 35,
|
|
'priority' => 100,
|
|
'is_active' => true,
|
|
]);
|
|
|
|
MarkupRule::applyToPart($part);
|
|
$part->refresh();
|
|
|
|
$this->assertEquals(135.00, (float) $part->sell_price);
|
|
}
|
|
|
|
public function test_priority_picks_first_matching_rule(): void
|
|
{
|
|
$this->setupTenant();
|
|
|
|
$part = Part::create([
|
|
'name' => 'Filtru',
|
|
'category' => 'Filtre',
|
|
'brand' => 'Bosch',
|
|
'buy_price' => 50,
|
|
'sell_price' => 50,
|
|
'stock' => 5,
|
|
'is_active' => true,
|
|
]);
|
|
|
|
// Brand rule (priority 1 → applied first)
|
|
MarkupRule::create(['type' => 'brand', 'key' => 'Bosch', 'markup_pct' => 50, 'priority' => 1, 'is_active' => true]);
|
|
MarkupRule::create(['type' => 'category', 'key' => 'Filtre', 'markup_pct' => 20, 'priority' => 100, 'is_active' => true]);
|
|
|
|
MarkupRule::applyToPart($part);
|
|
$part->refresh();
|
|
|
|
$this->assertEquals(75.00, (float) $part->sell_price);
|
|
}
|
|
|
|
public function test_inactive_rule_is_skipped(): void
|
|
{
|
|
$this->setupTenant();
|
|
|
|
$part = Part::create([
|
|
'name' => 'X', 'category' => 'Test',
|
|
'buy_price' => 100, 'sell_price' => 100,
|
|
'stock' => 1, 'is_active' => true,
|
|
]);
|
|
|
|
MarkupRule::create([
|
|
'type' => 'category', 'key' => 'Test',
|
|
'markup_pct' => 99, 'priority' => 1, 'is_active' => false,
|
|
]);
|
|
|
|
MarkupRule::applyToPart($part);
|
|
$part->refresh();
|
|
|
|
// Inactive rule skipped → fallback default markup 30%.
|
|
$this->assertEquals(130.00, (float) $part->sell_price);
|
|
}
|
|
|
|
private function setupTenant(): void
|
|
{
|
|
$plan = Plan::create([
|
|
'name' => 'Test', 'slug' => 'test', 'price' => 0, 'features' => [],
|
|
]);
|
|
$company = Company::create([
|
|
'plan_id' => $plan->id,
|
|
'slug' => 'unit-' . uniqid(),
|
|
'name' => 'Unit Test',
|
|
'status' => 'active',
|
|
]);
|
|
app(TenantManager::class)->setCurrent($company);
|
|
}
|
|
}
|