360 lines
14 KiB
Markdown
360 lines
14 KiB
Markdown
# Статус исправления багов VAT Operations Import
|
||
|
||
**Дата:** 2026-01-13
|
||
**Статус лимита токенов:** ~73K остаток
|
||
|
||
---
|
||
|
||
## ✅ ИСПРАВЛЕНО И РАБОТАЕТ
|
||
|
||
### БАГ 1: Фильтрация операций (income без expense)
|
||
**Статус:** ✅ РАБОТАЕТ
|
||
**Исправление:** Добавлена фильтрация в `vat_api.py` в функцию `get_vat_operations()` (строки 124-143)
|
||
**Проверено:** Пользователь подтвердил - фильтр работает
|
||
|
||
---
|
||
|
||
## ❌ НЕ РАБОТАЕТ / ЕСТЬ ПРОБЛЕМЫ
|
||
|
||
### БАГ 2: Визуальные баги (прогресс-бар, алерты)
|
||
**Статус:** ⚠️ ЧАСТИЧНО (требует проверки после bench build)
|
||
**Что исправлено в коде:**
|
||
- `journal_entry.js` строка 1198: `currentIndex - 1` → `currentIndex`
|
||
- `journal_entry.js` строки 1237-1239: убраны индивидуальные `frappe.show_alert()` во время импорта
|
||
|
||
**Почему может не работать:**
|
||
- Нужно выполнить `bench build --app invoice_az` чтобы скомпилировать JavaScript
|
||
- Нужно обновить страницу в браузере (Ctrl+F5)
|
||
|
||
**Проблема:** Пользователь не проверял после исправлений
|
||
|
||
---
|
||
|
||
### БАГ 3: Детальные ошибки не отображаются
|
||
**Статус:** ❌ НЕ РАБОТАЕТ
|
||
**Проблема:** При "Import Completed with Errors" нет информации о том, что именно пошло не так
|
||
|
||
**Что исправлено в коде:**
|
||
1. **vat_api.py** (строки 489-513): Добавлены поля `tin`, `customer_name`, `income`, `operation_date`, `operation_type`, `account_number`, `missing_tin` в errors
|
||
2. **journal_entry.js** (строка 1242): Изменено с `VATETaxes.errors.add(operation, error.error_type, error.message)` на `VATETaxes.errors.add(operation, error.error_type, error.message, error)` - передается полный объект
|
||
3. **journal_entry.js** (строки 628-654): Добавлено отображение Amount, Customer Name, Missing Account, Missing TIN
|
||
|
||
**Почему не работает:**
|
||
- JavaScript не пересобран: нужен `bench build --app invoice_az`
|
||
- Кэш браузера: нужен Ctrl+F5
|
||
|
||
**Как проверить что работает:**
|
||
1. Импортировать операцию с несуществующим TIN
|
||
2. Кликнуть "View Error Details"
|
||
3. Должны видеть:
|
||
- **Amount:** сумма в AZN
|
||
- **Customer Name:** название клиента из операции
|
||
- **Missing TIN:** TIN который не найден
|
||
- **Missing Account:** номер счета (226 или 211) который отсутствует
|
||
|
||
---
|
||
|
||
### БАГ 4: ПАРАДОКС УДАЛЕНИЯ (КРИТИЧЕСКАЯ ПРОБЛЕМА!)
|
||
**Статус:** 🔴 КРИТИЧЕСКИЙ БАГ - СОЗДАН DEADLOCK
|
||
|
||
**Проблема:**
|
||
1. Нельзя удалить **E-Taxes VAT Operations** → выходит ошибка "Cannot delete... because it is linked with Journal Entry"
|
||
2. Нельзя удалить **Journal Entry** → при попытке удалить JE, система пытается удалить связанный E-Taxes VAT Operations
|
||
3. E-Taxes VAT Operations выбрасывает ошибку из `on_trash()` → удаление JE прерывается
|
||
4. **РЕЗУЛЬТАТ: Невозможно удалить ни JE, ни VAT Operations!**
|
||
|
||
**Текущий код:**
|
||
|
||
**e_taxes_vat_operations.py** (строки 10-19):
|
||
```python
|
||
def on_trash(self):
|
||
"""Защита от удаления если связано с Journal Entry"""
|
||
if self.journal_entry:
|
||
# Проверяем, существует ли Journal Entry
|
||
if frappe.db.exists("Journal Entry", self.journal_entry):
|
||
frappe.throw(
|
||
_("Cannot delete or cancel E-Taxes VAT Operations {0} because it is linked with Journal Entry {1}").format(
|
||
self.name,
|
||
self.journal_entry
|
||
)
|
||
)
|
||
```
|
||
|
||
**vat_operations.py** (строки 28-34):
|
||
```python
|
||
# Удаляем с force=True чтобы обойти before_delete()
|
||
frappe.delete_doc(
|
||
'E-Taxes VAT Operations',
|
||
record.name,
|
||
ignore_permissions=True,
|
||
force=True # ⚠️ НЕ ОБХОДИТ on_trash!!!
|
||
)
|
||
```
|
||
|
||
**ПРОБЛЕМА:** `force=True` игнорирует только permissions, но **НЕ** игнорирует `on_trash()`!
|
||
|
||
---
|
||
|
||
## 🔧 РЕШЕНИЯ ДЛЯ БАГА 4 (ПАРАДОКС УДАЛЕНИЯ)
|
||
|
||
### Вариант 1: Использовать frappe.db.delete() (РЕКОМЕНДУЕТСЯ)
|
||
|
||
**Изменить `vat_operations.py`:**
|
||
```python
|
||
# ВМЕСТО:
|
||
frappe.delete_doc('E-Taxes VAT Operations', record.name, ignore_permissions=True, force=True)
|
||
|
||
# ИСПОЛЬЗОВАТЬ:
|
||
frappe.db.delete('E-Taxes VAT Operations', {'name': record.name})
|
||
frappe.db.commit()
|
||
```
|
||
|
||
**Плюсы:**
|
||
- Прямое удаление из БД, обходит все хуки
|
||
- Простое и надежное
|
||
|
||
**Минусы:**
|
||
- Не запускает cascade delete для связанных документов (но у VAT Operations нет связанных)
|
||
|
||
---
|
||
|
||
### Вариант 2: Проверка контекста в on_trash()
|
||
|
||
**Изменить `e_taxes_vat_operations.py`:**
|
||
```python
|
||
def on_trash(self):
|
||
"""Защита от удаления если связано с Journal Entry"""
|
||
# Проверяем флаг принудительного удаления
|
||
if getattr(self, '_skip_trash_validation', False):
|
||
return
|
||
|
||
if self.journal_entry:
|
||
if frappe.db.exists("Journal Entry", self.journal_entry):
|
||
frappe.throw(
|
||
_("Cannot delete or cancel E-Taxes VAT Operations {0} because it is linked with Journal Entry {1}").format(
|
||
self.name,
|
||
self.journal_entry
|
||
)
|
||
)
|
||
```
|
||
|
||
**Изменить `vat_operations.py`:**
|
||
```python
|
||
for record in vat_records:
|
||
# Получаем документ
|
||
doc = frappe.get_doc('E-Taxes VAT Operations', record.name)
|
||
|
||
# Устанавливаем флаг для обхода валидации
|
||
doc._skip_trash_validation = True
|
||
|
||
# Удаляем
|
||
doc.delete(ignore_permissions=True, force=True)
|
||
```
|
||
|
||
**Плюсы:**
|
||
- Сохраняет логику валидации для ручного удаления
|
||
- Разрешает каскадное удаление из кода
|
||
|
||
**Минусы:**
|
||
- Более сложная логика
|
||
- Использует "внутренний" флаг
|
||
|
||
---
|
||
|
||
### Вариант 3: Изменить логику защиты (САМЫЙ ПРАВИЛЬНЫЙ)
|
||
|
||
**Идея:** Разрешить удаление VAT Operations всегда, но проверять только если пытаемся удалить ВРУЧНУЮ (не программно)
|
||
|
||
**Изменить `e_taxes_vat_operations.py`:**
|
||
```python
|
||
def on_trash(self):
|
||
"""Защита от удаления если связано с Journal Entry"""
|
||
# Пропускаем проверку если удаление идет из кода (не от пользователя)
|
||
if frappe.flags.in_test or frappe.flags.in_migrate:
|
||
return
|
||
|
||
# Проверяем только при ручном удалении
|
||
if self.journal_entry:
|
||
if frappe.db.exists("Journal Entry", self.journal_entry):
|
||
frappe.throw(
|
||
_("Cannot delete E-Taxes VAT Operations {0} because it is linked with Journal Entry {1}. "
|
||
"Please delete the Journal Entry first.").format(
|
||
self.name,
|
||
self.journal_entry
|
||
)
|
||
)
|
||
```
|
||
|
||
**НО:** Это не различает программное удаление от ручного! Все равно заблокирует.
|
||
|
||
---
|
||
|
||
### Вариант 4: Вообще убрать защиту от удаления
|
||
|
||
**Просто удалить метод `on_trash()` из `e_taxes_vat_operations.py`**
|
||
|
||
**Плюсы:**
|
||
- Просто
|
||
- Нет парадокса
|
||
|
||
**Минусы:**
|
||
- Пользователь может случайно удалить VAT Operations вручную
|
||
- Нарушится связь с Journal Entry
|
||
|
||
---
|
||
|
||
## 📋 РЕКОМЕНДУЕМОЕ РЕШЕНИЕ
|
||
|
||
### Использовать **Вариант 1** - frappe.db.delete()
|
||
|
||
**Файл:** `/home/frappe/frappe-bench/apps/invoice_az/invoice_az/vat_operations.py`
|
||
|
||
**Заменить строки 28-34:**
|
||
|
||
```python
|
||
# СТАРЫЙ КОД (не работает):
|
||
frappe.delete_doc(
|
||
'E-Taxes VAT Operations',
|
||
record.name,
|
||
ignore_permissions=True,
|
||
force=True
|
||
)
|
||
|
||
# НОВЫЙ КОД:
|
||
frappe.db.delete('E-Taxes VAT Operations', {'name': record.name})
|
||
```
|
||
|
||
**Полная функция:**
|
||
```python
|
||
@frappe.whitelist()
|
||
def on_delete_journal_entry(doc, method):
|
||
"""Удаляет связанные E-Taxes VAT Operations при удалении Journal Entry"""
|
||
try:
|
||
vat_records = frappe.get_all(
|
||
"E-Taxes VAT Operations",
|
||
filters={"journal_entry": doc.name},
|
||
fields=["name"]
|
||
)
|
||
|
||
if vat_records:
|
||
for record in vat_records:
|
||
frappe.logger().info(
|
||
f"Deleting E-Taxes VAT Operations {record.name} "
|
||
f"due to Journal Entry {doc.name} deletion"
|
||
)
|
||
|
||
# Прямое удаление из БД (обходит on_trash)
|
||
frappe.db.delete('E-Taxes VAT Operations', {'name': record.name})
|
||
|
||
frappe.db.commit()
|
||
frappe.logger().info(f"Successfully deleted {len(vat_records)} VAT Operations records")
|
||
|
||
except Exception as e:
|
||
frappe.log_error(
|
||
f"Error deleting E-Taxes VAT Operations for Journal Entry {doc.name}: {str(e)}\n{frappe.get_traceback()}",
|
||
"Journal Entry Delete Error"
|
||
)
|
||
```
|
||
|
||
**После исправления:**
|
||
```bash
|
||
bench restart
|
||
```
|
||
|
||
**Тест:**
|
||
1. Импортировать операцию → создается JE + VAT Operations
|
||
2. Попытаться удалить VAT Operations вручную → ошибка (защита работает)
|
||
3. Удалить Journal Entry → VAT Operations автоматически удаляется (каскад работает)
|
||
|
||
---
|
||
|
||
## 📝 КОМАНДЫ ДЛЯ ПРИМЕНЕНИЯ ВСЕХ ИСПРАВЛЕНИЙ
|
||
|
||
```bash
|
||
# 1. Очистить кэш
|
||
bench clear-cache
|
||
|
||
# 2. Собрать JavaScript (для БАГ 2 и БАГ 3)
|
||
bench build --app invoice_az
|
||
|
||
# 3. Перезапустить сервер (для всех Python изменений)
|
||
bench restart
|
||
|
||
# 4. В браузере: Ctrl+F5 (полная перезагрузка страницы)
|
||
```
|
||
|
||
---
|
||
|
||
## 🧪 ТЕСТИРОВАНИЕ ПОСЛЕ ИСПРАВЛЕНИЙ
|
||
|
||
### Тест 1: Фильтрация
|
||
✅ **Работает** - пользователь подтвердил
|
||
|
||
### Тест 2: Визуальные баги
|
||
**Проверить:**
|
||
1. Импортировать 5-10 операций
|
||
2. Прогресс-бар должен идти от 0% до 100% плавно
|
||
3. Не должно быть зеленых алертов во время импорта
|
||
4. Только один диалог в конце
|
||
|
||
### Тест 3: Детальные ошибки
|
||
**Проверить:**
|
||
1. Импортировать операцию с несуществующим TIN
|
||
2. Кликнуть "View Error Details"
|
||
3. Должны увидеть: Amount, Customer Name, Missing TIN
|
||
4. Экспорт в CSV должен содержать эти поля
|
||
|
||
### Тест 4: Удаление (после исправления)
|
||
**Проверить:**
|
||
1. Импортировать операцию → создается JE + VAT Operations
|
||
2. Открыть VAT Operations напрямую → попытаться удалить → должна быть ошибка
|
||
3. Открыть Journal Entry → удалить → JE удален + VAT Operations автоматически удален
|
||
4. Проверить что VAT Operations больше нет в списке
|
||
|
||
---
|
||
|
||
## 📊 ИТОГОВАЯ СТАТИСТИКА
|
||
|
||
| Баг | Статус | Что нужно |
|
||
|-----|--------|-----------|
|
||
| **1. Фильтрация** | ✅ Работает | - |
|
||
| **2. Визуальные баги** | ⚠️ Требует bench build | `bench build --app invoice_az` |
|
||
| **3. Детальные ошибки** | ⚠️ Требует bench build | `bench build --app invoice_az` |
|
||
| **4. Парадокс удаления** | 🔴 Критический | Заменить `frappe.delete_doc` на `frappe.db.delete` |
|
||
|
||
---
|
||
|
||
## 📁 ИЗМЕНЕННЫЕ ФАЙЛЫ
|
||
|
||
1. ✅ `/home/frappe/frappe-bench/apps/invoice_az/invoice_az/vat_api.py`
|
||
- Строки 124-143: фильтрация в `get_vat_operations()`
|
||
- Строки 489-513: детальные ошибки в `import_vat_operations()`
|
||
|
||
2. ✅ `/home/frappe/frappe-bench/apps/invoice_az/invoice_az/client/journal_entry.js`
|
||
- Строка 1198: исправлен прогресс-бар
|
||
- Строки 1237-1239: убраны алерты
|
||
- Строка 1242: передача полного объекта ошибки
|
||
- Строки 628-654: отображение детальной информации
|
||
|
||
3. ✅ `/home/frappe/frappe-bench/apps/invoice_az/invoice_az/invoice_az/doctype/e_taxes_vat_operations/e_taxes_vat_operations.py`
|
||
- Строки 10-19: защита от удаления через `on_trash()`
|
||
|
||
4. ✅ `/home/frappe/frappe-bench/apps/invoice_az/invoice_az/vat_operations.py`
|
||
- Создан новый файл с каскадным удалением
|
||
- ⚠️ **ТРЕБУЕТ ИСПРАВЛЕНИЯ** - заменить `frappe.delete_doc` на `frappe.db.delete`
|
||
|
||
5. ✅ `/home/frappe/frappe-bench/apps/invoice_az/invoice_az/hooks.py`
|
||
- Добавлен хук для Journal Entry `on_trash` и `on_cancel`
|
||
|
||
---
|
||
|
||
## 🎯 ПРИОРИТЕТ ИСПРАВЛЕНИЙ
|
||
|
||
1. **ВЫСОКИЙ:** БАГ 4 - Парадокс удаления (блокирует удаление документов)
|
||
2. **СРЕДНИЙ:** БАГ 3 - Детальные ошибки (нужно для отладки)
|
||
3. **НИЗКИЙ:** БАГ 2 - Визуальные баги (косметические)
|
||
|
||
---
|
||
|
||
**Конец документа**
|