feat: implement product and attachment management service with supporting migrations and API controllers

This commit is contained in:
2026-06-29 12:13:21 -03:00
parent cd420e02d8
commit 49771ebb13
8 changed files with 128 additions and 9 deletions

View File

@@ -22,7 +22,8 @@ class ProductService
{
return DB::transaction(function () use ($tenant, $data) {
$attributeIds = $data['attribute_ids'] ?? [];
unset($data['attribute_ids']);
$images = $data['images'] ?? [];
unset($data['attribute_ids'], $data['images']);
/** @var Product $product */
$product = Product::query()->create([
@@ -32,7 +33,11 @@ class ProductService
$product->attributes()->sync($attributeIds);
return $product->load('attributes');
if (! empty($images)) {
$this->syncProductImages($product, $images);
}
return $product->load(['attributes', 'attachments']);
});
}
@@ -46,7 +51,9 @@ class ProductService
return DB::transaction(function () use ($product, $data) {
$hasAttributeIds = array_key_exists('attribute_ids', $data);
$attributeIds = $data['attribute_ids'] ?? [];
unset($data['attribute_ids']);
$hasImages = array_key_exists('images', $data);
$images = $data['images'] ?? [];
unset($data['attribute_ids'], $data['images']);
// Ensure tenant_codigo cannot be updated/changed
unset($data['tenant_codigo']);
@@ -57,7 +64,11 @@ class ProductService
$product->attributes()->sync($attributeIds);
}
return $product->load('attributes');
if ($hasImages) {
$this->syncProductImages($product, $images);
}
return $product->load(['attributes', 'attachments']);
});
}
@@ -70,6 +81,14 @@ class ProductService
foreach ($product->variants as $variant) {
$product->deleteVariant($variant);
}
// Delete product-level attachments from S3 and database
$existing = $product->attachments()->get();
$product->attachments()->detach();
foreach ($existing as $attachment) {
$this->attachmentService->delete($attachment);
}
$product->attributes()->detach();
$product->delete();
});
@@ -183,6 +202,32 @@ class ProductService
$variant->attachments()->sync($attachmentIds);
}
/**
* Upload a list of image files/base64 strings and sync them to a product.
*
* Same logic as syncImages but for products without variants.
*
* @param array<int, UploadedFile|string> $images
*/
protected function syncProductImages(Product $product, array $images): void
{
// Detach pivot record and delete attachment from S3 and database
$existing = $product->attachments()->get();
$product->attachments()->detach();
foreach ($existing as $attachment) {
$this->attachmentService->delete($attachment);
}
$attachmentIds = [];
foreach ($images as $image) {
$attachment = $this->attachmentService->store($image, 'products');
$attachmentIds[] = $attachment->id;
}
$product->attachments()->sync($attachmentIds);
}
/**
* Delete an attribute.
*/