Добавлены три документа: 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>
266 lines
12 KiB
Markdown
266 lines
12 KiB
Markdown
# Тестирование исправления загрузки сохранённых значений корректировки цены
|
||
|
||
## Дата исправления: 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) для надёжности
|
||
|
||
Это должно полностью исправить проблему с надёжностью загрузки сохранённых значений корректировки цены.
|
||
|
||
🎉 **Готово к тестированию!**
|