- Added buttons for assigning diagnosis and starting diagnosis based on job card status in the job card view. - Implemented a modal for assigning technicians for diagnosis, including form validation and technician selection. - Updated routes to include a test route for job cards. - Created a new Blade view for testing inspection inputs. - Developed comprehensive feature tests for the estimate module, including creation, viewing, editing, and validation of estimates. - Added tests for estimate model relationships and statistics calculations. - Introduced a basic feature test for job cards index.
357 lines
12 KiB
PHP
357 lines
12 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Livewire\Estimates\Create;
|
|
use App\Livewire\Estimates\Edit;
|
|
use App\Livewire\Estimates\Show;
|
|
use App\Models\Branch;
|
|
use App\Models\Customer;
|
|
use App\Models\Diagnosis;
|
|
use App\Models\Estimate;
|
|
use App\Models\JobCard;
|
|
use App\Models\User;
|
|
use App\Models\Vehicle;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Livewire\Livewire;
|
|
use Tests\TestCase;
|
|
|
|
class EstimateModuleTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
private User $user;
|
|
|
|
private Branch $branch;
|
|
|
|
private Customer $customer;
|
|
|
|
private Vehicle $vehicle;
|
|
|
|
private JobCard $jobCard;
|
|
|
|
private Diagnosis $diagnosis;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
// Create test data using factories
|
|
$this->user = User::factory()->create([
|
|
'role' => 'service_coordinator',
|
|
]);
|
|
|
|
// Give user required permissions for estimates
|
|
$permissions = [
|
|
['name' => 'service-orders.view', 'display_name' => 'View Service Orders', 'module' => 'service-orders'],
|
|
['name' => 'service-orders.create', 'display_name' => 'Create Service Orders', 'module' => 'service-orders'],
|
|
['name' => 'service-orders.update', 'display_name' => 'Update Service Orders', 'module' => 'service-orders'],
|
|
];
|
|
|
|
foreach ($permissions as $permissionData) {
|
|
$permission = \App\Models\Permission::firstOrCreate(
|
|
['name' => $permissionData['name']],
|
|
[
|
|
'display_name' => $permissionData['display_name'],
|
|
'description' => $permissionData['display_name'],
|
|
'module' => $permissionData['module'],
|
|
]
|
|
);
|
|
$this->user->permissions()->attach($permission);
|
|
}
|
|
|
|
$this->branch = Branch::create([
|
|
'name' => 'Main Branch',
|
|
'code' => 'MAIN',
|
|
'address' => '123 Test St',
|
|
'phone' => '555-0123',
|
|
'email' => 'main@test.com',
|
|
]);
|
|
|
|
$this->customer = Customer::factory()->create();
|
|
$this->vehicle = Vehicle::factory()->create([
|
|
'customer_id' => $this->customer->id,
|
|
]);
|
|
|
|
$this->jobCard = JobCard::factory()->create([
|
|
'customer_id' => $this->customer->id,
|
|
'vehicle_id' => $this->vehicle->id,
|
|
'branch_code' => $this->branch->code,
|
|
'status' => 'in_diagnosis',
|
|
'service_advisor_id' => $this->user->id,
|
|
]);
|
|
|
|
$this->diagnosis = Diagnosis::create([
|
|
'job_card_id' => $this->jobCard->id,
|
|
'service_coordinator_id' => $this->user->id,
|
|
'diagnostic_findings' => 'Worn brake pads detected',
|
|
'labor_operations' => [
|
|
[
|
|
'operation' => 'Replace front brake pads',
|
|
'estimated_hours' => 2.0,
|
|
'labor_rate' => 85.00,
|
|
],
|
|
],
|
|
'parts_required' => [
|
|
[
|
|
'part_name' => 'Front brake pads',
|
|
'part_number' => 'BP-TOY-001',
|
|
'quantity' => 1,
|
|
'estimated_cost' => 75.00,
|
|
],
|
|
],
|
|
'estimated_repair_time' => 2.5,
|
|
'diagnosis_status' => 'completed',
|
|
]);
|
|
|
|
$this->actingAs($this->user);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_can_create_an_estimate_from_diagnosis()
|
|
{
|
|
Livewire::test(Create::class, ['diagnosis' => $this->diagnosis])
|
|
->assertSet('diagnosis.id', $this->diagnosis->id)
|
|
->assertViewHas('diagnosis')
|
|
->call('save')
|
|
->assertHasNoErrors()
|
|
->assertRedirect();
|
|
|
|
$this->assertDatabaseHas('estimates', [
|
|
'job_card_id' => $this->jobCard->id,
|
|
'diagnosis_id' => $this->diagnosis->id,
|
|
'prepared_by_id' => $this->user->id,
|
|
'status' => 'draft',
|
|
]);
|
|
|
|
// Check that line items were created
|
|
$estimate = Estimate::latest()->first();
|
|
$this->assertGreaterThan(0, $estimate->lineItems()->count());
|
|
|
|
// Check that totals were calculated
|
|
$this->assertGreaterThan(0, $estimate->total_amount);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_calculates_totals_correctly()
|
|
{
|
|
$component = Livewire::test(Create::class, ['diagnosis' => $this->diagnosis]);
|
|
|
|
// Verify initial line items from diagnosis
|
|
$lineItems = $component->get('lineItems');
|
|
$this->assertNotEmpty($lineItems);
|
|
|
|
// Check that totals are calculated
|
|
$subtotal = $component->get('subtotal');
|
|
$taxAmount = $component->get('tax_amount');
|
|
$totalAmount = $component->get('total_amount');
|
|
|
|
$this->assertGreaterThan(0, $subtotal);
|
|
$this->assertGreaterThan(0, $taxAmount);
|
|
$this->assertGreaterThan(0, $totalAmount);
|
|
|
|
// Verify total calculation: subtotal + tax = total
|
|
$expectedTotal = $subtotal + $taxAmount;
|
|
$this->assertEquals($expectedTotal, $totalAmount);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_can_add_and_remove_line_items()
|
|
{
|
|
$component = Livewire::test(Create::class, ['diagnosis' => $this->diagnosis]);
|
|
|
|
$initialCount = count($component->get('lineItems'));
|
|
|
|
// Add a line item
|
|
$component->call('addLineItem');
|
|
$this->assertCount($initialCount + 1, $component->get('lineItems'));
|
|
|
|
// Remove a line item
|
|
$component->call('removeLineItem', 0);
|
|
$this->assertCount($initialCount, $component->get('lineItems'));
|
|
}
|
|
|
|
/** @test */
|
|
public function it_validates_required_fields()
|
|
{
|
|
Livewire::test(Create::class, ['diagnosis' => $this->diagnosis])
|
|
->set('terms_and_conditions', '')
|
|
->set('validity_period_days', 0)
|
|
->set('tax_rate', -1)
|
|
->call('save')
|
|
->assertHasErrors([
|
|
'terms_and_conditions',
|
|
'validity_period_days',
|
|
'tax_rate',
|
|
]);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_can_view_an_estimate()
|
|
{
|
|
$estimate = Estimate::create([
|
|
'estimate_number' => 'MAIN/EST0001',
|
|
'job_card_id' => $this->jobCard->id,
|
|
'diagnosis_id' => $this->diagnosis->id,
|
|
'prepared_by_id' => $this->user->id,
|
|
'labor_cost' => 170.00,
|
|
'parts_cost' => 90.00,
|
|
'subtotal' => 260.00,
|
|
'tax_rate' => 8.25,
|
|
'tax_amount' => 21.45,
|
|
'total_amount' => 281.45,
|
|
'validity_period_days' => 30,
|
|
'terms_and_conditions' => 'Test terms',
|
|
'status' => 'draft',
|
|
]);
|
|
|
|
Livewire::test(Show::class, ['estimate' => $estimate])
|
|
->assertSet('estimate.id', $estimate->id)
|
|
->assertSee($estimate->estimate_number)
|
|
->assertSee('$281.45')
|
|
->assertViewHas('estimate');
|
|
}
|
|
|
|
/** @test */
|
|
public function it_can_edit_an_estimate()
|
|
{
|
|
$estimate = Estimate::factory()->create([
|
|
'job_card_id' => $this->jobCard->id,
|
|
'terms_and_conditions' => 'Original terms',
|
|
'validity_period_days' => 30,
|
|
]);
|
|
|
|
// Test the component functionality directly without layout rendering
|
|
$component = Livewire::test(\App\Livewire\Estimates\Edit::class, ['estimate' => $estimate])
|
|
->set('terms_and_conditions', 'Updated terms and conditions')
|
|
->set('validity_period_days', 45);
|
|
|
|
// Assert the properties are set correctly
|
|
$component->assertSet('terms_and_conditions', 'Updated terms and conditions')
|
|
->assertSet('validity_period_days', 45);
|
|
|
|
// Call save method
|
|
$component->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$this->assertDatabaseHas('estimates', [
|
|
'id' => $estimate->id,
|
|
'terms_and_conditions' => 'Updated terms and conditions',
|
|
'validity_period_days' => 45,
|
|
]);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_generates_unique_estimate_numbers()
|
|
{
|
|
$initialCount = Estimate::count();
|
|
|
|
// Create first estimate
|
|
Livewire::test(Create::class, ['diagnosis' => $this->diagnosis])
|
|
->call('save');
|
|
|
|
$this->assertEquals($initialCount + 1, Estimate::count());
|
|
$firstEstimate = Estimate::latest()->first();
|
|
|
|
// Create another diagnosis for second estimate
|
|
$diagnosis2 = Diagnosis::create([
|
|
'job_card_id' => $this->jobCard->id,
|
|
'service_coordinator_id' => $this->user->id,
|
|
'diagnostic_findings' => 'Different issue',
|
|
'diagnosis_status' => 'completed',
|
|
]);
|
|
|
|
// Create second estimate
|
|
Livewire::test(Create::class, ['diagnosis' => $diagnosis2])
|
|
->call('save');
|
|
|
|
$this->assertEquals($initialCount + 2, Estimate::count());
|
|
$estimates = Estimate::latest()->take(2)->get();
|
|
$secondEstimate = $estimates->first();
|
|
$firstEstimate = $estimates->last();
|
|
|
|
$this->assertNotEquals($firstEstimate->estimate_number, $secondEstimate->estimate_number);
|
|
$this->assertStringContainsString('MAIN/EST', $firstEstimate->estimate_number);
|
|
$this->assertStringContainsString('MAIN/EST', $secondEstimate->estimate_number);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_updates_job_card_status_when_estimate_created()
|
|
{
|
|
$this->assertEquals('in_diagnosis', $this->jobCard->status);
|
|
|
|
Livewire::test(Create::class, ['diagnosis' => $this->diagnosis])
|
|
->call('save');
|
|
|
|
$this->jobCard->refresh();
|
|
$this->assertEquals('estimate_prepared', $this->jobCard->status);
|
|
}
|
|
|
|
/** @test */
|
|
public function estimate_routes_are_accessible()
|
|
{
|
|
// Skip permission checks for this test by using an admin role
|
|
$this->user->update(['role' => 'admin']);
|
|
|
|
$estimate = Estimate::create([
|
|
'estimate_number' => 'MAIN/EST0001',
|
|
'job_card_id' => $this->jobCard->id,
|
|
'diagnosis_id' => $this->diagnosis->id,
|
|
'prepared_by_id' => $this->user->id,
|
|
'labor_cost' => 170.00,
|
|
'parts_cost' => 90.00,
|
|
'subtotal' => 260.00,
|
|
'tax_rate' => 8.25,
|
|
'tax_amount' => 21.45,
|
|
'total_amount' => 281.45,
|
|
'validity_period_days' => 30,
|
|
'terms_and_conditions' => 'Test terms',
|
|
'status' => 'draft',
|
|
]);
|
|
|
|
// Test index route
|
|
$this->actingAs($this->user)
|
|
->get('/estimates')
|
|
->assertStatus(200);
|
|
|
|
// Test show route
|
|
$this->actingAs($this->user)
|
|
->get("/estimates/{$estimate->id}")
|
|
->assertStatus(200);
|
|
|
|
// Test edit route
|
|
$this->get("/estimates/{$estimate->id}/edit")
|
|
->assertStatus(200);
|
|
|
|
// Test create route
|
|
$this->get("/estimates/create/{$this->diagnosis->id}")
|
|
->assertStatus(200);
|
|
}
|
|
|
|
/** @test */
|
|
public function it_can_calculate_estimate_expiration()
|
|
{
|
|
$estimate = Estimate::create([
|
|
'estimate_number' => 'MAIN/EST0001',
|
|
'job_card_id' => $this->jobCard->id,
|
|
'diagnosis_id' => $this->diagnosis->id,
|
|
'prepared_by_id' => $this->user->id,
|
|
'labor_cost' => 170.00,
|
|
'parts_cost' => 90.00,
|
|
'subtotal' => 260.00,
|
|
'tax_rate' => 8.25,
|
|
'tax_amount' => 21.45,
|
|
'total_amount' => 281.45,
|
|
'validity_period_days' => 30,
|
|
'terms_and_conditions' => 'Test terms',
|
|
'status' => 'draft',
|
|
]);
|
|
|
|
$expectedValidUntil = $estimate->created_at->addDays(30);
|
|
$this->assertEquals($expectedValidUntil->format('Y-m-d'), $estimate->valid_until->format('Y-m-d'));
|
|
|
|
// Test if estimate is not expired (fresh estimate)
|
|
$this->assertFalse($estimate->is_expired);
|
|
}
|
|
}
|