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,69 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Add BOM Entry')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="page-title">Add BOM Entry</h1>
|
||||
<p class="page-subtitle"><a href="{{ route('production.bom.index') }}" class="text-blue-600 hover:underline">Bill of Materials</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('production.bom.store') }}" method="POST">
|
||||
@csrf
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Product (Finished Good) <span class="text-red-500">*</span></label>
|
||||
<select name="product_id" required class="form-select">
|
||||
<option value="">-- Select Product --</option>
|
||||
@foreach($products as $product)
|
||||
<option value="{{ $product->id }}" {{ old('product_id') == $product->id ? 'selected' : '' }}>
|
||||
{{ $product->item_code }} - {{ $product->item_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Raw Material <span class="text-red-500">*</span></label>
|
||||
<select name="raw_material_id" required class="form-select">
|
||||
<option value="">-- Select Raw Material --</option>
|
||||
@foreach($rawMaterials as $material)
|
||||
<option value="{{ $material->id }}" {{ old('raw_material_id') == $material->id ? 'selected' : '' }}>
|
||||
{{ $material->item_code }} - {{ $material->item_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Quantity Required <span class="text-red-500">*</span></label>
|
||||
<input type="number" name="quantity_required" value="{{ old('quantity_required') }}" min="0.001" step="0.001" required class="form-input">
|
||||
</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" class="form-input">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center gap-3">
|
||||
<button type="submit" class="btn-primary">Save BOM Entry</button>
|
||||
<a href="{{ route('production.bom.index') }}" class="btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,69 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Edit BOM Entry')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="page-title">Edit BOM Entry</h1>
|
||||
<p class="page-subtitle"><a href="{{ route('production.bom.index') }}" class="text-blue-600 hover:underline">Bill of Materials</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('production.bom.update', $bom) }}" method="POST">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Product (Finished Good) <span class="text-red-500">*</span></label>
|
||||
<select name="product_id" required class="form-select">
|
||||
<option value="">-- Select Product --</option>
|
||||
@foreach($products as $product)
|
||||
<option value="{{ $product->id }}" {{ old('product_id', $bom->product_id) == $product->id ? 'selected' : '' }}>
|
||||
{{ $product->item_code }} - {{ $product->item_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Raw Material <span class="text-red-500">*</span></label>
|
||||
<select name="raw_material_id" required class="form-select">
|
||||
<option value="">-- Select Raw Material --</option>
|
||||
@foreach($rawMaterials as $material)
|
||||
<option value="{{ $material->id }}" {{ old('raw_material_id', $bom->raw_material_id) == $material->id ? 'selected' : '' }}>
|
||||
{{ $material->item_code }} - {{ $material->item_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Quantity Required <span class="text-red-500">*</span></label>
|
||||
<input type="number" name="quantity_required" value="{{ old('quantity_required', $bom->quantity_required) }}" min="0.001" step="0.001" required class="form-input">
|
||||
</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', $bom->unit_of_measure) }}" required class="form-input">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center gap-3">
|
||||
<button type="submit" class="btn-primary">Update BOM Entry</button>
|
||||
<a href="{{ route('production.bom.index') }}" class="btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,65 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Bill of Materials')
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1 class="page-title">Bill of Materials</h1>
|
||||
<p class="page-subtitle">Define material requirements for each product</p>
|
||||
</div>
|
||||
<a href="{{ route('production.bom.create') }}" class="btn-primary">
|
||||
+ Add BOM Entry
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@php $currentProduct = null; @endphp
|
||||
@forelse($bomEntries as $entry)
|
||||
@if($currentProduct !== ($entry->product->item_name ?? ''))
|
||||
@if($currentProduct !== null)
|
||||
</tbody></table></div>
|
||||
@endif
|
||||
@php $currentProduct = $entry->product->item_name ?? ''; @endphp
|
||||
<div class="table-wrapper overflow-hidden mb-4">
|
||||
<div class="px-6 py-3 bg-blue-50 border-b border-blue-100 flex items-center justify-between">
|
||||
<h3 class="font-semibold text-blue-800 text-sm">{{ $currentProduct }}</h3>
|
||||
<span class="text-xs text-blue-500">{{ $entry->product->item_code ?? '' }}</span>
|
||||
</div>
|
||||
<table class="table-base">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Raw Material</th>
|
||||
<th class="text-right">Qty Required</th>
|
||||
<th>UOM</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@endif
|
||||
<tr>
|
||||
<td class="text-gray-800">{{ $entry->rawMaterial->item_name ?? '' }}</td>
|
||||
<td class="text-right text-gray-700">{{ number_format($entry->quantity_required, 2) }}</td>
|
||||
<td class="text-gray-500">{{ $entry->unit_of_measure }}</td>
|
||||
<td>
|
||||
<div class="flex items-center gap-2">
|
||||
<a href="{{ route('production.bom.edit', $entry) }}" class="btn-secondary btn-sm">Edit</a>
|
||||
<form action="{{ route('production.bom.destroy', $entry) }}" method="POST"
|
||||
onsubmit="confirmDelete(this,'Delete this BOM entry?','This bill of materials entry will be permanently removed.'); return false;">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
<button type="submit" class="btn-danger btn-sm">Delete</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<div class="card card-body text-center text-gray-400">
|
||||
No BOM entries found. <a href="{{ route('production.bom.create') }}" class="text-blue-600 hover:underline">Add the first one</a>.
|
||||
</div>
|
||||
@endforelse
|
||||
@if($currentProduct !== null && $bomEntries->count())
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endif
|
||||
@endsection
|
||||
@@ -0,0 +1,133 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Material Issues')
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1 class="page-title">Material Issues</h1>
|
||||
<p class="page-subtitle">Record materials issued for production</p>
|
||||
</div>
|
||||
<a href="{{ route('production.material-issues.create') }}" class="btn-primary">
|
||||
+ Issue Material
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper overflow-x-auto">
|
||||
<table class="table-base">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Production Order</th>
|
||||
<th>Item</th>
|
||||
<th>Warehouse</th>
|
||||
<th class="text-right">Quantity</th>
|
||||
<th>Issue Date</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($materialIssues as $issue)
|
||||
<tr>
|
||||
<td class="font-mono text-gray-700">
|
||||
<a href="{{ route('production.orders.show', $issue->productionOrder) }}" class="text-blue-600 hover:underline">
|
||||
{{ $issue->productionOrder->order_number ?? 'PRD-' . str_pad($issue->production_order_id, 5, '0', STR_PAD_LEFT) }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-gray-800">{{ $issue->item->item_name ?? '' }}</td>
|
||||
<td>{{ $issue->warehouse->name ?? '' }}</td>
|
||||
<td class="text-right text-gray-700">{{ number_format($issue->quantity, 2) }}</td>
|
||||
<td>{{ $issue->issue_date ? \Carbon\Carbon::parse($issue->issue_date)->format('d M Y') : '' }}</td>
|
||||
<td class="text-gray-500 text-xs">{{ $issue->notes ?? '-' }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="6" class="px-4 py-8 text-center text-gray-400">No material issues found.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if($materialIssues->hasPages())
|
||||
<div class="mt-4">{{ $materialIssues->links() }}</div>
|
||||
@endif
|
||||
|
||||
<!-- Inline Create Form -->
|
||||
<div class="mt-8">
|
||||
<h2 class="text-lg font-bold text-gray-800 mb-4">Issue New Material</h2>
|
||||
|
||||
@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('production.material-issues.store') }}" method="POST">
|
||||
@csrf
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
||||
|
||||
<div>
|
||||
<label class="form-label">Production Order <span class="text-red-500">*</span></label>
|
||||
<select name="production_order_id" required class="form-select">
|
||||
<option value="">-- Select Order --</option>
|
||||
@foreach($productionOrders as $po)
|
||||
<option value="{{ $po->id }}" {{ (old('production_order_id', request('production_order_id'))) == $po->id ? 'selected' : '' }}>
|
||||
{{ $po->order_number ?? 'PRD-' . str_pad($po->id, 5, '0', STR_PAD_LEFT) }} - {{ $po->product->item_name ?? '' }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<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">Quantity <span class="text-red-500">*</span></label>
|
||||
<input type="number" name="quantity" value="{{ old('quantity') }}" min="0.001" step="0.001" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Issue Date <span class="text-red-500">*</span></label>
|
||||
<input type="date" name="issue_date" value="{{ old('issue_date', date('Y-m-d')) }}" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Notes</label>
|
||||
<input type="text" name="notes" value="{{ old('notes') }}" class="form-input">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<button type="submit" class="btn-primary">Issue Material</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,61 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'New Production Order')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="page-title">New Production Order</h1>
|
||||
<p class="page-subtitle"><a href="{{ route('production.orders.index') }}" class="text-blue-600 hover:underline">Production Orders</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('production.orders.store') }}" method="POST">
|
||||
@csrf
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Product (Finished Good) <span class="text-red-500">*</span></label>
|
||||
<select name="product_id" required class="form-select">
|
||||
<option value="">-- Select Product --</option>
|
||||
@foreach($products as $product)
|
||||
<option value="{{ $product->id }}" {{ old('product_id') == $product->id ? 'selected' : '' }}>
|
||||
{{ $product->item_code }} - {{ $product->item_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Quantity to Produce <span class="text-red-500">*</span></label>
|
||||
<input type="number" name="quantity_to_produce" value="{{ old('quantity_to_produce') }}" min="0.01" step="0.01" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Production Date <span class="text-red-500">*</span></label>
|
||||
<input type="date" name="production_date" value="{{ old('production_date', date('Y-m-d')) }}" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Notes</label>
|
||||
<textarea name="notes" rows="3" class="form-textarea">{{ old('notes') }}</textarea>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center gap-3">
|
||||
<button type="submit" class="btn-primary">Create Order</button>
|
||||
<a href="{{ route('production.orders.index') }}" class="btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,62 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Edit Production Order')
|
||||
|
||||
@section('content')
|
||||
<div class="mb-6">
|
||||
<h1 class="page-title">Edit Production Order</h1>
|
||||
<p class="page-subtitle"><a href="{{ route('production.orders.index') }}" class="text-blue-600 hover:underline">Production Orders</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('production.orders.update', $order) }}" method="POST">
|
||||
@csrf
|
||||
@method('PUT')
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Product (Finished Good) <span class="text-red-500">*</span></label>
|
||||
<select name="product_id" required class="form-select">
|
||||
<option value="">-- Select Product --</option>
|
||||
@foreach($products as $product)
|
||||
<option value="{{ $product->id }}" {{ old('product_id', $order->product_id) == $product->id ? 'selected' : '' }}>
|
||||
{{ $product->item_code }} - {{ $product->item_name }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Quantity to Produce <span class="text-red-500">*</span></label>
|
||||
<input type="number" name="quantity_to_produce" value="{{ old('quantity_to_produce', $order->quantity_to_produce) }}" min="0.01" step="0.01" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Production Date <span class="text-red-500">*</span></label>
|
||||
<input type="date" name="production_date" value="{{ old('production_date', $order->production_date ? \Carbon\Carbon::parse($order->production_date)->format('Y-m-d') : '') }}" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div class="sm:col-span-2">
|
||||
<label class="form-label">Notes</label>
|
||||
<textarea name="notes" rows="3" class="form-textarea">{{ old('notes', $order->notes) }}</textarea>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-6 flex items-center gap-3">
|
||||
<button type="submit" class="btn-primary">Update Order</button>
|
||||
<a href="{{ route('production.orders.show', $order) }}" class="btn-secondary">Cancel</a>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -0,0 +1,82 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Production Orders')
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1 class="page-title">Production Orders</h1>
|
||||
<p class="page-subtitle">Manage manufacturing orders</p>
|
||||
</div>
|
||||
<a href="{{ route('production.orders.create') }}" class="btn-primary">
|
||||
+ New Order
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper overflow-x-auto">
|
||||
<table class="table-base">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order #</th>
|
||||
<th>Product</th>
|
||||
<th class="text-right">Qty to Produce</th>
|
||||
<th class="text-right">Produced</th>
|
||||
<th>Date</th>
|
||||
<th>Status</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($orders as $order)
|
||||
<tr>
|
||||
<td class="font-mono text-gray-700">{{ $order->order_number ?? 'PRD-' . str_pad($order->id, 5, '0', STR_PAD_LEFT) }}</td>
|
||||
<td class="font-medium text-gray-800">{{ $order->product->item_name ?? '' }}</td>
|
||||
<td class="text-right text-gray-700">{{ number_format($order->quantity_to_produce, 2) }}</td>
|
||||
<td class="text-right text-gray-700">{{ number_format($order->quantity_produced ?? 0, 2) }}</td>
|
||||
<td>{{ $order->production_date ? \Carbon\Carbon::parse($order->production_date)->format('d M Y') : '' }}</td>
|
||||
<td>
|
||||
@php
|
||||
$badgeClass = match($order->status ?? 'pending') {
|
||||
'pending' => 'badge-yellow',
|
||||
'in_progress' => 'badge-blue',
|
||||
'completed' => 'badge-green',
|
||||
'cancelled' => 'badge-red',
|
||||
default => 'badge-gray',
|
||||
};
|
||||
@endphp
|
||||
<span class="{{ $badgeClass }}">{{ ucwords(str_replace('_', ' ', $order->status ?? 'pending')) }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<div class="flex items-center gap-2 flex-wrap">
|
||||
<a href="{{ route('production.orders.show', $order) }}" class="btn-primary btn-sm">View</a>
|
||||
@if($order->status === 'pending')
|
||||
<form action="{{ route('production.orders.start', $order) }}" method="POST">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<button type="submit" class="btn-primary btn-sm">Start</button>
|
||||
</form>
|
||||
@endif
|
||||
@if($order->status === 'in_progress')
|
||||
<form action="{{ route('production.orders.complete', $order) }}" method="POST">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<button type="submit" class="btn-success btn-sm">Complete</button>
|
||||
</form>
|
||||
@endif
|
||||
<a href="{{ route('production.orders.edit', $order) }}" class="btn-secondary btn-sm">Edit</a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="7" class="px-4 py-8 text-center text-gray-400">No production orders found.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if($orders->hasPages())
|
||||
<div class="mt-4">{{ $orders->links() }}</div>
|
||||
@endif
|
||||
@endsection
|
||||
@@ -0,0 +1,168 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Production Order')
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1 class="page-title">Production Order</h1>
|
||||
<p class="page-subtitle">
|
||||
<a href="{{ route('production.orders.index') }}" class="text-blue-600 hover:underline">Production Orders</a>
|
||||
/ {{ $order->order_number ?? 'PRD-' . str_pad($order->id, 5, '0', STR_PAD_LEFT) }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<a href="{{ route('production.orders.edit', $order) }}" class="btn-secondary">Edit</a>
|
||||
@if($order->status === 'pending')
|
||||
<form action="{{ route('production.orders.start', $order) }}" method="POST">
|
||||
@csrf @method('PATCH')
|
||||
<button type="submit" class="btn-primary">Start Production</button>
|
||||
</form>
|
||||
@endif
|
||||
@if($order->status === 'in_progress')
|
||||
<form action="{{ route('production.orders.complete', $order) }}" method="POST">
|
||||
@csrf @method('PATCH')
|
||||
<button type="submit" class="btn-success">Mark Complete</button>
|
||||
</form>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Order Details -->
|
||||
<div class="grid grid-cols-1 lg:grid-cols-2 gap-4 mb-6">
|
||||
<div class="bg-white rounded-xl border border-gray-200 p-6 shadow-sm">
|
||||
<h2 class="text-sm font-semibold text-gray-500 uppercase tracking-wider mb-4">Order Details</h2>
|
||||
<dl class="space-y-3 text-sm">
|
||||
<div class="flex justify-between">
|
||||
<dt class="text-gray-500">Order Number</dt>
|
||||
<dd class="font-mono font-semibold text-gray-800">{{ $order->order_number ?? 'PRD-' . str_pad($order->id, 5, '0', STR_PAD_LEFT) }}</dd>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<dt class="text-gray-500">Product</dt>
|
||||
<dd class="font-medium text-gray-800">{{ $order->product->item_name ?? '' }}</dd>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<dt class="text-gray-500">Qty to Produce</dt>
|
||||
<dd class="text-gray-800">{{ number_format($order->quantity_to_produce, 2) }}</dd>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<dt class="text-gray-500">Qty Produced</dt>
|
||||
<dd class="text-gray-800">{{ number_format($order->quantity_produced ?? 0, 2) }}</dd>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<dt class="text-gray-500">Production Date</dt>
|
||||
<dd class="text-gray-800">{{ $order->production_date ? \Carbon\Carbon::parse($order->production_date)->format('d M Y') : '-' }}</dd>
|
||||
</div>
|
||||
<div class="flex justify-between">
|
||||
<dt class="text-gray-500">Status</dt>
|
||||
<dd>
|
||||
@php
|
||||
$badgeClass = match($order->status ?? 'pending') {
|
||||
'pending' => 'badge-yellow',
|
||||
'in_progress' => 'badge-blue',
|
||||
'completed' => 'badge-green',
|
||||
default => 'badge-gray',
|
||||
};
|
||||
@endphp
|
||||
<span class="{{ $badgeClass }}">{{ ucwords(str_replace('_', ' ', $order->status ?? 'pending')) }}</span>
|
||||
</dd>
|
||||
</div>
|
||||
@if($order->notes)
|
||||
<div>
|
||||
<dt class="text-gray-500">Notes</dt>
|
||||
<dd class="text-gray-700 mt-1">{{ $order->notes }}</dd>
|
||||
</div>
|
||||
@endif
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<!-- BOM for product -->
|
||||
<div class="bg-white rounded-xl border border-gray-200 p-6 shadow-sm">
|
||||
<h2 class="text-sm font-semibold text-gray-500 uppercase tracking-wider mb-4">Bill of Materials</h2>
|
||||
@if(isset($bom) && $bom->count())
|
||||
<table class="min-w-full text-sm">
|
||||
<thead>
|
||||
<tr class="border-b border-gray-200">
|
||||
<th class="pb-2 text-left font-semibold text-gray-600">Material</th>
|
||||
<th class="pb-2 text-right font-semibold text-gray-600">Qty Required</th>
|
||||
<th class="pb-2 text-left font-semibold text-gray-600">UOM</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="divide-y divide-gray-100">
|
||||
@foreach($bom as $bomItem)
|
||||
<tr>
|
||||
<td class="py-2 text-gray-800">{{ $bomItem->rawMaterial->item_name ?? '' }}</td>
|
||||
<td class="py-2 text-right text-gray-700">{{ number_format($bomItem->quantity_required, 2) }}</td>
|
||||
<td class="py-2 text-gray-500 pl-2">{{ $bomItem->unit_of_measure }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
@else
|
||||
<p class="text-sm text-gray-400">No BOM defined for this product.</p>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Material Issues -->
|
||||
@if(isset($materialIssues) && $materialIssues->count())
|
||||
<div class="bg-white rounded-xl border border-gray-200 shadow-sm overflow-hidden mb-6">
|
||||
<div class="px-6 py-4 border-b border-gray-200 flex items-center justify-between">
|
||||
<h2 class="text-base font-semibold text-gray-700">Material Issues</h2>
|
||||
<a href="{{ route('production.material-issues.create', ['production_order_id' => $order->id]) }}"
|
||||
class="btn-primary btn-sm">+ Issue Material</a>
|
||||
</div>
|
||||
<table class="table-base">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th>Warehouse</th>
|
||||
<th class="text-right">Qty</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($materialIssues as $issue)
|
||||
<tr>
|
||||
<td class="text-gray-800">{{ $issue->item->item_name ?? '' }}</td>
|
||||
<td>{{ $issue->warehouse->name ?? '' }}</td>
|
||||
<td class="text-right text-gray-700">{{ number_format($issue->quantity, 2) }}</td>
|
||||
<td>{{ $issue->issue_date ? \Carbon\Carbon::parse($issue->issue_date)->format('d M Y') : '' }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Production Output -->
|
||||
@if(isset($outputs) && $outputs->count())
|
||||
<div class="bg-white rounded-xl border border-gray-200 shadow-sm overflow-hidden mb-6">
|
||||
<div class="px-6 py-4 border-b border-gray-200 flex items-center justify-between">
|
||||
<h2 class="text-base font-semibold text-gray-700">Production Output</h2>
|
||||
<a href="{{ route('production.outputs.create', ['production_order_id' => $order->id]) }}"
|
||||
class="btn-primary btn-sm">+ Record Output</a>
|
||||
</div>
|
||||
<table class="table-base">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th>Warehouse</th>
|
||||
<th class="text-right">Qty</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($outputs as $output)
|
||||
<tr>
|
||||
<td class="text-gray-800">{{ $output->item->item_name ?? '' }}</td>
|
||||
<td>{{ $output->warehouse->name ?? '' }}</td>
|
||||
<td class="text-right text-gray-700">{{ number_format($output->quantity, 2) }}</td>
|
||||
<td>{{ $output->output_date ? \Carbon\Carbon::parse($output->output_date)->format('d M Y') : '' }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endif
|
||||
@endsection
|
||||
@@ -0,0 +1,133 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('title', 'Production Output')
|
||||
|
||||
@section('content')
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h1 class="page-title">Production Output</h1>
|
||||
<p class="page-subtitle">Record finished goods produced</p>
|
||||
</div>
|
||||
<a href="{{ route('production.outputs.create') }}" class="btn-primary">
|
||||
+ Record Output
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="table-wrapper overflow-x-auto">
|
||||
<table class="table-base">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Production Order</th>
|
||||
<th>Item</th>
|
||||
<th>Warehouse</th>
|
||||
<th class="text-right">Quantity</th>
|
||||
<th>Output Date</th>
|
||||
<th>Notes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($outputs as $output)
|
||||
<tr>
|
||||
<td class="font-mono text-gray-700">
|
||||
<a href="{{ route('production.orders.show', $output->productionOrder) }}" class="text-blue-600 hover:underline">
|
||||
{{ $output->productionOrder->order_number ?? 'PRD-' . str_pad($output->production_order_id, 5, '0', STR_PAD_LEFT) }}
|
||||
</a>
|
||||
</td>
|
||||
<td class="text-gray-800">{{ $output->item->item_name ?? '' }}</td>
|
||||
<td>{{ $output->warehouse->name ?? '' }}</td>
|
||||
<td class="text-right font-medium text-gray-800">{{ number_format($output->quantity, 2) }}</td>
|
||||
<td>{{ $output->output_date ? \Carbon\Carbon::parse($output->output_date)->format('d M Y') : '' }}</td>
|
||||
<td class="text-gray-500 text-xs">{{ $output->notes ?? '-' }}</td>
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="6" class="px-4 py-8 text-center text-gray-400">No production outputs recorded.</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@if($outputs->hasPages())
|
||||
<div class="mt-4">{{ $outputs->links() }}</div>
|
||||
@endif
|
||||
|
||||
<!-- Inline Create Form -->
|
||||
<div class="mt-8">
|
||||
<h2 class="text-lg font-bold text-gray-800 mb-4">Record Production Output</h2>
|
||||
|
||||
@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('production.outputs.store') }}" method="POST">
|
||||
@csrf
|
||||
<div class="grid grid-cols-1 gap-5 sm:grid-cols-2">
|
||||
|
||||
<div>
|
||||
<label class="form-label">Production Order <span class="text-red-500">*</span></label>
|
||||
<select name="production_order_id" required class="form-select">
|
||||
<option value="">-- Select Order --</option>
|
||||
@foreach($productionOrders as $po)
|
||||
<option value="{{ $po->id }}" {{ (old('production_order_id', request('production_order_id'))) == $po->id ? 'selected' : '' }}>
|
||||
{{ $po->order_number ?? 'PRD-' . str_pad($po->id, 5, '0', STR_PAD_LEFT) }} - {{ $po->product->item_name ?? '' }}
|
||||
</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Item (Finished Good) <span class="text-red-500">*</span></label>
|
||||
<select name="item_id" required class="form-select">
|
||||
<option value="">-- Select Item --</option>
|
||||
@foreach($products as $product)
|
||||
<option value="{{ $product->id }}" {{ old('item_id') == $product->id ? 'selected' : '' }}>
|
||||
{{ $product->item_code }} - {{ $product->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">Quantity <span class="text-red-500">*</span></label>
|
||||
<input type="number" name="quantity" value="{{ old('quantity') }}" min="0.001" step="0.001" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Output Date <span class="text-red-500">*</span></label>
|
||||
<input type="date" name="output_date" value="{{ old('output_date', date('Y-m-d')) }}" required class="form-input">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="form-label">Notes</label>
|
||||
<input type="text" name="notes" value="{{ old('notes') }}" class="form-input">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="mt-6">
|
||||
<button type="submit" class="btn-primary">Record Output</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
Reference in new issue
Block a user