feat: Implement restock management, refactor warehouse views, and enhance stock activity logging for sales.

This commit is contained in:
Yoga Pangestu 2026-01-02 13:13:34 +07:00
parent 77d3d25cd9
commit cc917ac946
13 changed files with 546 additions and 144 deletions

View File

@ -76,6 +76,11 @@ public function approveApproval(StockOpname $stockOpname): void
}
$itemable = $item->itemable;
if (! $itemable) {
continue;
}
$morphType = class_basename($itemable);
$relationMap = [
@ -90,9 +95,11 @@ public function approveApproval(StockOpname $stockOpname): void
$relationName = $relationMap[$morphType];
$currentStock = $outlet->$relationName()
$currentPivot = $outlet->$relationName()
->where($itemable->getTable().'.id', $itemable->id)
->first()?->pivot?->stock ?? 0;
->first();
$currentStock = $currentPivot?->pivot?->stock ?? 0;
$quantity = $item->qty_physical;
@ -100,26 +107,13 @@ public function approveApproval(StockOpname $stockOpname): void
$itemable->id => ['stock' => $quantity],
]);
StockActivityLogService::log(
logName: 'Stock Opname',
event: 'Mengubah',
description: sprintf(
'Stok %s di %s diperbarui dari %s menjadi %s',
$itemable->name,
$outlet->name,
$currentStock,
$quantity
),
performedOn: $itemable,
outlet: $outlet,
StockActivityLogService::stockOpname(
stockOpname: $stockOpname,
product: $itemable,
quantityChange: $quantity - $currentStock,
previousStock: $currentStock,
newStock: $quantity,
extraProperties: [
// Preserving 'itemable_id' pointing to StockOpnameItem id as per original code overwriting
'itemable_id' => $item->id ?? null,
'itemable_type' => $item->itemable_type,
]
note: $stockOpname->note
);
}
});

View File

@ -1,89 +0,0 @@
<?php
namespace App\Livewire\Studio\Master;
use App\Livewire\Forms\Studio\Master\WarehouseForm;
use App\Models\Warehouse as WarehouseModel;
use App\Traits\Authorization\WithAuthorization;
use App\Traits\Components\WithCloseModal;
use App\Traits\Components\WithConfirmation;
use App\Traits\Components\WithToast;
use App\Traits\Notification\WithSubscribeNotification;
use App\Traits\Utilities\WithUpdatedData;
use Flux\Flux;
use Illuminate\Contracts\View\View;
use Livewire\Attributes\On;
use Livewire\Attributes\Title;
use Livewire\Component;
#[Title('Gudang')]
class Warehouse extends Component
{
use WithAuthorization, WithCloseModal, WithConfirmation, WithSubscribeNotification, WithToast, WithUpdatedData;
public WarehouseForm $form;
public string $method = 'create';
public string $modalTitle = '';
public function create(): void
{
$this->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', [
'pageTitle' => 'Gudang',
]);
}
}

View File

@ -40,6 +40,11 @@ public function outlets(): BelongsToMany
return $this->belongsToMany(Outlet::class)->withPivot('stock');
}
public function warehouses(): BelongsToMany
{
return $this->belongsToMany(Warehouse::class)->withPivot('stock');
}
public function purchaseItems(): MorphMany
{
return $this->morphMany(PurchaseItem::class, 'purchasable');
@ -49,4 +54,9 @@ public function items(): MorphMany
{
return $this->morphMany(OrderItem::class, 'orderable');
}
public function restockItems(): MorphMany
{
return $this->morphMany(RestockItem::class, 'restockable');
}
}

View File

@ -99,4 +99,9 @@ public function stockOpname(): HasMany
{
return $this->hasMany(StockOpname::class);
}
public function restocks(): HasMany
{
return $this->hasMany(Restock::class);
}
}

View File

