invoice_az/BUGS_VAT_OPERATIONS.md

14 KiB
Raw Permalink Blame History

Статус исправления багов 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 - 1currentIndex
  • 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):

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

Тест:

  1. Импортировать операцию → создается JE + VAT Operations
  2. Попытаться удалить VAT Operations вручную → ошибка (защита работает)
  3. Удалить 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: Визуальные баги

Проверить:

  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 - Визуальные баги (косметические)

Конец документа