# Техническое задание: Автоматизация заполнения Декларации по налогу на имущество

## 1. Общее описание

**Цель:** Автоматизировать заполнение дочерних таблиц Əlavə 1 и Əlavə 2 в декларации по налогу на имущество (Property Tax Return) на основе данных об активах (Assets) с использованием логики отчета "Asset Depreciations and Balances" из ERPNext.

**Дата создания:** 2025-12-11

**Версия:** 1.0

---

## 2. Бизнес-требования

### 2.1 Функциональные требования

1. **Добавление полей выбора периода:**
   - Добавить два взаимоисключающих чекбокса в форму Property Tax Return:
     - `Tam İl` (Полный год) - по умолчанию включен
     - `İl Ərzində` (В течение года)
   - Чекбоксы должны располагаться сразу после поля `İl` (Год) на главной странице декларации

2. **Автоматическое заполнение данных:**
   - При изменении года (`İl`) или чекбоксов система должна автоматически:
     - Получить данные об активах из базы данных
     - Рассчитать балансовые стоимости активов
     - Агрегировать данные по типам активов и налоговым статьям
     - Заполнить соответствующие строки в дочерних таблицах

3. **Источник данных:**
   - Все расчеты должны базироваться на отчете ERPNext "Asset Depreciations and Balances"
   - Использовать данные из doctype `Asset` компании пользователя

### 2.2 Пользовательский сценарий

1. Пользователь открывает/создает документ Property Tax Return
2. Заполняет поле `İl` (год декларации, например: 2024)
3. Выбирает режим расчета:
   - `Tam İl` - если компания работала полный год
   - `İl Ərzində` - если компания была создана в течение года
4. Система автоматически:
   - Преобразует год в диапазон дат (01.01.YYYY - 31.12.YYYY)
   - Получает данные об активах
   - Заполняет таблицы Əlavə 1 и Əlavə 2

---

## 3. Технические требования

### 3.1 Изменения в схеме данных

#### 3.1.1 Property Tax Return DocType JSON

**Файл:** `/home/frappe/frappe-bench/apps/taxes_az/taxes_az/taxes_az/doctype/property_tax_return/property_tax_return.json`

**Новые поля:**

```json
{
  "fieldname": "tam_il",
  "fieldtype": "Check",
  "label": "Tam İl",
  "default": "1"
},
{
  "fieldname": "il_erzinde",
  "fieldtype": "Check",
  "label": "İl Ərzində",
  "default": "0"
}
```

**Позиция:** После поля `il` в массиве `field_order`

### 3.2 Логика расчетов

#### 3.2.1 Преобразование даты

- **Вход:** Год (Int, например: 2024)
- **Выход:**
  - `from_date` = "2024-01-01"
  - `to_date` = "2024-12-31"

#### 3.2.2 Режимы расчета

##### Режим "Tam İl" (Полный год)

**Для Əlavə 2 (Taxable Assets):**
- Поле `hesabatilininəvvəlinəəsasvəsaitlərinqalıqdəyəri` (501.1) ← Остаточная стоимость на начало года
- Поле `hesabatilinsonunaəsasvəsaitlərinqalıqdəyəri` (504.1) ← Остаточная стоимость на конец года

**Для Əlavə 1 (Tax Exempt Assets):**
- Поле `hesabatilininəvvəlinəəsasvəsaitlərinqalıqdəyərimanatla5012` (501.2) ← Остаточная стоимость на начало года
- Поле `ilinsonunaəsasvəsaitlərinqalıqdəyəri` (504.2) ← Остаточная стоимость на конец года

##### Режим "İl Ərzində" (В течение года)

**Для Əlavə 2 (Taxable Assets):**
- Поле `hesabatilierzindeuçotaalınan` (503.1) ← Стоимость новых приобретений
- Поле `hesabatilinsonunaəsasvəsaitlərinqalıqdəyəri` (504.1) ← Остаточная стоимость на конец года

**Для Əlavə 1 (Tax Exempt Assets):**
- Поле `hesabatiliərzindəəsasvəsaitlərinqalıqdəyəri` (503.2) ← Стоимость новых приобретений
- Поле `ilinsonunaəsasvəsaitlərinqalıqdəyəri` (504.2) ← Остаточная стоимость на конец года

### 3.3 Правила агрегации данных

