Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
public function up(): void
{
Schema::table('pim_product_data', function (Blueprint $table) {
$table->foreignId('tax_class_id')
->nullable()
->after('product_status_id')
->constrained('pim_tax_classes')
->nullOnDelete()
->cascadeOnUpdate();
});
}

public function down(): void
{
Schema::table('pim_product_data', function (Blueprint $table) {
$table->dropForeign(['tax_class_id']);
$table->dropColumn('tax_class_id');
});
}
};
56 changes: 55 additions & 1 deletion src/Filament/Resources/ProductResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class ProductResource extends Resource

protected static ?string $recordTitleAttribute = 'name';

public static function form(Schema $form): Schema
public static function schema(Schema $form): Schema
{
return $form
->components([
Expand Down Expand Up @@ -226,6 +226,21 @@ public static function form(Schema $form): Schema
->searchable()
->preload(),

Select::make("tenant_data.{$tenantId}.tax_class_id")
->label('Tax class')
->options(function () use ($tenantId) {
$query = \Eclipse\Catalogue\Models\TaxClass::query();
$tenantFK = config('eclipse-catalogue.tenancy.foreign_key', 'site_id');
if ($tenantFK) {
$query->where($tenantFK, $tenantId);
}

return $query->orderBy('name')->pluck('name', 'id')->toArray();
})
->searchable()
->preload()
->placeholder('Select tax class'),

Select::make("tenant_data.{$tenantId}.groups")
->label('Groups')
->multiple()
Expand Down Expand Up @@ -685,6 +700,18 @@ public static function table(Table $table): Table
return is_array($category->name) ? ($category->name[app()->getLocale()] ?? reset($category->name)) : $category->name;
}),

TextColumn::make('tax_class')
->label('Tax class')
->toggleable(isToggledHiddenByDefault: true)
->getStateUsing(function (Product $record) {
$taxClass = $record->currentTenantData()?->taxClass;
if (! $taxClass) {
return null;
}

return $taxClass->name;
}),

TextColumn::make('type.name')
->label(__('eclipse-catalogue::product.table.columns.type')),

Expand Down Expand Up @@ -792,6 +819,33 @@ public static function table(Table $table): Table
$q->whereIn('product_status_id', (array) $selected);
});
}),
SelectFilter::make('tax_class_id')
->label('Tax class')
->multiple()
->options(function () {
$query = \Eclipse\Catalogue\Models\TaxClass::query();
$tenantFK = config('eclipse-catalogue.tenancy.foreign_key');
$currentTenant = \Filament\Facades\Filament::getTenant();
if ($tenantFK && $currentTenant) {
$query->where($tenantFK, $currentTenant->id);
}

return $query->orderBy('name')->pluck('name', 'id')->toArray();
})
->query(function (Builder $query, array $data) {
$selected = $data['values'] ?? ($data['value'] ?? null);
if (empty($selected)) {
return;
}
$tenantFK = config('eclipse-catalogue.tenancy.foreign_key');
$currentTenant = \Filament\Facades\Filament::getTenant();
$query->whereHas('productData', function ($q) use ($selected, $tenantFK, $currentTenant) {
if ($tenantFK && $currentTenant) {
$q->where($tenantFK, $currentTenant->id);
}
$q->whereIn('tax_class_id', (array) $selected);
});
}),
SelectFilter::make('category_id')
->label('Categories')
->multiple()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ protected function getFormMutuallyExclusiveFlagSets(): array
return [];
}

public function form(Schema $schema): Schema
public function schema(Schema $schema): Schema
{
return $schema;
}
Expand Down
4 changes: 3 additions & 1 deletion src/Filament/Resources/ProductResource/Pages/EditProduct.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ protected function mutateFormDataBeforeFill(array $data): array
$data['sorting_label'] = $recordData->sorting_label;
$data['category_id'] = $recordData->category_id ?? null;
$data['product_status_id'] = $recordData->product_status_id ?? null;
$data['tax_class_id'] = $recordData->tax_class_id ?? null;
}

$data['groups'] = $this->record->groups()->pluck('pim_group.id')->toArray();
Expand All @@ -117,6 +118,7 @@ protected function mutateFormDataBeforeFill(array $data): array
'sorting_label' => $tenantRecord->sorting_label,
'category_id' => $tenantRecord->category_id ?? null,
'product_status_id' => $tenantRecord->product_status_id ?? null,
'tax_class_id' => $tenantRecord->tax_class_id ?? null,
'groups' => $this->record->groups()
->where('pim_group.'.config('eclipse-catalogue.tenancy.foreign_key', 'site_id'), $tenantId)
->pluck('pim_group.id')
Expand Down Expand Up @@ -217,7 +219,7 @@ protected function getFormMutuallyExclusiveFlagSets(): array
return [];
}

public function form(Schema $schema): Schema
public function schema(Schema $schema): Schema
{
return $schema;
}
Expand Down
43 changes: 22 additions & 21 deletions src/Filament/Resources/TaxClassResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
use Filament\Resources\Resource;
use Filament\Schemas\Components\Grid;
use Filament\Schemas\Schema;
use Filament\Tables\Columns\IconColumn;
use Filament\Tables\Columns\TextColumn;
Expand All @@ -36,10 +37,6 @@ class TaxClassResource extends Resource

protected static ?string $recordTitleAttribute = 'name';

protected static bool $isScopedToTenant = true;

protected static ?string $tenantOwnershipRelationshipName = 'tenant';

public static function getModelLabel(): string
{
return __('eclipse-catalogue::tax-class.singular');
Expand Down Expand Up @@ -71,14 +68,9 @@ public static function form(Schema $schema): Schema
}

return $rule;
}
},
),

Textarea::make('description')
->label(__('eclipse-catalogue::tax-class.fields.description'))
->rows(3)
->maxLength(65535),

TextInput::make('rate')
->label(__('eclipse-catalogue::tax-class.fields.rate'))
->required()
Expand All @@ -88,17 +80,26 @@ public static function form(Schema $schema): Schema
->step(0.01)
->suffix('%'),

Toggle::make('is_default')
->label(__('eclipse-catalogue::tax-class.fields.is_default'))
->helperText(__('eclipse-catalogue::tax-class.messages.default_class_help')),

Placeholder::make('created_at')
->label('Created Date')
->content(fn (?TaxClass $record): string => $record?->created_at?->diffForHumans() ?? '-'),

Placeholder::make('updated_at')
->label('Last Modified Date')
->content(fn (?TaxClass $record): string => $record?->updated_at?->diffForHumans() ?? '-'),
Textarea::make('description')
->label(__('eclipse-catalogue::tax-class.fields.description'))
->rows(3)
->maxLength(65535)
->columnSpanFull(),

Grid::make(3)
->schema([
Toggle::make('is_default')
->label(__('eclipse-catalogue::tax-class.fields.is_default'))
->helperText(__('eclipse-catalogue::tax-class.messages.default_class_help')),

Placeholder::make('created_at')
->label('Created Date')
->content(fn (?TaxClass $record): string => $record?->created_at?->diffForHumans() ?? '-'),

Placeholder::make('updated_at')
->label('Last Modified Date')
->content(fn (?TaxClass $record): string => $record?->updated_at?->diffForHumans() ?? '-'),
]),
]);
}

Expand Down
6 changes: 6 additions & 0 deletions src/Models/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ class Product extends Model implements HasMedia
'available_from_date',
'category_id',
'product_status_id',
'tax_class_id',
];

public function status(): ?ProductStatus
Expand All @@ -99,6 +100,11 @@ public function category(): ?Category
return $this->currentTenantData()?->category;
}

public function taxClass(): ?\Eclipse\Catalogue\Models\TaxClass
{
return $this->currentTenantData()?->taxClass;
}

public function type(): BelongsTo
{
return $this->belongsTo(ProductType::class, 'product_type_id');
Expand Down
7 changes: 7 additions & 0 deletions src/Models/ProductData.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class ProductData extends Model
'product_id',
'category_id',
'product_status_id',
'tax_class_id',
'sorting_label',
'is_active',
'available_from_date',
Expand Down Expand Up @@ -56,6 +57,12 @@ public function status(): BelongsTo
return $this->belongsTo(ProductStatus::class, 'product_status_id');
}

/** @return BelongsTo<\Eclipse\Catalogue\Models\TaxClass, self> */
public function taxClass(): BelongsTo
{
return $this->belongsTo(\Eclipse\Catalogue\Models\TaxClass::class, 'tax_class_id');
}

