docs: Добавить документацию по исправлению race condition при загрузке корректировки цены
Добавлены три документа: 1. FINAL_FIX_SUMMARY.md - Финальное резюме исправления 2. ADJUSTMENT_VALUE_FIX_TESTING.md - План тестирования и проверки 3. TECHNICAL_RACE_CONDITION_FIX.md - Глубокий технический анализ проблемы и решения Документы включают: - Описание проблемы и решения - Пошаговый план тестирования (4 сценария) - Анализ race condition на примере JS event loop - Трёхуровневая защита от race condition - Логирование для отладки - Сравнение подходов синхронизации 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
265
ADJUSTMENT_VALUE_FIX_TESTING.md
Normal file
265
ADJUSTMENT_VALUE_FIX_TESTING.md
Normal file
@@ -0,0 +1,265 @@
|
||||
# Тестирование исправления загрузки сохранённых значений корректировки цены
|
||||
|
||||
## Дата исправления: 2025-11-02
|
||||
## Коммит: c7bf23c
|
||||
|
||||
---
|
||||
|
||||
## Описание проблемы (которая была исправлена)
|
||||
|
||||
**Проблема:** Сохранённые значения корректировки цены не отображались на странице редактирования комплекта.
|
||||
- Отображались только в 1 из 10 случаев
|
||||
- Большую часть времени поля были пустыми
|
||||
- Когда отображались, то сразу затирались какой-то переинициализацией
|
||||
|
||||
**URL для воспроизведения:** `http://grach.localhost:8000/products/kits/4/update/`
|
||||
|
||||
**Корневая причина:**
|
||||
1. При загрузке значений в input-поля срабатывают события `input` и `change`
|
||||
2. Эти события вызывают `calculateFinalPrice()` и `validateSingleAdjustment()`
|
||||
3. Функция `calculateFinalPrice()` перезаписывает скрытые поля (`id_price_adjustment_type`, `id_price_adjustment_value`) со значениями по умолчанию
|
||||
4. Получается race condition: значения загружаются → события срабатывают → значения стираются
|
||||
|
||||
---
|
||||
|
||||
## Что было исправлено
|
||||
|
||||
### Решение: Два уровня защиты от перезаписи
|
||||
|
||||
**Уровень 1: Флаг `isLoadingAdjustmentValues`**
|
||||
- Подавляет события `input` и `change` во время загрузки значений
|
||||
- Код видит эти события, но пропускает обработку
|
||||
- Логирует в консоль: "Skipping event during adjustment value loading"
|
||||
|
||||
**Уровень 2: Флаг `isInitializing`**
|
||||
- Даже если событие обработается, `calculateFinalPrice()` не перезапишет скрытые поля
|
||||
- Проверка: `if (!isInitializing) { adjustmentTypeInput.value = ...; }`
|
||||
|
||||
**Уровень 3: `requestAnimationFrame`**
|
||||
- Гарантирует что `isInitializing = false` устанавливается в конце frame
|
||||
- Синхронизация с браузерным rendering cycle
|
||||
|
||||
### Файлы изменены
|
||||
|
||||
**`productkit_edit.html`** (строки 435, 683-696, 912-935)
|
||||
```javascript
|
||||
// Строка 435: Добавлен новый флаг
|
||||
let isLoadingAdjustmentValues = false;
|
||||
|
||||
// Строки 683-696: Добавлена проверка в event listeners
|
||||
input.addEventListener('input', () => {
|
||||
if (isLoadingAdjustmentValues) {
|
||||
console.log('Skipping event during adjustment value loading');
|
||||
return;
|
||||
}
|
||||
validateSingleAdjustment();
|
||||
calculateFinalPrice();
|
||||
});
|
||||
|
||||
// Строки 912-935: Используется флаг во время загрузки значений
|
||||
isLoadingAdjustmentValues = true;
|
||||
console.log('isLoadingAdjustmentValues = true, suppressing input/change events');
|
||||
|
||||
// Загрузка значений
|
||||
// ...
|
||||
|
||||
isLoadingAdjustmentValues = false;
|
||||
console.log('isLoadingAdjustmentValues = false, events are enabled again');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Как тестировать исправление
|
||||
|
||||
### Тестовые данные
|
||||
Используются комплекты в тенанте "grach":
|
||||
- **Kit #4:** "Комплект Роза" с корректировкой `increase_percent: 10.00`
|
||||
- **Kit #2:** "Комплект белые розы" с корректировкой `increase_amount: 5.00`
|
||||
|
||||
### Сценарий 1: Проверка отображения на странице редактирования (10 раз)
|
||||
|
||||
**Цель:** Убедиться что значение отображается ВСЕГДА, а не 1 раз из 10
|
||||
|
||||
**Шаги:**
|
||||
1. Открыть http://grach.localhost:8000/products/kits/4/update/
|
||||
2. Нажать Ctrl+F5 (очистить кэш и перезагрузить)
|
||||
3. Найти блок "НА СКОЛЬКО БЫЛА ИЗМЕНЕНА ЦЕНА"
|
||||
4. Должно отображаться: поле "Увеличить на %" с значением **10**
|
||||
5. Повторить шаги 2-4 ещё 9 раз (всего 10 раз)
|
||||
|
||||
**Ожидаемый результат:** 10/10 раз значение 10 отображается в поле
|
||||
|
||||
**Признаки успеха:**
|
||||
- ✅ Поле не пустое
|
||||
- ✅ Значение = 10
|
||||
- ✅ Остальные 3 поля (Увеличить на сумму, Уменьшить на %, Уменьшить на сумму) - отключены (disabled)
|
||||
- ✅ Они помечены серым цветом (не активны)
|
||||
|
||||
### Сценарий 2: Проверка логирования в консоли браузера
|
||||
|
||||
**Цель:** Убедиться что логирование показывает правильный порядок выполнения
|
||||
|
||||
**Шаги:**
|
||||
1. Открыть http://grach.localhost:8000/products/kits/4/update/
|
||||
2. Нажать F12 (открыть DevTools)
|
||||
3. Перейти на вкладку **Console**
|
||||
4. Нажать Ctrl+F5
|
||||
5. В консоли должны появиться логи (отсортировать по времени вверх):
|
||||
|
||||
**Ожидаемые логи (в таком порядке):**
|
||||
```
|
||||
Loading saved adjustment values: {type: 'increase_percent', value: 10}
|
||||
isLoadingAdjustmentValues = true, suppressing input/change events
|
||||
Loaded increase_percent: 10
|
||||
isLoadingAdjustmentValues = false, events are enabled again
|
||||
calculateFinalPrice: calculating...
|
||||
[несколько логов о расчётах цен]
|
||||
Initialization complete, isInitializing = false
|
||||
```
|
||||
|
||||
**Признаки успеха:**
|
||||
- ✅ `isLoadingAdjustmentValues = true` появляется ДО загрузки значений
|
||||
- ✅ `Loaded increase_percent: 10` показывает что значение загружено
|
||||
- ✅ `isLoadingAdjustmentValues = false` появляется ПОСЛЕ загрузки
|
||||
- ✅ `Initialization complete` появляется в конце
|
||||
- ✅ Нет ошибок в консоли (красных сообщений)
|
||||
|
||||
### Сценарий 3: Проверка редактирования корректировки
|
||||
|
||||
**Цель:** Убедиться что можно изменить значение и оно сохраняется
|
||||
|
||||
**Шаги:**
|
||||
1. Открыть http://grach.localhost:8000/products/kits/4/update/
|
||||
2. В поле "Увеличить на %" изменить значение с 10 на 15
|
||||
3. Нажать кнопку "Сохранить"
|
||||
4. Открыть страницу редактирования снова (F5)
|
||||
5. Проверить что значение = 15
|
||||
|
||||
**Ожидаемый результат:**
|
||||
- ✅ Значение измененo на 15
|
||||
- ✅ Сохранилось в БД
|
||||
- ✅ При перезагрузке отображается 15
|
||||
|
||||
### Сценарий 4: Проверка другого комплекта (с decrease_percent)
|
||||
|
||||
**Цель:** Убедиться что исправление работает для всех 4 типов корректировки
|
||||
|
||||
**Шаги:**
|
||||
1. Создать новый комплект
|
||||
2. Добавить товар
|
||||
3. В блоке "НА СКОЛЬКО БЫЛА ИЗМЕНЕНА ЦЕНА" выбрать "Уменьшить на %" и ввести 20
|
||||
4. Сохранить
|
||||
5. Открыть для редактирования
|
||||
6. Проверить что "Уменьшить на %" = 20
|
||||
7. Повторить 5 раз
|
||||
|
||||
**Ожидаемый результат:** 5/5 раз значение отображается правильно
|
||||
|
||||
---
|
||||
|
||||
## Что смотреть в консоли браузера (для отладки)
|
||||
|
||||
**F12 → Console → Filter (Фильтр)**
|
||||
|
||||
Полезные логи:
|
||||
```javascript
|
||||
// Загрузка сохранённых значений
|
||||
"Loading saved adjustment values:"
|
||||
"isLoadingAdjustmentValues = true"
|
||||
"Loaded increase_percent: 10"
|
||||
"isLoadingAdjustmentValues = false"
|
||||
|
||||
// События которые подавляются
|
||||
"Skipping event during adjustment value loading"
|
||||
|
||||
// Инициализация завершена
|
||||
"Initialization complete, isInitializing = false"
|
||||
```
|
||||
|
||||
**Если видите эти логи в консоли - значит исправление работает правильно.**
|
||||
|
||||
---
|
||||
|
||||
## Возможные проблемы и решения
|
||||
|
||||
### Проблема: Значение всё ещё не отображается
|
||||
**Решение:**
|
||||
1. Откройте консоль (F12)
|
||||
2. Проверьте логи - есть ли ошибки?
|
||||
3. Проверьте что комплект в БД имеет значение `price_adjustment_value` > 0
|
||||
4. Очистите браузерный кэш (Ctrl+Shift+Delete)
|
||||
5. Нажмите Ctrl+F5 на странице редактирования
|
||||
|
||||
### Проблема: Логи не появляются
|
||||
**Решение:**
|
||||
1. Проверьте что консоль не отфильтрована (нет активного фильтра)
|
||||
2. Нажмите Ctrl+F5 (hard refresh)
|
||||
3. Проверьте что в productkit_edit.html есть код с логами (смотрите коммит c7bf23c)
|
||||
|
||||
### Проблема: Значение загружается но потом исчезает
|
||||
**Решение:**
|
||||
1. Это была исходная проблема
|
||||
2. Если она всё ещё есть - значит исправление не развернулось
|
||||
3. Проверьте git статус: `git log -1`
|
||||
4. Должен быть коммит "c7bf23c fix: Улучшить загрузку сохранённых значений"
|
||||
5. Если коммита нет - обновите файл productkit_edit.html вручную
|
||||
|
||||
---
|
||||
|
||||
## Результаты тестирования
|
||||
|
||||
Заполните после выполнения тестов:
|
||||
|
||||
| Сценарий | Попыток | Успешных | Результат |
|
||||
|----------|---------|----------|-----------|
|
||||
| 1. Отображение (10 раз) | 10 | __/10 | ✅ / ❌ |
|
||||
| 2. Логирование | 1 | __/1 | ✅ / ❌ |
|
||||
| 3. Редактирование | 1 | __/1 | ✅ / ❌ |
|
||||
| 4. Другой тип коррекции | 5 | __/5 | ✅ / ❌ |
|
||||
|
||||
**Итоговый результат:** ✅ ПРОЙДЕНО / ❌ НЕ ПРОЙДЕНО
|
||||
|
||||
---
|
||||
|
||||
## Архитектура исправления
|
||||
|
||||
```
|
||||
Загрузка страницы редактирования
|
||||
↓
|
||||
1. DOMContentLoaded срабатывает
|
||||
↓
|
||||
2. Инициализация переменных
|
||||
- isInitializing = true
|
||||
- isLoadingAdjustmentValues = false
|
||||
- priceCache = {}
|
||||
↓
|
||||
3. Регистрация event listeners (с проверкой isLoadingAdjustmentValues)
|
||||
↓
|
||||
4. setTimeout 500ms → Загрузка сохранённых значений
|
||||
↓
|
||||
5a. Устанавливаем isLoadingAdjustmentValues = true
|
||||
5b. Заполняем поля (input события ПОДАВЛЯЮТСЯ благодаря флагу)
|
||||
5c. Вызываем validateSingleAdjustment()
|
||||
5d. Устанавливаем isLoadingAdjustmentValues = false
|
||||
↓
|
||||
6. calculateFinalPrice() с isInitializing = true
|
||||
(не перезапишет скрытые поля даже если они обновятся)
|
||||
↓
|
||||
7. requestAnimationFrame × 2 → isInitializing = false
|
||||
(в конце frame cycle, после всех events)
|
||||
↓
|
||||
8. ГОТОВО: значения загружены, события обрабатываются, скрытые поля защищены
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Заключение
|
||||
|
||||
Исправление использует трёхуровневую защиту:
|
||||
1. **Подавление событий** (isLoadingAdjustmentValues) во время загрузки
|
||||
2. **Защита скрытых полей** (isInitializing) от перезаписи
|
||||
3. **Синхронизация с браузером** (requestAnimationFrame) для надёжности
|
||||
|
||||
Это должно полностью исправить проблему с надёжностью загрузки сохранённых значений корректировки цены.
|
||||
|
||||
🎉 **Готово к тестированию!**
|
||||
Reference in New Issue
Block a user