store/app/Models/Cutting.php
Yoga Pangestu 3d00511626
Some checks failed
linter / quality (push) Waiting to run
tests / ci (8.3) (push) Has been cancelled
tests / ci (8.4) (push) Has been cancelled
tests / ci (8.5) (push) Has been cancelled
feat: enhance PresignedUploadController to support local uploads and improve S3 integration; add localUpload method for handling uploads when S3 is not the default disk
2026-07-02 22:53:28 +07:00

131 lines
3.3 KiB
PHP

<?php
namespace App\Models;
use App\Enums\CuttingStatus;
use App\Models\Concerns\HasModuleMedia;
use App\Models\Concerns\HasRejection;
use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Validation\ValidationException;
use Spatie\MediaLibrary\HasMedia;
#[Guarded(['id'])]
#[Appends([
'created_at_formatted',
'status_label',
])]
class Cutting extends Model implements HasMedia
{
// 1. Use Trait
use HasFactory, HasModuleMedia, HasRejection, InteractsWithActivityLog, SoftDeletes;
// 2. Casting
protected function casts(): array
{
return [
'cost_per_unit' => 'integer',
'other_cost' => 'integer',
'sewing_cost' => 'integer',
'status' => CuttingStatus::class,
'total_material_cost' => 'integer',
];
}
// 3. Scope (grouped by column, then alphabetical)
// Column Group: status
#[Scope]
protected function completed(Builder $query): void
{
$query->where('status', CuttingStatus::COMPLETED);
}
#[Scope]
protected function inProgress(Builder $query): void
{
$query->where('status', CuttingStatus::IN_PROGRESS);
}
#[Scope]
protected function pendingVerification(Builder $query): void
{
$query->where('status', CuttingStatus::PENDING_VERIFICATION);
}
#[Scope]
protected function verified(Builder $query): void
{
$query->where('status', CuttingStatus::VERIFIED);
}
// 4. Attribute
public function createdAtFormatted(): Attribute
{
return Attribute::make(
get: fn () => $this->created_at?->translatedFormat('l, d F Y H:i'),
);
}
public function statusLabel(): Attribute
{
return Attribute::make(
get: fn () => $this->status->label(),
);
}
// 5. Other Methods
public static function mediaModuleName(): string
{
return 'cutting';
}
public function registerMediaCollections(): void
{
$this->addMediaCollection('images');
}
public function ensureEditable(): void
{
if (! $this->status->isEditable()) {
throw ValidationException::withMessages([
'status' => 'Proses cutting tidak dapat diubah.',
]);
}
}
// 6. Relation
public function createdBy(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by_id');
}
public function materials(): HasMany
{
return $this->hasMany(CuttingMaterial::class);
}
public function resultPrices(): HasMany
{
return $this->hasMany(CuttingResultPrice::class);
}
public function results(): HasMany
{
return $this->hasMany(CuttingResult::class);
}
public function submittedBy(): BelongsTo
{
return $this->belongsTo(User::class, 'submitted_by_id');
}
}