20-02-2026
This commit is contained in:
parent
854ce02bf6
commit
4d6b4930b2
128 changed files with 18247 additions and 2093 deletions
246
app/Models/Product.php
Normal file
246
app/Models/Product.php
Normal file
|
|
@ -0,0 +1,246 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\PriceType;
|
||||
use App\Enums\ProductStatus;
|
||||
use App\Enums\ProductType;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
|
||||
class Product extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
protected $fillable = [
|
||||
'partner_id',
|
||||
'partner_product_number',
|
||||
'b2in_article_number',
|
||||
'brand_id',
|
||||
'collection_id',
|
||||
'hub_id',
|
||||
'name',
|
||||
'slug',
|
||||
'product_type',
|
||||
'status',
|
||||
'price_type',
|
||||
'price_display_text',
|
||||
'description_short',
|
||||
'description_long',
|
||||
'care_instructions',
|
||||
'width_cm',
|
||||
'height_cm',
|
||||
'depth_cm',
|
||||
'dimensions_specific',
|
||||
'assembly_status',
|
||||
'meta_title',
|
||||
'meta_description',
|
||||
'is_curated',
|
||||
'curated_at',
|
||||
'curated_by',
|
||||
'curation_notes',
|
||||
'is_available',
|
||||
'country_of_origin',
|
||||
'main_material',
|
||||
'surface_material',
|
||||
'cover_material',
|
||||
'color_finish',
|
||||
'certificates',
|
||||
'assembly_time_min',
|
||||
'load_capacity_kg',
|
||||
'delivery_type',
|
||||
'assembly_service',
|
||||
'service_radius_km',
|
||||
'warranty_months',
|
||||
'production_time_days',
|
||||
'productIsAvailable',
|
||||
'visible_from',
|
||||
'visible_until',
|
||||
'co2_footprint_kg',
|
||||
'recycling_percentage',
|
||||
'is_regional_production',
|
||||
'storage_volume_liters',
|
||||
'assembly_effort_score',
|
||||
'design_score',
|
||||
];
|
||||
|
||||
/**
|
||||
* @return array<string, string>
|
||||
*/
|
||||
protected function casts(): array
|
||||
{
|
||||
return [
|
||||
'product_type' => ProductType::class,
|
||||
'status' => ProductStatus::class,
|
||||
'price_type' => PriceType::class,
|
||||
'dimensions_specific' => 'array',
|
||||
'is_curated' => 'boolean',
|
||||
'curated_at' => 'datetime',
|
||||
'is_available' => 'boolean',
|
||||
'productIsAvailable' => 'boolean',
|
||||
'certificates' => 'array',
|
||||
'assembly_service' => 'boolean',
|
||||
'is_regional_production' => 'boolean',
|
||||
'visible_from' => 'date',
|
||||
'visible_until' => 'date',
|
||||
'co2_footprint_kg' => 'decimal:2',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Produkt gehört zu einem Partner (Händler oder Hersteller).
|
||||
*/
|
||||
public function partner(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Partner::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produkt gehört zu einer Marke.
|
||||
*/
|
||||
public function brand(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Brand::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produkt gehört zu einer Kollektion.
|
||||
*/
|
||||
public function collection(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Collection::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produkt gehört zu einem Hub (regionale Zuordnung).
|
||||
*/
|
||||
public function hub(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Hub::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* User, der das Produkt kuratiert/freigegeben hat.
|
||||
*/
|
||||
public function curator(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(User::class, 'curated_by');
|
||||
}
|
||||
|
||||
/**
|
||||
* Produkt kann mehreren Kategorien zugeordnet sein.
|
||||
*/
|
||||
public function categories(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Category::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produkt kann mehrere Tags haben.
|
||||
*/
|
||||
public function tags(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(Tag::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produkt hat mehrere Varianten (Farben, Größen, etc.).
|
||||
*/
|
||||
public function variants(): HasMany
|
||||
{
|
||||
return $this->hasMany(ProductVariant::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Polymorphe Beziehung zu Media (Bilder, Videos, PDFs).
|
||||
*/
|
||||
public function media(): MorphMany
|
||||
{
|
||||
return $this->morphMany(Media::class, 'model');
|
||||
}
|
||||
|
||||
/**
|
||||
* Holzherkunft-Einträge für EUDR-Compliance.
|
||||
*/
|
||||
public function woodOrigins(): HasMany
|
||||
{
|
||||
return $this->hasMany(ProductWoodOrigin::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Änderungshistorie.
|
||||
*/
|
||||
public function activities(): HasMany
|
||||
{
|
||||
return $this->hasMany(ProductActivity::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verwandte Produkte.
|
||||
*/
|
||||
public function relatedProducts(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(self::class, 'related_products', 'product_id', 'related_product_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope: Nur aktive Produkte.
|
||||
*/
|
||||
public function scopeActive(Builder $query): void
|
||||
{
|
||||
$query->where('status', ProductStatus::Active);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope: Nur kuratierte/freigegebene Produkte.
|
||||
*/
|
||||
public function scopeCurated(Builder $query): void
|
||||
{
|
||||
$query->where('is_curated', true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope: Nur Produkte, die auf Freigabe warten.
|
||||
*/
|
||||
public function scopePending(Builder $query): void
|
||||
{
|
||||
$query->where('status', ProductStatus::Pending);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope: Nur Local Stock Produkte (Säule A).
|
||||
*/
|
||||
public function scopeLocalStock(Builder $query): void
|
||||
{
|
||||
$query->where('product_type', ProductType::LocalStock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope: Nur Smart Order Produkte (Säule B).
|
||||
*/
|
||||
public function scopeSmartOrder(Builder $query): void
|
||||
{
|
||||
$query->where('product_type', ProductType::SmartOrder);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope: Produkte in einem bestimmten Hub.
|
||||
*/
|
||||
public function scopeInHub(Builder $query, int $hubId): void
|
||||
{
|
||||
$query->where('hub_id', $hubId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope: Verfügbare Produkte (aktiv, kuratiert, verfügbar).
|
||||
*/
|
||||
public function scopeAvailable(Builder $query): void
|
||||
{
|
||||
$query->active()->curated()->where('is_available', true);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue