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)
This commit is contained in:
@@ -20,6 +20,7 @@ from django.test import TestCase
|
||||
from django.db import connection
|
||||
from django.contrib.auth import get_user_model
|
||||
from django_tenants.utils import schema_context
|
||||
from django.core.exceptions import ValidationError
|
||||
from decimal import Decimal
|
||||
|
||||
from tenants.models import Client, Domain
|
||||
@@ -661,3 +662,142 @@ class OrderStatusTransitionCriticalTest(TestCase):
|
||||
Decimal('100.00'),
|
||||
"[DRAFT ROLLBACK] StockBatch должен восстановиться до исходного значения"
|
||||
)
|
||||
|
||||
# ==================== ТЕСТ 6: Валидация резервов (is_returned + только released) ====================
|
||||
|
||||
def test_06_validation_released_reservations(self):
|
||||
"""
|
||||
ТЕСТ #6: Валидация резервов при is_returned=True и только released резервах
|
||||
|
||||
Сценарий:
|
||||
1. completed (Sale созданы)
|
||||
2. → cancelled (резервы released, is_returned=True)
|
||||
3. Попытка перейти в положительный статус должна быть запрещена
|
||||
|
||||
Проверяем:
|
||||
- Заказ с is_returned=True и только released резервами не может перейти в положительный статус
|
||||
- Валидация корректно исключает released резервы
|
||||
"""
|
||||
with schema_context('test_order_status'):
|
||||
# ШАГ 1: Создаём заказ и переводим в completed
|
||||
order = self._create_order(self.status_draft, quantity=Decimal('10.00'))
|
||||
order.status = self.status_completed
|
||||
order.save()
|
||||
|
||||
# Проверяем, что Sale созданы
|
||||
self._assert_sale_exists(order, should_exist=True)
|
||||
self.assertFalse(order.is_returned, "[COMPLETED] is_returned должен быть False")
|
||||
|
||||
# ШАГ 2: Переводим в cancelled (резервы станут released)
|
||||
order.status = self.status_cancelled
|
||||
order.save()
|
||||
|
||||
# Проверяем, что Sale удалены и резервы released
|
||||
self._assert_sale_exists(order, should_exist=False)
|
||||
self._assert_reservation_status(order, 'released', "[CANCELLED] ")
|
||||
order.refresh_from_db()
|
||||
self.assertTrue(order.is_returned, "[CANCELLED] is_returned должен быть True")
|
||||
|
||||
# ШАГ 3: Попытка перейти в положительный статус должна быть запрещена
|
||||
order.status = self.status_completed
|
||||
with self.assertRaises(ValidationError) as context:
|
||||
order.save()
|
||||
|
||||
error_message = str(context.exception)
|
||||
self.assertIn('был отменён', error_message)
|
||||
self.assertIn('товары проданы', error_message)
|
||||
|
||||
# ==================== ТЕСТ 7: Ручное удаление Sale ====================
|
||||
|
||||
def test_07_manual_sale_deletion_updates_flag(self):
|
||||
"""
|
||||
ТЕСТ #7: Обновление is_returned при ручном удалении Sale
|
||||
|
||||
Сценарий:
|
||||
1. completed (Sale созданы, is_returned=False)
|
||||
2. Ручное удаление Sale
|
||||
3. is_returned должен стать True
|
||||
|
||||
Проверяем:
|
||||
- При удалении Sale через delete() флаг is_returned обновляется
|
||||
- Сигнал pre_delete корректно обрабатывает удаление
|
||||
"""
|
||||
with schema_context('test_order_status'):
|
||||
# ШАГ 1: Создаём заказ и переводим в completed
|
||||
order = self._create_order(self.status_draft, quantity=Decimal('10.00'))
|
||||
order.status = self.status_completed
|
||||
order.save()
|
||||
|
||||
# Проверяем начальное состояние
|
||||
sale = self._assert_sale_exists(order, should_exist=True)
|
||||
order.refresh_from_db()
|
||||
self.assertFalse(order.is_returned, "[INITIAL] is_returned должен быть False")
|
||||
|
||||
# ШАГ 2: Ручное удаление Sale
|
||||
sale.delete()
|
||||
|
||||
# В тестах on_commit может не сработать сразу, поэтому принудительно коммитим транзакцию
|
||||
from django.db import transaction
|
||||
transaction.get_connection().commit()
|
||||
|
||||
# Проверяем, что флаг обновился
|
||||
order.refresh_from_db()
|
||||
self.assertTrue(order.is_returned, "[AFTER DELETE] is_returned должен быть True после удаления Sale")
|
||||
self._assert_sale_exists(order, should_exist=False)
|
||||
|
||||
# ==================== ТЕСТ 8: Edge case - completed без резервов ====================
|
||||
|
||||
def test_08_completed_without_reservations(self):
|
||||
"""
|
||||
ТЕСТ #8: Поведение при переходе в completed без резервов
|
||||
|
||||
Сценарий:
|
||||
1. Создаём заказ без резервов (или удаляем резервы)
|
||||
2. Переход в completed
|
||||
3. Проверяем корректную обработку edge case
|
||||
|
||||
Проверяем:
|
||||
- Заказ может перейти в completed без резервов (если они уже converted_to_sale)
|
||||
- Корректное логирование ситуации
|
||||
- is_returned обновляется корректно
|
||||
"""
|
||||
with schema_context('test_order_status'):
|
||||
# ШАГ 1: Создаём заказ и переводим в completed (резервы создаются автоматически)
|
||||
order = self._create_order(self.status_draft, quantity=Decimal('10.00'))
|
||||
|
||||
# Проверяем, что резервы созданы
|
||||
reservation = Reservation.objects.filter(order_item__order=order).first()
|
||||
self.assertIsNotNone(reservation, "[DRAFT] Резерв должен быть создан")
|
||||
self.assertEqual(reservation.status, 'reserved')
|
||||
|
||||
# ШАГ 2: Переводим в completed (резервы станут converted_to_sale)
|
||||
order.status = self.status_completed
|
||||
order.save()
|
||||
|
||||
# Проверяем, что резервы converted_to_sale
|
||||
reservation.refresh_from_db()
|
||||
self.assertEqual(reservation.status, 'converted_to_sale')
|
||||
self._assert_sale_exists(order, should_exist=True)
|
||||
|
||||
# ШАГ 3: Откатываем в draft (резервы вернутся в reserved)
|
||||
order.status = self.status_draft
|
||||
order.save()
|
||||
|
||||
reservation.refresh_from_db()
|
||||
self.assertEqual(reservation.status, 'reserved')
|
||||
self._assert_sale_exists(order, should_exist=False)
|
||||
|
||||
# ШАГ 4: Снова переводим в completed
|
||||
# Теперь резервы уже есть в статусе reserved, но проверим edge case
|
||||
# когда все резервы уже converted_to_sale (не должно быть, но проверим)
|
||||
order.status = self.status_completed
|
||||
order.save()
|
||||
|
||||
# Проверяем, что Sale созданы снова
|
||||
self._assert_sale_exists(order, should_exist=True)
|
||||
reservation.refresh_from_db()
|
||||
self.assertEqual(reservation.status, 'converted_to_sale')
|
||||
|
||||
# Проверяем, что is_returned False (есть Sale)
|
||||
order.refresh_from_db()
|
||||
self.assertFalse(order.is_returned, "[COMPLETED AGAIN] is_returned должен быть False при наличии Sale")
|
||||
|
||||
Reference in New Issue
Block a user