feat: implement product variant CRUD operations and tenant configuration seeding

This commit is contained in:
2026-06-29 11:59:07 -03:00
parent 9b7d728117
commit 0206ee2985
10 changed files with 227 additions and 96 deletions

View File

@@ -2,14 +2,17 @@
namespace App\Domains\Catalog\Services;
use App\Domains\Attachable\Services\AttachmentService;
use App\Domains\Catalog\Models\Attribute;
use App\Domains\Catalog\Models\Product;
use App\Domains\Catalog\Models\ProductVariant;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\DB;
class ProductService
{
public function __construct(protected AttachmentService $attachmentService) {}
/**
* Create a product.
*
@@ -80,9 +83,16 @@ class ProductService
public function createVariant(Product $product, array $data): ProductVariant
{
return DB::transaction(function () use ($product, $data) {
$images = $data['images'] ?? [];
unset($data['images']);
$variant = $product->createVariant($data);
return $variant->load(['product', 'definitions.attribute']);
if (! empty($images)) {
$this->syncImages($variant, $images);
}
return $variant->load(['product', 'definitions.attribute', 'attachments']);
});
}
@@ -94,11 +104,19 @@ class ProductService
public function updateVariant(ProductVariant $variant, array $data): ProductVariant
{
return DB::transaction(function () use ($variant, $data) {
$hasImages = array_key_exists('images', $data);
$images = $data['images'] ?? [];
unset($data['images']);
/** @var Product $product */
$product = $variant->product;
$updatedVariant = $product->updateVariant($variant, $data);
return $updatedVariant->load(['product', 'definitions.attribute']);
if ($hasImages) {
$this->syncImages($updatedVariant, $images);
}
return $updatedVariant->load(['product', 'definitions.attribute', 'attachments']);
});
}
@@ -138,6 +156,29 @@ class ProductService
});
}
/**
* Upload a list of image files/base64 strings and sync them to a variant.
*
* When called on update, the existing attachments are detached first so the
* final set always matches exactly what was sent in the request.
*
* @param array<int, UploadedFile|string> $images
*/
protected function syncImages(ProductVariant $variant, array $images): void
{
// Detach any existing attachments before replacing them
$variant->attachments()->detach();
$attachmentIds = [];
foreach ($images as $image) {
$attachment = $this->attachmentService->store($image, 'variants');
$attachmentIds[] = $attachment->id;
}
$variant->attachments()->sync($attachmentIds);
}
/**
* Delete an attribute.
*/