chore: initial commit of existing codebase

This commit is contained in:
ghassan committed 2026-05-19 12:40:08 +03:00
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 &amp; 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