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

---

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