update
This commit is contained in:
parent
b9b8c69129
commit
1f0a6bff5f
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
Binary file not shown.
@ -38,6 +38,7 @@ DJANGO_APPS = [
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'django.contrib.humanize',
|
||||
]
|
||||
|
||||
THIRD_PARTY_APPS = [
|
||||
|
||||
Binary file not shown.
@ -341,26 +341,26 @@ class InventoryLocationDetailView(LoginRequiredMixin, DetailView):
|
||||
|
||||
# Stock items at this location
|
||||
context['stock_items'] = InventoryStock.objects.filter(
|
||||
tenant=self.request.user.tenant,
|
||||
inventory_item__tenant=self.request.user.tenant,
|
||||
location=location
|
||||
).select_related('item').order_by('item__item_name')
|
||||
).select_related('inventory_item').order_by('inventory_item__item_name')
|
||||
|
||||
# Location statistics
|
||||
context['total_items'] = InventoryStock.objects.filter(
|
||||
tenant=self.request.user.tenant,
|
||||
inventory_item__tenant=self.request.user.tenant,
|
||||
location=location
|
||||
).count()
|
||||
|
||||
context['total_quantity'] = InventoryStock.objects.filter(
|
||||
tenant=self.request.user.tenant,
|
||||
inventory_item__tenant=self.request.user.tenant,
|
||||
location=location
|
||||
).aggregate(total=Sum('quantity'))['total'] or 0
|
||||
).aggregate(total=Sum('quantity_available'))['total'] or 0
|
||||
|
||||
context['total_value'] = InventoryStock.objects.filter(
|
||||
tenant=self.request.user.tenant,
|
||||
inventory_item__tenant=self.request.user.tenant,
|
||||
location=location
|
||||
).aggregate(
|
||||
total_value=Sum(F('quantity') * F('unit_cost'))
|
||||
total_value=Sum(F('quantity_available') * F('unit_cost'))
|
||||
)['total_value'] or 0
|
||||
|
||||
return context
|
||||
@ -503,27 +503,27 @@ class InventoryItemDetailView(LoginRequiredMixin, DetailView):
|
||||
|
||||
# Stock information across all locations
|
||||
context['stock_locations'] = InventoryStock.objects.filter(
|
||||
tenant=self.request.user.tenant,
|
||||
item=item
|
||||
inventory_item__tenant=self.request.user.tenant,
|
||||
inventory_item=item
|
||||
).select_related('location').order_by('location__location_name')
|
||||
|
||||
# Item statistics
|
||||
context['total_stock'] = InventoryStock.objects.filter(
|
||||
tenant=self.request.user.tenant,
|
||||
item=item
|
||||
).aggregate(total=Sum('quantity'))['total'] or 0
|
||||
inventory_item__tenant=self.request.user.tenant,
|
||||
inventory_item=item
|
||||
).aggregate(total=Sum('quantity_available'))['total'] or 0
|
||||
|
||||
context['total_value'] = InventoryStock.objects.filter(
|
||||
tenant=self.request.user.tenant,
|
||||
item=item
|
||||
inventory_item__tenant=self.request.user.tenant,
|
||||
inventory_item=item
|
||||
).aggregate(
|
||||
total_value=Sum(F('quantity') * F('unit_cost'))
|
||||
total_value=Sum(F('quantity_available') * F('unit_cost'))
|
||||
)['total_value'] or 0
|
||||
|
||||
# Recent purchase orders for this item
|
||||
context['recent_orders'] = PurchaseOrderItem.objects.filter(
|
||||
purchase_order__tenant=self.request.user.tenant,
|
||||
item=item
|
||||
inventory_item=item
|
||||
).select_related('purchase_order').order_by('-purchase_order__order_date')[:5]
|
||||
|
||||
return context
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -4,9 +4,9 @@
|
||||
{% block title %}{{ object.item_name }} - Inventory Item Details{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<link href="{% static 'assets/plugins/datatables.net-bs5/css/dataTables.bootstrap5.min.css' %}" rel="stylesheet" />
|
||||
<link href="{% static 'assets/plugins/datatables.net-responsive-bs5/css/responsive.bootstrap5.min.css' %}" rel="stylesheet" />
|
||||
<link href="{% static 'assets/plugins/chart.js/dist/Chart.min.css' %}" rel="stylesheet" />
|
||||
<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 %}
|
||||
@ -96,11 +96,11 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="fw-bold">Unit Cost:</td>
|
||||
<td class="fw-bold text-success">${{ object.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>${{ object.list_price }}</td>
|
||||
<td><span class="symbol">ê</span>{{ object.list_price|floatformat:'2g' }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
@ -237,7 +237,7 @@
|
||||
</div>
|
||||
<div class="col-md-3">
|
||||
<div class="text-center p-3 bg-success text-white rounded">
|
||||
<div class="fs-24px fw-bold">${{ object.total_value|floatformat:2 }}</div>
|
||||
<div class="fs-24px fw-bold"><span class="symbol">ê</span>{{ object.total_value|floatformat:'2g' }}</div>
|
||||
<div class="small">Total Value</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -303,10 +303,15 @@
|
||||
<span class="text-muted">No expiration</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<span class="badge bg-{{ stock.get_quality_status_color }}">
|
||||
{{ stock.get_quality_status_display }}
|
||||
</span>
|
||||
{% 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">
|
||||
@ -336,7 +341,7 @@
|
||||
<div class="panel-heading">
|
||||
<h4 class="panel-title">Recent Transactions</h4>
|
||||
<div class="panel-heading-btn">
|
||||
<a href="{% url 'inventory:transaction_list' %}?item={{ object.pk }}" class="btn btn-xs btn-outline-secondary me-2">
|
||||
<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>
|
||||
@ -405,7 +410,7 @@
|
||||
<i class="fa fa-plus me-2"></i>Add Stock
|
||||
</a>
|
||||
|
||||
<a href="{% url 'inventory:stock_adjustment_create' %}?item={{ object.pk }}" class="btn btn-warning">
|
||||
<a href="#" class="btn btn-warning">
|
||||
<i class="fa fa-adjust me-2"></i>Adjust Stock
|
||||
</a>
|
||||
|
||||
@ -594,32 +599,32 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script src="{% static 'assets/plugins/datatables.net/js/jquery.dataTables.min.js' %}"></script>
|
||||
<script src="{% static 'assets/plugins/datatables.net-bs5/js/dataTables.bootstrap5.min.js' %}"></script>
|
||||
<script src="{% static 'assets/plugins/chart.js/dist/Chart.min.js' %}"></script>
|
||||
<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 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 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');
|
||||
|
||||
@ -4,9 +4,9 @@
|
||||
{% block title %}{% if object %}Edit {{ object.item_name }}{% else %}Add New Item{% endif %} - Inventory{% endblock %}
|
||||
|
||||
{% block css %}
|
||||
<link href="{% static 'assets/plugins/select2/dist/css/select2.min.css' %}" rel="stylesheet" />
|
||||
<link href="{% static 'assets/plugins/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css' %}" rel="stylesheet" />
|
||||
<link href="{% static 'assets/plugins/jquery-file-upload/css/jquery.fileupload.css' %}" rel="stylesheet" />
|
||||
<link href="{% static 'plugins/select2/dist/css/select2.min.css' %}" rel="stylesheet" />
|
||||
<link href="{% static 'plugins/bootstrap-datepicker/dist/css/bootstrap-datepicker.min.css' %}" rel="stylesheet" />
|
||||
{#<link href="{% static 'plugins/jquery-file-upload/css/jquery.fileupload.css' %}" rel="stylesheet" />#}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@ -642,30 +642,30 @@ function toggleConditionalFields() {
|
||||
}
|
||||
}
|
||||
|
||||
function generateItemCode() {
|
||||
var category = $('#id_category').val();
|
||||
var itemType = $('#id_item_type').val();
|
||||
|
||||
if (!category) {
|
||||
toastr.warning('Please select a category first');
|
||||
return;
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
url: '{% url "inventory:generate_item_code" %}',
|
||||
data: {
|
||||
'category': category,
|
||||
'item_type': itemType
|
||||
},
|
||||
success: function(response) {
|
||||
$('#id_item_code').val(response.item_code);
|
||||
toastr.success('Item code generated: ' + response.item_code);
|
||||
},
|
||||
error: function() {
|
||||
toastr.error('Failed to generate item code');
|
||||
}
|
||||
});
|
||||
}
|
||||
{#function generateItemCode() {#}
|
||||
{# var category = $('#id_category').val();#}
|
||||
{# var itemType = $('#id_item_type').val();#}
|
||||
{# #}
|
||||
{# if (!category) {#}
|
||||
{# toastr.warning('Please select a category first');#}
|
||||
{# return;#}
|
||||
{# }#}
|
||||
{# #}
|
||||
{# $.ajax({#}
|
||||
{# url: '{% url "inventory:generate_item_code" %}',#}
|
||||
{# data: {#}
|
||||
{# 'category': category,#}
|
||||
{# 'item_type': itemType#}
|
||||
{# },#}
|
||||
{# success: function(response) {#}
|
||||
{# $('#id_item_code').val(response.item_code);#}
|
||||
{# toastr.success('Item code generated: ' + response.item_code);#}
|
||||
{# },#}
|
||||
{# error: function() {#}
|
||||
{# toastr.error('Failed to generate item code');#}
|
||||
{# }#}
|
||||
{# });#}
|
||||
{# }#}
|
||||
|
||||
function scanBarcode() {
|
||||
// Implementation for barcode scanning
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -465,10 +465,10 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<a class="me-3" href="{% url 'inventory:stock_detail' stock.id %}">
|
||||
<a class="btn btn-xs btn-outline-primary me-1" href="{% url 'inventory:stock_detail' stock.id %}">
|
||||
<i class="fas fa-eye"></i>
|
||||
</a>
|
||||
<a class="me-3" href="{% url 'inventory:stock_update' stock.id %}">
|
||||
<a class="btn btn-xs btn-outline-secondary" href="{% url 'inventory:stock_update' stock.id %}">
|
||||
<i class="fas fa-edit"></i>
|
||||
</a>
|
||||
</td>
|
||||
|
||||
@ -301,44 +301,7 @@
|
||||
|
||||
<!-- Pagination -->
|
||||
{% if is_paginated %}
|
||||
<div class="pagination-wrapper">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 col-md-5">
|
||||
<div class="dataTables_info">
|
||||
Showing {{ page_obj.start_index }} to {{ page_obj.end_index }} of {{ paginator.count }} entries
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-12 col-md-7">
|
||||
<div class="dataTables_paginate">
|
||||
<ul class="pagination">
|
||||
{% if page_obj.has_previous %}
|
||||
<li class="paginate_button page-item previous">
|
||||
<a href="?page={{ page_obj.previous_page_number }}" class="page-link">Previous</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
|
||||
{% for num in page_obj.paginator.page_range %}
|
||||
{% if page_obj.number == num %}
|
||||
<li class="paginate_button page-item active">
|
||||
<a href="#" class="page-link">{{ num }}</a>
|
||||
</li>
|
||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||
<li class="paginate_button page-item">
|
||||
<a href="?page={{ num }}" class="page-link">{{ num }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
{% if page_obj.has_next %}
|
||||
<li class="paginate_button page-item next">
|
||||
<a href="?page={{ page_obj.next_page_number }}" class="page-link">Next</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% include 'partial/pagination.html' %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user