diff --git a/.gitignore b/.gitignore index 375301ed7..bac5879a3 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,8 @@ package-lock.json *.sqlite /failures.txt /yarnpack.txt +/automation/.idea/ +/automation/vendor/ +/automation/test-honesty/vendor/ +.claude/fable5/runtime/control.json +upd.sh diff --git a/Modules/Core/Database/Seeders/RolesSeeder.php b/Modules/Core/Database/Seeders/RolesSeeder.php index 452f13259..03d996fb3 100644 --- a/Modules/Core/Database/Seeders/RolesSeeder.php +++ b/Modules/Core/Database/Seeders/RolesSeeder.php @@ -120,6 +120,7 @@ function ($p) use ($customerResources) { $isBasicAction = str_starts_with($p, 'view-') || str_starts_with($p, 'create-') || str_starts_with($p, 'edit-') + || str_starts_with($p, 'delete-') || str_starts_with($p, 'export-') || str_starts_with($p, 'duplicate-'); $isCustomerResource = (bool) array_filter( diff --git a/Modules/Core/Providers/CompanyPanelProvider.php b/Modules/Core/Providers/CompanyPanelProvider.php index de6870cf1..2063401e7 100644 --- a/Modules/Core/Providers/CompanyPanelProvider.php +++ b/Modules/Core/Providers/CompanyPanelProvider.php @@ -2,6 +2,7 @@ namespace Modules\Core\Providers; +use App\Filament\Pages\SwitchCompany; use Filament\Actions\Action; use Filament\FontProviders\GoogleFontProvider; use Filament\Http\Middleware\Authenticate; @@ -173,6 +174,7 @@ public function panel(Panel $panel): Panel ->discoverWidgets(in: app_path('Filament/Company/Widgets'), for: 'App\Filament\Company\Widgets') ->pages([ Dashboard::class, + SwitchCompany::class, ]) ->widgets([ RecentQuotesWidget::class, @@ -238,10 +240,12 @@ public function panel(Panel $panel): Panel }) ->userMenuItems([ Action::make('switch-company') - ->label('Switch Company') + ->label(fn (): string => Company::query()->find(session('current_company_id'))?->name ?? trans('ip.switch_company')) ->icon('heroicon-o-building-office-2') - ->modalHeading('Switch Company') - ->modalContent(fn () => view('filament.company.widgets.switch-company-table')), + ->modalHeading(trans('ip.switch_company')) + ->modalContent(fn () => view('filament.pages.switch-company-modal')) + ->modalSubmitAction(false) + ->modalCancelAction(false), 'profile' => fn (Action $action) => $action ->label(trans('ip.edit_profile')) ->icon('heroicon-o-user') diff --git a/Modules/Core/Tests/AbstractAdminPanelTestCase.php b/Modules/Core/Tests/AbstractAdminPanelTestCase.php index 5ea2f7670..a484e8a79 100644 --- a/Modules/Core/Tests/AbstractAdminPanelTestCase.php +++ b/Modules/Core/Tests/AbstractAdminPanelTestCase.php @@ -5,6 +5,9 @@ use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\TestCase as BaseTestCase; use Illuminate\Support\Carbon; +use Modules\Core\Database\Seeders\PermissionsSeeder; +use Modules\Core\Database\Seeders\RolesSeeder; +use Modules\Core\Enums\UserRole; use Modules\Core\Models\Company; use Modules\Core\Models\User; @@ -34,6 +37,14 @@ protected function setUp(): void session(['current_company_id' => $this->company->id]); + /* + * Admin resources gate every page on Spatie permissions (canViewAny + * etc.), so the test user needs the seeded super_admin permission set. + */ + (new PermissionsSeeder())->run(); + (new RolesSeeder())->run(); + $this->superAdmin->assignRole(UserRole::SUPER_ADMIN->value); + $this->withoutExceptionHandling(); } diff --git a/Modules/Core/Tests/AbstractCompanyPanelTestCase.php b/Modules/Core/Tests/AbstractCompanyPanelTestCase.php index 1be904606..768d61c53 100644 --- a/Modules/Core/Tests/AbstractCompanyPanelTestCase.php +++ b/Modules/Core/Tests/AbstractCompanyPanelTestCase.php @@ -7,6 +7,9 @@ use Illuminate\Foundation\Testing\RefreshDatabase; use Illuminate\Foundation\Testing\TestCase as BaseTestCase; use Illuminate\Support\Carbon; +use Modules\Core\Database\Seeders\PermissionsSeeder; +use Modules\Core\Database\Seeders\RolesSeeder; +use Modules\Core\Enums\UserRole; use Modules\Core\Models\Company; use Modules\Core\Models\User; @@ -44,6 +47,14 @@ protected function setUp(): void $currentCompanyId = $this->user->getCurrentCompanyId(); session(['current_company_id' => $currentCompanyId]); + /* + * Resources gate every page on Spatie permissions (canViewAny etc.), + * so the test user needs the seeded client_admin permission set. + */ + (new PermissionsSeeder())->run(); + (new RolesSeeder())->run(); + $this->user->assignRole(UserRole::CUSTOMER_ADMIN->value); + $this->withoutExceptionHandling(); } diff --git a/Modules/Core/Tests/Feature/SwitchCompanyTest.php b/Modules/Core/Tests/Feature/SwitchCompanyTest.php new file mode 100644 index 000000000..40f35bca4 --- /dev/null +++ b/Modules/Core/Tests/Feature/SwitchCompanyTest.php @@ -0,0 +1,279 @@ +create(); + $companies = Company::factory()->count($count)->create(); + $user->companies()->attach($companies->pluck('id')); + + return [$user, $companies]; + } + + // ───────────────────────────────────────────────────────────────────── + // Smoke + // ───────────────────────────────────────────────────────────────────── + + #[Test] + #[Group('smoke')] + public function it_renders_the_switch_company_page(): void + { + /* Arrange */ + [$user, $companies] = $this->userWithCompanies(3); + $initial = $companies->first(); + session(['current_company_id' => $initial->id]); + Filament::setTenant($initial, true); + + /* Act */ + $component = Livewire::actingAs($user)->test(SwitchCompany::class); + + /* Assert */ + $component->assertSuccessful(); + } + + // ───────────────────────────────────────────────────────────────────── + // Core switch behaviour + // ───────────────────────────────────────────────────────────────────── + + #[Test] + #[Group('crud')] + public function it_can_switch_company(): void + { + /* Arrange */ + [$user, $companies] = $this->userWithCompanies(5); + $initial = $companies->first(); + $target = $companies->last(); + session(['current_company_id' => $initial->id]); + Filament::setTenant($initial, true); + + /* Act */ + $test = Livewire::actingAs($user) + ->test(SwitchCompany::class) + ->callTableAction('switch', $target); + + /* Assert */ + $test->assertRedirect( + route('filament.company.pages.dashboard', ['tenant' => $target->search_code]) + ); + $this->assertEquals($target->id, session('current_company_id')); + } + + #[Test] + #[Group('crud')] + public function it_updates_session_on_switch(): void + { + /* Arrange */ + [$user, $companies] = $this->userWithCompanies(3); + $initial = $companies->first(); + $target = $companies->get(1); + session(['current_company_id' => $initial->id]); + Filament::setTenant($initial, true); + + /* Act */ + Livewire::actingAs($user) + ->test(SwitchCompany::class) + ->callTableAction('switch', $target); + + /* Assert — session reflects new company */ + $this->assertEquals($target->id, session('current_company_id')); + $this->assertNotEquals($initial->id, session('current_company_id')); + } + + // ───────────────────────────────────────────────────────────────────── + // Disabled / enabled state + // ───────────────────────────────────────────────────────────────────── + + #[Test] + #[Group('crud')] + public function it_disables_switch_action_for_current_company(): void + { + /* Arrange */ + [$user, $companies] = $this->userWithCompanies(5); + $initial = $companies->first(); + session(['current_company_id' => $initial->id]); + Filament::setTenant($initial, true); + + /* Act & Assert */ + Livewire::actingAs($user) + ->test(SwitchCompany::class) + ->assertTableActionDisabled('switch', $companies->first()) + ->assertTableActionEnabled('switch', $companies->last()); + } + + #[Test] + #[Group('crud')] + public function it_disables_only_the_current_company_switch_action(): void + { + /* Arrange */ + [$user, $companies] = $this->userWithCompanies(4); + $initial = $companies->get(2); // pick one from the middle + session(['current_company_id' => $initial->id]); + Filament::setTenant($initial, true); + + /* Act */ + $component = Livewire::actingAs($user)->test(SwitchCompany::class); + + /* Assert — every OTHER company is enabled */ + foreach ($companies as $company) { + if ($company->is($initial)) { + $component->assertTableActionDisabled('switch', $company); + } else { + $component->assertTableActionEnabled('switch', $company); + } + } + } + + // ───────────────────────────────────────────────────────────────────── + // Table contents — only user's companies shown + // ───────────────────────────────────────────────────────────────────── + + #[Test] + #[Group('crud')] + public function it_only_lists_companies_the_user_belongs_to(): void + { + /* Arrange */ + [$user, $myCompanies] = $this->userWithCompanies(3); + [$other, $otherCompanies] = $this->userWithCompanies(2); + session(['current_company_id' => $myCompanies->first()->id]); + Filament::setTenant($myCompanies->first(), true); + + /* Act */ + $component = Livewire::actingAs($user)->test(SwitchCompany::class); + + /* Assert — my companies visible, other user's companies absent */ + $component->assertSuccessful(); + foreach ($myCompanies as $company) { + $this->assertDatabaseHas('companies', ['id' => $company->id]); + } + foreach ($otherCompanies as $company) { + // company exists in DB but should NOT appear for this user + $this->assertDatabaseHas('companies', ['id' => $company->id]); + } + // Verify via the query that only the user's companies are included + $ids = Company::query() + ->whereHas('users', fn ($q) => $q->where('users.id', $user->id)) + ->pluck('id'); + foreach ($myCompanies as $c) { + $this->assertTrue($ids->contains($c->id)); + } + foreach ($otherCompanies as $c) { + $this->assertFalse($ids->contains($c->id)); + } + } + + #[Test] + #[Group('crud')] + public function it_shows_all_companies_for_a_user_with_many(): void + { + /* Arrange */ + [$user, $companies] = $this->userWithCompanies(10); + session(['current_company_id' => $companies->first()->id]); + Filament::setTenant($companies->first(), true); + + /* Act */ + $component = Livewire::actingAs($user)->test(SwitchCompany::class); + + /* Assert */ + $component->assertSuccessful(); + $count = Company::query() + ->whereHas('users', fn ($q) => $q->where('users.id', $user->id)) + ->count(); + $this->assertEquals(10, $count); + } + + // ───────────────────────────────────────────────────────────────────── + // Security — cannot switch to a company the user doesn't belong to + // ───────────────────────────────────────────────────────────────────── + + #[Test] + #[Group('security')] + public function it_cannot_switch_to_a_company_the_user_does_not_belong_to(): void + { + /* Arrange */ + [$user, $myCompanies] = $this->userWithCompanies(2); + [$other, $foreignCompany] = $this->userWithCompanies(1); + $foreignCompany = $foreignCompany->first(); + session(['current_company_id' => $myCompanies->first()->id]); + Filament::setTenant($myCompanies->first(), true); + + /* Act — foreign company does not appear in the table, so action is never mounted; + * assert via the underlying query that it would be excluded */ + $accessible = Company::query() + ->whereHas('users', fn ($q) => $q->where('users.id', $user->id)) + ->pluck('id'); + + /* Assert */ + $this->assertFalse($accessible->contains($foreignCompany->id)); + $this->assertEquals($myCompanies->first()->id, session('current_company_id')); + } + + // ───────────────────────────────────────────────────────────────────── + // Edge cases + // ───────────────────────────────────────────────────────────────────── + + #[Test] + #[Group('edge-cases')] + public function it_renders_correctly_when_user_has_only_one_company(): void + { + /* Arrange */ + $user = User::factory()->create(); + $company = Company::factory()->create(); + $user->companies()->attach($company->id); + session(['current_company_id' => $company->id]); + Filament::setTenant($company, true); + + /* Act */ + $component = Livewire::actingAs($user)->test(SwitchCompany::class); + + /* Assert — page renders; single company switch action is disabled */ + $component->assertSuccessful(); + $component->assertTableActionDisabled('switch', $company); + } + + #[Test] + #[Group('edge-cases')] + public function it_switches_back_to_original_company(): void + { + /* Arrange */ + [$user, $companies] = $this->userWithCompanies(2); + $companyA = $companies->first(); + $companyB = $companies->last(); + session(['current_company_id' => $companyA->id]); + Filament::setTenant($companyA, true); + + /* Act — switch A → B, then B → A */ + Livewire::actingAs($user) + ->test(SwitchCompany::class) + ->callTableAction('switch', $companyB); + + $this->assertEquals($companyB->id, session('current_company_id')); + session(['current_company_id' => $companyB->id]); + Filament::setTenant($companyB, true); + + Livewire::actingAs($user) + ->test(SwitchCompany::class) + ->callTableAction('switch', $companyA); + + /* Assert — back to A */ + $this->assertEquals($companyA->id, session('current_company_id')); + } +} diff --git a/Modules/Invoices/Tests/Feature/InvoicesTest.php b/Modules/Invoices/Tests/Feature/InvoicesTest.php index cd401fec8..8d50d5708 100644 --- a/Modules/Invoices/Tests/Feature/InvoicesTest.php +++ b/Modules/Invoices/Tests/Feature/InvoicesTest.php @@ -8,6 +8,7 @@ use Illuminate\Support\Str; use Livewire\Livewire; use Modules\Clients\Models\Relation; +use Modules\Core\Enums\NumberingType; use Modules\Core\Models\Numbering; use Modules\Core\Models\TaxRate; use Modules\Core\Tests\AbstractCompanyPanelTestCase; @@ -38,7 +39,7 @@ public function it_lists_invoices(): void /* Arrange */ $user = $this->user; $customer = Relation::factory()->for($this->company)->customer()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::INVOICE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); $productUnit = ProductUnit::factory()->for($this->company)->create(); @@ -87,7 +88,7 @@ public function it_creates_an_invoice_through_a_modal(): void { /* Arrange */ $customer = Relation::factory()->for($this->company)->customer()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::INVOICE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); $productUnit = ProductUnit::factory()->for($this->company)->create(); @@ -141,7 +142,7 @@ public function it_fails_to_create_invoice_through_a_modal_without_required_invo { /* Arrange */ $customer = Relation::factory()->for($this->company)->customer()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::INVOICE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); $productUnit = ProductUnit::factory()->for($this->company)->create(); @@ -186,7 +187,7 @@ public function it_fails_to_create_invoice_through_a_modal_without_required_invo { /* Arrange */ $customer = Relation::factory()->for($this->company)->customer()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::INVOICE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); $productUnit = ProductUnit::factory()->for($this->company)->create(); @@ -229,7 +230,7 @@ public function it_fails_to_create_invoice_through_a_modal_without_required_cust { /* Arrange */ $customer = Relation::factory()->for($this->company)->customer()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::INVOICE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); $productUnit = ProductUnit::factory()->for($this->company)->create(); @@ -274,7 +275,7 @@ public function it_updates_an_invoice_through_a_modal(): void { /* Arrange */ $customer = Relation::factory()->for($this->company)->customer()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::INVOICE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); $productUnit = ProductUnit::factory()->for($this->company)->create(); @@ -325,7 +326,7 @@ public function it_updates_an_invoice_through_a_modal(): void public function it_creates_an_invoice_with_items(): void { $customer = Relation::factory()->for($this->company)->customer()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::INVOICE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); $productUnit = ProductUnit::factory()->for($this->company)->create(); @@ -381,7 +382,7 @@ public function it_fails_to_create_invoice_without_required_invoice_number(): vo /* Arrange */ $user = $this->user; $customer = Relation::factory()->for($this->company)->customer()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::INVOICE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); $productUnit = ProductUnit::factory()->for($this->company)->create(); @@ -425,7 +426,7 @@ public function it_fails_to_create_invoice_without_required_invoice_status(): vo /* Arrange */ $user = $this->user; $customer = Relation::factory()->for($this->company)->customer()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::INVOICE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); $productUnit = ProductUnit::factory()->for($this->company)->create(); @@ -467,7 +468,7 @@ public function it_fails_to_create_invoice_without_required_customer(): void /* Arrange */ $user = $this->user; $customer = Relation::factory()->for($this->company)->customer()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::INVOICE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); $productUnit = ProductUnit::factory()->for($this->company)->create(); @@ -510,7 +511,7 @@ public function it_updates_an_invoice(): void { /* Arrange */ $customer = Relation::factory()->for($this->company)->customer()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::INVOICE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); $productUnit = ProductUnit::factory()->for($this->company)->create(); @@ -586,7 +587,7 @@ public function it_deletes_an_invoice(): void /* Arrange */ $user = $this->user; $customer = Relation::factory()->for($this->company)->customer()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::INVOICE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); $productUnit = ProductUnit::factory()->for($this->company)->create(); diff --git a/Modules/Quotes/Tests/Feature/QuotesTest.php b/Modules/Quotes/Tests/Feature/QuotesTest.php index 2fdfdce56..5b3e5baf2 100644 --- a/Modules/Quotes/Tests/Feature/QuotesTest.php +++ b/Modules/Quotes/Tests/Feature/QuotesTest.php @@ -7,6 +7,7 @@ use Illuminate\Support\Str; use Livewire\Livewire; use Modules\Clients\Models\Relation; +use Modules\Core\Enums\NumberingType; use Modules\Core\Models\Numbering; use Modules\Core\Models\TaxRate; use Modules\Core\Tests\AbstractCompanyPanelTestCase; @@ -65,7 +66,7 @@ public function it_creates_a_quote_through_a_modal(): void { /* Arrange */ $prospect = Relation::factory()->for($this->company)->prospect()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::QUOTE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); @@ -139,7 +140,7 @@ public function it_creates_a_quote_through_a_modal(): void public function it_fails_to_create_a_quote_through_a_modal_without_required_prospect(): void { /* Arrange */ - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::QUOTE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); @@ -295,7 +296,7 @@ public function it_updates_a_quote_through_a_modal(): void { /* Arrange */ $prospect = Relation::factory()->for($this->company)->prospect()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::QUOTE->value])->create(); $quote = Quote::factory() ->for($this->company) @@ -348,7 +349,7 @@ public function it_creates_a_quote(): void { /* Arrange */ $prospect = Relation::factory()->for($this->company)->prospect()->create(); - $documentGroup = Numbering::factory()->for($this->company)->create(); + $documentGroup = Numbering::factory()->for($this->company)->state(['type' => NumberingType::QUOTE->value])->create(); $taxRate = TaxRate::factory()->for($this->company)->create(); $productCategory = ProductCategory::factory()->for($this->company)->create(); diff --git a/app/Filament/Pages/SwitchCompany.php b/app/Filament/Pages/SwitchCompany.php new file mode 100644 index 000000000..ced0a5538 --- /dev/null +++ b/app/Filament/Pages/SwitchCompany.php @@ -0,0 +1,75 @@ +query( + Company::query() + ->whereHas('users', fn ($q) => $q->where('users.id', Auth::id())) + ->orderBy('name') + ) + ->columns([ + TextColumn::make('name') + ->label(trans('ip.company')) + ->searchable() + ->weight(fn (Company $record): string => $record->id === session('current_company_id') ? 'bold' : 'normal'), + TextColumn::make('search_code') + ->label(trans('ip.code')) + ->badge(), + IconColumn::make('active') + ->label(trans('ip.current')) + ->state(fn (Company $record): bool => $record->id === session('current_company_id')) + ->boolean() + ->trueIcon('heroicon-o-check-circle') + ->falseIcon('heroicon-o-minus'), + ]) + ->recordActions([ + Action::make('switch') + ->label(trans('ip.switch')) + ->icon('heroicon-o-arrow-right-circle') + ->color('primary') + ->disabled(fn (Company $record): bool => $record->id === session('current_company_id')) + ->action(function (Company $record): void { + session(['current_company_id' => $record->id]); + $this->redirect( + route('filament.company.pages.dashboard', ['tenant' => Str::lower($record->search_code)]) + ); + }), + ]) + ->paginated(false); + } +} diff --git a/composer.json b/composer.json index b3603f84c..b3c54f2fa 100644 --- a/composer.json +++ b/composer.json @@ -49,12 +49,14 @@ "psr-4": { "App\\": "app/", "Modules\\": "Modules/", - "Database\\Seeders\\": "database/seeders/" + "Database\\Seeders\\": "database/seeders/", + "Fable5\\": "automation/fable5/src/" } }, "autoload-dev": { "psr-4": { - "Tests\\": "tests/" + "Tests\\": "tests/", + "Fable5\\Tests\\": "automation/fable5/tests/" } }, "scripts": { diff --git a/pint_output.log b/pint_output.log new file mode 100644 index 000000000..79f26c47c --- /dev/null +++ b/pint_output.log @@ -0,0 +1,5 @@ + + + No dirty files found. + + diff --git a/resources/lang/en/ip.php b/resources/lang/en/ip.php index e60cf5855..8328aa7de 100644 --- a/resources/lang/en/ip.php +++ b/resources/lang/en/ip.php @@ -99,7 +99,9 @@ 'closed' => 'Closed', 'column' => 'Column', 'company' => 'Company', + 'code' => 'Code', 'confirm' => 'Confirm', + 'current' => 'Current', 'confirm_deletion' => 'Confirm deletion', 'continue' => 'Continue', 'create_recurring' => 'Create Recurring', @@ -398,6 +400,8 @@ 'success' => 'Success', 'summary' => 'Summary', 'sumex' => 'Sumex', + 'switch' => 'Switch', + 'switch_company' => 'Switch Company', 'sumex_information' => 'Sumex Information', 'sumex_settings' => 'Sumex Settings', 'tax' => 'Tax', diff --git a/resources/views/filament/pages/switch-company-modal.blade.php b/resources/views/filament/pages/switch-company-modal.blade.php new file mode 100644 index 000000000..9ae93768b --- /dev/null +++ b/resources/views/filament/pages/switch-company-modal.blade.php @@ -0,0 +1 @@ +@livewire(\App\Filament\Pages\SwitchCompany::class) diff --git a/resources/views/filament/pages/switch-company.blade.php b/resources/views/filament/pages/switch-company.blade.php new file mode 100644 index 000000000..ce096a2d8 --- /dev/null +++ b/resources/views/filament/pages/switch-company.blade.php @@ -0,0 +1,3 @@ + + {{ $this->table }} +