load('productPrices'); $media = $variant->getMedia('photos')->first(); return [ 'id' => $variant->id, 'product_id' => $variant->product_id, 'name' => $variant->name, 'stock' => $variant->stock, 'reject_stock' => $variant->reject_stock, 'retail_stock' => $variant->retail_stock, 'photo_key' => $media?->file_name, 'photo_url' => $media ? $this->s3Service->getTemporaryUrl($media->file_name) : null, 'prices' => $variant->productPrices->map(fn ($p) => [ 'type' => $p->type->value, 'price' => $p->price, ]), ]; } public function update(ProductVariant $variant, array $data): ProductVariant { DB::transaction(function () use ($variant, $data) { $variant->update([ 'name' => $data['name'], 'stock' => $data['stock'], 'reject_stock' => $data['reject_stock'], 'retail_stock' => $data['retail_stock'], ]); $variant->productPrices()->delete(); foreach ($data['prices'] as $priceData) { ProductPrice::create([ 'variant_id' => $variant->id, 'type' => $priceData['type'], 'price' => $priceData['price'], ]); } if (! empty($data['photo_key'])) { $variant->clearMediaCollection('photos'); $this->registerPhotos($variant, [$data['photo_key']]); } }); NotificationService::notify( roles: ['Owner', 'Developer', 'Direktur', 'Admin Toko'], title: 'Varian Diperbarui', body: "Varian \"{$variant->name}\" berhasil diperbarui".' oleh '.auth()->user()->full_name.'.', url: route('admin.master.products.index'), ); return $variant->fresh(); } public function delete(Product $product, ProductVariant $variant): bool { $result = DB::transaction(function () use ($variant) { $variant->productPrices()->delete(); $variant->clearMediaCollection('photos'); return $variant->delete(); }); NotificationService::notify( roles: ['Owner', 'Developer', 'Direktur', 'Admin Toko'], title: 'Varian Dihapus', body: "Varian \"{$variant->name}\" dari produk \"{$product->name}\" berhasil dihapus".' oleh '.auth()->user()->full_name.'.', url: route('admin.master.products.index'), ); return $result; } public function registerPhotos(ProductVariant $variant, array $photoKeys): void { foreach ($photoKeys as $order => $s3Key) { $fileName = pathinfo($s3Key, PATHINFO_BASENAME); $name = pathinfo($s3Key, PATHINFO_FILENAME); Media::create([ 'model_type' => ProductVariant::class, 'model_id' => $variant->id, 'uuid' => Str::uuid(), 'collection_name' => 'photos', 'name' => $name, 'file_name' => $s3Key, 'mime_type' => 'image/jpeg', 'disk' => 's3', 'conversions_disk' => 's3', 'size' => 0, 'manipulations' => [], 'custom_properties' => [], 'generated_conversions' => [], 'responsive_images' => [], 'order_column' => $order + 1, ]); } } public function getTemporaryUrl(ProductVariant $variant): ?string { $media = $variant->getMedia('photos')->first(); return $media ? $this->s3Service->getTemporaryUrl($media->file_name) : null; } }