159 lines
5.7 KiB
PHP
159 lines
5.7 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Admin\Master\RawMaterial;
|
|
|
|
use App\Enums\Role;
|
|
use App\Models\RawMaterial;
|
|
use App\Models\RawMaterialPrice;
|
|
use App\Services\Concerns\LogsFormHistory;
|
|
use App\Services\Concerns\RegistersMedia;
|
|
use App\Services\NotificationService;
|
|
use App\Services\S3PresignedService;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
class RawMaterialVariantService
|
|
{
|
|
use LogsFormHistory, RegistersMedia;
|
|
|
|
public function __construct(
|
|
private S3PresignedService $s3Service,
|
|
) {}
|
|
|
|
public function getForCutting(): array
|
|
{
|
|
return RawMaterial::query()
|
|
->select(['id', 'name', 'unit', 'is_active'])
|
|
->with([
|
|
'rawMaterialPrices:id,raw_material_id,variant,price,stock',
|
|
'rawMaterialPrices.media',
|
|
])
|
|
->active()
|
|
->orderBy('name')
|
|
->get()
|
|
->each(function (RawMaterial $rawMaterial) {
|
|
$rawMaterial->rawMaterialPrices->each(function (RawMaterialPrice $price) {
|
|
$media = $price->getFirstMedia('images');
|
|
$price->photo_url = $media
|
|
? $this->s3Service->getTemporaryUrl($media->getPath())
|
|
: null;
|
|
$price->photo_conversion_url = $media
|
|
? ($media->getGeneratedConversions()->contains('thumb')
|
|
? $this->s3Service->getTemporaryUrl($media->getPath('thumb'))
|
|
: $this->s3Service->getTemporaryUrl($media->getPath()))
|
|
: null;
|
|
});
|
|
})
|
|
->toArray();
|
|
}
|
|
|
|
public function getForEdit(RawMaterialPrice $variant): array
|
|
{
|
|
$variant->load('media');
|
|
|
|
$media = $variant->getMedia('images');
|
|
$photoKeys = $media->map(fn ($m) => $m->getCustomProperty('s3_key') ?? $m->file_name)->toArray();
|
|
$photoUrls = $media->map(fn ($m) => $this->s3Service->getTemporaryUrl($m->getPath()))->toArray();
|
|
|
|
return [
|
|
'id' => $variant->id,
|
|
'raw_material_id' => $variant->raw_material_id,
|
|
'variant' => $variant->variant,
|
|
'price' => $variant->price,
|
|
'stock' => $variant->stock,
|
|
'photo_key' => $photoKeys[0] ?? null,
|
|
'photo_url' => $photoUrls[0] ?? null,
|
|
];
|
|
}
|
|
|
|
public function update(RawMaterialPrice $variant, array $data): RawMaterialPrice
|
|
{
|
|
$rawMaterial = $variant->rawMaterial;
|
|
$oldValues = $this->getRawMaterialLogValues($rawMaterial);
|
|
|
|
DB::transaction(function () use ($variant, $data) {
|
|
$variant->update([
|
|
'variant' => $data['variant'],
|
|
'price' => $data['price'],
|
|
'stock' => $data['stock'],
|
|
]);
|
|
|
|
if (array_key_exists('photo_key', $data)) {
|
|
$existingKey = $variant->getMedia('images')->first()?->getCustomProperty('s3_key');
|
|
$newKey = $data['photo_key'];
|
|
|
|
if ($existingKey !== $newKey) {
|
|
$variant->clearMediaCollection('images');
|
|
if ($newKey) {
|
|
$this->registerPhoto($variant, $newKey);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
NotificationService::notify(
|
|
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_BAHAN_BAKU],
|
|
title: 'Varian Diperbarui',
|
|
body: "Varian \"{$variant->variant}\" berhasil diperbarui".' oleh '.auth()->user()->full_name.'.',
|
|
url: route('admin.master.raw-materials.index', ['highlight' => $variant->raw_material_id]),
|
|
);
|
|
|
|
$rawMaterial->refresh();
|
|
$this->logUpdated($rawMaterial, 'Bahan Baku', $oldValues, $this->getRawMaterialLogValues($rawMaterial));
|
|
|
|
return $variant->fresh();
|
|
}
|
|
|
|
public function destroy(RawMaterial $rawMaterial, RawMaterialPrice $variant): bool
|
|
{
|
|
$oldValues = $this->getRawMaterialLogValues($rawMaterial);
|
|
|
|
if ($variant->stock > 0) {
|
|
throw ValidationException::withMessages([
|
|
'variant' => 'Varian tidak dapat dihapus karena masih memiliki stok.',
|
|
]);
|
|
}
|
|
|
|
$activeCuttingUsage = $variant->cuttingMaterials()
|
|
->whereHas('cutting', fn ($q) => $q->inProgress())
|
|
->exists();
|
|
|
|
if ($activeCuttingUsage) {
|
|
throw ValidationException::withMessages([
|
|
'variant' => 'Varian tidak dapat dihapus karena masih digunakan di cutting yang sedang diproses.',
|
|
]);
|
|
}
|
|
|
|
$result = DB::transaction(function () use ($variant) {
|
|
return $variant->delete();
|
|
});
|
|
|
|
NotificationService::notify(
|
|
roles: [Role::OWNER, Role::DEVELOPER, Role::ADMIN_BAHAN_BAKU],
|
|
title: 'Varian Dihapus',
|
|
body: "Varian \"{$variant->variant}\" dari bahan baku \"{$rawMaterial->name}\" berhasil dihapus".' oleh '.auth()->user()->full_name.'.',
|
|
url: route('admin.master.raw-materials.index'),
|
|
);
|
|
|
|
$this->logDeleted($rawMaterial, 'Bahan Baku', $oldValues);
|
|
|
|
return $result;
|
|
}
|
|
|
|
private function getRawMaterialLogValues(RawMaterial $rawMaterial): array
|
|
{
|
|
$rawMaterial->load('rawMaterialPrices');
|
|
|
|
return [
|
|
'Nama Bahan Baku' => $rawMaterial->name,
|
|
'Satuan' => $rawMaterial->unit?->label(),
|
|
'Status' => $this->formatBoolean($rawMaterial->is_active),
|
|
'Varian' => $rawMaterial->rawMaterialPrices->map(fn ($price) => [
|
|
'Nama Varian' => $price->variant,
|
|
'Harga' => $this->formatCurrency($price->price),
|
|
'Stok' => number_format((float) $price->stock, 2, ',', '.'),
|
|
])->toArray(),
|
|
];
|
|
}
|
|
}
|