#### 3.3.1 Для Əlavə 2 (Налогооблагаемые активы)

**Источник данных:**
- Активы с заполненным полем `taxable_asset_type`

**Правило сопоставления:**
- Значение `taxable_asset_type` из актива = Значение "Vergiyə cəlb olunan əmlakların kateqoriyası" в строке таблицы Əlavə 2

**Возможные значения `taxable_asset_type`:**
1. Çoxmərtəbəli (çoxmənzilli) yaşayış binaları
2. Qeyri-yaşayış binaları (sahələri)
3. Əmlak kompleksi kimi müəssisələr
4. Qurğular
5. Mənzillər
6. Fərdi yaşayış və bağ evləri
7. Maşınlar və avadanlıqlar
8. Yüksək texnologiyalar məhsulu olan hesablama texnikası
9. Nəqliyyat vasitələri
10. Digər əsas vəsaitlər

**Логика:**
- Получить все активы компании с `taxable_asset_type IS NOT NULL`
- Для каждого актива рассчитать балансовые стоимости
- Агрегировать (суммировать) по `taxable_asset_type`
- Найти соответствующую строку в Əlavə 2 по совпадению `taxable_asset_type`
- Обновить значения полей в найденной строке

#### 3.3.2 Для Əlavə 1 (Налогово-освобожденные активы)

**Источник данных:**
- Активы с заполненным полем `industrial_tax_article` ИЛИ `tax_exempt_tax_article`
- ИСКЛЮЧИТЬ активы с `agricultural_tax_article` (налог на сельскохозяйственные земли)

**Правило сопоставления:**
1. Извлечь номер статьи из названия Tax Article (например: "199.1", "207.3", "227.1")
2. Найти строку в Əlavə 1, где поле "Azadolma səbəbi" содержит этот номер

**Примеры извлечения номера статьи:**
- "Vergi Məcəlləsinin 199.1-ci maddəsinə əsasən" → "199.1"
- "Vergi Məcəlləsinin 207.3-cü maddəsinə əsasən" → "207.3"
- "Vergi Məcəlləsinin 199.4.1-ci maddəsinə əsasən" → "199.4.1"

**Логика:**
- Получить все активы с `industrial_tax_article` или `tax_exempt_tax_article`
- Для каждого актива:
  - Извлечь номер статьи regex: `(\d+(?:\.\d+)*(?:-\d+)?)`
  - Рассчитать балансовые стоимости
- Агрегировать по номеру статьи
- Найти соответствующую строку в Əlavə 1
- Обновить значения полей

### 3.4 Расчет балансовых стоимостей

Использовать логику стандартного отчета ERPNext "Asset Depreciations and Balances":

**Формулы:**

1. **Остаточная стоимость на начало периода (Opening Balance):**
   ```
   Чистая стоимость активов, приобретенных до from_date
   = Валовая стоимость - Накопленная амортизация на from_date
   ```

2. **Стоимость новых приобретений (New Purchases):**
   ```
   Валовая стоимость активов, приобретенных в период [from_date, to_date]
   ```

3. **Остаточная стоимость на конец периода (Closing Balance):**
   ```
   Opening Balance
   + New Purchases
   - Sold Assets
   - Scrapped Assets
   - Capitalized Assets
   + Adjustments during period
   - Accumulated Depreciation as on to_date
   ```

**Источники данных для расчетов:**
- `tabAsset` - основные данные об активах
- `tabGL Entry` - записи амортизации и корректировок стоимости
- `tabAsset Category Account` - счета амортизации
- `tabAsset Capitalization` - капитализированные активы (если доступно в версии ERPNext)

### 3.5 Важные ограничения

1. **НЕ создавать новые строки** в дочерних таблицах
   - Строки в Əlavə 1 и Əlavə 2 должны быть предварительно созданы клиентскими скриптами
   - Система только ОБНОВЛЯЕТ значения в существующих строках

2. **Сохранять строки без совпадений**
   - Если для строки не найдено данных об активах, не очищать ее значения
   - Оставлять строку как есть

3. **Обработка дубликатов**
   - Если актив имеет оба поля (`tax_exempt_tax_article` И `taxable_asset_type`), включить его в обе таблицы
   - Приоритет при наличии нескольких tax article полей: `industrial_tax_article` > `tax_exempt_tax_article`

---

## 4. Архитектура решения

