|
|
@ -1,5 +1,13 @@
|
|
|
|
from django.contrib import admin
|
|
|
|
from django.contrib import admin
|
|
|
|
from .models import Warehouse, StorageLocation, StockOperation
|
|
|
|
from .models import Warehouse, StorageLocation, StockOperation
|
|
|
|
|
|
|
|
from django.urls import path
|
|
|
|
|
|
|
|
from django.shortcuts import render
|
|
|
|
|
|
|
|
import matplotlib.pyplot as plt
|
|
|
|
|
|
|
|
from io import BytesIO
|
|
|
|
|
|
|
|
import base64
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import matplotlib
|
|
|
|
|
|
|
|
matplotlib.use('Agg')
|
|
|
|
|
|
|
|
|
|
|
|
@admin.register(Warehouse)
|
|
|
|
@admin.register(Warehouse)
|
|
|
|
class WarehouseAdmin(admin.ModelAdmin):
|
|
|
|
class WarehouseAdmin(admin.ModelAdmin):
|
|
|
@ -19,3 +27,43 @@ class StockOperationAdmin(admin.ModelAdmin):
|
|
|
|
list_display = ('product', 'warehouse', 'operation_type', 'quantity', 'operation_date')
|
|
|
|
list_display = ('product', 'warehouse', 'operation_type', 'quantity', 'operation_date')
|
|
|
|
search_fields = ('product__name', 'warehouse__name', 'operation_type')
|
|
|
|
search_fields = ('product__name', 'warehouse__name', 'operation_type')
|
|
|
|
list_filter = ('operation_type', 'operation_date')
|
|
|
|
list_filter = ('operation_type', 'operation_date')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def changelist_view(self, request, extra_context=None):
|
|
|
|
|
|
|
|
extra_context = extra_context or {}
|
|
|
|
|
|
|
|
extra_context['custom_button'] = {
|
|
|
|
|
|
|
|
'url': 'statistics/',
|
|
|
|
|
|
|
|
'label': 'Просмотреть статистику'
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return super().changelist_view(request, extra_context)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_urls(self):
|
|
|
|
|
|
|
|
urls = super().get_urls()
|
|
|
|
|
|
|
|
custom_urls = [
|
|
|
|
|
|
|
|
path('statistics/', self.admin_site.admin_view(self.statistics_view), name='stock_operation_statistics'),
|
|
|
|
|
|
|
|
]
|
|
|
|
|
|
|
|
return custom_urls + urls
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def statistics_view(self, request):
|
|
|
|
|
|
|
|
operations = StockOperation.objects.all()
|
|
|
|
|
|
|
|
incoming_count = operations.filter(operation_type='Incoming').count()
|
|
|
|
|
|
|
|
outgoing_count = operations.filter(operation_type='Outgoing').count()
|
|
|
|
|
|
|
|
transfer_count = operations.filter(operation_type='Transfer').count()
|
|
|
|
|
|
|
|
writeoff_count = operations.filter(operation_type='WriteOff').count()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
labels = ['Incoming', 'Outgoing', 'Transfer', 'WriteOff']
|
|
|
|
|
|
|
|
data = [incoming_count, outgoing_count, transfer_count, writeoff_count]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
plt.figure(figsize=(6, 6))
|
|
|
|
|
|
|
|
plt.pie(data, labels=labels, autopct='%1.1f%%', startangle=90)
|
|
|
|
|
|
|
|
plt.axis('equal')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
buffer = BytesIO()
|
|
|
|
|
|
|
|
plt.savefig(buffer, format='png')
|
|
|
|
|
|
|
|
buffer.seek(0)
|
|
|
|
|
|
|
|
image_png = buffer.getvalue()
|
|
|
|
|
|
|
|
buffer.close()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
chart = base64.b64encode(image_png).decode('utf-8')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
context = {'chart': chart}
|
|
|
|
|
|
|
|
return render(request, 'admin/warehouse/stock_statistics.html', context)
|