@ -53,6 +53,11 @@ public function outlets(): BelongsToMany
return $this->belongsToMany(Outlet::class)->withPivot('stock');
}
public function warehouses(): BelongsToMany
{
return $this->belongsToMany(Warehouse::class)->withPivot('stock');
}
public function purchaseItems(): MorphMany
{
return $this->morphMany(PurchaseItem::class, 'purchasable');
@ -62,4 +67,9 @@ public function items(): MorphMany
{
return $this->morphMany(OrderItem::class, 'orderable');
}
public function restockItems(): MorphMany
{
return $this->morphMany(RestockItem::class, 'restockable');
}
}

View File

@ -40,6 +40,11 @@ public function outlets(): BelongsToMany
return $this->belongsToMany(Outlet::class)->withPivot('stock');
}
public function warehouses(): BelongsToMany
{
return $this->belongsToMany(Warehouse::class)->withPivot('stock');
}
public function purchaseItems(): MorphMany
{
return $this->morphMany(PurchaseItem::class, 'purchasable');
@ -49,4 +54,9 @@ public function items(): MorphMany
{
return $this->morphMany(OrderItem::class, 'orderable');
}
public function restockItems(): MorphMany
{
return $this->morphMany(RestockItem::class, 'restockable');
}
}

View File

@ -2,14 +2,167 @@
namespace App\Services;
use App\Models\Order;
use App\Models\Outlet;
use App\Models\Purchase;
use App\Models\Restock;
use App\Models\StockOpname;
use App\Models\Warehouse;
use Illuminate\Database\Eloquent\Model;
class StockActivityLogService
{
public const LOG_PURCHASE = 'purchase';
public const LOG_DISTRIBUTION = 'distribution';
public const LOG_SALE = 'sale';
public const LOG_STOCK_OPNAME = 'stock_opname';
/**
* Log stock related activity.
* Log purchase activity (Incoming to Warehouse).
*/
public static function log(
public static function purchase(
Purchase $purchase,
Model $product,
int $quantity,
int $previousStock,
int $newStock,
?Model $causedBy = null
): void {
self::logWarehouse(
logName: self::LOG_PURCHASE,
event: 'increase',
description: "Purchase #{$purchase->hash_id}: Added {$quantity} stock to Warehouse.",
performedOn: $product,
warehouse: $purchase->warehouse,
quantityChange: $quantity,
previousStock: $previousStock,
newStock: $newStock,
extraProperties: [
'purchase_id' => $purchase->id,
'purchase_hash' => $purchase->hash_id,
],
causedBy: $causedBy
);
}
/**
* Log distribution activity (Warehouse to Outlet).
* This logs two events: Out from Warehouse, In to Outlet.
*/
public static function distribution(
Restock $restock,
Model $product,
int $quantity,
int $warehousePreviousStock,
int $warehouseNewStock,
int $outletPreviousStock,
int $outletNewStock,
?Model $causedBy = null
): void {
// Log Warehouse Out
self::logWarehouse(
logName: self::LOG_DISTRIBUTION,
event: 'decrease',
description: "Restock #{$restock->hash_id}: Moved {$quantity} stock from Warehouse to Outlet.",
performedOn: $product,
warehouse: $restock->warehouse,
quantityChange: -1 * abs($quantity),
previousStock: $warehousePreviousStock,
newStock: $warehouseNewStock,
extraProperties: [
'restock_id' => $restock->id,
'restock_hash' => $restock->hash_id,
'target_outlet_id' => $restock->outlet_id,
],
causedBy: $causedBy
);
// Log Outlet In
self::logOutlet(
logName: self::LOG_DISTRIBUTION,
event: 'increase',
description: "Restock #{$restock->hash_id}: Received {$quantity} stock from Warehouse.",
performedOn: $product,
outlet: $restock->outlet,
quantityChange: abs($quantity),
previousStock: $outletPreviousStock,
newStock: $outletNewStock,
extraProperties: [
'restock_id' => $restock->id,
'restock_hash' => $restock->hash_id,
'source_warehouse_id' => $restock->warehouse_id,
],
causedBy: $causedBy
);
}
/**
* Log sale activity (Outlet to Customer).
*/
public static function sale(
Order $order,
Model $product,
int $quantity,
int $previousStock,
int $newStock,
?Model $causedBy = null
): void {
self::logOutlet(
logName: self::LOG_SALE,
event: 'decrease',
description: "Order #{$order->hash_id}: Sold {$quantity} items.",
performedOn: $product,
outlet: $order->outlet,
quantityChange: -1 * abs($quantity),
previousStock: $previousStock,
newStock: $newStock,
extraProperties: [
'order_id' => $order->id,
'order_hash' => $order->hash_id,
],
causedBy: $causedBy ?? $order->user
);
}
/**
* Log stock opname activity (Adjustment in Outlet).
*/
public static function stockOpname(
StockOpname $stockOpname,
Model $product,
int $quantityChange,
int $previousStock,
int $newStock,
?string $note = null,
?Model $causedBy = null
): void {
$event = $quantityChange > 0 ? 'increase' : 'decrease';
self::logOutlet(
logName: self::LOG_STOCK_OPNAME,
event: $event,
description: "Stock Opname #{$stockOpname->hash_id}: Adjusted stock by {$quantityChange}.",
performedOn: $product,
outlet: $stockOpname->outlet,
quantityChange: $quantityChange,
previousStock: $previousStock,
newStock: $newStock,
extraProperties: [
'stock_opname_id' => $stockOpname->id,
'stock_opname_hash' => $stockOpname->hash_id,
'note' => $note,
],
causedBy: $causedBy
);
}
/**
* Log stock related activity for Outlet.
*/
public static function logOutlet(
string $logName,
string $event,
string $description,
@ -28,6 +181,42 @@ public static function log(
'quantity_change' => $quantityChange,
'previous_stock' => $previousStock,
'new_stock' => $newStock,
'location_type' => 'outlet',
'location_name' => $outlet->name ?? 'Unknown Outlet',
], $extraProperties);
activity($logName)
->performedOn($performedOn)
->causedBy($causedBy)
->withProperties($properties)
->event($event)
->log($description);
}
/**
* Log stock related activity for Warehouse.
*/
public static function logWarehouse(
string $logName,
string $event,
string $description,
Model $performedOn,
Warehouse $warehouse,
int $quantityChange,
int $previousStock,
int $newStock,
array $extraProperties = [],
?Model $causedBy = null
): void {
$causedBy = $causedBy ?: auth()->user();
$properties = array_merge([
'warehouse_id' => $warehouse->getKey(),
'quantity_change' => $quantityChange,
'previous_stock' => $previousStock,
'new_stock' => $newStock,
'location_type' => 'warehouse',
'location_name' => $warehouse->name ?? 'Unknown Warehouse',
], $extraProperties);
activity($logName)

View File

@ -39,24 +39,26 @@ public function increaseOutletStock($outlet, $item): void
'stock' => $currentStock + $quantity,
]);
} else {
$currentStock = 0;
$outlet->{$relation}()->attach($item->orderable_id, [
'stock' => $quantity,
]);
}
$newStock = $currentStock + $quantity;
StockActivityLogService::log(
logName: 'Order',
event: 'Menambah',
description: 'Stok '.$item->orderable->name.' di '.$outlet->name.' bertambah '.formatCurrencyNumber($quantity),
StockActivityLogService::logOutlet(
logName: StockActivityLogService::LOG_SALE,
event: 'increase',
description: 'Stok '.$item->orderable->name.' di '.$outlet->name.' bertambah '.formatCurrencyNumber($quantity).' (Pembatalan/Edit Order)',
performedOn: $item->orderable,
outlet: $outlet,
quantityChange: $quantity,
quantityChange: abs($quantity),
previousStock: $currentStock,
newStock: $currentStock + $quantity,
newStock: $newStock,
extraProperties: [
'orderable_id' => $item->orderable_id,
'orderable_type' => $item->orderable_type,
'purchase_id' => $item->purchase_id ?? null,
'order_id' => $item->order_id ?? null,
]
);
}
@ -101,21 +103,33 @@ public function decreaseOutletStock($outlet, $item)
'stock' => $newStock,
]);
StockActivityLogService::log(
logName: 'Order',
event: 'Mengurangi',
description: 'Stok '.$item->orderable->name.' di '.$outlet->name.' berkurang '.formatCurrencyNumber($quantity),
performedOn: $item->orderable,
outlet: $outlet,
quantityChange: $quantity,
previousStock: $currentStock,
newStock: $currentStock - $quantity,
extraProperties: [
'orderable_id' => $item->orderable_id,
'orderable_type' => $item->orderable_type,
'purchase_id' => $item->purchase_id ?? null,
]
);
$order = $item->order ?? \App\Models\Order::find($item->order_id);
if ($order) {
StockActivityLogService::sale(
order: $order,
product: $item->orderable,
quantity: $quantity,
previousStock: $currentStock,
newStock: $newStock
);
} else {
StockActivityLogService::logOutlet(
logName: StockActivityLogService::LOG_SALE,
event: 'decrease',
description: 'Stok '.$item->orderable->name.' di '.$outlet->name.' berkurang '.formatCurrencyNumber($quantity),
performedOn: $item->orderable,
outlet: $outlet,
quantityChange: -1 * abs($quantity),
previousStock: $currentStock,
newStock: $newStock,
extraProperties: [
'orderable_id' => $item->orderable_id,
'orderable_type' => $item->orderable_type,
'order_id' => $item->order_id ?? null,
]
);
}
return ['status' => true];
}