### 4.1 Серверная часть (Python)

**Файл:** `property_tax_return.py`

#### 4.1.1 Основной метод API

```python
@frappe.whitelist()
def populate_property_tax_tables(company, year, from_date, to_date,
                                 calculation_mode, existing_elave_1, existing_elave_2)
```

**Параметры:**
- `company` - Название компании
- `year` - Год декларации
- `from_date` - Дата начала периода (YYYY-MM-DD)
- `to_date` - Дата окончания периода (YYYY-MM-DD)
- `calculation_mode` - Режим расчета: 'tam_il' или 'il_erzinde'
- `existing_elave_1` - JSON массив существующих строк Əlavə 1
- `existing_elave_2` - JSON массив существующих строк Əlavə 2

**Возвращает:**
```python
{
    'success': True/False,
    'elave_1_data': {
        'matching_key': {
            'field_name': value,
            ...
        },
        ...
    },
    'elave_2_data': {
        'matching_key': {
            'field_name': value,
            ...
        },
        ...
    },
    'error': 'Error message' (если success=False)
}
```

#### 4.1.2 Вспомогательные функции

1. **get_taxable_assets_aggregated(company, from_date, to_date)**
   - Получает налогооблагаемые активы
   - Агрегирует по `taxable_asset_type`

2. **get_tax_exempt_assets_aggregated(company, from_date, to_date)**
   - Получает налогово-освобожденные активы
   - Агрегирует по номеру статьи

3. **get_asset_balances_using_standard_logic(company, from_date, to_date, asset_names)**
   - Рассчитывает балансовые стоимости активов
   - Использует логику стандартного отчета ERPNext

4. **extract_article_number(tax_article_name)**
   - Извлекает номер статьи из названия Tax Article
   - Использует regex: `(\d+(?:\.\d+)*(?:-\d+)?)`

5. **find_matching_azadolma_sebeb(article_number, existing_rows)**
   - Находит строку в Əlavə 1 по номеру статьи

6. **check_erpnext_version()**
   - Проверяет версию ERPNext для совместимости полей

7. **get_asset_cost_details(...)** - Получает данные о стоимости активов

8. **get_asset_depreciation_details(...)** - Получает данные об амортизации

9. **get_asset_value_adjustments(...)** - Получает корректировки стоимости

### 4.2 Клиентская часть (JavaScript)

**Файл:** `property_tax_return.js`

#### 4.2.1 Обработчики событий формы

```javascript
frappe.ui.form.on('Property tax return', {
    refresh: function(frm) {
        // Инициализация взаимоисключающих чекбоксов
        setup_checkbox_exclusivity(frm);
    },

    il: function(frm) {
        // Автоматическая перезагрузка при изменении года
        reload_property_tax_data(frm);
    },

    tam_il: function(frm) {
        // Обработка изменения чекбокса "Полный год"
        // Снимает il_erzinde, если tam_il включен
        // Перезагружает данные
    },

    il_erzinde: function(frm) {
        // Обработка изменения чекбокса "В течение года"
        // Снимает tam_il, если il_erzinde включен
        // Перезагружает данные
    }
});
```

#### 4.2.2 Вспомогательные функции

1. **setup_checkbox_exclusivity(frm)**
   - Гарантирует, что только один чекбокс выбран
   - Если оба сняты, устанавливает tam_il=1

2. **reload_property_tax_data(frm)**
   - Валидирует входные данные
   - Показывает индикатор загрузки
   - Вызывает серверный метод
   - Обновляет дочерние таблицы
   - Показывает сообщения об успехе/ошибке

3. **update_child_table_values(frm, table_name, data_map)**
   - Обновляет значения в строках дочерних таблиц
   - Использует квадратные скобки для полей с юникодными символами
   - Не создает новые строки

---

## 5. Обработка ошибок

### 5.1 Валидация на клиенте

1. **Год не указан:**
   ```
   Сообщение: "Please select a year (İl) first"
   Действие: Прерывание выполнения
   ```

2. **Ни один чекбокс не выбран:**
   ```
   Сообщение: "Please select either Tam İl or İl Ərzində"
   Действие: Прерывание выполнения
   ```

### 5.2 Обработка на сервере

1. **Ошибка получения данных:**
   - Логирование в Error Log: `frappe.log_error()`
   - Возврат `{'success': False, 'error': error_message}`

