feat: add getNames method to ProductService for retrieving product names

This commit is contained in:
Yoga Pangestu 2026-08-09 16:31:03 +07:00
parent 0cce4ee73d
commit 485ae8e5ce

View File

@ -11,6 +11,7 @@
use App\Services\S3PresignedService; use App\Services\S3PresignedService;
use App\Services\StockMutationService; use App\Services\StockMutationService;
use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException; use Illuminate\Validation\ValidationException;
@ -24,6 +25,12 @@ public function __construct(
private StockMutationService $stockMutationService, private StockMutationService $stockMutationService,
) {} ) {}
public function getNames(): Collection
{
return Product::select(['id', 'name'])
->get();
}
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
{ {
$paginator = Product::query() $paginator = Product::query()
@ -33,10 +40,10 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
'productVariants:id,product_id,name,stock,reject_stock,retail_stock', 'productVariants:id,product_id,name,stock,reject_stock,retail_stock',
'productVariants.productPrices:id,variant_id,type,price', 'productVariants.productPrices:id,variant_id,type,price',
]) ])
->when($search, fn ($q) => $q->where('name', 'like', "%{$search}%")) ->when($search, fn($q) => $q->where('name', 'like', "%{$search}%"))
->when($filters['name'] ?? null, fn ($q, $name) => $q->where('name', 'like', "%{$name}%")) ->when($filters['name'] ?? null, fn($q, $name) => $q->where('name', 'like', "%{$name}%"))
->when($filters['status'] ?? null, fn ($q, $status) => $q->where('status', $status)) ->when($filters['status'] ?? null, fn($q, $status) => $q->where('status', $status))
->when($filters['category'] ?? null, fn ($q, $categoryId) => $q->whereHas('categories', function ($cq) use ($categoryId) { ->when($filters['category'] ?? null, fn($q, $categoryId) => $q->whereHas('categories', function ($cq) use ($categoryId) {
$cq->where('categories.id', $categoryId); $cq->where('categories.id', $categoryId);
})) }))
->when(($filters['stock'] ?? null) === 'empty', function ($q) { ->when(($filters['stock'] ?? null) === 'empty', function ($q) {
@ -51,7 +58,7 @@ public function paginated(int $perPage = 25, string $search = '', string $sort =
$paginator->getCollection()->each(function ($product) { $paginator->getCollection()->each(function ($product) {
$product->productVariants->each(function ($variant) { $product->productVariants->each(function ($variant) {
$media = $variant->getMedia('photos'); $media = $variant->getMedia('photos');
$variant->photo_urls = $media->map(fn ($m) => $this->s3Service->getTemporaryUrl($m->file_name))->toArray(); $variant->photo_urls = $media->map(fn($m) => $this->s3Service->getTemporaryUrl($m->file_name))->toArray();
}); });
}); });
@ -77,7 +84,7 @@ public function store(array $data): Product
// Bulk insert variants // Bulk insert variants
$now = now(); $now = now();
$variantRows = collect($data['variants'])->map(fn ($v) => [ $variantRows = collect($data['variants'])->map(fn($v) => [
'product_id' => $product->id, 'product_id' => $product->id,
'name' => $v['name'], 'name' => $v['name'],
'stock' => $v['stock'], 'stock' => $v['stock'],
@ -91,7 +98,7 @@ public function store(array $data): Product
// Map variant name -> variant ID // Map variant name -> variant ID
$insertedVariants = ProductVariant::where('product_id', $product->id)->get(); $insertedVariants = ProductVariant::where('product_id', $product->id)->get();
$variantMap = $insertedVariants->mapWithKeys(fn ($v) => [$v->name => $v->id]); $variantMap = $insertedVariants->mapWithKeys(fn($v) => [$v->name => $v->id]);
// Bulk insert prices // Bulk insert prices
$priceRows = []; $priceRows = [];
@ -137,7 +144,7 @@ public function store(array $data): Product
NotificationService::notify( NotificationService::notify(
roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO], roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
title: 'Produk Baru', title: 'Produk Baru',
body: "Produk \"{$product->name}\" berhasil ditambahkan".' oleh '.auth()->user()->full_name.'.', body: "Produk \"{$product->name}\" berhasil ditambahkan" . ' oleh ' . auth()->user()->full_name . '.',
url: route('admin.master.products.index'), url: route('admin.master.products.index'),
); );
@ -155,7 +162,7 @@ public function getForEdit(Product $product): array
$variants = $product->productVariants->map(function (ProductVariant $variant) { $variants = $product->productVariants->map(function (ProductVariant $variant) {
$media = $variant->getMedia('photos'); $media = $variant->getMedia('photos');
$photoKeys = $media->pluck('file_name')->toArray(); $photoKeys = $media->pluck('file_name')->toArray();
$photoUrls = $media->map(fn ($m) => $this->s3Service->getTemporaryUrl($m->file_name))->toArray(); $photoUrls = $media->map(fn($m) => $this->s3Service->getTemporaryUrl($m->file_name))->toArray();
return [ return [
'id' => $variant->id, 'id' => $variant->id,
@ -165,7 +172,7 @@ public function getForEdit(Product $product): array
'retail_stock' => $variant->retail_stock, 'retail_stock' => $variant->retail_stock,
'photo_keys' => $photoKeys, 'photo_keys' => $photoKeys,
'photo_urls' => $photoUrls, 'photo_urls' => $photoUrls,
'prices' => $variant->productPrices->map(fn ($p) => [ 'prices' => $variant->productPrices->map(fn($p) => [
'type' => $p->type->value, 'type' => $p->type->value,
'price' => $p->price, 'price' => $p->price,
]), ]),
@ -223,7 +230,7 @@ public function update(Product $product, array $data): Product
$existingVariantsMap = ProductVariant::whereIn('id', $existingVariantIds) $existingVariantsMap = ProductVariant::whereIn('id', $existingVariantIds)
->with('media') ->with('media')
->get() ->get()
->mapWithKeys(fn ($v) => [$v->id => $v]); ->mapWithKeys(fn($v) => [$v->id => $v]);
// Collect old stock data + identify changed variants // Collect old stock data + identify changed variants
$oldStockDataMap = []; $oldStockDataMap = [];
@ -249,7 +256,7 @@ public function update(Product $product, array $data): Product
// Bulk update changed variants (only changed ones, not all) // Bulk update changed variants (only changed ones, not all)
if ($changedIds !== []) { if ($changedIds !== []) {
$changedUpdates = collect($data['variants']) $changedUpdates = collect($data['variants'])
->filter(fn ($v) => isset($v['id']) && in_array($v['id'], $changedIds)); ->filter(fn($v) => isset($v['id']) && in_array($v['id'], $changedIds));
foreach ($changedUpdates as $variantData) { foreach ($changedUpdates as $variantData) {
$existingVariantsMap[$variantData['id']]->update([ $existingVariantsMap[$variantData['id']]->update([
@ -262,11 +269,11 @@ public function update(Product $product, array $data): Product
} }
// Bulk create new variants // Bulk create new variants
$newVariantsData = collect($data['variants'])->filter(fn ($v) => ! isset($v['id'])); $newVariantsData = collect($data['variants'])->filter(fn($v) => ! isset($v['id']));
$newVariantIdMap = []; $newVariantIdMap = [];
if ($newVariantsData->isNotEmpty()) { if ($newVariantsData->isNotEmpty()) {
$newVariantRows = $newVariantsData->map(fn ($v) => [ $newVariantRows = $newVariantsData->map(fn($v) => [
'product_id' => $product->id, 'product_id' => $product->id,
'name' => $v['name'], 'name' => $v['name'],
'stock' => $v['stock'], 'stock' => $v['stock'],
@ -283,7 +290,7 @@ public function update(Product $product, array $data): Product
->whereIn('name', $newVariantsData->pluck('name')->toArray()) ->whereIn('name', $newVariantsData->pluck('name')->toArray())
->get(); ->get();
$newVariantIdMap = $newlyCreated->mapWithKeys(fn ($v) => [$v->name => $v->id])->toArray(); $newVariantIdMap = $newlyCreated->mapWithKeys(fn($v) => [$v->name => $v->id])->toArray();
} }
// Build variant_id lookup: existing by id, new by name // Build variant_id lookup: existing by id, new by name
@ -347,7 +354,7 @@ public function update(Product $product, array $data): Product
} }
} }
$changedModels = collect($changedIds)->map(fn ($id) => $existingVariantsMap[$id])->filter(); $changedModels = collect($changedIds)->map(fn($id) => $existingVariantsMap[$id])->filter();
$this->stockMutationService->recordBulkAdjustment( $this->stockMutationService->recordBulkAdjustment(
$changedModels, $changedModels,
$oldStockDataMap, $oldStockDataMap,
@ -388,7 +395,7 @@ public function update(Product $product, array $data): Product
NotificationService::notify( NotificationService::notify(
roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO], roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
title: 'Produk Diperbarui', title: 'Produk Diperbarui',
body: "Produk \"{$product->name}\" berhasil diperbarui".' oleh '.auth()->user()->full_name.'.', body: "Produk \"{$product->name}\" berhasil diperbarui" . ' oleh ' . auth()->user()->full_name . '.',
url: route('admin.master.products.index'), url: route('admin.master.products.index'),
); );
@ -414,7 +421,7 @@ public function destroy(Product $product): bool
NotificationService::notify( NotificationService::notify(
roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO], roles: [Role::OWNER, Role::DEVELOPER, Role::DIREKTUR, Role::ADMIN_TOKO],
title: 'Produk Dihapus', title: 'Produk Dihapus',
body: "Produk \"{$product->name}\" berhasil dihapus".' oleh '.auth()->user()->full_name.'.', body: "Produk \"{$product->name}\" berhasil dihapus" . ' oleh ' . auth()->user()->full_name . '.',
url: route('admin.master.products.index'), url: route('admin.master.products.index'),
); );
@ -439,7 +446,7 @@ public function approve(Product $product): void
NotificationService::notify( NotificationService::notify(
roles: [Role::OWNER, Role::DEVELOPER], roles: [Role::OWNER, Role::DEVELOPER],
title: 'Produk Disetujui', title: 'Produk Disetujui',
body: "Produk \"{$product->name}\" telah disetujui oleh ".auth()->user()->full_name.'.', body: "Produk \"{$product->name}\" telah disetujui oleh " . auth()->user()->full_name . '.',
url: route('admin.master.products.index'), url: route('admin.master.products.index'),
additionalUser: $product->createdBy ?? null, additionalUser: $product->createdBy ?? null,
); );
@ -455,7 +462,7 @@ public function reject(Product $product, string $reason = ''): void
NotificationService::notify( NotificationService::notify(
roles: [Role::OWNER, Role::DEVELOPER], roles: [Role::OWNER, Role::DEVELOPER],
title: 'Produk Ditolak', title: 'Produk Ditolak',
body: "Produk \"{$product->name}\" telah ditolak oleh ".auth()->user()->full_name.'.', body: "Produk \"{$product->name}\" telah ditolak oleh " . auth()->user()->full_name . '.',
url: route('admin.master.products.index'), url: route('admin.master.products.index'),
additionalUser: $product->createdBy ?? null, additionalUser: $product->createdBy ?? null,
); );
@ -471,7 +478,7 @@ public function resubmit(Product $product): void
NotificationService::notify( NotificationService::notify(
roles: [Role::OWNER, Role::DEVELOPER], roles: [Role::OWNER, Role::DEVELOPER],
title: 'Produk Diajukan Ulang', title: 'Produk Diajukan Ulang',
body: "Produk \"{$product->name}\" telah diajukan ulang oleh ".auth()->user()->full_name.'.', body: "Produk \"{$product->name}\" telah diajukan ulang oleh " . auth()->user()->full_name . '.',
url: route('admin.master.products.index'), url: route('admin.master.products.index'),
); );
} }