694 lines
33 KiB
HTML
694 lines
33 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
|
|
{% block title %}{{ object.item_name }} - Inventory Item Details{% endblock %}
|
|
|
|
{% block css %}
|
|
<link href="{% static 'plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css' %}" rel="stylesheet" />
|
|
<link href="{% static 'plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css' %}" rel="stylesheet" />
|
|
<link href="{% static 'plugins/chart.js/dist/Chart.min.css' %}" rel="stylesheet" />
|
|
{% endblock %}
|
|
|
|
{% block content %}
|
|
<!-- BEGIN breadcrumb -->
|
|
<ol class="breadcrumb float-xl-end">
|
|
<li class="breadcrumb-item"><a href="{% url 'core:dashboard' %}">Dashboard</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'inventory:dashboard' %}">Inventory</a></li>
|
|
<li class="breadcrumb-item"><a href="{% url 'inventory:item_list' %}">Items</a></li>
|
|
<li class="breadcrumb-item active">{{ object.item_code }}</li>
|
|
</ol>
|
|
<!-- END breadcrumb -->
|
|
|
|
<!-- BEGIN page-header -->
|
|
<h1 class="page-header">
|
|
{{ object.item_name }}
|
|
<small>{{ object.item_code }} - Inventory Item Details</small>
|
|
</h1>
|
|
<!-- END page-header -->
|
|
|
|
<div class="row">
|
|
<div class="col-xl-8">
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Item Information</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="{% url 'inventory:item_update' object.pk %}" class="btn btn-xs btn-primary me-2">
|
|
<i class="fa fa-edit"></i> Edit
|
|
</a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<table class="table table-borderless">
|
|
<tr>
|
|
<td class="fw-bold" width="150">Item Code:</td>
|
|
<td>{{ object.item_code }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Item Name:</td>
|
|
<td>{{ object.item_name }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Category:</td>
|
|
<td>
|
|
<span class="badge bg-secondary">{{ object.get_category_display }}</span>
|
|
{% if object.subcategory %}
|
|
<br><small class="text-muted">{{ object.subcategory }}</small>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Item Type:</td>
|
|
<td>
|
|
<span class="badge bg-{{ object.get_item_type_color }}">{{ object.get_item_type_display }}</span>
|
|
</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Unit of Measure:</td>
|
|
<td>{{ object.get_unit_of_measure_display }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Package Size:</td>
|
|
<td>{{ object.package_size }} {{ object.get_unit_of_measure_display }}{{ object.package_size|pluralize }}</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<table class="table table-borderless">
|
|
<tr>
|
|
<td class="fw-bold" width="150">Manufacturer:</td>
|
|
<td>{{ object.manufacturer|default:"Not specified" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Model Number:</td>
|
|
<td>{{ object.model_number|default:"Not specified" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Part Number:</td>
|
|
<td>{{ object.part_number|default:"Not specified" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">UPC Code:</td>
|
|
<td>{{ object.upc_code|default:"Not specified" }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">Unit Cost:</td>
|
|
<td class="fw-bold text-success"><span class="symbol">ê</span>{{ object.unit_cost|floatformat:'2g' }}</td>
|
|
</tr>
|
|
<tr>
|
|
<td class="fw-bold">List Price:</td>
|
|
<td><span class="symbol">ê</span>{{ object.list_price|floatformat:'2g' }}</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
{% if object.description %}
|
|
<div class="mt-4">
|
|
<h6>Description</h6>
|
|
<div class="bg-light p-3 rounded">{{ object.description }}</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Item Features -->
|
|
<div class="mt-4">
|
|
<h6>Item Features</h6>
|
|
<div class="row">
|
|
<div class="col-md-6">
|
|
<div class="mb-2">
|
|
<i class="fa fa-{{ object.is_active|yesno:'check text-success,times text-danger' }} me-2"></i>
|
|
Active Item
|
|
</div>
|
|
<div class="mb-2">
|
|
<i class="fa fa-{{ object.is_tracked|yesno:'check text-success,times text-muted' }} me-2"></i>
|
|
Inventory Tracked
|
|
</div>
|
|
<div class="mb-2">
|
|
<i class="fa fa-{{ object.is_serialized|yesno:'check text-success,times text-muted' }} me-2"></i>
|
|
Serial Number Tracking
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6">
|
|
<div class="mb-2">
|
|
<i class="fa fa-{{ object.is_lot_tracked|yesno:'check text-success,times text-muted' }} me-2"></i>
|
|
Lot Number Tracking
|
|
</div>
|
|
<div class="mb-2">
|
|
<i class="fa fa-{{ object.has_expiration|yesno:'check text-success,times text-muted' }} me-2"></i>
|
|
Has Expiration Date
|
|
</div>
|
|
<div class="mb-2">
|
|
<i class="fa fa-{{ object.controlled_substance|yesno:'check text-warning,times text-muted' }} me-2"></i>
|
|
Controlled Substance
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Regulatory Information -->
|
|
{% if object.fda_approved or object.controlled_substance or object.dea_schedule %}
|
|
<div class="mt-4">
|
|
<h6>Regulatory Information</h6>
|
|
<div class="row">
|
|
{% if object.fda_approved %}
|
|
<div class="col-md-4">
|
|
<div class="text-center p-3 bg-success text-white rounded">
|
|
<i class="fa fa-check-circle fa-2x mb-2"></i>
|
|
<div>FDA Approved</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
{% if object.controlled_substance %}
|
|
<div class="col-md-4">
|
|
<div class="text-center p-3 bg-warning text-white rounded">
|
|
<i class="fa fa-exclamation-triangle fa-2x mb-2"></i>
|
|
<div>Controlled Substance</div>
|
|
{% if object.dea_schedule %}
|
|
<small>{{ object.get_dea_schedule_display }}</small>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Clinical Information -->
|
|
{% if object.clinical_use or object.contraindications %}
|
|
<div class="mt-4">
|
|
<h6>Clinical Information</h6>
|
|
{% if object.clinical_use %}
|
|
<div class="mb-3">
|
|
<strong>Clinical Use:</strong><br>
|
|
<div class="bg-light p-3 rounded">{{ object.clinical_use }}</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if object.contraindications %}
|
|
<div class="mb-3">
|
|
<strong>Contraindications:</strong><br>
|
|
<div class="bg-warning-subtle p-3 rounded border border-warning">
|
|
<i class="fa fa-exclamation-triangle text-warning me-2"></i>
|
|
{{ object.contraindications }}
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Stock Information</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="{% url 'inventory:stock_create' %}?item={{ object.pk }}" class="btn btn-xs btn-success me-2">
|
|
<i class="fa fa-plus"></i> Add Stock
|
|
</a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<!-- Stock Summary -->
|
|
<div class="row mb-4">
|
|
<div class="col-md-3">
|
|
<div class="text-center p-3 bg-primary text-white rounded">
|
|
<div class="fs-24px fw-bold">{{ object.current_stock }}</div>
|
|
<div class="small">Current Stock</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center p-3 bg-warning text-white rounded">
|
|
<div class="fs-24px fw-bold">{{ object.reorder_point }}</div>
|
|
<div class="small">Reorder Point</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center p-3 bg-info text-white rounded">
|
|
<div class="fs-24px fw-bold">{{ object.reorder_quantity }}</div>
|
|
<div class="small">Reorder Quantity</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<div class="text-center p-3 bg-success text-white rounded">
|
|
<div class="fs-24px fw-bold"><span class="symbol">ê</span>{{ object.total_value|floatformat:'2g' }}</div>
|
|
<div class="small">Total Value</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stock Status Alert -->
|
|
{% if object.needs_reorder %}
|
|
<div class="alert alert-warning d-flex align-items-center mb-4">
|
|
<i class="fa fa-exclamation-triangle fa-2x me-3"></i>
|
|
<div>
|
|
<h6 class="alert-heading mb-1">Reorder Required</h6>
|
|
<p class="mb-0">Current stock ({{ object.current_stock }}) is at or below the reorder point ({{ object.reorder_point }}). Consider placing a new order.</p>
|
|
</div>
|
|
<div class="ms-auto">
|
|
<a href="{% url 'inventory:purchase_order_create' %}?item={{ object.pk }}" class="btn btn-warning">
|
|
<i class="fa fa-shopping-cart me-2"></i>Create Order
|
|
</a>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Stock by Location -->
|
|
{% if object.inventory_stocks.exists %}
|
|
<div class="table-responsive">
|
|
<table class="table table-sm">
|
|
<thead>
|
|
<tr>
|
|
<th>Location</th>
|
|
<th>Lot Number</th>
|
|
<th>Quantity</th>
|
|
<th>Expiration</th>
|
|
<th>Quality Status</th>
|
|
<th>Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for stock in object.inventory_stocks.all %}
|
|
<tr>
|
|
<td>
|
|
<a href="{% url 'inventory:location_detail' stock.location.pk %}" class="text-decoration-none">
|
|
{{ stock.location.name }}
|
|
</a>
|
|
</td>
|
|
<td>{{ stock.lot_number|default:"-" }}</td>
|
|
<td>
|
|
<span class="fw-bold">{{ stock.quantity_on_hand }}</span>
|
|
{% if stock.quantity_reserved > 0 %}
|
|
<br><small class="text-muted">({{ stock.quantity_reserved }} reserved)</small>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
{% if stock.expiration_date %}
|
|
{% if stock.is_expired %}
|
|
<span class="text-danger fw-bold">{{ stock.expiration_date|date:"M d, Y" }}</span>
|
|
<br><small class="text-danger">Expired</small>
|
|
{% elif stock.days_to_expiry <= 30 %}
|
|
<span class="text-warning fw-bold">{{ stock.expiration_date|date:"M d, Y" }}</span>
|
|
<br><small class="text-warning">{{ stock.days_to_expiry }} days</small>
|
|
{% else %}
|
|
{{ stock.expiration_date|date:"M d, Y" }}
|
|
{% endif %}
|
|
{% else %}
|
|
<span class="text-muted">No expiration</span>
|
|
{% endif %}
|
|
</td>
|
|
|
|
<td>
|
|
{% if stock.quality_status == 'GOOD' %}
|
|
<span class="badge bg-success">{{ stock.get_quality_status_display }}</span>
|
|
{% elif stock.quality_status == 'QUARANTINE' %}
|
|
<span class="badge bg-warning">{{ stock.get_quality_status_display }}</span>
|
|
{% else %}
|
|
<span class="badge bg-danger">{{ stock.get_quality_status_display }}</span>
|
|
{% endif %}
|
|
</td>
|
|
<td>
|
|
<a href="{% url 'inventory:stock_detail' stock.pk %}" class="btn btn-xs btn-outline-primary">
|
|
<i class="fa fa-eye"></i>
|
|
</a>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center py-4 text-muted">
|
|
<i class="fa fa-boxes fa-3x mb-3"></i>
|
|
<p>No stock records found for this item.</p>
|
|
<a href="{% url 'inventory:stock_create' %}?item={{ object.pk }}" class="btn btn-primary">
|
|
<i class="fa fa-plus me-2"></i>Add Initial Stock
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Recent Transactions</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="#" class="btn btn-xs btn-outline-secondary me-2">
|
|
<i class="fa fa-list"></i> View All
|
|
</a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
{% if recent_transactions %}
|
|
<div class="timeline">
|
|
{% for transaction in recent_transactions %}
|
|
<div class="timeline-item">
|
|
<div class="timeline-time">{{ transaction.transaction_date|date:"M d" }}</div>
|
|
<div class="timeline-icon bg-{{ transaction.get_transaction_type_color }}">
|
|
<i class="fa fa-{{ transaction.get_transaction_icon }}"></i>
|
|
</div>
|
|
<div class="timeline-body">
|
|
<div class="timeline-header">
|
|
<span class="fw-bold">{{ transaction.get_transaction_type_display }}</span>
|
|
<span class="badge bg-{{ transaction.get_transaction_type_color }} ms-2">
|
|
{{ transaction.quantity_change|floatformat:0 }}
|
|
</span>
|
|
</div>
|
|
<div class="timeline-content">
|
|
<div class="small text-muted">
|
|
{{ transaction.location.name }}
|
|
{% if transaction.reference_number %}
|
|
• Ref: {{ transaction.reference_number }}
|
|
{% endif %}
|
|
</div>
|
|
{% if transaction.notes %}
|
|
<div class="small">{{ transaction.notes|truncatechars:100 }}</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endfor %}
|
|
</div>
|
|
{% else %}
|
|
<div class="text-center py-4 text-muted">
|
|
<i class="fa fa-exchange-alt fa-3x mb-3"></i>
|
|
<p>No recent transactions for this item.</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
</div>
|
|
|
|
<div class="col-xl-4">
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Quick Actions</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="d-grid gap-2">
|
|
<a href="{% url 'inventory:item_update' object.pk %}" class="btn btn-primary">
|
|
<i class="fa fa-edit me-2"></i>Edit Item
|
|
</a>
|
|
|
|
<a href="{% url 'inventory:stock_create' %}?item={{ object.pk }}" class="btn btn-success">
|
|
<i class="fa fa-plus me-2"></i>Add Stock
|
|
</a>
|
|
|
|
<a href="#" class="btn btn-warning">
|
|
<i class="fa fa-adjust me-2"></i>Adjust Stock
|
|
</a>
|
|
|
|
{% if object.needs_reorder %}
|
|
<a href="{% url 'inventory:purchase_order_create' %}?item={{ object.pk }}" class="btn btn-info">
|
|
<i class="fa fa-shopping-cart me-2"></i>Create Purchase Order
|
|
</a>
|
|
{% endif %}
|
|
|
|
<button class="btn btn-outline-secondary" onclick="printItemLabel()">
|
|
<i class="fa fa-print me-2"></i>Print Label
|
|
</button>
|
|
|
|
<button class="btn btn-outline-info" onclick="showStockChart()">
|
|
<i class="fa fa-chart-line me-2"></i>Stock History
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Storage Requirements</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
{% if object.storage_temperature_min or object.storage_temperature_max or object.storage_requirements %}
|
|
<table class="table table-sm table-borderless">
|
|
{% if object.storage_temperature_min or object.storage_temperature_max %}
|
|
<tr>
|
|
<td class="text-muted">Temperature:</td>
|
|
<td>
|
|
{% if object.storage_temperature_min and object.storage_temperature_max %}
|
|
{{ object.storage_temperature_min }}°C to {{ object.storage_temperature_max }}°C
|
|
{% elif object.storage_temperature_min %}
|
|
Above {{ object.storage_temperature_min }}°C
|
|
{% elif object.storage_temperature_max %}
|
|
Below {{ object.storage_temperature_max }}°C
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% endif %}
|
|
|
|
{% if object.storage_humidity_min or object.storage_humidity_max %}
|
|
<tr>
|
|
<td class="text-muted">Humidity:</td>
|
|
<td>
|
|
{% if object.storage_humidity_min and object.storage_humidity_max %}
|
|
{{ object.storage_humidity_min }}% to {{ object.storage_humidity_max }}%
|
|
{% elif object.storage_humidity_min %}
|
|
Above {{ object.storage_humidity_min }}%
|
|
{% elif object.storage_humidity_max %}
|
|
Below {{ object.storage_humidity_max }}%
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% endif %}
|
|
|
|
{% if object.shelf_life_days %}
|
|
<tr>
|
|
<td class="text-muted">Shelf Life:</td>
|
|
<td>{{ object.shelf_life_days }} days</td>
|
|
</tr>
|
|
{% endif %}
|
|
</table>
|
|
|
|
{% if object.storage_requirements %}
|
|
<div class="mt-3">
|
|
<strong>Special Requirements:</strong><br>
|
|
<div class="bg-light p-3 rounded small">{{ object.storage_requirements }}</div>
|
|
</div>
|
|
{% endif %}
|
|
{% else %}
|
|
<div class="text-center py-3 text-muted">
|
|
<i class="fa fa-thermometer-half fa-2x mb-2"></i>
|
|
<p class="mb-0">No special storage requirements specified.</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Supplier Information</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
{% if object.primary_supplier %}
|
|
<div class="d-flex align-items-center mb-3">
|
|
<div class="flex-fill">
|
|
<div class="fw-bold">{{ object.primary_supplier.name }}</div>
|
|
<div class="text-muted small">Primary Supplier</div>
|
|
</div>
|
|
<a href="{% url 'inventory:supplier_detail' object.primary_supplier.pk %}" class="btn btn-sm btn-outline-primary">
|
|
View Details
|
|
</a>
|
|
</div>
|
|
|
|
{% if object.primary_supplier.contact_email %}
|
|
<div class="small mb-2">
|
|
<i class="fa fa-envelope me-2"></i>{{ object.primary_supplier.contact_email }}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% if object.primary_supplier.contact_phone %}
|
|
<div class="small mb-2">
|
|
<i class="fa fa-phone me-2"></i>{{ object.primary_supplier.contact_phone }}
|
|
</div>
|
|
{% endif %}
|
|
{% else %}
|
|
<div class="text-center py-3 text-muted">
|
|
<i class="fa fa-truck fa-2x mb-2"></i>
|
|
<p class="mb-0">No primary supplier assigned.</p>
|
|
<a href="{% url 'inventory:item_update' object.pk %}" class="btn btn-sm btn-outline-primary mt-2">
|
|
Assign Supplier
|
|
</a>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
|
|
<!-- BEGIN panel -->
|
|
<div class="panel panel-inverse">
|
|
<div class="panel-heading">
|
|
<h4 class="panel-title">Item History</h4>
|
|
<div class="panel-heading-btn">
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-expand"><i class="fa fa-expand"></i></a>
|
|
<a href="javascript:;" class="btn btn-xs btn-icon btn-default" data-toggle="panel-collapse"><i class="fa fa-minus"></i></a>
|
|
</div>
|
|
</div>
|
|
<div class="panel-body">
|
|
<div class="small text-muted">
|
|
<div class="mb-2">
|
|
<strong>Created:</strong> {{ object.created_at|date:"M d, Y H:i" }}
|
|
{% if object.created_by %}
|
|
<br>by {{ object.created_by.get_full_name }}
|
|
{% endif %}
|
|
</div>
|
|
<div class="mb-2">
|
|
<strong>Last Updated:</strong> {{ object.updated_at|date:"M d, Y H:i" }}
|
|
</div>
|
|
{% if object.notes %}
|
|
<div class="mt-3">
|
|
<strong>Notes:</strong><br>
|
|
<div class="bg-light p-2 rounded">{{ object.notes }}</div>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- END panel -->
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Stock Chart Modal -->
|
|
<div class="modal fade" id="stockChartModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title">Stock Level History</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<div style="height: 400px;">
|
|
<canvas id="stock-chart"></canvas>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="button" class="btn btn-primary" onclick="exportStockChart()">Export Chart</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block js %}
|
|
<script src="{% static 'plugins/datatables.net/js/dataTables.min.js' %}"></script>
|
|
<script src="{% static 'plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js' %}"></script>
|
|
<script src="{% static 'plugins/chart.js/dist/chart.js' %}"></script>
|
|
<script>
|
|
var stockChart;
|
|
|
|
{#function printItemLabel() {#}
|
|
{# window.open('{% url "inventory:item_label_print" object.pk %}', '_blank');#}
|
|
{# }#}
|
|
|
|
function showStockChart() {
|
|
$('#stockChartModal').modal('show');
|
|
loadStockChart();
|
|
}
|
|
|
|
{#function loadStockChart() {#}
|
|
{# $.ajax({#}
|
|
{# url: '{% url "inventory:item_stock_history" object.pk %}',#}
|
|
{# success: function(data) {#}
|
|
{# renderStockChart(data);#}
|
|
{# },#}
|
|
{# error: function() {#}
|
|
{# toastr.error('Failed to load stock history data');#}
|
|
{# }#}
|
|
{# });#}
|
|
{# }#}
|
|
|
|
function renderStockChart(data) {
|
|
var ctx = document.getElementById('stock-chart').getContext('2d');
|
|
|
|
if (stockChart) {
|
|
stockChart.destroy();
|
|
}
|
|
|
|
stockChart = new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: data.labels,
|
|
datasets: [{
|
|
label: 'Stock Level',
|
|
data: data.stock_levels,
|
|
borderColor: 'rgb(75, 192, 192)',
|
|
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
|
tension: 0.1
|
|
}, {
|
|
label: 'Reorder Point',
|
|
data: data.reorder_points,
|
|
borderColor: 'rgb(255, 99, 132)',
|
|
backgroundColor: 'rgba(255, 99, 132, 0.2)',
|
|
borderDash: [5, 5],
|
|
tension: 0.1
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
maintainAspectRatio: false,
|
|
scales: {
|
|
y: {
|
|
beginAtZero: true,
|
|
title: {
|
|
display: true,
|
|
text: 'Quantity'
|
|
}
|
|
},
|
|
x: {
|
|
title: {
|
|
display: true,
|
|
text: 'Date'
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function exportStockChart() {
|
|
if (stockChart) {
|
|
var url = stockChart.toBase64Image();
|
|
var link = document.createElement('a');
|
|
link.download = 'stock-history-{{ object.item_code }}.png';
|
|
link.href = url;
|
|
link.click();
|
|
}
|
|
}
|
|
|
|
// Auto-refresh stock information every 5 minutes
|
|
setInterval(function() {
|
|
location.reload();
|
|
}, 300000);
|
|
</script>
|
|
{% endblock %}
|
|
|