2. **Нет активов:**
   - Возврат пустых словарей для elave_1_data и elave_2_data
   - `{'success': True, 'elave_1_data': {}, 'elave_2_data': {}}`

3. **Отсутствующие custom fields:**
   - Логирование предупреждения
   - Продолжение работы без ошибки

### 5.3 Визуальная обратная связь

1. **Во время загрузки:**
   ```javascript
   frappe.dom.freeze(__('Loading property tax data...'));
   ```

2. **При успехе:**
   ```javascript
   frappe.show_alert({
       message: __('Property tax data loaded successfully'),
       indicator: 'green'
   });
   ```

3. **При ошибке:**
   ```javascript
   frappe.msgprint({
       title: __('Error'),
       message: error_message,
       indicator: 'red'
   });
   ```

---

## 6. Тестирование

### 6.1 Модульное тестирование (Python)

**Тестовые случаи:**

1. **extract_article_number()**
   - Входные данные: "Vergi Məcəlləsinin 199.1-ci maddəsinə əsasən"
   - Ожидаемый результат: "199.1"

2. **get_taxable_assets_aggregated()**
   - Создать 3 актива с одним `taxable_asset_type`
   - Проверить корректность агрегации

3. **get_asset_balances_using_standard_logic()**
   - Создать активы с амортизацией
   - Сравнить результаты с отчетом "Asset Depreciations and Balances"

### 6.2 Интеграционное тестирование

1. **Полный рабочий процесс - Tam İl:**
   - Создать Property Tax Return
   - Выбрать год 2024
   - Включить "Tam İl"
   - Проверить заполнение полей 501.x и 504.x

2. **Полный рабочий процесс - İl Ərzində:**
   - Создать Property Tax Return
   - Выбрать год 2024
   - Включить "İl Ərzində"
   - Проверить заполнение полей 503.x и 504.x

3. **Переключение между режимами:**
   - Изменить с "Tam İl" на "İl Ərzində"
   - Проверить пересчет значений

### 6.3 Тестирование UI

1. **Взаимоисключающие чекбоксы:**
   - Включить "Tam İl" → "İl Ərzində" должен быть выключен
   - Включить "İl Ərzində" → "Tam İl" должен быть выключен
   - Снять оба → "Tam İl" должен автоматически включиться

2. **Индикаторы загрузки:**
   - Проверить отображение при вызове сервера
   - Проверить исчезновение после завершения

---

## 7. Производительность

### 7.1 Оптимизация запросов

1. **Единый вызов сервера:**
   - Все данные получаются за один запрос
   - Избегать множественных вызовов API

2. **Пакетная обработка активов:**
   - Получение всех активов одним SQL запросом
   - Использование оператора IN для фильтрации

3. **Агрегация в памяти:**
   - Суммирование значений в Python, а не в SQL
   - Уменьшение нагрузки на БД

### 7.2 Ожидаемая производительность

- **До 100 активов:** < 3 секунд
- **100-500 активов:** 3-10 секунд
- **500+ активов:** 10-30 секунд

### 7.3 Timeout настройки

```javascript
// В JavaScript нет explicit timeout, используется стандартный Frappe timeout
// Для Python метода можно увеличить через:
frappe.call({
    ...,
    timeout: 120000 // 2 минуты
});
```

---

## 8. Безопасность

### 8.1 Аутентификация и авторизация

1. **Метод доступен только аутентифицированным пользователям:**
   ```python
   @frappe.whitelist()
   ```

2. **Проверка прав на doctype:**
   - Пользователь должен иметь права на Property Tax Return
   - Автоматически проверяется Frappe framework

3. **Фильтрация по компании:**
   - Данные фильтруются по компании пользователя
   - Невозможно получить данные других компаний

### 8.2 Валидация входных данных

1. **Тип данных:**
   - `year` должен быть Integer
   - `from_date`, `to_date` должны быть в формате YYYY-MM-DD
   - `calculation_mode` должен быть 'tam_il' или 'il_erzinde'

2. **SQL Injection Prevention:**
   - Использование параметризованных запросов
   - Никаких прямых вставок пользовательского ввода в SQL

---

## 9. Миграция и развертывание

### 9.1 Шаги развертывания

1. **Обновление JSON схемы:**
   ```bash
   cd /home/frappe/frappe-bench
   bench --site site1 migrate
   ```

