Fix Docker setup: add gunicorn, fix permissions, update docker-compose and entrypoint, add deployment instructions

This commit is contained in:
2025-12-21 15:05:58 +03:00
parent ec02360eac
commit a55be3095b
5 changed files with 38 additions and 21 deletions

View File

@@ -187,7 +187,7 @@
<th>Себестоимость:</th>
<td>
<strong class="fs-5">{{ product.cost_price }} руб.</strong>
{% if product.cost_price_details.batches %}
{% if cost_price_details.batches %}
<button class="btn btn-sm btn-outline-info ms-2" type="button" data-bs-toggle="collapse" data-bs-target="#costDetails" aria-expanded="false" aria-controls="costDetails">
<i class="bi bi-info-circle"></i> Детали расчета
</button>
@@ -196,7 +196,7 @@
{% endif %}
</td>
</tr>
{% if product.cost_price_details.batches %}
{% if cost_price_details.batches %}
<tr>
<td colspan="2">
<div class="collapse" id="costDetails">
@@ -206,13 +206,13 @@
<div class="row mb-3">
<div class="col-md-6">
<div class="alert alert-info mb-0">
<small><strong>Кешированная стоимость:</strong> {{ product.cost_price_details.cached_cost }} руб.</small>
<small><strong>Кешированная стоимость:</strong> {{ cost_price_details.cached_cost }} руб.</small>
</div>
</div>
<div class="col-md-6">
<div class="alert alert-{% if product.cost_price_details.is_synced %}success{% else %}warning{% endif %} mb-0">
<small><strong>Рассчитанная стоимость:</strong> {{ product.cost_price_details.calculated_cost }} руб.</small>
{% if not product.cost_price_details.is_synced %}
<div class="alert alert-{% if cost_price_details.is_synced %}success{% else %}warning{% endif %} mb-0">
<small><strong>Рассчитанная стоимость:</strong> {{ cost_price_details.calculated_cost }} руб.</small>
{% if not cost_price_details.is_synced %}
<br><small class="text-danger">⚠ Требуется синхронизация!</small>
{% endif %}
</div>
@@ -231,7 +231,7 @@
</tr>
</thead>
<tbody>
{% for batch in product.cost_price_details.batches %}
{% for batch in cost_price_details.batches %}
<tr>
<td>{{ batch.warehouse_name }}</td>
<td class="text-end">{{ batch.quantity }}</td>
@@ -244,9 +244,9 @@
<tfoot class="table-secondary">
<tr>
<th>Итого:</th>
<th class="text-end">{{ product.cost_price_details.total_quantity }}</th>
<th class="text-end">{{ cost_price_details.total_quantity }}</th>
<th class="text-end" colspan="3">
<strong>Средневзвешенная: {{ product.cost_price_details.calculated_cost }} руб.</strong>
<strong>Средневзвешенная: {{ cost_price_details.calculated_cost }} руб.</strong>
</th>
</tr>
</tfoot>

View File

@@ -161,10 +161,14 @@ class ProductDetailView(LoginRequiredMixin, ManagerOwnerRequiredMixin, DetailVie
context_object_name = 'product'
def get_queryset(self):
# Предзагрузка фотографий и аннотация остатков
# Предзагрузка фотографий, категорий, тегов и аннотация остатков
total_available = Coalesce(Sum('stocks__quantity_available'), Value(0), output_field=DecimalField())
total_reserved = Coalesce(Sum('stocks__quantity_reserved'), Value(0), output_field=DecimalField())
return super().get_queryset().prefetch_related('photos').annotate(
return super().get_queryset().prefetch_related(
'photos',
'categories',
'tags'
).annotate(
total_available=total_available,
total_reserved=total_reserved,
total_free=total_available - total_reserved,
@@ -172,9 +176,16 @@ class ProductDetailView(LoginRequiredMixin, ManagerOwnerRequiredMixin, DetailVie
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Добавляем фотографии товара в контекст
context['product_photos'] = self.object.photos.all().order_by('order', 'created_at')
context['photos_count'] = self.object.photos.count()
# Добавляем фотографии товара в контекст (используем уже загруженные через prefetch_related)
product_photos = list(self.object.photos.all())
product_photos.sort(key=lambda x: (x.order, x.created_at))
context['product_photos'] = product_photos
context['photos_count'] = len(product_photos)
# Кешируем cost_price_details, чтобы не делать множественные запросы к БД
from ..services.cost_calculator import ProductCostCalculator
context['cost_price_details'] = ProductCostCalculator.get_cost_details(self.object)
return context