14 KiB
Статус исправления багов 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→currentIndexjournal_entry.jsстроки 1237-1239: убраны индивидуальныеfrappe.show_alert()во время импорта
Почему может не работать:
- Нужно выполнить
bench build --app invoice_azчтобы скомпилировать JavaScript - Нужно обновить страницу в браузере (Ctrl+F5)
Проблема: Пользователь не проверял после исправлений
БАГ 3: Детальные ошибки не отображаются
Статус: ❌ НЕ РАБОТАЕТ Проблема: При "Import Completed with Errors" нет информации о том, что именно пошло не так
Что исправлено в коде:
- vat_api.py (строки 489-513): Добавлены поля
tin,customer_name,income,operation_date,operation_type,account_number,missing_tinв errors - journal_entry.js (строка 1242): Изменено с
VATETaxes.errors.add(operation, error.error_type, error.message)наVATETaxes.errors.add(operation, error.error_type, error.message, error)- передается полный объект - journal_entry.js (строки 628-654): Добавлено отображение Amount, Customer Name, Missing Account, Missing TIN
Почему не работает:
- JavaScript не пересобран: нужен
bench build --app invoice_az - Кэш браузера: нужен Ctrl+F5
Как проверить что работает:
- Импортировать операцию с несуществующим TIN
- Кликнуть "View Error Details"
- Должны видеть:
- Amount: сумма в AZN
- Customer Name: название клиента из операции
- Missing TIN: TIN который не найден
- Missing Account: номер счета (226 или 211) который отсутствует
БАГ 4: ПАРАДОКС УДАЛЕНИЯ (КРИТИЧЕСКАЯ ПРОБЛЕМА!)
Статус: 🔴 КРИТИЧЕСКИЙ БАГ - СОЗДАН DEADLOCK
Проблема:
- Нельзя удалить E-Taxes VAT Operations → выходит ошибка "Cannot delete... because it is linked with Journal Entry"
- Нельзя удалить Journal Entry → при попытке удалить JE, система пытается удалить связанный E-Taxes VAT Operations
- E-Taxes VAT Operations выбрасывает ошибку из
on_trash()→ удаление JE прерывается - РЕЗУЛЬТАТ: Невозможно удалить ни JE, ни VAT Operations!
Текущий код:
e_taxes_vat_operations.py (строки 10-19):
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):
# Удаляем с 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:
# ВМЕСТО:
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:
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:
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:
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:
# СТАРЫЙ КОД (не работает):
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.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"
)
После исправления:
bench restart
Тест:
- Импортировать операцию → создается JE + VAT Operations
- Попытаться удалить VAT Operations вручную → ошибка (защита работает)
- Удалить Journal Entry → VAT Operations автоматически удаляется (каскад работает)
📝 КОМАНДЫ ДЛЯ ПРИМЕНЕНИЯ ВСЕХ ИСПРАВЛЕНИЙ
# 1. Очистить кэш
bench clear-cache
# 2. Собрать JavaScript (для БАГ 2 и БАГ 3)
bench build --app invoice_az
# 3. Перезапустить сервер (для всех Python изменений)
bench restart
# 4. В браузере: Ctrl+F5 (полная перезагрузка страницы)
🧪 ТЕСТИРОВАНИЕ ПОСЛЕ ИСПРАВЛЕНИЙ
Тест 1: Фильтрация
✅ Работает - пользователь подтвердил
Тест 2: Визуальные баги
Проверить:
- Импортировать 5-10 операций
- Прогресс-бар должен идти от 0% до 100% плавно
- Не должно быть зеленых алертов во время импорта
- Только один диалог в конце
Тест 3: Детальные ошибки
Проверить:
- Импортировать операцию с несуществующим TIN
- Кликнуть "View Error Details"
- Должны увидеть: Amount, Customer Name, Missing TIN
- Экспорт в CSV должен содержать эти поля
Тест 4: Удаление (после исправления)
Проверить:
- Импортировать операцию → создается JE + VAT Operations
- Открыть VAT Operations напрямую → попытаться удалить → должна быть ошибка
- Открыть Journal Entry → удалить → JE удален + VAT Operations автоматически удален
- Проверить что 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 |
📁 ИЗМЕНЕННЫЕ ФАЙЛЫ
-
✅
/home/frappe/frappe-bench/apps/invoice_az/invoice_az/vat_api.py- Строки 124-143: фильтрация в
get_vat_operations() - Строки 489-513: детальные ошибки в
import_vat_operations()
- Строки 124-143: фильтрация в
-
✅
/home/frappe/frappe-bench/apps/invoice_az/invoice_az/client/journal_entry.js- Строка 1198: исправлен прогресс-бар
- Строки 1237-1239: убраны алерты
- Строка 1242: передача полного объекта ошибки
- Строки 628-654: отображение детальной информации
-
✅
/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()
- Строки 10-19: защита от удаления через
-
✅
/home/frappe/frappe-bench/apps/invoice_az/invoice_az/vat_operations.py- Создан новый файл с каскадным удалением
- ⚠️ ТРЕБУЕТ ИСПРАВЛЕНИЯ - заменить
frappe.delete_docнаfrappe.db.delete
-
✅
/home/frappe/frappe-bench/apps/invoice_az/invoice_az/hooks.py- Добавлен хук для Journal Entry
on_trashиon_cancel
- Добавлен хук для Journal Entry
🎯 ПРИОРИТЕТ ИСПРАВЛЕНИЙ
- ВЫСОКИЙ: БАГ 4 - Парадокс удаления (блокирует удаление документов)
- СРЕДНИЙ: БАГ 3 - Детальные ошибки (нужно для отладки)
- НИЗКИЙ: БАГ 2 - Визуальные баги (косметические)
Конец документа