Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
16 changes: 16 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,22 @@ DB_CONNECTION=sqlite
DB_DATABASE=:memory:
```

### AAA phase comment style

Phase labels (`Arrange`, `Act`, `Assert`) inside test methods **must** use block comments. Line comments (`//`) are **prohibited** for phase labels.

```php
/* Arrange */
...
/* Act */
...
/* Assert */

/* Act & Assert */ ← combined phase label, same rule
```

**Never** write `// Arrange`, `// Act`, or `// Assert`.

---

## Key model notes
Expand Down
1 change: 1 addition & 0 deletions Modules/Core/Database/Seeders/RolesSeeder.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
6 changes: 3 additions & 3 deletions Modules/Core/Support/AbstractCalculator.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ public function updateAndSave($document, string $itemsRelation = 'items', array
*/
protected function calculateItemSubtotal($item): float
{
$quantity = (float) ($item['quantity'] ?? $item->quantity ?? 0);
$price = (float) ($item['price'] ?? $item->price ?? 0);
$quantity = (float) (is_array($item) ? ($item['quantity'] ?? 0) : ($item->quantity ?? 0));
$price = (float) (is_array($item) ? ($item['price'] ?? 0) : ($item->price ?? 0));

return $quantity * $price;
}
Expand All @@ -115,7 +115,7 @@ protected function calculateItemSubtotal($item): float
*/
protected function calculateItemTaxes($item, float $subtotal): array
{
$discount = (float) ($item['discount'] ?? $item->discount ?? 0);
$discount = (float) (is_array($item) ? ($item['discount'] ?? 0) : ($item->discount ?? 0));
$discountedSubtotal = max($subtotal - $discount, 0);

// Get tax rates from relationships if available, otherwise use 0
Expand Down
11 changes: 11 additions & 0 deletions Modules/Core/Tests/AbstractAdminPanelTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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();
}

Expand Down
11 changes: 11 additions & 0 deletions Modules/Core/Tests/AbstractCompanyPanelTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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();
}

Expand Down
25 changes: 13 additions & 12 deletions Modules/Invoices/Tests/Feature/InvoicesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
Loading
Loading