'test'], ['name' => 'T', 'price' => 0, 'features' => []]); $this->company = Company::create([ 'plan_id' => $plan->id, 'slug' => 'pb-' . uniqid(), 'name' => 'PB Co', 'status' => 'active', ]); app(TenantManager::class)->setCurrent($this->company); } public function test_pipeline_columns_partition_leads_deals_and_wos_by_stage(): void { $client = Client::create(['name' => 'C', 'phone' => '+37399000111', 'type' => 'individual', 'status' => 'active']); $vehicle = Vehicle::create(['client_id' => $client->id, 'make' => 'BMW', 'model' => 'X5', 'plate' => 'X5-1']); // 1 lead in col "request" Lead::create(['name' => 'Anon', 'phone' => '+37300000001', 'source' => 'instagram', 'status' => 'new']); // 1 deal stage=new also in "request" Deal::create(['client_id' => $client->id, 'vehicle_id' => $vehicle->id, 'name' => 'BMW X5 — Frâne', 'price' => 5600, 'stage' => 'new']); // 1 deal in "quote" Deal::create(['client_id' => $client->id, 'vehicle_id' => $vehicle->id, 'name' => 'BMW X5 — Suspensie', 'price' => 8400, 'stage' => 'contact', 'quote_status' => 'sent', 'quote_sent_at' => now()->subHour()]); // 1 deal in "scheduled" Deal::create(['client_id' => $client->id, 'vehicle_id' => $vehicle->id, 'name' => 'BMW X5 — Revizie', 'price' => 3200, 'stage' => 'scheduled', 'scheduled_at' => now()->addDay()]); // 1 WO in "in_work" WorkOrder::create(['number' => WorkOrder::generateNumber($this->company->id), 'client_id' => $client->id, 'vehicle_id' => $vehicle->id, 'opened_at' => today(), 'status' => 'in_work', 'total' => 7200]); // 1 WO in "ready" WorkOrder::create(['number' => WorkOrder::generateNumber($this->company->id), 'client_id' => $client->id, 'vehicle_id' => $vehicle->id, 'opened_at' => today(), 'status' => 'ready', 'total' => 7800]); // 1 WO paid today $paidWo = WorkOrder::create(['number' => WorkOrder::generateNumber($this->company->id), 'client_id' => $client->id, 'vehicle_id' => $vehicle->id, 'opened_at' => today(), 'closed_at' => today(), 'status' => 'done', 'pay_status' => 'paid', 'total' => 4100]); $page = new PipelineBoard; $cols = $page->getColumns(); $this->assertEquals(2, $cols['request']['count'], 'lead + new deal'); $this->assertEquals(1, $cols['quote']['count']); $this->assertEquals(1, $cols['scheduled']['count']); $this->assertEquals(1, $cols['in_work']['count']); $this->assertEquals(1, $cols['ready']['count']); $this->assertEquals(1, $cols['paid']['count']); // sums $this->assertEquals(5600.0, $cols['request']['sum']); // lead has 0 budget, deal has 5600 $this->assertEquals(8400.0, $cols['quote']['sum']); $this->assertEquals(7200.0, $cols['in_work']['sum']); } public function test_stats_computes_active_and_pipeline_total(): void { $client = Client::create(['name' => 'C', 'phone' => '+37399000222', 'type' => 'individual', 'status' => 'active']); Deal::create(['client_id' => $client->id, 'name' => 'D1', 'price' => 1000, 'stage' => 'new']); Deal::create(['client_id' => $client->id, 'name' => 'D2', 'price' => 2000, 'stage' => 'contact']); Deal::create(['client_id' => $client->id, 'name' => 'D3', 'price' => 3000, 'stage' => 'scheduled', 'scheduled_at' => now()->addDay()]); // Payments today $wo = WorkOrder::create(['number' => WorkOrder::generateNumber($this->company->id), 'client_id' => $client->id, 'opened_at' => today(), 'status' => 'done', 'total' => 4500]); Payment::create(['client_id' => $client->id, 'work_order_id' => $wo->id, 'paid_at' => today(), 'amount' => 4500, 'method' => 'cash']); $stats = (new PipelineBoard)->getStats(); $this->assertEquals(3, $stats['active']); $this->assertEquals(6000.0, $stats['pipeline_mdl']); $this->assertEquals(4500.0, $stats['closed_today_mdl']); } public function test_move_lead_to_quote_converts_lead_into_deal(): void { $lead = Lead::create(['name' => 'X', 'phone' => '+37399123456', 'car' => 'VW', 'model' => 'Passat', 'budget' => 1500, 'status' => 'new', 'source' => 'site']); Livewire::test(PipelineBoard::class)->call('moveCard', "lead:{$lead->id}", 'quote'); $lead->refresh(); $this->assertEquals('converted', $lead->status); $this->assertNotNull($lead->deal_id); $deal = Deal::find($lead->deal_id); $this->assertEquals('contact', $deal->stage); $this->assertEquals('sent', $deal->quote_status); $this->assertNotNull($deal->quote_sent_at); } public function test_move_deal_to_in_work_creates_work_order(): void { $client = Client::create(['name' => 'C', 'phone' => '+37399111222', 'type' => 'individual', 'status' => 'active']); $vehicle = Vehicle::create(['client_id' => $client->id, 'make' => 'BMW', 'model' => 'X5', 'plate' => 'WX-1']); $deal = Deal::create(['client_id' => $client->id, 'vehicle_id' => $vehicle->id, 'name' => 'BMW X5 — Repair', 'price' => 7200, 'stage' => 'scheduled']); Livewire::test(PipelineBoard::class)->call('moveCard', "deal:{$deal->id}", 'in_work'); $deal->refresh(); $this->assertEquals('in_work', $deal->stage); $wo = WorkOrder::where('deal_id', $deal->id)->first(); $this->assertNotNull($wo); $this->assertEquals('in_work', $wo->status); $this->assertEquals(7200.0, (float) $wo->total); $this->assertEquals($client->id, $wo->client_id); $this->assertEquals($vehicle->id, $wo->vehicle_id); } public function test_move_wo_to_paid_creates_payment_for_balance_and_marks_done(): void { $client = Client::create(['name' => 'C', 'phone' => '+37399333444', 'type' => 'individual', 'status' => 'active']); $wo = WorkOrder::create(['number' => WorkOrder::generateNumber($this->company->id), 'client_id' => $client->id, 'opened_at' => today(), 'status' => 'ready', 'total' => 7800]); Livewire::test(PipelineBoard::class)->call('moveCard', "wo:{$wo->id}", 'paid'); $wo->refresh(); $this->assertEquals('done', $wo->status); $this->assertEquals(today()->toDateString(), $wo->closed_at?->toDateString()); $this->assertEquals('paid', $wo->pay_status); $this->assertEquals(7800.0, (float) Payment::where('work_order_id', $wo->id)->sum('amount')); } public function test_filter_mine_narrows_to_assigned_user(): void { $me = User::create(['name' => 'Me', 'email' => 'me@example.com', 'password' => bcrypt('x'), 'role' => 'master', 'status' => 'active']); $other = User::create(['name' => 'Other', 'email' => 'other@example.com', 'password' => bcrypt('x'), 'role' => 'master', 'status' => 'active']); $this->actingAs($me); $client = Client::create(['name' => 'C', 'phone' => '+37399555666', 'type' => 'individual', 'status' => 'active']); Deal::create(['client_id' => $client->id, 'name' => 'mine', 'price' => 1000, 'stage' => 'new', 'assigned_to' => $me->id]); Deal::create(['client_id' => $client->id, 'name' => 'other', 'price' => 2000, 'stage' => 'new', 'assigned_to' => $other->id]); $page = new PipelineBoard; $page->activeFilter = 'mine'; $cols = $page->getColumns(); $this->assertEquals(1, $cols['request']['count']); $this->assertEquals('mine', $cols['request']['cards'][0]['subject']); } public function test_open_card_loads_panel_detail_for_deal(): void { $client = Client::create(['name' => 'Ion Popescu', 'phone' => '+37369123456', 'type' => 'individual', 'status' => 'active']); $vehicle = Vehicle::create(['client_id' => $client->id, 'make' => 'BMW', 'model' => 'X5', 'plate' => 'CIU001']); $deal = Deal::create(['client_id' => $client->id, 'vehicle_id' => $vehicle->id, 'name' => 'BMW X5 — Diag', 'price' => 7200, 'stage' => 'contact', 'quote_status' => 'sent', 'quote_sent_at' => now()->subHour()]); $page = new PipelineBoard; $page->openCard("deal:{$deal->id}"); $detail = $page->getOpenCardDetail(); $this->assertNotNull($detail); $this->assertEquals('BMW X5 — Diag', $detail['title']); $this->assertEquals('Ion Popescu', $detail['fields']['Client']); $this->assertEquals('+37369123456', $detail['fields']['Telefon']); $this->assertCount(6, $detail['stages']); $this->assertTrue($detail['stages'][0]['done']); // Cerere $this->assertTrue($detail['stages'][1]['current']); // Calculație } }