View File

@ -15,6 +15,11 @@ public function run(): void
OutletSeeder::class,
UserSeeder::class,
TierSeeder::class,
BrandSeeder::class,
CategorySeeder::class,
PerfumeSeeder::class,
ProductSeeder::class,
BottleSeeder::class,
]);
} else {
$this->call([

View File

@ -226,6 +226,7 @@ public function run(): void
'update outlet',
'delete outlet',
'view user',
'create user',
'update user',
'delete user',
@ -267,7 +268,6 @@ public function run(): void
'delete bottle',
'audit bottle',
'view payroll',
'manage adjustment',
'delete order',
@ -379,7 +379,6 @@ public function run(): void
'update bottle',
'delete bottle',
'view payroll',
'manage adjustment',
'delete order',
@ -388,6 +387,11 @@ public function run(): void
'create purchase',
'delete purchase',
'view restock',
'create restock',
'update restock',
'delete restock',
'view stock opname',
'manage stock opname',
'show stock opname',

View File

@ -0,0 +1,213 @@
<flux:main>
<div class="flex justify-between items-center">
<div>
<flux:heading size="xl">{{ $pageTitle }}</flux:heading>
</div>
<div>
<flux:button href="{{ route('studio.manage.restock.index') }}" wire:navigate class="text-sm">
Kembali
</flux:button>
</div>
</div>
<div class="mt-6">
<flux:callout icon="megaphone" color="blue" class="mb-6">
<flux:callout.heading>Informasi Restock</flux:callout.heading>
<flux:callout.text>
Proses restock akan **mengurangi** stok di Gudang dan **menambah** stok di Outlet yang dipilih.
</flux:callout.text>
</flux:callout>
<div class="flex flex-col lg:flex-row gap-4">
<div class="w-full lg:w-3/4 space-y-4">
<flux:card class="space-y-6 p-6">
<flux:input label="Catatan" placeholder="Restock rutin mingguan" wire:model="form.note"
autocomplete="off" />
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<flux:field>
<flux:label>Tanggal Restock <span class="text-red-500 ms-1">*</span></flux:label>
<flux:date-picker with-today wire:model="form.restock_date" placeholder="Pilih Tanggal"
autocomplete="off" locale="id-ID" selectable-header />
<flux:error name="form.restock_date" />
</flux:field>
<flux:field>
<flux:label>Gudang <span class="text-red-500 ms-1">*</span></flux:label>
<flux:select variant="listbox" searchable placeholder="Pilih Gudang"
wire:model.live="form.warehouse_id">
@foreach ($warehouses as $key => $value)
<flux:select.option value="{{ $key }}">{{ $value }}
</flux:select.option>
@endforeach
</flux:select>
<flux:error name="form.warehouse_id" />
</flux:field>
<flux:field>
<flux:label>Outlet <span class="text-red-500 ms-1">*</span></flux:label>
<flux:select variant="listbox" searchable placeholder="Pilih Outlet"
wire:model.live="form.outlet_id">
@foreach ($outlets as $key => $value)
<flux:select.option value="{{ $key }}">{{ $value }}
</flux:select.option>
@endforeach
</flux:select>
<flux:error name="form.outlet_id" />
</flux:field>
</div>
</flux:card>
@if ($form->warehouse_id && $form->outlet_id)
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<flux:card class="space-y-6 p-6">
<flux:select label="Parfum" variant="listbox" searchable placeholder="Cari parfum..."
wire:model="form.perfume_id">
@foreach ($perfumes as $key => $perfume)
<flux:select.option value="{{ $key }}">{{ $perfume }}
</flux:select.option>
@endforeach
</flux:select>
<flux:input label="Kuantitas" placeholder="500" wire:model="form.quantity_perfume"
autocomplete="off" x-mask:dynamic="$money($input, ',')" />
<div class="flex justify-end">
<flux:button variant="primary" color="zinc" wire:click="addItem('parfum')">
Tambah
</flux:button>
</div>
</flux:card>
<flux:card class="space-y-6 p-6">
<flux:select label="Produk" variant="listbox" searchable placeholder="Cari produk..."
wire:model="form.product_id">
@foreach ($products as $key => $product)
<flux:select.option value="{{ $key }}">{{ $product }}
</flux:select.option>
@endforeach
</flux:select>
<flux:input label="Kuantitas" placeholder="10" wire:model="form.quantity_product"
autocomplete="off" x-mask:dynamic="$money($input, ',')" />
<div class="flex justify-end">
<flux:button variant="primary" color="zinc" wire:click="addItem('produk')">
Tambah
</flux:button>
</div>
</flux:card>
<flux:card class="space-y-6 p-6">
<flux:select label="Botol" variant="listbox" searchable placeholder="Cari botol..."
wire:model="form.bottle_id">
@foreach ($bottles as $key => $bottle)
<flux:select.option value="{{ $key }}">{{ $bottle }}
</flux:select.option>
@endforeach
</flux:select>
<flux:input label="Kuantitas" placeholder="50" wire:model="form.quantity_bottle"
autocomplete="off" x-mask:dynamic="$money($input, ',')" />
<div class="flex justify-end">
<flux:button variant="primary" color="zinc" wire:click="addItem('botol')">
Tambah
</flux:button>
</div>
</flux:card>
</div>
@else
<flux:card class="p-6 text-center text-zinc-500 italic">
Silakan pilih Gudang Asal dan Outlet Tujuan terlebih dahulu untuk menampilkan daftar item.
</flux:card>
@endif
</div>
<div class="w-full lg:w-1/3 space-y-4">
<flux:card class="space-y-6 p-6">
<div class="space-y-3">
<h3 class="text-sm font-medium">Gambar</h3>
<div class="dropzone-wrapper">
<livewire:dropzone wire:model="form.image" :rules="['image', 'mimes:png,jpeg', 'max:10420']" :max-files="1"
:key="'image'" :files="$form->image" />
@error('form.image')
<div class="mt-3 text-sm font-medium text-red-500 dark:text-red-400">
{{ $message }}
</div>
@enderror
</div>
</div>
</flux:card>
<flux:card class="space-y-6 p-6">
<h3 class="text-sm font-medium">Keranjang Restock</h3>
<div class="divide-y text-sm">
<flux:table>
<flux:table.columns>
<flux:table.column>Item</flux:table.column>
<flux:table.column>Qty</flux:table.column>
<flux:table.column>Aksi</flux:table.column>
</flux:table.columns>
<flux:table.rows>
@forelse($restockItems as $item)
<flux:table.row>
<flux:table.cell>
<flux:heading>
<div>{{ $item->restockable->name }}</div>
</flux:heading>
</flux:table.cell>
<flux:table.cell>
{{ formatCurrencyNumber($item->quantity, '') }}
</flux:table.cell>
<flux:table.cell class="space-x-2">
<flux:modal.trigger name="form-modal">
<flux:tooltip content="Ubah">
<flux:button variant="primary" color="yellow" icon="pencil-square"
size="sm"
wire:click="$dispatch('modal:open', {'item': '{{ $item->id }}'})">
</flux:button>
</flux:tooltip>
</flux:modal.trigger>
<flux:button variant="danger" icon="trash" size="sm"
wire:click="deleteItem('{{ $item->id }}')">
</flux:button>
</flux:table.cell>
</flux:table.row>
@empty
<flux:table.row>
<flux:table.cell colspan="3" class="text-center">
<span class="text-sm text-zinc-500 italic">Keranjang Kosong...</span>
</flux:table.cell>
</flux:table.row>
@endforelse
</flux:table.rows>
</flux:table>
</div>
</flux:card>
</div>
</div>
<div class="flex justify-start mt-4">
<flux:button variant="primary" class="sm:w-auto cursor-pointer" wire:click="save">
Simpan
</flux:button>
</div>
</div>
<flux:modal name="form-modal" class="w-[95%] max-w-sm md:max-w-xl mx-auto" @close="closeModal('form-modal')">
<div class="p-4 space-y-6">
<flux:heading size="lg">Ubah {{ $modalTitle }}</flux:heading>
<flux:input label="Kuantitas" placeholder="Masukkan kuantitas" wire:model="form.quantity_edit"
autocomplete="off" x-mask:dynamic="$money($input, ',')" />
<div class="flex">
<flux:spacer />
<flux:button variant="primary" color="zinc" class="sm:w-auto cursor-pointer"
wire:click="updateItem">
Perbarui
</flux:button>
</div>
</div>
</flux:modal>
</flux:main>

View File

@ -0,0 +1,35 @@
<flux:main>
<div class="flex justify-between items-center">
<div>
<flux:heading size="xl">{{ $pageTitle }}</flux:heading>
</div>
@can('create restock')
<div>
<flux:button href="{{ route('studio.manage.restock.create') }}" variant="primary" wire:navigate
class="text-sm">
Tambah
</flux:button>
</div>
@endcan
</div>
<div class="mt-6">
<flux:callout icon="megaphone" color="blue" class="mb-6">
<flux:callout.heading>Informasi</flux:callout.heading>
<flux:callout.text>
Menghapus data restock otomatis mengembalikan stok gudang.
</flux:callout.text>
</flux:callout>
<livewire:datatable.manage.restocks-table />
</div>
@include('components.modals.confirmation', [
'modalName' => 'delete-confirmation',
'modalTitle' => 'Apakah Anda yakin?',
'modalMessage' => 'Data restock akan dihapus dari riwayat.',
'buttonVariant' => 'primary',
'buttonColor' => 'danger',
'buttonText' => 'Ya, Hapus',
])
</flux:main>

View File

@ -22,7 +22,6 @@
use App\Livewire\Studio\Finance\Payroll as PayrollComponent;
use App\Livewire\Studio\Information\Broadcast as BroadcastComponent;
use App\Livewire\Studio\Information\Faq as FaqComponent;
use App\Livewire\Studio\Information\PriceRequest as PriceRequestComponent;
use App\Livewire\Studio\Information\Testimonial as TestimonialComponent;
use App\Livewire\Studio\Loyalty\Customer as CustomerComponent;
use App\Livewire\Studio\Loyalty\RedemptionVerification;
@ -39,6 +38,8 @@
use App\Livewire\Studio\Manage\Order\Show as OrderShow;
use App\Livewire\Studio\Manage\Purchase\Create as PurchaseCreate;
use App\Livewire\Studio\Manage\Purchase\Index as PurchaseIndex;
use App\Livewire\Studio\Manage\Restock\Create as RestockCreate;
use App\Livewire\Studio\Manage\Restock\Index as RestockIndex;
use App\Livewire\Studio\Manage\StockOpname\Index as StockOpnameIndex;
use App\Livewire\Studio\Manage\StockOpname\Manage as StockOpnameManage;
use App\Livewire\Studio\Manage\StockOpname\Show as StockOpnameShow;
@ -50,7 +51,8 @@
use App\Livewire\Studio\Master\User\Create as UserCreate;
use App\Livewire\Studio\Master\User\Edit as UserEdit;
use App\Livewire\Studio\Master\User\Index as UserIndex;
use App\Livewire\Studio\Master\Warehouse as WarehouseComponent;
use App\Livewire\Studio\Master\Warehouse\Index as WarehouseIndex;
use App\Livewire\Studio\Master\Warehouse\Show as WarehouseShow;
use App\Livewire\Studio\Setting\Account as AccountComponent;
use App\Livewire\Studio\Setting\Application as ApplicationComponent;
use Illuminate\Support\Facades\Route;
@ -73,8 +75,9 @@
Route::get('/{outlet}/edit', OutletEdit::class)->name('edit')->middleware('can:update outlet');
});
Route::prefix('warehouse')->name('warehouse.')->group(function () {
Route::get('/', WarehouseComponent::class)->name('index')->middleware('can:view warehouse');
Route::prefix('warehouses')->name('warehouse.')->group(function () {
Route::get('/', WarehouseIndex::class)->name('index')->middleware('can:view warehouse');
Route::get('/{warehouse}/show', WarehouseShow::class)->name('show')->middleware('can:view warehouse');
});
Route::prefix('users')->name('user.')->group(function () {
@ -165,6 +168,11 @@
Route::get('/create', PurchaseCreate::class)->name('create')->middleware('can:create purchase');
});
Route::prefix('restocks')->name('restock.')->group(function () {
Route::get('/', RestockIndex::class)->name('index')->middleware('can:view restock');
Route::get('/create', RestockCreate::class)->name('create')->middleware('can:create restock');
});
Route::prefix('stock-opname')->name('stock_opname.')->group(function () {
Route::get('/', StockOpnameIndex::class)->name('index')->middleware('can:view stock opname');
Route::get('/{stockOpname}/show', StockOpnameShow::class)->name('show')->middleware('can:show stock opname');
@ -181,12 +189,6 @@
Route::prefix('information')->name('studio.information.')->group(function () {
Route::get('/broadcasts', BroadcastComponent::class)->name('broadcast.index')->middleware('can:view broadcast');
Route::prefix('price-requests')->name('price_request.')->group(function () {
Route::get('/', PriceRequestComponent::class)->name('index')->middleware('can:view price request');
Route::patch('/{priceRequest}/approve', PriceRequestComponent::class)->name('approve')->middleware('can:approve price request');
Route::patch('/{priceRequest}/reject', PriceRequestComponent::class)->name('reject')->middleware('can:reject price request');
});
Route::prefix('faqs')->name('faq.')->group(function () {
Route::get('/', FaqComponent::class)->name('index')->middleware('can:view faq');
});