From 77babcf44c149039f4a5ba1b24355e98de4fc23a Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Thu, 1 Jan 2026 15:27:16 +0700 Subject: [PATCH] feat(warehouse): membuat fitur gudang --- .../{Manage => Master}/WarehousesTable.php | 10 +- .../Studio/Master/Warehouse/Index.php | 89 ++++++++++++++++++ app/Livewire/Studio/Master/Warehouse/Show.php | 91 +++++++++++++++++++ ..._100001_create_warehouse_perfume_table.php | 31 +++++++ ..._100002_create_warehouse_product_table.php | 31 +++++++ ...7_100003_create_bottle_warehouse_table.php | 31 +++++++ .../index.blade.php} | 5 +- .../studio/master/warehouse/show.blade.php | 61 +++++++++++++ 8 files changed, 345 insertions(+), 4 deletions(-) rename app/Livewire/Datatable/{Manage => Master}/WarehousesTable.php (75%) create mode 100644 app/Livewire/Studio/Master/Warehouse/Index.php create mode 100644 app/Livewire/Studio/Master/Warehouse/Show.php create mode 100644 database/migrations/2025_12_27_100001_create_warehouse_perfume_table.php create mode 100644 database/migrations/2025_12_27_100002_create_warehouse_product_table.php create mode 100644 database/migrations/2025_12_27_100003_create_bottle_warehouse_table.php rename resources/views/livewire/studio/master/{warehouse.blade.php => warehouse/index.blade.php} (89%) create mode 100644 resources/views/livewire/studio/master/warehouse/show.blade.php diff --git a/app/Livewire/Datatable/Manage/WarehousesTable.php b/app/Livewire/Datatable/Master/WarehousesTable.php similarity index 75% rename from app/Livewire/Datatable/Manage/WarehousesTable.php rename to app/Livewire/Datatable/Master/WarehousesTable.php index 91363d4..beec81f 100644 --- a/app/Livewire/Datatable/Manage/WarehousesTable.php +++ b/app/Livewire/Datatable/Master/WarehousesTable.php @@ -1,6 +1,6 @@ label(function ($row) { $actions = ''; + if (auth()->user()->can('show warehouse')) { + $actions .= view('components.actions.table.show', [ + 'showRoute' => route('studio.master.warehouse.show', $row->hash), + ])->render(); + } + if (auth()->user()->can('update warehouse')) { $actions .= view('components.actions.table.edit-modal', [ 'id' => $row->hash, @@ -42,7 +48,7 @@ public function columns(): array return $actions; }) ->html() - ->hideIf(auth()->user()->cannot('update warehouse') && auth()->user()->cannot('delete warehouse')), + ->hideIf(auth()->user()->cannot('view warehouse') && auth()->user()->cannot('update warehouse') && auth()->user()->cannot('delete warehouse')), ]; } diff --git a/app/Livewire/Studio/Master/Warehouse/Index.php b/app/Livewire/Studio/Master/Warehouse/Index.php new file mode 100644 index 0000000..336aa61 --- /dev/null +++ b/app/Livewire/Studio/Master/Warehouse/Index.php @@ -0,0 +1,89 @@ +canOrAbort('create warehouse'); + + $this->form->store(); + + $this->dispatch('refreshDatatable'); + + $this->toast('Gudang berhasil ditambahkan.'); + + Flux::modals()->close(); + } + + public function update(): void + { + $this->canOrAbort('update warehouse'); + + $this->form->update(); + + $this->dispatch('refreshDatatable'); + + $this->toast('Gudang berhasil diperbarui.'); + + Flux::modals()->close(); + } + + public function delete(WarehouseModel $warehouse): void + { + $this->canOrAbort('delete warehouse'); + + $this->form->warehouse = $warehouse; + + $this->form->delete(); + + $this->dispatch('refreshDatatable'); + + $this->toast('Gudang berhasil dihapus.'); + + Flux::modals()->close(); + } + + #[On('modal:open')] + public function openModal(string $method, string $modalTitle, ?string $id = null): void + { + $this->resetValidation(); + $this->resetErrorBag(); + + $this->method = $method; + $this->modalTitle = $modalTitle; + + $id && $this->form->setWarehouse(WarehouseModel::byHashOrFail($id)); + } + + public function render(): View + { + return view('livewire.studio.master.warehouse.index', [ + 'pageTitle' => 'Gudang', + ]); + } +} diff --git a/app/Livewire/Studio/Master/Warehouse/Show.php b/app/Livewire/Studio/Master/Warehouse/Show.php new file mode 100644 index 0000000..5d9125e --- /dev/null +++ b/app/Livewire/Studio/Master/Warehouse/Show.php @@ -0,0 +1,91 @@ +warehouse = $warehouse; + } + + public function getStatsProperty() + { + $perfumesCount = $this->warehouse->perfumes()->count(); + $productsCount = $this->warehouse->products()->count(); + $bottlesCount = $this->warehouse->bottles()->count(); + $totalItems = $perfumesCount + $productsCount + $bottlesCount; + + return [ + [ + 'title' => 'Total Item', + 'value' => number_format($totalItems, 0, ',', '.'), + ], + [ + 'title' => 'Parfum', + 'value' => number_format($perfumesCount, 0, ',', '.'), + ], + [ + 'title' => 'Produk', + 'value' => number_format($productsCount, 0, ',', '.'), + ], + [ + 'title' => 'Botol', + 'value' => number_format($bottlesCount, 0, ',', '.'), + ], + ]; + } + + public function getItemsProperty() + { + $warehouse = $this->warehouse; + + $perfumes = $warehouse->perfumes()->get()->map(function ($item) { + return [ + 'id' => 'perfume_'.$item->id, + 'type' => 'Parfum', + 'name' => $item->name, + 'stock' => $item->pivot->stock ?? 0, + ]; + }); + + $products = $warehouse->products()->get()->map(function ($item) { + return [ + 'id' => 'product_'.$item->id, + 'type' => 'Produk', + 'name' => $item->name, + 'stock' => $item->pivot->stock ?? 0, + ]; + }); + + $bottles = $warehouse->bottles()->get()->map(function ($item) { + return [ + 'id' => 'bottle_'.$item->id, + 'type' => 'Botol', + 'name' => $item->name, + 'stock' => $item->pivot->stock ?? 0, + ]; + }); + + return $perfumes->concat($products)->concat($bottles); + } + + public function render(): View + { + return view('livewire.studio.master.warehouse.show', [ + 'pageTitle' => 'Detail Gudang', + 'stats' => $this->stats, + ]); + } +} diff --git a/database/migrations/2025_12_27_100001_create_warehouse_perfume_table.php b/database/migrations/2025_12_27_100001_create_warehouse_perfume_table.php new file mode 100644 index 0000000..c4383a7 --- /dev/null +++ b/database/migrations/2025_12_27_100001_create_warehouse_perfume_table.php @@ -0,0 +1,31 @@ +id(); + $table->foreignId('warehouse_id')->constrained()->cascadeOnDelete(); + $table->foreignId('perfume_id')->constrained()->cascadeOnDelete(); + $table->unsignedInteger('stock')->default(0); + $table->timestamp('created_at')->useCurrent(); + $table->timestamp('updated_at')->nullable()->useCurrentOnUpdate(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('perfume_warehouse'); + } +}; diff --git a/database/migrations/2025_12_27_100002_create_warehouse_product_table.php b/database/migrations/2025_12_27_100002_create_warehouse_product_table.php new file mode 100644 index 0000000..5c1726e --- /dev/null +++ b/database/migrations/2025_12_27_100002_create_warehouse_product_table.php @@ -0,0 +1,31 @@ +id(); + $table->foreignId('warehouse_id')->constrained()->cascadeOnDelete(); + $table->foreignId('product_id')->constrained()->cascadeOnDelete(); + $table->unsignedInteger('stock')->default(0); + $table->timestamp('created_at')->useCurrent(); + $table->timestamp('updated_at')->nullable()->useCurrentOnUpdate(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('product_warehouse'); + } +}; diff --git a/database/migrations/2025_12_27_100003_create_bottle_warehouse_table.php b/database/migrations/2025_12_27_100003_create_bottle_warehouse_table.php new file mode 100644 index 0000000..3ff2f14 --- /dev/null +++ b/database/migrations/2025_12_27_100003_create_bottle_warehouse_table.php @@ -0,0 +1,31 @@ +id(); + $table->foreignId('bottle_id')->constrained()->cascadeOnDelete(); + $table->foreignId('warehouse_id')->constrained()->cascadeOnDelete(); + $table->unsignedInteger('stock')->default(0); + $table->timestamp('created_at')->useCurrent(); + $table->timestamp('updated_at')->nullable()->useCurrentOnUpdate(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('bottle_warehouse'); + } +}; diff --git a/resources/views/livewire/studio/master/warehouse.blade.php b/resources/views/livewire/studio/master/warehouse/index.blade.php similarity index 89% rename from resources/views/livewire/studio/master/warehouse.blade.php rename to resources/views/livewire/studio/master/warehouse/index.blade.php index d28767b..547d3e0 100644 --- a/resources/views/livewire/studio/master/warehouse.blade.php +++ b/resources/views/livewire/studio/master/warehouse/index.blade.php @@ -14,7 +14,7 @@
- +
@include('components.modals.confirmation', [ @@ -38,7 +38,8 @@ Deskripsi - + diff --git a/resources/views/livewire/studio/master/warehouse/show.blade.php b/resources/views/livewire/studio/master/warehouse/show.blade.php new file mode 100644 index 0000000..7d5e058 --- /dev/null +++ b/resources/views/livewire/studio/master/warehouse/show.blade.php @@ -0,0 +1,61 @@ + +
+
+ {{ $pageTitle }} +
+
+ + Kembali + +
+
+ +
+ @if (!empty($stats)) +
+ @foreach ($stats as $stat) +
+ {{ $stat['title'] }} + {{ $stat['value'] }} +
+ @endforeach +
+ @endif + + +
+ Daftar Item + Daftar semua item yang tersedia di gudang ini. +
+ + + + Tipe + Item + Stok + + + + @forelse ($this->items as $item) + + + + {{ $item['type'] }} + + {{ $item['name'] }} + {{ number_format($item['stock'], 0, ',', '.') }} + + @empty + + Tidak ada item di gudang + ini. + + + @endforelse + + +
+
+