/** @return BelongsTo<\Eclipse\Core\Models\Site, self> */
public function site(): BelongsTo
{
Expand Down
8 changes: 4 additions & 4 deletions src/Models/TaxClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ protected static function boot()
{
parent::boot();

static::creating(function (self $category): void {
static::creating(function (self $model): void {
// Set tenant foreign key, if configured
$tenantModel = config('eclipse-catalogue.tenancy.model');
$tenantFK = config('eclipse-catalogue.tenancy.foreign_key');
Expand All @@ -55,11 +55,11 @@ protected static function boot()
throw new RuntimeException('Tenancy is enabled, but no tenant is set');
}

$category->{$tenantFK} = $tenant->id;
$model->{$tenantFK} = $tenant->id;
}
});

static::saving(function ($model) {
static::saving(function (self $model) {
// If this class is being set as default, unset all other defaults within the same tenant
if ($model->is_default) {
$query = static::where('is_default', true)
Expand All @@ -76,7 +76,7 @@ protected static function boot()
}
});

static::deleting(function ($model) {
static::deleting(function (self $model) {
// Prevent deletion of default class
if ($model->is_default) {
throw ValidationException::withMessages([
Expand Down
102 changes: 102 additions & 0 deletions tests/Feature/ProductTaxClassTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

use Eclipse\Catalogue\Models\Product;
use Eclipse\Catalogue\Models\ProductData;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

beforeEach(function (): void {
$this->setUpSuperAdminAndTenant();
});

it('can set and unset tax class per tenant', function (): void {
$tenantFK = config('eclipse-catalogue.tenancy.foreign_key');
$tenantModel = config('eclipse-catalogue.tenancy.model');
$currentTenantId = $tenantModel::first()->id;

$taxClass = \Eclipse\Catalogue\Models\TaxClass::create([
'name' => 'Standard',
'rate' => 22.00,
'is_default' => false,
$tenantFK => $currentTenantId,
]);

$product = Product::factory()->create(['name' => 'Test Product']);

// Set
ProductData::factory()->create([
'product_id' => $product->id,
$tenantFK => $currentTenantId,
'tax_class_id' => $taxClass->id,
'is_active' => true,
]);

expect($product->fresh()->currentTenantData()->tax_class_id)->toBe($taxClass->id);

// Unset
$product->currentTenantData()->update(['tax_class_id' => null]);
expect($product->fresh()->currentTenantData()->tax_class_id)->toBeNull();
});

it('table column is hidden by default and shows correct value when enabled', function (): void {
$tenantFK = config('eclipse-catalogue.tenancy.foreign_key');
$tenantModel = config('eclipse-catalogue.tenancy.model');
$currentTenantId = $tenantModel::first()->id;

$taxClass = \Eclipse\Catalogue\Models\TaxClass::create([
'name' => 'Reduced',
'rate' => 9.50,
'is_default' => false,
$tenantFK => $currentTenantId,
]);

$product = Product::factory()->create(['name' => 'With Tax']);
ProductData::factory()->create([
'product_id' => $product->id,
$tenantFK => $currentTenantId,
'tax_class_id' => $taxClass->id,
'is_active' => true,
]);

expect($product->fresh()->taxClass()->name)->toBe('Reduced');
});

it('filter returns correct products within tenant', function (): void {
$tenantFK = config('eclipse-catalogue.tenancy.foreign_key');
$tenantModel = config('eclipse-catalogue.tenancy.model');
$currentTenantId = $tenantModel::first()->id;

$standard = \Eclipse\Catalogue\Models\TaxClass::create([
'name' => 'Standard',
'rate' => 22.00,
'is_default' => false,
$tenantFK => $currentTenantId,
]);
$reduced = \Eclipse\Catalogue\Models\TaxClass::create([
'name' => 'Reduced',
'rate' => 9.50,
'is_default' => false,
$tenantFK => $currentTenantId,
]);

$p1 = Product::factory()->create(['name' => 'P1']);
$p2 = Product::factory()->create(['name' => 'P2']);
$p3 = Product::factory()->create(['name' => 'P3']);

ProductData::factory()->create(['product_id' => $p1->id, $tenantFK => $currentTenantId, 'tax_class_id' => $standard->id, 'is_active' => true]);
ProductData::factory()->create(['product_id' => $p2->id, $tenantFK => $currentTenantId, 'tax_class_id' => $reduced->id, 'is_active' => true]);
ProductData::factory()->create(['product_id' => $p3->id, $tenantFK => $currentTenantId, 'tax_class_id' => null, 'is_active' => true]);

$productsWithStandardTax = Product::query()
->whereHas('productData', function ($q) use ($standard, $tenantFK, $currentTenantId) {
$q->where('tax_class_id', $standard->id);
if ($tenantFK) {
$q->where($tenantFK, $currentTenantId);
}
})
->get();

expect($productsWithStandardTax)->toHaveCount(1);
expect($productsWithStandardTax->first()->name)->toBe('P1');
});
Loading