2. **Очистка кэша:**
   ```bash
   bench --site site1 clear-cache
   ```

3. **Перезапуск (опционально):**
   ```bash
   bench restart
   ```

### 9.2 Откат изменений

1. **Удаление новых полей через UI:**
   - Customize Form → Property Tax Return
   - Удалить поля tam_il и il_erzinde

2. **Откат кода:**
   ```bash
   git revert <commit_hash>
   bench --site site1 migrate
   ```

---

## 10. Документация для пользователей

### 10.1 Краткая инструкция

**Заголовок:** Автоматическое заполнение декларации по налогу на имущество

**Шаги:**

1. Откройте документ "Property Tax Return" (Декларация по налогу на имущество)
2. Заполните поле "İl" (Год), например: 2024
3. Выберите период:
   - **Tam İl** - если компания работала полный год
   - **İl Ərzində** - если компания была создана в течение года
4. Система автоматически заполнит таблицы Əlavə 1 и Əlavə 2 данными из ваших активов

**Примечания:**
- Для работы функции необходимо, чтобы в системе были созданы активы (Assets) с заполненными полями:
  - `taxable_asset_type` - для налогооблагаемых активов
  - `industrial_tax_article` или `tax_exempt_tax_article` - для освобожденных от налога активов
- Данные рассчитываются на основе фактической амортизации активов

---

## 11. Список файлов

### 11.1 Измененные файлы

1. **property_tax_return.json**
   - Путь: `/home/frappe/frappe-bench/apps/taxes_az/taxes_az/taxes_az/doctype/property_tax_return/property_tax_return.json`
   - Изменения: Добавлены поля tam_il и il_erzinde

2. **property_tax_return.py**
   - Путь: `/home/frappe/frappe-bench/apps/taxes_az/taxes_az/taxes_az/doctype/property_tax_return/property_tax_return.py`
   - Изменения: Реализован весь серверный код (~684 строки)

3. **property_tax_return.js**
   - Путь: `/home/frappe/frappe-bench/apps/taxes_az/taxes_az/taxes_az/doctype/property_tax_return/property_tax_return.js`
   - Изменения: Добавлен клиентский код автозаполнения (~177 строк)

### 11.2 Новые файлы

1. **TECHNICAL_SPECIFICATION_PROPERTY_TAX_AUTOMATION.md** (этот документ)
   - Путь: `/home/frappe/frappe-bench/apps/taxes_az/TECHNICAL_SPECIFICATION_PROPERTY_TAX_AUTOMATION.md`

---

## 12. Известные ограничения

1. **Предварительное создание строк:**
   - Строки в Əlavə 1 и Əlavə 2 должны быть созданы заранее клиентскими скриптами
   - Система не создает новые строки автоматически

2. **Один год за раз:**
   - Расчет выполняется только для одного календарного года
   - Невозможно рассчитать для нескольких лет одновременно

3. **Зависимость от ERPNext версии:**
   - Код проверяет наличие полей net_purchase_amount и Asset Capitalization
   - Может требовать адаптации для очень старых версий ERPNext

4. **Производительность для больших объемов:**
   - Для компаний с 1000+ активами может потребоваться оптимизация
   - Рекомендуется тестирование на реальных данных

---

## 13. Будущие улучшения

### 13.1 Краткосрочные (v1.1)

1. Добавить кнопку принудительного пересчета
2. Показывать количество обработанных активов
3. Логирование детальной информации о расчетах

### 13.2 Долгосрочные (v2.0)

1. Поддержка расчета за произвольный период (не только календарный год)
2. Экспорт детального отчета по расчетам в Excel
3. Предварительный просмотр изменений перед применением
4. Batch processing для очень больших объемов данных

---

## 14. Контакты и поддержка

**Разработчик:** Claude (Anthropic)
**Дата разработки:** 2025-12-11
**Версия системы:** Frappe v15, ERPNext
**Git репозиторий:** `/home/frappe/frappe-bench/apps/taxes_az`

---

## 15. История изменений

| Версия | Дата | Описание | Автор |
|--------|------|----------|-------|
| 1.0 | 2025-12-11 | Первоначальная разработка и развертывание | Claude |
| 1.0.1 | 2025-12-11 | Исправление ошибок в JavaScript (квадратные скобки для Unicode полей) | Claude |

---

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