Files
Andrey Smakotin 812ecb53e6 Fix media file storage path and permissions
- Fix MEDIA_ROOT path to match Docker volume mount (/app/myproject/media)
- Update docker-compose.yml volume mounts to match MEDIA_ROOT
- Add setup_directories() function in entrypoint.sh to create media directories with proper permissions
- Add logging to TenantAwareFileSystemStorage for debugging
- Fix is_returned flag logic improvements (from previous work)
2025-12-21 16:54:44 +03:00

114 lines
4.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
from django.shortcuts import render
from django.views.generic import ListView, CreateView, UpdateView, DeleteView, DetailView
from django.urls import reverse_lazy
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from ..models import Sale, SaleBatchAllocation
from ..forms import SaleForm
class SaleListView(LoginRequiredMixin, ListView):
"""
Список всех продаж товара (истории реализации)
"""
model = Sale
template_name = 'inventory/sale/sale_list.html'
context_object_name = 'sales'
paginate_by = 20
def get_queryset(self):
queryset = Sale.objects.select_related('product', 'warehouse', 'order').order_by('-date')
# Фильтры (если переданы)
product_id = self.request.GET.get('product')
warehouse_id = self.request.GET.get('warehouse')
processed = self.request.GET.get('processed')
if product_id:
queryset = queryset.filter(product_id=product_id)
if warehouse_id:
queryset = queryset.filter(warehouse_id=warehouse_id)
if processed:
queryset = queryset.filter(processed=processed == 'true')
return queryset
class SaleCreateView(LoginRequiredMixin, CreateView):
"""
Регистрация новой продажи товара.
После сохранения автоматически применяется FIFO (через сигнал).
"""
model = Sale
form_class = SaleForm
template_name = 'inventory/sale/sale_form.html'
success_url = reverse_lazy('inventory:sale-list')
def form_valid(self, form):
messages.success(
self.request,
f'Продажа товара "{form.instance.product.name}" ({form.instance.quantity} шт) успешно зарегистрирована.'
)
return super().form_valid(form)
class SaleDetailView(LoginRequiredMixin, DetailView):
"""
Просмотр деталей продажи с распределением по партиям.
Показывает SaleBatchAllocation для данной продажи.
"""
model = Sale
template_name = 'inventory/sale/sale_detail.html'
context_object_name = 'sale'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Получаем все распределения этой продажи по партиям
context['allocations'] = SaleBatchAllocation.objects.filter(
sale=self.object
).select_related('batch', 'batch__product')
return context
class SaleUpdateView(LoginRequiredMixin, UpdateView):
"""
Редактирование продажи (только если ещё не обработана).
Обработанные продажи редактировать нельзя.
"""
model = Sale
form_class = SaleForm
template_name = 'inventory/sale/sale_form.html'
success_url = reverse_lazy('inventory:sale-list')
def form_valid(self, form):
messages.success(self.request, f'Продажа товара обновлена.')
return super().form_valid(form)
class SaleDeleteView(LoginRequiredMixin, DeleteView):
"""
Отмена/удаление продажи товара.
"""
model = Sale
template_name = 'inventory/sale/sale_confirm_delete.html'
success_url = reverse_lazy('inventory:sale-list')
def delete(self, request, *args, **kwargs):
sale = self.get_object()
order = sale.order
result = super().delete(request, *args, **kwargs)
# Обновляем флаг заказа после удаления Sale
if order:
from inventory.signals import update_is_returned_flag
update_is_returned_flag(order)
messages.success(
request,
f'Продажа товара "{sale.product.name}" отменена.'
)
return result