chore: initial commit of existing codebase
This commit is contained in:
commit
11e94889b2
292 files changed
+38586
No files matched your search
@@ -0,0 +1,84 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Add Item')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="page-title">Add Item</h1>
|
||||
<p class="page-subtitle"><a href="{{ route('inventory.items.index') }}" class="text-blue-600 hover:underline">Items</a> / New</p>
|
||||
</div>
|
||||
|
||||
@if($errors->any())
|
||||
<div class="mb-4 px-4 py-3 bg-red-50 border border-red-200 rounded-lg text-sm text-red-700">
|
||||
<ul class="list-disc list-inside space-y-1">
|
||||
@foreach($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card card-body max-w-2xl">
|
||||
<form action="{{ route('inventory.items.store') }}" method="POST">
|
||||
@csrf
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
||||
|
||||
<div>
|
||||
<label class="form-label">Item Code <span class="text-red-500">*</span></label>
|
||||
<input type="text" name="item_code" value="{{ old('item_code') }}" required
|
||||
placeholder="e.g. RAW-001" class="form-input">
|
||||
<p class="text-xs text-gray-400 mt-1">Unique code for this item</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Item Name <span class="text-red-500">*</span></label>
|
||||
<input type="text" name="item_name" value="{{ old('item_name') }}" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Category <span class="text-red-500">*</span></label>
|
||||
<select name="category" required class="form-select">
|
||||
<option value="">-- Select Category --</option>
|
||||
<option value="raw_material" {{ old('category') === 'raw_material' ? 'selected' : '' }}>Raw Material</option>
|
||||
<option value="wip" {{ old('category') === 'wip' ? 'selected' : '' }}>Work In Progress (WIP)</option>
|
||||
<option value="finished_good" {{ old('category') === 'finished_good' ? 'selected' : '' }}>Finished Good</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Unit of Measure <span class="text-red-500">*</span></label>
|
||||
<input type="text" name="unit_of_measure" value="{{ old('unit_of_measure') }}" required
|
||||
placeholder="e.g. KG, PCS, Ltr" class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Minimum Stock Level</label>
|
||||
<input type="number" name="minimum_stock_level" value="{{ old('minimum_stock_level', 0) }}" min="0" step="0.01" class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Cost Price</label>
|
||||
<input type="number" name="cost_price" value="{{ old('cost_price', 0) }}" min="0" step="0.01" class="form-input">
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Description</label>
|
||||
<textarea name="description" rows="3" class="form-textarea">{{ old('description') }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2 flex items-center gap-2">
|
||||
<input type="checkbox" name="is_active" id="is_active" value="1"
|
||||
{{ old('is_active', '1') ? 'checked' : '' }}
|
||||
class="h-4 w-4 text-blue-600 border-gray-300 rounded">
|
||||
<label for="is_active" class="form-label mb-0">Active</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center gap-3">
|
||||
<button type="submit" class="btn-primary">Save Item</button>
|
||||
<a href="{{ route('inventory.items.index') }}" class="btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,82 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Edit Item')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="page-title">Edit Item</h1>
|
||||
<p class="page-subtitle"><a href="{{ route('inventory.items.index') }}" class="text-blue-600 hover:underline">Items</a> / Edit</p>
|
||||
</div>
|
||||
|
||||
@if($errors->any())
|
||||
<div class="mb-4 px-4 py-3 bg-red-50 border border-red-200 rounded-lg text-sm text-red-700">
|
||||
<ul class="list-disc list-inside space-y-1">
|
||||
@foreach($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card card-body max-w-2xl">
|
||||
<form action="{{ route('inventory.items.update', $item) }}" method="POST">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
||||
|
||||
<div>
|
||||
<label class="form-label">Item Code <span class="text-red-500">*</span></label>
|
||||
<input type="text" name="item_code" value="{{ old('item_code', $item->item_code) }}" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Item Name <span class="text-red-500">*</span></label>
|
||||
<input type="text" name="item_name" value="{{ old('item_name', $item->item_name) }}" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Category <span class="text-red-500">*</span></label>
|
||||
<select name="category" required class="form-select">
|
||||
<option value="">-- Select Category --</option>
|
||||
<option value="raw_material" {{ old('category', $item->category) === 'raw_material' ? 'selected' : '' }}>Raw Material</option>
|
||||
<option value="wip" {{ old('category', $item->category) === 'wip' ? 'selected' : '' }}>Work In Progress (WIP)</option>
|
||||
<option value="finished_good" {{ old('category', $item->category) === 'finished_good' ? 'selected' : '' }}>Finished Good</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Unit of Measure <span class="text-red-500">*</span></label>
|
||||
<input type="text" name="unit_of_measure" value="{{ old('unit_of_measure', $item->unit_of_measure) }}" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Minimum Stock Level</label>
|
||||
<input type="number" name="minimum_stock_level" value="{{ old('minimum_stock_level', $item->minimum_stock_level) }}" min="0" step="0.01" class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Cost Price</label>
|
||||
<input type="number" name="cost_price" value="{{ old('cost_price', $item->cost_price) }}" min="0" step="0.01" class="form-input">
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Description</label>
|
||||
<textarea name="description" rows="3" class="form-textarea">{{ old('description', $item->description) }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2 flex items-center gap-2">
|
||||
<input type="checkbox" name="is_active" id="is_active" value="1"
|
||||
{{ old('is_active', $item->is_active) ? 'checked' : '' }}
|
||||
class="h-4 w-4 text-blue-600 border-gray-300 rounded">
|
||||
<label for="is_active" class="form-label mb-0">Active</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center gap-3">
|
||||
<button type="submit" class="btn-primary">Update Item</button>
|
||||
<a href="{{ route('inventory.items.index') }}" class="btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,204 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Inventory Items')
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1 class="page-title">Inventory Items</h1>
|
||||
<p class="page-subtitle">Manage all stock items</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<a href="{{ route('inventory.items.export-pdf') }}" class="btn btn-secondary" title="Export items as PDF">
|
||||
<svg width="15" height="15" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M7 21h10a2 2 0 002-2V9.414a1 1 0 00-.293-.707l-5.414-5.414A1 1 0 0012.586 3H7a2 2 0 00-2 2v14a2 2 0 002 2z"/>
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 13h6M9 17h4"/>
|
||||
</svg>
|
||||
Export PDF
|
||||
</a>
|
||||
<a href="{{ route('inventory.items.template') }}" class="btn btn-secondary" title="Download Excel import template">
|
||||
<svg width="15" height="15" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"/>
|
||||
</svg>
|
||||
Template
|
||||
</a>
|
||||
<button onclick="document.getElementById('import-modal').classList.remove('hidden')"
|
||||
class="btn btn-success" title="Import items from Excel">
|
||||
<svg width="15" height="15" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/>
|
||||
</svg>
|
||||
Import Excel
|
||||
</button>
|
||||
<a href="{{ route('inventory.items.create') }}" class="btn-primary">
|
||||
+ Add Item
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper overflow-x-auto">
|
||||
<table class="table-base">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Code</th>
|
||||
<th>Name</th>
|
||||
<th>Category</th>
|
||||
<th>UOM</th>
|
||||
<th class="text-right">Min Stock</th>
|
||||
<th class="text-right">Cost Price</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($items as $item)
|
||||
<tr>
|
||||
<td class="font-mono text-gray-700">{{ $item->item_code }}</td>
|
||||
<td class="font-medium text-gray-800">{{ $item->item_name }}</td>
|
||||
<td>
|
||||
@php
|
||||
$catBadgeClass = match($item->category) {
|
||||
'raw_material' => 'badge-blue',
|
||||
'wip' => 'badge-yellow',
|
||||
'finished_good' => 'badge-green',
|
||||
default => 'badge-gray',
|
||||
};
|
||||
$catLabels = ['raw_material' => 'Raw Material', 'wip' => 'WIP', 'finished_good' => 'Finished Good'];
|
||||
@endphp
|
||||
<span class="{{ $catBadgeClass }}">
|
||||
{{ $catLabels[$item->category] ?? ucfirst($item->category) }}
|
||||
</span>
|
||||
</td>
|
||||
<td>{{ $item->unit_of_measure }}</td>
|
||||
<td class="text-right">{{ number_format($item->minimum_stock_level, 2) }}</td>
|
||||
<td class="text-right text-gray-800">{{ number_format($item->cost_price, 2) }}</td>
|
||||
<td>
|
||||
@if($item->is_active)
|
||||
<span class="badge-green">Active</span>
|
||||
@else
|
||||
<span class="badge-gray">Inactive</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="{{ route('inventory.items.edit', $item) }}" class="btn-secondary btn-sm">Edit</a>
|
||||
<form action="{{ route('inventory.items.destroy', $item) }}" method="POST"
|
||||
onsubmit="confirmDelete(this,'Delete this item?','This inventory item will be permanently removed.'); return false;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn-danger btn-sm">Delete</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="8" class="px-4 py-8 text-center text-gray-400">No items found.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if($items->hasPages())
|
||||
<div class="mt-4">{{ $items->links() }}</div>
|
||||
@endif
|
||||
|
||||
{{-- ═══════════ Import Modal ═══════════ --}}
|
||||
<div id="import-modal"
|
||||
class="hidden fixed inset-0 z-50 flex items-center justify-center"
|
||||
style="background:rgba(0,0,0,.45);">
|
||||
<div class="bg-white rounded-2xl shadow-xl w-full max-w-md mx-4" style="animation:fadeInUp .2s ease;">
|
||||
<div class="flex items-center justify-between px-6 py-4 border-b border-slate-100">
|
||||
<h2 class="text-base font-semibold text-slate-800">Import Items from Excel</h2>
|
||||
<button onclick="document.getElementById('import-modal').classList.add('hidden')"
|
||||
class="text-slate-400 hover:text-slate-600 transition-colors">
|
||||
<svg width="18" height="18" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form action="{{ route('inventory.items.import') }}" method="POST" enctype="multipart/form-data" class="p-6">
|
||||
@csrf
|
||||
|
||||
<label for="import-file"
|
||||
id="drop-zone"
|
||||
class="flex flex-col items-center justify-center gap-3 w-full border-2 border-dashed border-slate-300 rounded-xl p-8 cursor-pointer transition-colors hover:border-blue-400 hover:bg-blue-50"
|
||||
ondragover="event.preventDefault(); this.classList.add('border-blue-500','bg-blue-50')"
|
||||
ondragleave="this.classList.remove('border-blue-500','bg-blue-50')"
|
||||
ondrop="itemHandleDrop(event)">
|
||||
<svg width="36" height="36" fill="none" stroke="#94a3b8" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5"
|
||||
d="M9 13h6M12 10v6m-7 4h14a2 2 0 002-2V7a2 2 0 00-2-2h-5.586a1 1 0 01-.707-.293l-1.414-1.414A1 1 0 0010.586 3H5a2 2 0 00-2 2v14a2 2 0 002 2z"/>
|
||||
</svg>
|
||||
<div class="text-center">
|
||||
<p id="item-drop-label" class="text-sm font-medium text-slate-700">
|
||||
Click to choose or drag & drop your file
|
||||
</p>
|
||||
<p class="text-xs text-slate-400 mt-1">Accepts: .xlsx, .xls — max 10 MB</p>
|
||||
</div>
|
||||
<input id="import-file" type="file" name="file" accept=".xlsx,.xls"
|
||||
class="sr-only" onchange="itemUpdateLabel(this)">
|
||||
</label>
|
||||
|
||||
<div class="mt-4 p-3 rounded-lg bg-amber-50 border border-amber-200 text-xs text-amber-700 flex gap-2">
|
||||
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24" class="flex-shrink-0 mt-0.5">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>
|
||||
</svg>
|
||||
<span>
|
||||
Supports the <strong>Forkoll inventory format</strong> and the
|
||||
<strong>standard item template</strong>. Categories are auto-detected.
|
||||
Items marked "Not in Use" are imported as inactive. Duplicate names are skipped.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end gap-3 mt-5">
|
||||
<button type="button"
|
||||
onclick="document.getElementById('import-modal').classList.add('hidden')"
|
||||
class="btn-secondary">
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit" class="btn-primary">
|
||||
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"/>
|
||||
</svg>
|
||||
Import
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@keyframes fadeInUp {
|
||||
from { opacity:0; transform:translateY(12px); }
|
||||
to { opacity:1; transform:translateY(0); }
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
function itemUpdateLabel(input) {
|
||||
document.getElementById('item-drop-label').textContent =
|
||||
input.files.length ? input.files[0].name : 'Click to choose or drag & drop your file';
|
||||
}
|
||||
function itemHandleDrop(e) {
|
||||
e.preventDefault();
|
||||
document.getElementById('drop-zone').classList.remove('border-blue-500', 'bg-blue-50');
|
||||
const file = e.dataTransfer.files[0];
|
||||
if (!file) return;
|
||||
const input = document.getElementById('import-file');
|
||||
const dt = new DataTransfer();
|
||||
dt.items.add(file);
|
||||
input.files = dt.files;
|
||||
itemUpdateLabel(input);
|
||||
}
|
||||
document.getElementById('import-modal').addEventListener('click', function(e) {
|
||||
if (e.target === this) this.classList.add('hidden');
|
||||
});
|
||||
</script>
|
||||
@endsection
|
||||
@@ -0,0 +1,149 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Inventory Items</title>
|
||||
<style>
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
body { font-family: 'DejaVu Sans', Arial, sans-serif; font-size: 10.5px; color: #1e293b; background: #fff; }
|
||||
|
||||
.header {
|
||||
display: flex; justify-content: space-between; align-items: flex-start;
|
||||
padding: 22px 28px 14px; border-bottom: 2px solid #2563eb; margin-bottom: 18px;
|
||||
}
|
||||
.brand { display: flex; align-items: center; gap: 10px; }
|
||||
.brand-box { width:34px;height:34px;border-radius:8px;background:#2563eb;display:flex;align-items:center;justify-content:center; }
|
||||
.brand-name { font-size:16px;font-weight:700;color:#0f172a; }
|
||||
.brand-sub { font-size:9px;color:#64748b;margin-top:1px; }
|
||||
.report-info { text-align:right; }
|
||||
.report-title { font-size:14px;font-weight:700;color:#1e293b; }
|
||||
.report-meta { font-size:9px;color:#64748b;margin-top:2px; }
|
||||
|
||||
.summary { display:flex;gap:10px;margin:0 28px 16px; }
|
||||
.sc { flex:1;padding:9px 12px;background:#f1f5f9;border-radius:8px;border-left:3px solid #2563eb; }
|
||||
.sc .val { font-size:18px;font-weight:700;color:#2563eb; }
|
||||
.sc .lbl { font-size:9px;color:#64748b;margin-top:1px; }
|
||||
.sc.blue { border-color:#3b82f6; } .sc.blue .val { color:#3b82f6; }
|
||||
.sc.green { border-color:#10b981; } .sc.green .val { color:#10b981; }
|
||||
.sc.amber { border-color:#f59e0b; } .sc.amber .val { color:#f59e0b; }
|
||||
.sc.gray { border-color:#94a3b8; } .sc.gray .val { color:#94a3b8; }
|
||||
|
||||
.table-wrap { padding: 0 28px; }
|
||||
table { width:100%;border-collapse:collapse;font-size:10px; }
|
||||
thead th {
|
||||
background:#1e293b;color:#fff;font-weight:600;font-size:8.5px;
|
||||
letter-spacing:.06em;text-transform:uppercase;padding:7px 9px;text-align:left;
|
||||
}
|
||||
tbody tr:nth-child(even) { background:#f8fafc; }
|
||||
tbody td { padding:6px 9px;color:#334155;border-bottom:1px solid #e2e8f0;vertical-align:middle; }
|
||||
tbody td:nth-child(2) { font-weight:600;color:#0f172a; }
|
||||
|
||||
.badge { display:inline-block;padding:2px 6px;border-radius:20px;font-size:8px;font-weight:700; }
|
||||
.fg { background:#d1fae5;color:#065f46; }
|
||||
.rm { background:#dbeafe;color:#1e40af; }
|
||||
.wip { background:#fef3c7;color:#92400e; }
|
||||
.act { background:#d1fae5;color:#065f46; }
|
||||
.ina { background:#f1f5f9;color:#64748b; }
|
||||
|
||||
.section-row td {
|
||||
background:#f8fafc;font-weight:700;font-size:9px;
|
||||
color:#64748b;letter-spacing:.06em;text-transform:uppercase;
|
||||
padding:5px 9px;border-bottom:1px solid #e2e8f0;
|
||||
}
|
||||
|
||||
.footer { margin-top:20px;padding:10px 28px 0;border-top:1px solid #e2e8f0;display:flex;justify-content:space-between;font-size:9px;color:#94a3b8; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="header">
|
||||
<div class="brand">
|
||||
<div class="brand-box">
|
||||
<svg width="17" height="17" fill="none" stroke="#fff" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||||
d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div class="brand-name">SteelERP</div>
|
||||
<div class="brand-sub">Manufacturing & Trading</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="report-info">
|
||||
<div class="report-title">Inventory Items List</div>
|
||||
<div class="report-meta">Generated: {{ now()->format('d M Y, H:i') }}</div>
|
||||
<div class="report-meta">Total Records: {{ $items->count() }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@php
|
||||
$fg = $items->where('category', 'finished_good')->count();
|
||||
$rm = $items->where('category', 'raw_material')->count();
|
||||
$wip = $items->where('category', 'wip')->count();
|
||||
$active = $items->where('is_active', true)->count();
|
||||
$inactive= $items->where('is_active', false)->count();
|
||||
$grouped = $items->groupBy('category');
|
||||
$catLabels = ['finished_good' => 'Finished Goods', 'raw_material' => 'Raw Materials', 'wip' => 'Work In Progress'];
|
||||
@endphp
|
||||
|
||||
<div class="summary">
|
||||
<div class="sc"><div class="val">{{ $items->count() }}</div><div class="lbl">Total Items</div></div>
|
||||
<div class="sc green"><div class="val">{{ $fg }}</div><div class="lbl">Finished Goods</div></div>
|
||||
<div class="sc blue"><div class="val">{{ $rm }}</div><div class="lbl">Raw Materials</div></div>
|
||||
<div class="sc amber"><div class="val">{{ $wip }}</div><div class="lbl">WIP</div></div>
|
||||
<div class="sc gray"><div class="val">{{ $inactive }}</div><div class="lbl">Inactive</div></div>
|
||||
</div>
|
||||
|
||||
<div class="table-wrap">
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width:9%">Code</th>
|
||||
<th style="width:32%">Item Name</th>
|
||||
<th style="width:12%">Category</th>
|
||||
<th style="width:7%">UOM</th>
|
||||
<th style="width:10%;text-align:right">Min Stock</th>
|
||||
<th style="width:10%;text-align:right">Cost Price</th>
|
||||
<th style="width:8%">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($grouped as $category => $catItems)
|
||||
<tr class="section-row">
|
||||
<td colspan="7">{{ $catLabels[$category] ?? ucfirst(str_replace('_', ' ', $category)) }}</td>
|
||||
</tr>
|
||||
@foreach($catItems as $i => $item)
|
||||
<tr>
|
||||
<td style="font-family:monospace;font-size:9px;color:#94a3b8;">{{ $item->item_code }}</td>
|
||||
<td>{{ $item->item_name }}</td>
|
||||
<td>
|
||||
@if($item->category === 'finished_good') <span class="badge fg">Fin. Good</span>
|
||||
@elseif($item->category === 'raw_material') <span class="badge rm">Raw Mat.</span>
|
||||
@else <span class="badge wip">WIP</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $item->unit_of_measure }}</td>
|
||||
<td style="text-align:right">{{ number_format($item->minimum_stock_level, 2) }}</td>
|
||||
<td style="text-align:right">{{ number_format($item->cost_price, 4) }}</td>
|
||||
<td>
|
||||
@if($item->is_active) <span class="badge act">Active</span>
|
||||
@else <span class="badge ina">Inactive</span>
|
||||
@endif
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
@endforeach
|
||||
@if($items->isEmpty())
|
||||
<tr><td colspan="7" style="text-align:center;padding:20px;color:#94a3b8;">No items found.</td></tr>
|
||||
@endif
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<span>SteelERP — Confidential</span>
|
||||
<span>Exported by: {{ Auth::user()->name ?? '—' }}</span>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,77 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Manual Stock Adjustment')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="page-title">Manual Stock Adjustment</h1>
|
||||
<p class="page-subtitle"><a href="{{ route('inventory.movements.index') }}" class="text-blue-600 hover:underline">Stock Movements</a> / New</p>
|
||||
</div>
|
||||
|
||||
@if($errors->any())
|
||||
<div class="mb-4 px-4 py-3 bg-red-50 border border-red-200 rounded-lg text-sm text-red-700">
|
||||
<ul class="list-disc list-inside space-y-1">
|
||||
@foreach($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card card-body max-w-xl">
|
||||
<form action="{{ route('inventory.movements.store') }}" method="POST">
|
||||
@csrf
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
||||
|
||||
<div>
|
||||
<label class="form-label">Item <span class="text-red-500">*</span></label>
|
||||
<select name="item_id" required class="form-select">
|
||||
<option value="">-- Select Item --</option>
|
||||
@foreach($items as $item)
|
||||
<option value="{{ $item->id }}" {{ old('item_id') == $item->id ? 'selected' : '' }}>
|
||||
{{ $item->item_code }} - {{ $item->item_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Warehouse <span class="text-red-500">*</span></label>
|
||||
<select name="warehouse_id" required class="form-select">
|
||||
<option value="">-- Select Warehouse --</option>
|
||||
@foreach($warehouses as $warehouse)
|
||||
<option value="{{ $warehouse->id }}" {{ old('warehouse_id') == $warehouse->id ? 'selected' : '' }}>
|
||||
{{ $warehouse->name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Type <span class="text-red-500">*</span></label>
|
||||
<select name="type" required class="form-select">
|
||||
<option value="">-- Select Type --</option>
|
||||
<option value="in" {{ old('type') === 'in' ? 'selected' : '' }}>IN (Stock In)</option>
|
||||
<option value="out" {{ old('type') === 'out' ? 'selected' : '' }}>OUT (Stock Out)</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Quantity <span class="text-red-500">*</span></label>
|
||||
<input type="number" name="quantity" value="{{ old('quantity') }}" min="0.01" step="0.01" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Notes</label>
|
||||
<textarea name="notes" rows="2" class="form-textarea">{{ old('notes') }}</textarea>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center gap-3">
|
||||
<button type="submit" class="btn-primary">Save Adjustment</button>
|
||||
<a href="{{ route('inventory.movements.index') }}" class="btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,59 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Stock Movements')
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1 class="page-title">Stock Movements</h1>
|
||||
<p class="page-subtitle">Track all inventory movements</p>
|
||||
</div>
|
||||
<a href="{{ route('inventory.movements.create') }}" class="btn-primary">
|
||||
+ Manual Adjustment
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper overflow-x-auto">
|
||||
<table class="table-base">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th>Warehouse</th>
|
||||
<th>Type</th>
|
||||
<th class="text-right">Quantity</th>
|
||||
<th>Reference</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($movements as $movement)
|
||||
<tr>
|
||||
<td class="text-gray-800">
|
||||
<span class="font-mono text-xs text-gray-500">{{ $movement->item->item_code ?? '' }}</span>
|
||||
<span class="ml-1">{{ $movement->item->item_name ?? '' }}</span>
|
||||
</td>
|
||||
<td class="text-gray-700">{{ $movement->warehouse->name ?? '' }}</td>
|
||||
<td>
|
||||
@if(strtolower($movement->type) === 'in')
|
||||
<span class="badge-green">IN</span>
|
||||
@else
|
||||
<span class="badge-red">OUT</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="text-right font-medium text-gray-800">{{ number_format($movement->quantity, 2) }}</td>
|
||||
<td class="text-gray-500 text-xs">{{ $movement->reference ?? '-' }}</td>
|
||||
<td>{{ $movement->created_at ? $movement->created_at->format('d M Y') : '' }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="6" class="px-4 py-8 text-center text-gray-400">No movements recorded.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if($movements->hasPages())
|
||||
<div class="mt-4">{{ $movements->links() }}</div>
|
||||
@endif
|
||||
@endsection
|
||||
@@ -0,0 +1,61 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Low Stock Report')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="page-title">Low Stock Report</h1>
|
||||
<p class="page-subtitle">Items currently below their minimum stock level</p>
|
||||
</div>
|
||||
|
||||
@if(isset($stocks) && $stocks->count() > 0)
|
||||
<div class="mb-4 px-4 py-3 bg-red-50 border border-red-200 rounded-lg text-sm text-red-700 font-medium">
|
||||
{{ $stocks->count() }} item(s) are below minimum stock level. Immediate action may be required.
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="table-wrapper overflow-x-auto">
|
||||
<table class="table-base">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item Code</th>
|
||||
<th>Item Name</th>
|
||||
<th>Category</th>
|
||||
<th>Warehouse</th>
|
||||
<th class="text-right">Current Qty</th>
|
||||
<th class="text-right">Min Stock</th>
|
||||
<th class="text-right">Shortage</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($stocks as $stock)
|
||||
@php $shortage = $stock->item->minimum_stock_level - $stock->quantity; @endphp
|
||||
<tr class="bg-red-50">
|
||||
<td class="font-mono text-red-700">{{ $stock->item->item_code ?? '' }}</td>
|
||||
<td class="font-medium text-red-800">{{ $stock->item->item_name ?? '' }}</td>
|
||||
<td>
|
||||
@php
|
||||
$catLabels = ['raw_material'=>'Raw Material','wip'=>'WIP','finished_good'=>'Finished Good'];
|
||||
@endphp
|
||||
<span class="text-gray-600">{{ $catLabels[$stock->item->category ?? ''] ?? ucfirst($stock->item->category ?? '') }}</span>
|
||||
</td>
|
||||
<td class="text-gray-600">{{ $stock->warehouse->name ?? '' }}</td>
|
||||
<td class="text-right font-bold text-red-700">{{ number_format($stock->quantity, 2) }}</td>
|
||||
<td class="text-right text-gray-600">{{ number_format($stock->item->minimum_stock_level ?? 0, 2) }}</td>
|
||||
<td class="text-right font-semibold text-red-600">{{ number_format($shortage, 2) }}</td>
|
||||
<td>
|
||||
<span class="badge-red">LOW STOCK</span>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="8" class="px-4 py-8 text-center text-green-600 font-medium">
|
||||
All items are above minimum stock levels.
|
||||
</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,80 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Movement Report')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="page-title">Movement Report</h1>
|
||||
<p class="page-subtitle">View stock movements within a date range</p>
|
||||
</div>
|
||||
|
||||
<!-- Date Range Filter -->
|
||||
<div class="card card-body mb-6">
|
||||
<form method="GET" action="{{ route('inventory.reports.movement') }}" class="flex flex-wrap items-end gap-4">
|
||||
<div>
|
||||
<label class="form-label">From Date</label>
|
||||
<input type="date" name="from_date" value="{{ request('from_date') }}" class="form-input">
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">To Date</label>
|
||||
<input type="date" name="to_date" value="{{ request('to_date') }}" class="form-input">
|
||||
</div>
|
||||
<div>
|
||||
<label class="form-label">Item (optional)</label>
|
||||
<select name="item_id" class="form-select">
|
||||
<option value="">All Items</option>
|
||||
@foreach($items as $item)
|
||||
<option value="{{ $item->id }}" {{ request('item_id') == $item->id ? 'selected' : '' }}>
|
||||
{{ $item->item_code }} - {{ $item->item_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<button type="submit" class="btn-primary">Filter</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper overflow-x-auto">
|
||||
<table class="table-base">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th>Warehouse</th>
|
||||
<th>Type</th>
|
||||
<th class="text-right">Quantity</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($movements as $movement)
|
||||
<tr>
|
||||
<td class="text-gray-800">
|
||||
<span class="font-mono text-xs text-gray-500">{{ $movement->item->item_code ?? '' }}</span>
|
||||
<span class="ml-1">{{ $movement->item->item_name ?? '' }}</span>
|
||||
</td>
|
||||
<td class="text-gray-700">{{ $movement->warehouse->name ?? '' }}</td>
|
||||
<td>
|
||||
@if(strtolower($movement->type) === 'in')
|
||||
<span class="badge-green">IN</span>
|
||||
@else
|
||||
<span class="badge-red">OUT</span>
|
||||
@endif
|
||||
</td>
|
||||
<td class="text-right font-medium text-gray-800">{{ number_format($movement->quantity, 2) }}</td>
|
||||
<td>{{ $movement->created_at ? $movement->created_at->format('d M Y') : '' }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="5" class="px-4 py-8 text-center text-gray-400">No movements found for selected filters.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if(isset($movements) && $movements->hasPages())
|
||||
<div class="mt-4">{{ $movements->links() }}</div>
|
||||
@endif
|
||||
@endsection
|
||||
@@ -0,0 +1,45 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Inventory Summary')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="page-title">Inventory Summary</h1>
|
||||
<p class="page-subtitle">Current stock levels across all warehouses</p>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper overflow-x-auto">
|
||||
<table class="table-base">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item Code</th>
|
||||
<th>Item Name</th>
|
||||
<th>Warehouse</th>
|
||||
<th class="text-right">Quantity</th>
|
||||
<th class="text-right">Min Stock</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($stocks as $stock)
|
||||
@php $isLow = $stock->quantity < $stock->item->minimum_stock_level; @endphp
|
||||
<tr class="{{ $isLow ? 'bg-red-50' : '' }}">
|
||||
<td class="font-mono {{ $isLow ? 'text-red-700' : 'text-gray-700' }}">{{ $stock->item->item_code ?? '' }}</td>
|
||||
<td class="font-medium {{ $isLow ? 'text-red-800' : 'text-gray-800' }}">
|
||||
{{ $stock->item->item_name ?? '' }}
|
||||
@if($isLow)
|
||||
<span class="ml-2 px-1.5 py-0.5 text-xs font-bold rounded bg-red-200 text-red-800">LOW</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>{{ $stock->warehouse->name ?? '' }}</td>
|
||||
<td class="text-right font-semibold {{ $isLow ? 'text-red-700' : 'text-gray-800' }}">{{ number_format($stock->quantity, 2) }}</td>
|
||||
<td class="text-right text-gray-500">{{ number_format($stock->item->minimum_stock_level ?? 0, 2) }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="5" class="px-4 py-8 text-center text-gray-400">No stock data available.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,62 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Inventory Valuation')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="page-title">Inventory Valuation</h1>
|
||||
<p class="page-subtitle">Total value of current stock</p>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper overflow-x-auto">
|
||||
<table class="table-base">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item Code</th>
|
||||
<th>Item Name</th>
|
||||
<th>Category</th>
|
||||
<th class="text-right">Total Qty</th>
|
||||
<th class="text-right">Cost Price</th>
|
||||
<th class="text-right">Total Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($valuations as $row)
|
||||
<tr>
|
||||
<td class="font-mono text-gray-700">{{ $row->item_code }}</td>
|
||||
<td class="font-medium text-gray-800">{{ $row->item_name }}</td>
|
||||
<td>
|
||||
@php
|
||||
$catBadgeClass = match($row->category) {
|
||||
'raw_material' => 'badge-blue',
|
||||
'wip' => 'badge-yellow',
|
||||
'finished_good' => 'badge-green',
|
||||
default => 'badge-gray',
|
||||
};
|
||||
$catLabels = ['raw_material'=>'Raw Material','wip'=>'WIP','finished_good'=>'Finished Good'];
|
||||
@endphp
|
||||
<span class="{{ $catBadgeClass }}">
|
||||
{{ $catLabels[$row->category] ?? ucfirst($row->category) }}
|
||||
</span>
|
||||
</td>
|
||||
<td class="text-right text-gray-700">{{ number_format($row->total_qty, 2) }}</td>
|
||||
<td class="text-right text-gray-600">{{ number_format($row->cost_price, 2) }}</td>
|
||||
<td class="text-right font-semibold text-gray-800">{{ number_format($row->total_value, 2) }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="6" class="px-4 py-8 text-center text-gray-400">No valuation data available.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
@if(isset($grandTotal))
|
||||
<tfoot class="bg-blue-50 border-t-2 border-blue-200">
|
||||
<tr>
|
||||
<td colspan="5" class="px-4 py-3 text-right font-bold text-gray-800 text-sm">Grand Total</td>
|
||||
<td class="px-4 py-3 text-right font-bold text-blue-700 text-base">{{ number_format($grandTotal, 2) }}</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
@endif
|
||||
</table>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,62 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Add Warehouse')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="page-title">Add Warehouse</h1>
|
||||
<p class="page-subtitle"><a href="{{ route('inventory.warehouses.index') }}" class="text-blue-600 hover:underline">Warehouses</a> / New</p>
|
||||
</div>
|
||||
|
||||
@if($errors->any())
|
||||
<div class="mb-4 px-4 py-3 bg-red-50 border border-red-200 rounded-lg text-sm text-red-700">
|
||||
<ul class="list-disc list-inside space-y-1">
|
||||
@foreach($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card card-body max-w-xl">
|
||||
<form action="{{ route('inventory.warehouses.store') }}" method="POST">
|
||||
@csrf
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
||||
|
||||
<div>
|
||||
<label class="form-label">Code <span class="text-red-500">*</span></label>
|
||||
<input type="text" name="code" value="{{ old('code') }}" required
|
||||
placeholder="e.g. WH-01" class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Name <span class="text-red-500">*</span></label>
|
||||
<input type="text" name="name" value="{{ old('name') }}" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Location</label>
|
||||
<input type="text" name="location" value="{{ old('location') }}" class="form-input">
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Description</label>
|
||||
<textarea name="description" rows="3" class="form-textarea">{{ old('description') }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2 flex items-center gap-2">
|
||||
<input type="checkbox" name="is_active" id="is_active" value="1"
|
||||
{{ old('is_active', '1') ? 'checked' : '' }}
|
||||
class="h-4 w-4 text-blue-600 border-gray-300 rounded">
|
||||
<label for="is_active" class="form-label mb-0">Active</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center gap-3">
|
||||
<button type="submit" class="btn-primary">Save Warehouse</button>
|
||||
<a href="{{ route('inventory.warehouses.index') }}" class="btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,62 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Edit Warehouse')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="page-title">Edit Warehouse</h1>
|
||||
<p class="page-subtitle"><a href="{{ route('inventory.warehouses.index') }}" class="text-blue-600 hover:underline">Warehouses</a> / Edit</p>
|
||||
</div>
|
||||
|
||||
@if($errors->any())
|
||||
<div class="mb-4 px-4 py-3 bg-red-50 border border-red-200 rounded-lg text-sm text-red-700">
|
||||
<ul class="list-disc list-inside space-y-1">
|
||||
@foreach($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card card-body max-w-xl">
|
||||
<form action="{{ route('inventory.warehouses.update', $warehouse) }}" method="POST">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
||||
|
||||
<div>
|
||||
<label class="form-label">Code <span class="text-red-500">*</span></label>
|
||||
<input type="text" name="code" value="{{ old('code', $warehouse->code) }}" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Name <span class="text-red-500">*</span></label>
|
||||
<input type="text" name="name" value="{{ old('name', $warehouse->name) }}" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Location</label>
|
||||
<input type="text" name="location" value="{{ old('location', $warehouse->location) }}" class="form-input">
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Description</label>
|
||||
<textarea name="description" rows="3" class="form-textarea">{{ old('description', $warehouse->description) }}</textarea>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2 flex items-center gap-2">
|
||||
<input type="checkbox" name="is_active" id="is_active" value="1"
|
||||
{{ old('is_active', $warehouse->is_active) ? 'checked' : '' }}
|
||||
class="h-4 w-4 text-blue-600 border-gray-300 rounded">
|
||||
<label for="is_active" class="form-label mb-0">Active</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center gap-3">
|
||||
<button type="submit" class="btn-primary">Update Warehouse</button>
|
||||
<a href="{{ route('inventory.warehouses.index') }}" class="btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,64 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Warehouses')
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1 class="page-title">Warehouses</h1>
|
||||
<p class="page-subtitle">Manage storage locations</p>
|
||||
</div>
|
||||
<a href="{{ route('inventory.warehouses.create') }}" class="btn-primary">
|
||||
+ Add Warehouse
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper overflow-x-auto">
|
||||
<table class="table-base">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Code</th>
|
||||
<th>Name</th>
|
||||
<th>Location</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($warehouses as $warehouse)
|
||||
<tr>
|
||||
<td class="font-mono text-gray-700">{{ $warehouse->code }}</td>
|
||||
<td class="font-medium text-gray-800">{{ $warehouse->name }}</td>
|
||||
<td>{{ $warehouse->location }}</td>
|
||||
<td>
|
||||
@if($warehouse->is_active)
|
||||
<span class="badge-green">Active</span>
|
||||
@else
|
||||
<span class="badge-gray">Inactive</span>
|
||||
@endif
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="{{ route('inventory.warehouses.edit', $warehouse) }}" class="btn-secondary btn-sm">Edit</a>
|
||||
<form action="{{ route('inventory.warehouses.destroy', $warehouse) }}" method="POST"
|
||||
onsubmit="confirmDelete(this,'Delete this warehouse?','This warehouse will be permanently removed.'); return false;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn-danger btn-sm">Delete</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="5" class="px-4 py-8 text-center text-gray-400">No warehouses found.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if($warehouses->hasPages())
|
||||
<div class="mt-4">{{ $warehouses->links() }}</div>
|
||||
@endif
|
||||
@endsection
|
||||
Reference in new issue
Block a user