298 lines
19 KiB
PHP
298 lines
19 KiB
PHP
<div class="space-y-6">
|
|
@if($showHistory ?? false)
|
|
<livewire:inventory.parts.history :part="$part" />
|
|
@else
|
|
<!-- Enhanced Header with Status -->
|
|
<div class="bg-white dark:bg-zinc-800 rounded-lg border border-zinc-200 dark:border-zinc-700 p-6">
|
|
<div class="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4">
|
|
<div class="flex-1">
|
|
<div class="flex items-center space-x-3 mb-2">
|
|
<h1 class="text-3xl font-bold text-zinc-900 dark:text-white dark:text-white">{{ $part->name }}</h1>
|
|
@if($part->quantity_on_hand <= 0)
|
|
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-200">
|
|
Out of Stock
|
|
</span>
|
|
@elseif($part->quantity_on_hand <= $part->minimum_stock_level)
|
|
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-orange-100 text-orange-800 dark:bg-orange-900 dark:text-orange-200">
|
|
Low Stock
|
|
</span>
|
|
@else
|
|
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-200">
|
|
In Stock
|
|
</span>
|
|
@endif
|
|
</div>
|
|
<div class="flex items-center space-x-4 text-sm text-zinc-600 dark:text-zinc-400 dark:text-gray-400">
|
|
<span class="font-mono font-semibold">{{ $part->part_number }}</span>
|
|
@if($part->barcode)
|
|
<span class="font-mono">{{ $part->barcode }}</span>
|
|
@endif
|
|
@if($part->category)
|
|
<span class="px-2 py-1 bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 rounded-md text-xs font-medium">
|
|
{{ ucfirst(str_replace('_', ' ', $part->category)) }}
|
|
</span>
|
|
@endif
|
|
</div>
|
|
@if($part->description)
|
|
<p class="mt-3 text-gray-700 dark:text-gray-300">{{ $part->description }}</p>
|
|
@endif
|
|
</div>
|
|
|
|
<div class="flex flex-col sm:flex-row items-start sm:items-center space-y-2 sm:space-y-0 sm:space-x-3">
|
|
<flux:button wire:click="edit" variant="primary" size="sm" icon="pencil">
|
|
Edit Part
|
|
</flux:button>
|
|
<flux:button wire:click="showHistory" variant="outline" size="sm" icon="clock">
|
|
View History
|
|
</flux:button>
|
|
<flux:button wire:navigate href="{{ route('inventory.stock-movements.create', ['part_id' => $part->id]) }}" variant="outline" size="sm" icon="arrow-path">
|
|
Record Movement
|
|
</flux:button>
|
|
<flux:button wire:click="goBack" variant="ghost" size="sm" icon="arrow-left">
|
|
Back
|
|
</flux:button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Quick Stats Cards -->
|
|
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
|
|
<div class="bg-gradient-to-r from-blue-50 to-blue-100 dark:from-blue-900/20 dark:to-blue-800/20 rounded-lg p-6 border border-blue-200 dark:border-blue-700">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm font-medium text-blue-800 dark:text-blue-200">Current Stock</p>
|
|
<p class="text-3xl font-bold text-blue-900 dark:text-blue-100">{{ number_format($part->quantity_on_hand) }}</p>
|
|
@if($part->unit_of_measurement)
|
|
<p class="text-xs text-blue-600 dark:text-blue-300">{{ $part->unit_of_measurement }}</p>
|
|
@endif
|
|
</div>
|
|
<div class="p-3 bg-blue-500 rounded-lg">
|
|
<flux:icon.cube class="w-6 h-6 text-white" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-gradient-to-r from-green-50 to-green-100 dark:from-green-900/20 dark:to-green-800/20 rounded-lg p-6 border border-green-200 dark:border-green-700">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm font-medium text-green-800 dark:text-green-200">Sell Price</p>
|
|
<p class="text-3xl font-bold text-green-900 dark:text-green-100">${{ number_format($part->sell_price, 2) }}</p>
|
|
@if($part->sell_price > $part->cost_price)
|
|
<p class="text-xs text-green-600 dark:text-green-300">
|
|
{{ number_format((($part->sell_price - $part->cost_price) / $part->cost_price) * 100, 1) }}% margin
|
|
</p>
|
|
@endif
|
|
</div>
|
|
<div class="p-3 bg-green-500 rounded-lg">
|
|
<flux:icon.currency-dollar class="w-6 h-6 text-white" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-gradient-to-r from-orange-50 to-orange-100 dark:from-orange-900/20 dark:to-orange-800/20 rounded-lg p-6 border border-orange-200 dark:border-orange-700">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm font-medium text-orange-800 dark:text-orange-200">Cost Price</p>
|
|
<p class="text-3xl font-bold text-orange-900 dark:text-orange-100">${{ number_format($part->cost_price, 2) }}</p>
|
|
<p class="text-xs text-orange-600 dark:text-orange-300">Per unit</p>
|
|
</div>
|
|
<div class="p-3 bg-orange-500 rounded-lg">
|
|
<flux:icon.calculator class="w-6 h-6 text-white" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="bg-gradient-to-r from-purple-50 to-purple-100 dark:from-purple-900/20 dark:to-purple-800/20 rounded-lg p-6 border border-purple-200 dark:border-purple-700">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<p class="text-sm font-medium text-purple-800 dark:text-purple-200">Total Value</p>
|
|
<p class="text-3xl font-bold text-purple-900 dark:text-purple-100">${{ number_format($part->quantity_on_hand * $part->cost_price, 2) }}</p>
|
|
<p class="text-xs text-purple-600 dark:text-purple-300">Inventory value</p>
|
|
</div>
|
|
<div class="p-3 bg-purple-500 rounded-lg">
|
|
<flux:icon.chart-bar class="w-6 h-6 text-white" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Part Details -->
|
|
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
<!-- Main Information -->
|
|
<div class="lg:col-span-2">
|
|
<div class="bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg p-6">
|
|
<h3 class="text-lg font-medium text-zinc-900 dark:text-white dark:text-white mb-4">Part Information</h3>
|
|
|
|
<dl class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
<div>
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400">Name</dt>
|
|
<dd class="mt-1 text-sm text-zinc-900 dark:text-white dark:text-white">{{ $part->name }}</dd>
|
|
</div>
|
|
|
|
<div>
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400">Part Number</dt>
|
|
<dd class="mt-1 text-sm text-zinc-900 dark:text-white dark:text-white">{{ $part->part_number }}</dd>
|
|
</div>
|
|
|
|
<div>
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400">Category</dt>
|
|
<dd class="mt-1 text-sm text-zinc-900 dark:text-white dark:text-white">{{ $part->category ?? 'N/A' }}</dd>
|
|
</div>
|
|
|
|
<div>
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400">Brand</dt>
|
|
<dd class="mt-1 text-sm text-zinc-900 dark:text-white dark:text-white">{{ $part->brand ?? 'N/A' }}</dd>
|
|
</div>
|
|
|
|
<div>
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400">Supplier</dt>
|
|
<dd class="mt-1 text-sm text-zinc-900 dark:text-white dark:text-white">{{ $part->supplier->name ?? 'N/A' }}</dd>
|
|
</div>
|
|
|
|
<div>
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400">Location</dt>
|
|
<dd class="mt-1 text-sm text-zinc-900 dark:text-white dark:text-white">{{ $part->location ?? 'N/A' }}</dd>
|
|
</div>
|
|
|
|
<div class="sm:col-span-2">
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400">Description</dt>
|
|
<dd class="mt-1 text-sm text-zinc-900 dark:text-white dark:text-white">{{ $part->description ?? 'No description available' }}</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
|
|
<!-- Recent Stock Movements -->
|
|
<div class="bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg p-6 mt-6">
|
|
<h3 class="text-lg font-medium text-zinc-900 dark:text-white dark:text-white mb-4">Recent Stock Movements</h3>
|
|
|
|
@if($part->stockMovements->count() > 0)
|
|
<div class="overflow-hidden">
|
|
<table class="min-w-full divide-y divide-zinc-200 dark:divide-zinc-700">
|
|
<thead>
|
|
<tr>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400 uppercase tracking-wider">Date</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400 uppercase tracking-wider">Type</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400 uppercase tracking-wider">Quantity</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400 uppercase tracking-wider">User</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400 uppercase tracking-wider">Notes</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-zinc-200 dark:divide-zinc-700">
|
|
@foreach($part->stockMovements->take(5) as $movement)
|
|
<tr>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-zinc-900 dark:text-white dark:text-white">
|
|
{{ $movement->created_at->format('M d, Y g:i A') }}
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap">
|
|
<flux:badge size="sm" color="{{ $movement->movement_type === 'in' ? 'green' : 'red' }}">
|
|
{{ ucfirst($movement->movement_type) }}
|
|
</flux:badge>
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium">
|
|
<span class="{{ $movement->movement_type === 'in' ? 'text-green-600 dark:text-green-400' : 'text-red-600 dark:text-red-400' }}">
|
|
{{ $movement->movement_type === 'in' ? '+' : '-' }}{{ number_format($movement->quantity) }}
|
|
</span>
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-zinc-500 dark:text-zinc-400 dark:text-gray-400">
|
|
{{ $movement->createdBy->name ?? 'System' }}
|
|
</td>
|
|
<td class="px-6 py-4 text-sm text-zinc-500 dark:text-zinc-400 dark:text-gray-400 max-w-xs truncate">
|
|
{{ $movement->notes }}
|
|
</td>
|
|
</tr>
|
|
@endforeach
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
@if($part->stockMovements->count() > 5)
|
|
<div class="mt-4 text-center">
|
|
<flux:button wire:click="showHistory" variant="outline" size="sm">
|
|
View All Movement History
|
|
</flux:button>
|
|
</div>
|
|
@endif
|
|
@else
|
|
<p class="text-sm text-zinc-500 dark:text-zinc-400 dark:text-gray-400">No stock movements recorded yet.</p>
|
|
@endif
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sidebar -->
|
|
<div class="space-y-6">
|
|
<!-- Stock Information -->
|
|
<div class="bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg p-6">
|
|
<h3 class="text-lg font-medium text-zinc-900 dark:text-white dark:text-white mb-4">Stock Information</h3>
|
|
|
|
<dl class="space-y-3">
|
|
<div>
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400">Current Stock</dt>
|
|
<dd class="mt-1">
|
|
<span class="text-2xl font-bold text-zinc-900 dark:text-white dark:text-white">{{ number_format($part->quantity_on_hand) }}</span>
|
|
@if($part->isLowStock())
|
|
<flux:badge color="red" size="sm" class="ml-2">Low Stock</flux:badge>
|
|
@endif
|
|
</dd>
|
|
</div>
|
|
|
|
<div>
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400">Minimum Stock Level</dt>
|
|
<dd class="mt-1 text-sm text-zinc-900 dark:text-white dark:text-white">{{ number_format($part->minimum_stock_level) }}</dd>
|
|
</div>
|
|
|
|
<div>
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400">Maximum Stock Level</dt>
|
|
<dd class="mt-1 text-sm text-zinc-900 dark:text-white dark:text-white">{{ number_format($part->maximum_stock_level) }}</dd>
|
|
</div>
|
|
</dl>
|
|
</div>
|
|
|
|
<!-- Pricing Information -->
|
|
<div class="bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg p-6">
|
|
<h3 class="text-lg font-medium text-zinc-900 dark:text-white dark:text-white mb-4">Pricing</h3>
|
|
|
|
<dl class="space-y-3">
|
|
<div>
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400">Cost Price</dt>
|
|
<dd class="mt-1 text-lg font-semibold text-zinc-900 dark:text-white dark:text-white">${{ number_format($part->cost_price, 2) }}</dd>
|
|
</div>
|
|
|
|
<div>
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400">Sell Price</dt>
|
|
<dd class="mt-1 text-lg font-semibold text-zinc-900 dark:text-white dark:text-white">${{ number_format($part->sell_price, 2) }}</dd>
|
|
</div>
|
|
|
|
@if($part->markup_percentage)
|
|
<div>
|
|
<dt class="text-sm font-medium text-zinc-500 dark:text-zinc-400 dark:text-gray-400">Markup</dt>
|
|
<dd class="mt-1 text-sm">
|
|
<flux:badge color="blue" size="sm">{{ $part->markup_percentage }}%</flux:badge>
|
|
</dd>
|
|
</div>
|
|
@endif
|
|
</dl>
|
|
</div>
|
|
|
|
<!-- Quick Actions -->
|
|
<div class="bg-white dark:bg-zinc-800 border border-zinc-200 dark:border-zinc-700 rounded-lg p-6">
|
|
<h3 class="text-lg font-medium text-zinc-900 dark:text-white dark:text-white mb-4">Quick Actions</h3>
|
|
|
|
<div class="space-y-3">
|
|
<flux:button wire:click="showHistory" variant="outline" size="sm" class="w-full">
|
|
View Complete History
|
|
</flux:button>
|
|
|
|
<flux:button wire:click="addStockMovement" variant="outline" size="sm" class="w-full">
|
|
Add Stock Movement
|
|
</flux:button>
|
|
|
|
<flux:button wire:click="createPurchaseOrder" variant="outline" size="sm" class="w-full">
|
|
Create Purchase Order
|
|
</flux:button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
</div>
|