chore(property-tax): remove Property Tax Gov pilot doctypes

The Property Tax Gov family (parent + 10 child tables) was a duplicate of
Property tax return, used as a pilot for page-based declaration calc. It is
no longer needed; the original Property tax return is untouched and remains
the only property-tax declaration.

Both tables were empty (0 documents). `bench migrate` drops the orphaned
DocTypes; the empty `tabProperty Tax Gov*` tables were dropped manually since
migrate leaves them behind.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ali 2026-07-09 11:35:18 +00:00
parent 94c25e19e2
commit 682902a828
38 changed files with 0 additions and 3416 deletions

View File

@ -1,218 +0,0 @@
# Property Tax Gov — полный разбор
## Назначение
Это доктайп для формирования **декларации по налогу на имущество** (Əmlak vergisinin
bəyannaməsi) для азербайджанской системы E-Taxes. Он берёт данные об основных средствах
(Asset) из ERPNext, агрегирует их, рассчитывает налог по формулам, извлечённым из самого
кабинета new.e-taxes.gov.az, и экспортирует результат в XML для подачи.
Это часть пилота **Property Tax Gov** — нового семейства доктайпов с расчётом «по странице,
без авторизации», заменяющего старые `property_tax_return_ai`.
## Файлы доктайпа
| Файл | Роль |
|------|------|
| `property_tax_gov.json` | Определение полей: 3 таба, ~8 дочерних таблиц |
| `property_tax_gov.py` | Бэкенд: агрегация Asset → строки таблиц + мост к Node-калькулятору |
| `property_tax_gov.js` | Клиент: автозаполнение, расчёт формул, валидация, XML-экспорт |
| `gns_property_calc.bundle.js` | Извлечённый из кабинета ГНС `useCalculation` (эталон формул) |
| `gns_property_calc_cli.js` | stdin/stdout-обёртка Node для bundle |
---
## 1. Структура формы (JSON)
Три основных таба:
1. **Ümumi məlumat** (Общая информация) — шапка декларации: налоговый орган
(`vergiorqanı` — большой Select со всеми территориальными управлениями), год (`il`),
ВОЕН, ФИО/название плательщика, тип плательщика (Hüquqi/Fiziki), вид деклараций и т.д.
2. **Əmlak vergisinin hesablanması** (Расчёт налога на имущество) — 8 «cədvəl»
(расчётных таблиц):
- `vergi_hesab_1ci` / `vergi_hesab_1ci_1` — остаток на начало года (501) / на дату создания (503)
- `vergi_hesab_2ci` — остаток на конец года (504)
- `vergi_hesab_3cu` — сверхзастрахованные ОС (505)
- `vergi_hesab_4cu` — ставка налога (506), `vergi_hesab_4cu_1` — кол-во месяцев (507)
- `vergi_hesab_5ci` — рассчитанный налог (509/510)
- `vergi_hesab_6ci` — сумма к уплате в бюджет (511)
3. **Əlavə 1** (`elave_1`) и **Əlavə 2** (`elave_2`) — два приложения, **источники данных**:
- **Əlavə 1** — имущество, **освобождённое** от налога, сгруппированное по статьям НК
(199.1, 199.4.1, 207.3 …). Ключевое поле строки — `azadolmasəbəbi` (основание освобождения).
- **Əlavə 2** — имущество, **подлежащее** налогообложению, по категориям (Binalar,
Mənzillər, Nəqliyyat vasitələri …). Ключевое поле — `vergiyəcəlbolunanəmlaklarınkateqoriyası`.
### Ключевая развилка: два режима
Два взаимоисключающих чекбокса в шапке управляют всей логикой:
- **`tam_il`** (Tam İl) — компания работала **полный год**.
- **`il_erzinde`** (İl Ərzində) — компания **создана в течение года** (неполный период).
Клиентский код (`setup_checkbox_exclusivity`, обработчики `tam_il`/`il_erzinde`) гарантирует,
что ровно один из них всегда включён.
---
## 2. Автозаполнение из Asset (Python-бэкенд)
Когда выбран год и режим, JS вызывает `reload_property_tax_data()` → серверный
`populate_property_tax_tables()`.
**Поток данных:**
```
tabAsset (docstatus=1, company, purchase_date<=to_date)
├─ taxable_asset_type заполнен ──→ get_taxable_assets_aggregated() ──→ Əlavə 2
└─ industrial/tax_exempt_tax_article ─→ get_tax_exempt_assets_aggregated() ─→ Əlavə 1
```
Сердце расчёта — `get_asset_balances_using_standard_logic()`. Это **точная репликация
стандартного отчёта ERPNext «Asset Depreciations and Balances»**:
- `get_asset_cost_details` — валовая стоимость (на начало периода, новые покупки,
проданные/списанные/капитализированные);
- `get_asset_depreciation_details` — накопленная амортизация из GL Entry
(через `tabAsset Category Account`);
- `get_asset_value_adjustments` — переоценки.
Из них считается `net_asset_value_as_on_from_date/to_date` (остаточная стоимость).
Плюс `insurance_value` = (застрахованная сумма валовая стоимость), если объект
застрахован выше стоимости.
**Версионная совместимость:** код проверяет колонки таблицы Asset и сам выбирает
`gross_purchase_amount` / `net_purchase_amount` / `purchase_amount`, потому что ERPNext v15
переименовал поле (`gross_purchase_amount` → `net_purchase_amount`).
**Сопоставление со строками таблиц** — нечёткое (fuzzy):
- `extract_article_number()` достаёт «199.1» из «Vergi Məcəlləsinin 199.1-ci maddəsinə əsasən»
регуляркой;
- `find_matching_azadolma_sebeb()` ищет строку Əlavə 1, чей `azadolmasəbəbi` содержит этот номер;
- `find_matching_category()` сопоставляет `taxable_asset_type` со строкой Əlavə 2 по частичному
вхождению («Mənzillər» ↔ «1.5 Mənzillər»).
**Бизнес-правило для İl Ərzində:** если у компании, созданной в течение года, нет новых покупок
(`value_of_new_purchase < 0.01`), все поля строки обнуляются. Также в зависимости от режима
данные кладутся в разные колонки: в `tam_il` — в «остаток на начало года» (501),
в `il_erzinde` — в «принято на учёт в течение года» (503).
Сервер возвращает не строки, а **карты `{ключ_строки: {поле: значение}}`**, а уже клиент
применяет их к существующим строкам через `update_child_table_values()`.
---
## 3. Расчётный движок (клиент)
Здесь самое тонкое место. Файл содержит **два поколения кода расчёта**, и работает только второе.
### Старый код (строки 269919)
Ручные функции: `calculate_509_1`, `calculate_509_2`, `calculate_binalar_totals`,
`calculate_elave_*_totals`, `calculate_vergi_hesab_3cu_totals`. Они напрямую считали формулы:
- `509.1 = ((501.1 + 504.1) / 2) * 1% + 505.1 * 1%` (полный год);
- `509.2 = ((503.1 + 504.1) / 24 * 507) * 1% + 505.1 * 1%` (неполный год, 507 = число месяцев).
### Новый код (строки 10421264) — **активный**
В конце файла все шесть `calculate_*` **переопределены заново** как тонкие делегаторы:
```js
function calculate_509_1(frm) { gns_property_recalc(frm); }
// ... и т.д.
```
Это работает за счёт **hoisting функций в JS: последнее объявление побеждает**. То есть все
старые триггеры (обработчики дочерних таблиц на строках 9241040) теперь незаметно вызывают
новый единый движок `gns_property_recalc()`. Старые тела функций мертвы, но оставлены.
**Как считает новый движок** (`_gns_property_recalc_now`):
1. `ptgov_sum()` суммирует строки `elave_1` → объект `a1` (приложение 1, освобождённые),
`elave_2``a2` (облагаемые). При суммировании Əlavə 2 исключаются «итоговые» строки —
родитель «1. Binalar» и «CƏMİ» (`ptgov_is_excluded_e2`).
2. `full = !il_erzinde`, `months` берётся из строки 507.
3. `ptgov_calc_byArticle()` строит карту `{номер_статьи: значение}` — те же формулы, что и в
старом коде, но в одном месте, с округлением half-up до 2 знаков (`ptgov_round2`). Облагается
**только** Əlavə 2; 511 (к уплате) = 509.
4. Результаты разносятся по всем выходным cədvəl-таблицам: по номеру статьи (`ptgov_article`
парсит «509.1» из метки `göstəricilər`) в поле `manatla`; ставка 506 → `faizlə = 1`.
**Защита от рекурсии:** флаг `frm.__ptgov_writing` ставится перед записью значений, чтобы наши же
`set_value` не зациклили обработчики `manatla`. Плюс debounce 250 мс (`_ptgov_timer`).
### Про Node-мост (`compute_via_gns` + bundle)
По задумке предполагалось гонять **родной калькулятор кабинета** (`useCalculation`, извлечённый
в `gns_property_calc.bundle.js`) офлайн через Node-subprocess. Сейчас же, как явно сказано в
комментарии (строки 11031107), **формулы переписаны нативно в JS**, а bundle и
`compute_via_gns` остаются в репо как **эталонный источник**, из которого формулы выведены и
сверены. То есть в рантайме Node не вызывается — всё считается в браузере.
---
## 4. Условная логика отображения
`apply_conditional_table_logic()` показывает/прячет таблицы под режим:
- `tam_il` → видна `vergi_hesab_1ci` (501); строки 509.1/511.1 в 5-й/6-й таблицах;
- `il_erzinde` → видны `vergi_hesab_1ci_1` (503) и `vergi_hesab_4cu_1` (месяцы); строки
509.2/511.2; колонки 501.x скрываются (`toggle_field_readonly`).
Строки 5-й/6-й таблиц **полностью пересоздаются** под режим (`filter_vergi_hesab_5ci_rows`),
при этом старые значения сохраняются в `window.property_tax_saved_values` и восстанавливаются.
`calculate_months_for_vergi_hesab_4cu_1()` (Python) находит самый ранний Asset по
`available_for_use_date` в году и считает число месяцев до конца года для формулы 509.2.
---
## 5. Валидация
`validate_minimum_asset_value()` — только в режиме `il_erzinde`: стоимость ОС в колонках
503.1/503.2 не может быть **< 500 манат** (но > 0). При нарушении:
- блокирует сохранение (`frm.validated = false`);
- подсвечивает ячейки красным (`highlight_invalid_cells`);
- показывает HTML-предупреждение и ставит 🔴 в заголовок таба (`update_tab_title`).
---
## 6. Шаблонные строки и кнопки
- `ptgov_ensure_rows()` — при `refresh` заполняет пустые дочерние таблицы каноническими наборами
строк (`PTGOV_E1_ROWS` — 23 статьи освобождения, `PTGOV_E2_ROWS` — 12 категорий, cədvəl-таблицы
— из `options` поля `göstəricilər`).
- `ptgov_set_readonly()` — делает вычисляемые колонки (`manatla`, `faizlə`) read-only.
- Кнопки: **«Şablon sətirləri yarat»** (создать шаблонные строки), **«ГНС ilə hesabla»**
(пересчитать вручную), **«Export XML»** (через `xml_mapping_tool.generate_xml`).
---
## Сводный поток работы
```
Пользователь: выбирает год + режим (Tam İl / İl Ərzində)
JS reload_property_tax_data → Python populate_property_tax_tables
tabAsset → агрегация (ERPNext balance-логика) → карты {строка: значения}
JS раскладывает по Əlavə 1 / Əlavə 2
любое изменение строки → gns_property_recalc (debounce 250ms)
ptgov_sum → ptgov_calc_byArticle → разнос по cədvəl (501→511)
валидация (min 500 ман.) → Export XML → подача в E-Taxes
```
---
## Главное при правках этого файла
1. Активен только **второй** блок расчёта (делегаторы внизу). Старые `calculate_509_*`
мёртвый код, переопределён hoisting'ом. Правь `ptgov_calc_byArticle`, а не их.
2. Сопоставление Asset ↔ строки таблиц — **нечёткое по подстроке**, легко ломается при
изменении меток строк.
3. Поля имеют азербайджанские имена с диакритикой (`göstəricilər`, `manatla`) — копируй точно.
4. Node-мост (`compute_via_gns`) сейчас не в рантайме, а как эталон формул.

File diff suppressed because one or more lines are too long

View File

@ -1,12 +0,0 @@
// CLI: stdin JSON model -> stdout JSON of computed {path: value}. Used by property_tax_gov.py.
const { calc } = require('./gns_property_calc.bundle.js');
let d = '';
process.stdin.on('data', (c) => (d += c));
process.stdin.on('end', () => {
try {
process.stdout.write(JSON.stringify(calc(JSON.parse(d || '{}'))));
} catch (e) {
process.stderr.write(String((e && e.stack) || e));
process.exit(1);
}
});

File diff suppressed because it is too large Load Diff

View File

@ -1,385 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-01-13 14:18:26.085350",
"default_view": "List",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"\u00fcmumi_m\u0259lumat_tab",
"html_pegz",
"idar\u0259",
"vergiorqan\u0131",
"vergid\u00f6vr\u00fc",
"il",
"tam_il",
"il_erzinde",
"\u015f\u0259xsi",
"v\u00f6en",
"soyad\u0131",
"atas\u0131n\u0131nad\u0131",
"mobn\u00f6mr\u02591",
"mobn\u00f6mr\u02592",
"column_break_yjgp",
"\u00f6d\u0259yicitipi",
"ad\u0131",
"\u015f\u0259h\u0259rn\u00f6mr\u0259si1",
"\u015f\u0259h\u0259rn\u00f6mr\u0259si2",
"section_break_pcfz",
"\u0259sasf\u0259aliyy\u0259tn\u00f6v\u00fcn\u00fcnkodu",
"t\u0259qdimolunmu\u015f\u0259lav\u0259l\u0259rinsay\u0131",
"b\u0259yannam\u0259ninn\u00f6v\u00fc",
"d\u0259qiql\u0259\u015fdirilmi\u015fb\u0259yannam\u0259nint\u0259qdimedilm\u0259sibar\u0259d\u0259bildiri\u015f",
"column_break_xcxz",
"section_break_vfvd",
"b\u0259yan_edil\u0259c\u0259k_m\u0259lumat\u0131m_yoxdur",
"section_break_wnwr",
"column_break_dblg",
"s\u0259tirl\u0259rd\u0259nbirinise\u00e7in",
"\u0259mlak_vergisinin_hesablanmas\u0131_tab",
"html_ikbb",
"vergi_hesab_1ci",
"html_uhqz",
"vergi_hesab_1ci_1",
"section_break_bhtd",
"html_umxi",
"vergi_hesab_2ci",
"section_break_fugy",
"html_exjg",
"vergi_hesab_3cu",
"section_break_bhet",
"html_tuak",
"vergi_hesab_4cu",
"vergi_hesab_4cu_1",
"section_break_cnpg",
"html_mxir",
"vergi_hesab_5ci",
"section_break_klzd",
"html_ctml",
"vergi_hesab_6ci",
"\u0259lav\u0259_1_tab",
"html_hken",
"warning_elave_1_html",
"elave_1",
"\u0259lav\u0259_2_tab",
"html_ybie",
"elave_2"
],
"fields": [
{
"fieldname": "\u00fcmumi_m\u0259lumat_tab",
"fieldtype": "Tab Break",
"label": "\u00dcmumi m\u0259lumat"
},
{
"fieldname": "html_pegz",
"fieldtype": "HTML",
"options": "<p style=\"text-align: center;font-size: 20px;font-weight: bold;color: blue;\"> \u018fmlak vergisinin b\u0259yannam\u0259si</p>"
},
{
"fieldname": "vergiorqan\u0131",
"fieldtype": "Select",
"label": "Vergi orqan\u0131",
"options": "2 sayl\u0131 \u018frazi Vergil\u0259r Ba\u015f idar\u0259si\tSumqay\u0131t\t02\n3 sayl\u0131 \u018frazi Vergil\u0259r \u0130dar\u0259si\tQuba\t03\n4 sayl\u0131 \u018frazi Vergil\u0259r \u0130dar\u0259si\t\u015eamax\u0131\t04\n5 sayl\u0131 \u018frazi Vergil\u0259r \u0130dar\u0259si\t\u015eirvan\t05\n6 sayl\u0131 \u018frazi Vergil\u0259r Ba\u015f \u0130dar\u0259si\tL\u0259nk\u0259ran\t06\nQaraba\u011f \u018frazi Vergil\u0259r Ba\u015f \u0130dar\u0259si\tA\u011fdam, F\u00fczuli, \u015eu\u015fa, Xocal\u0131, Xocav\u0259nd\t07\n8 sayl\u0131 \u018frazi Vergil\u0259r \u0130dar\u0259si\tBeyl\u0259qan\t08\n9 sayl\u0131 \u018frazi Vergil\u0259r \u0130dar\u0259si\tG\u00f6y\u00e7ay\t09\n10 sayl\u0131 \u018frazi Vergil\u0259r \u0130dar\u0259si\tQ\u0259b\u0259l\u0259\t10\n11 sayl\u0131 \u018frazi Vergil\u0259r Ba\u015f \u0130dar\u0259si\tYevlax\t11\n12 sayl\u0131 \u018frazi Vergil\u0259r Ba\u015f \u0130dar\u0259si\tG\u0259nc\u0259\t12\n13 sayl\u0131 \u018frazi Vergil\u0259r \u0130dar\u0259si\tZaqatala\t13\n14 sayl\u0131 \u018frazi Vergil\u0259r \u0130dar\u0259si\t\u015e\u0259mkir\t14\nD\u00f6vl\u0259t Vergi xidm\u0259tinin Milli G\u0259lirl\u0259r Ba\u015f idar\u0259si\tBak\u0131\t16\nD\u00f6vl\u0259t Vergi xidm\u0259tinin Bak\u0131 \u015f\u0259h\u0259ri Lokal G\u0259lirl\u0259r Ba\u015f idar\u0259si\tBak\u0131\t19\nD\u00f6vl\u0259t Vergi xidm\u0259tinin Bak\u0131 \u015f\u0259h\u0259ri Ki\u00e7ik Sahibkarl\u0131qla \u0130\u015f \u00fczr\u0259 Ba\u015f idar\u0259si\tBak\u0131\t39\nNax\u00e7\u0131van \u015f\u0259h\u0259ri \u00fczr\u0259 Vergil\u0259r \u0130dar\u0259si\tNax\u00e7\u0131van\t27\n2 sayl\u0131 \u018frazi Vergil\u0259r \u0130dar\u0259si (Nax\u00e7\u0131van MR)\t\u015e\u0259rur, S\u0259d\u0259r\u0259k, K\u0259ng\u0259rli\t30\n3 sayl\u0131 \u018frazi Vergil\u0259r \u0130dar\u0259si (Nax\u00e7\u0131van MR)\t\u015eahbuz, Bab\u0259k\t26\n4 sayl\u0131 \u018frazi Vergil\u0259r \u0130dar\u0259si (Nax\u00e7\u0131van MR)\tCulfa, Ordubad\t24\n\u015e\u0259rqi Z\u0259ng\u0259zur \u018frazi Vergil\u0259r \u0130dar\u0259si\tC\u0259bray\u0131l, K\u0259lb\u0259c\u0259r, La\u00e7\u0131n, Qubadl\u0131, Z\u0259ngilan\t55"
},
{
"fieldname": "vergid\u00f6vr\u00fc",
"fieldtype": "Select",
"label": "Vergi d\u00f6vr\u00fc",
"options": "\u0130llik"
},
{
"fieldname": "il",
"fieldtype": "Int",
"label": "\u0130l",
"length": 4
},
{
"default": "1",
"fieldname": "tam_il",
"fieldtype": "Check",
"label": "Tam \u0130l"
},
{
"default": "0",
"fieldname": "il_erzinde",
"fieldtype": "Check",
"label": "\u0130l \u018frzind\u0259"
},
{
"fieldname": "\u015f\u0259xsi",
"fieldtype": "Section Break",
"label": "\u015e\u0259xsi"
},
{
"fieldname": "v\u00f6en",
"fieldtype": "Int",
"label": "V\u00d6EN"
},
{
"fieldname": "soyad\u0131",
"fieldtype": "Data",
"label": "Soyad\u0131"
},
{
"fieldname": "atas\u0131n\u0131nad\u0131",
"fieldtype": "Data",
"label": "Atas\u0131n\u0131n ad\u0131"
},
{
"fieldname": "mobn\u00f6mr\u02591",
"fieldtype": "Int",
"label": "Mob n\u00f6mr\u0259 1"
},
{
"fieldname": "mobn\u00f6mr\u02592",
"fieldtype": "Int",
"label": "Mob n\u00f6mr\u0259 2"
},
{
"fieldname": "column_break_yjgp",
"fieldtype": "Column Break"
},
{
"fieldname": "\u00f6d\u0259yicitipi",
"fieldtype": "Select",
"label": "\u00d6d\u0259yici tipi",
"options": "H\u00fcquqi\nFiziki"
},
{
"fieldname": "ad\u0131",
"fieldtype": "Data",
"label": "Ad\u0131"
},
{
"fieldname": "\u015f\u0259h\u0259rn\u00f6mr\u0259si1",
"fieldtype": "Int",
"label": "\u015e\u0259h\u0259r n\u00f6mr\u0259si 1"
},
{
"fieldname": "\u015f\u0259h\u0259rn\u00f6mr\u0259si2",
"fieldtype": "Int",
"label": "\u015e\u0259h\u0259r n\u00f6mr\u0259si 2"
},
{
"fieldname": "section_break_pcfz",
"fieldtype": "Section Break"
},
{
"fieldname": "\u0259sasf\u0259aliyy\u0259tn\u00f6v\u00fcn\u00fcnkodu",
"fieldtype": "Int",
"label": "\u018fsas f\u0259aliyy\u0259t n\u00f6v\u00fcn\u00fcn kodu"
},
{
"fieldname": "t\u0259qdimolunmu\u015f\u0259lav\u0259l\u0259rinsay\u0131",
"fieldtype": "Int",
"label": "T\u0259qdim olunmu\u015f \u0259lav\u0259l\u0259rin say\u0131"
},
{
"fieldname": "b\u0259yannam\u0259ninn\u00f6v\u00fc",
"fieldtype": "Select",
"label": "B\u0259yannam\u0259nin n\u00f6v\u00fc",
"options": "Cari\nD\u0259qiql\u0259\u015fdirilmi\u015f\nL\u0259\u011fv olma\nL\u0259\u011fvin d\u0259qiql\u0259\u015fdirilmi\u015fi\nAnaloji\nK\u00f6n\u00fcll\u00fc a\u00e7\u0131qlama"
},
{
"fieldname": "d\u0259qiql\u0259\u015fdirilmi\u015fb\u0259yannam\u0259nint\u0259qdimedilm\u0259sibar\u0259d\u0259bildiri\u015f",
"fieldtype": "Float",
"label": "D\u0259qiql\u0259\u015fdirilmi\u015f b\u0259yannam\u0259nin t\u0259qdim edilm\u0259si bar\u0259d\u0259 bildiri\u015fin n\u00f6mr\u0259si",
"precision": "2"
},
{
"fieldname": "column_break_xcxz",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_vfvd",
"fieldtype": "Section Break"
},
{
"default": "0",
"fieldname": "b\u0259yan_edil\u0259c\u0259k_m\u0259lumat\u0131m_yoxdur",
"fieldtype": "Check",
"label": "B\u0259yan edil\u0259c\u0259k m\u0259lumat\u0131m yoxdur"
},
{
"fieldname": "html_ikbb",
"fieldtype": "HTML",
"options": "<p style=\"text-align: center;font-size: 15px;font-weight: bold;color: black;\"> Hesabat ilinin \u0259vv\u0259lin\u0259</p>"
},
{
"fieldname": "\u0259lav\u0259_1_tab",
"fieldtype": "Tab Break",
"js_parent_subtab": "Verginin hesablanmas\u0131",
"label": "\u018flav\u0259 1"
},
{
"fieldname": "html_ctml",
"fieldtype": "HTML",
"options": "<p style=\"text-align: center;font-size: 15px;font-weight: bold;color: black;\"> B\u00fcdc\u0259y\u0259 \u00f6d\u0259nilm\u0259li verginin m\u0259bl\u0259\u011fi </p>"
},
{
"fieldname": "html_hken",
"fieldtype": "HTML",
"options": "<p style=\"text-align: center;font-size: 15px;font-weight: bold;color: black;\"> Vergid\u0259n azad olunan \u0259mlak\u0131n d\u0259y\u0259ri haqq\u0131nda m\u0259lumat</p>"
},
{
"fieldname": "html_ybie",
"fieldtype": "HTML",
"options": "<p style=\"text-align: center;font-size: 15px;font-weight: bold;color: black;\"> Vergiy\u0259 c\u0259lb olunan \u0259sas v\u0259saitin d\u0259y\u0259ri haqq\u0131nda m\u0259lumat</p>"
},
{
"fieldname": "warning_elave_1_html",
"fieldtype": "HTML",
"hidden": 1
},
{
"fieldname": "\u0259mlak_vergisinin_hesablanmas\u0131_tab",
"fieldtype": "Tab Break",
"label": "\u018fmlak vergisinin hesablanmas\u0131"
},
{
"fieldname": "\u0259lav\u0259_2_tab",
"fieldtype": "Tab Break",
"js_parent_subtab": "Verginin hesablanmas\u0131",
"label": "\u018flav\u0259 2"
},
{
"fieldname": "section_break_fugy",
"fieldtype": "Section Break"
},
{
"fieldname": "html_exjg",
"fieldtype": "HTML",
"options": "<p style=\"text-align: center;font-size: 15px;font-weight: bold;color: black;\"> Art\u0131q qiym\u0259t\u0259 s\u0131\u011fortalanan \u0259sas v\u0259saitl\u0259r</p>"
},
{
"fieldname": "section_break_bhet",
"fieldtype": "Section Break"
},
{
"fieldname": "html_tuak",
"fieldtype": "HTML"
},
{
"fieldname": "section_break_bhtd",
"fieldtype": "Section Break"
},
{
"fieldname": "html_umxi",
"fieldtype": "HTML",
"options": "<p style=\"text-align: center;font-size: 15px;font-weight: bold;color: black;\"> Hesabat ilinin sonuna</p>"
},
{
"fieldname": "section_break_cnpg",
"fieldtype": "Section Break"
},
{
"fieldname": "html_mxir",
"fieldtype": "HTML",
"options": "<p style=\"text-align: center;font-size: 15px;font-weight: bold;color: black;\"> Hesablanm\u0131\u015f verginin m\u0259bl\u0259\u011fi</p>"
},
{
"fieldname": "idar\u0259",
"fieldtype": "Section Break",
"label": "\u0130dar\u0259"
},
{
"fieldname": "section_break_klzd",
"fieldtype": "Section Break"
},
{
"fieldname": "vergi_hesab_1ci",
"fieldtype": "Table",
"options": "Property Tax Gov Emlak vergi hesablamasi 1ci cedvel"
},
{
"fieldname": "vergi_hesab_2ci",
"fieldtype": "Table",
"options": "Property Tax Gov Emlak vergi hesablamasi 2ci cedvel"
},
{
"fieldname": "vergi_hesab_3cu",
"fieldtype": "Table",
"options": "Property Tax Gov Emlak vergi hesablamasi 3cu cedvel"
},
{
"fieldname": "vergi_hesab_4cu",
"fieldtype": "Table",
"options": "Property Tax Gov Emlak vergi hesablamasi 4cu cedvel"
},
{
"fieldname": "vergi_hesab_5ci",
"fieldtype": "Table",
"options": "Property Tax Gov Emlak vergi hesablamasi 5ci cedvel"
},
{
"fieldname": "vergi_hesab_6ci",
"fieldtype": "Table",
"options": "Property Tax Gov Emlak vergi hesablamasi 6ci cedvel"
},
{
"fieldname": "elave_1",
"fieldtype": "Table",
"options": "Property Tax Gov Elave 1"
},
{
"fieldname": "elave_2",
"fieldtype": "Table",
"options": "Property Tax Gov Elave 2"
},
{
"fieldname": "section_break_wnwr",
"fieldtype": "Section Break"
},
{
"default": "M\u00fc\u0259ssis\u0259 il \u0259rzind\u0259 tam f\u0259aliyy\u0259t g\u00f6st\u0259rdiyi halda",
"fieldname": "s\u0259tirl\u0259rd\u0259nbirinise\u00e7in",
"fieldtype": "Select",
"label": "S\u0259tirl\u0259rd\u0259n birini se\u00e7in",
"options": "M\u00fc\u0259ssis\u0259 il \u0259rzind\u0259 yarand\u0131\u011f\u0131 halda\nM\u00fc\u0259ssis\u0259 il \u0259rzind\u0259 tam f\u0259aliyy\u0259t g\u00f6st\u0259rdiyi halda"
},
{
"fieldname": "column_break_dblg",
"fieldtype": "Column Break"
},
{
"fieldname": "html_uhqz",
"fieldtype": "HTML",
"options": "<p style=\"text-align: center;font-size: 15px;font-weight: bold;color: black;\"> M\u00fc\u0259ssis\u0259nin yaranma v\u0259 ya \u0259mlak vergisinin \u00f6d\u0259yicisi olma tarixin\u0259</p>"
},
{
"fieldname": "vergi_hesab_1ci_1",
"fieldtype": "Table",
"options": "Property Tax Gov Emlak vergi hesablamasi 1ci cedvel 1"
},
{
"fieldname": "vergi_hesab_4cu_1",
"fieldtype": "Table",
"options": "Property Tax Gov Emlak vergi hesablamasi 4cu cedvel 1"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-12-29 18:27:42.028445",
"modified_by": "Administrator",
"module": "Taxes Az",
"name": "Property Tax Gov",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@ -1,886 +0,0 @@
# Copyright (c) 2025, Jey Soft and contributors
# For license information, please see license.txt
import frappe
from frappe.model.document import Document
from frappe.utils import flt, add_days
import re
import json
class PropertyTaxGov(Document):
pass
# ---------------------------------------------------------------------------
# GNS calc bridge — runs the cabinet's OWN calculation code (useCalculation,
# extracted from new.e-taxes.gov.az declaration bundle) offline via Node.
# No authorization / no network: the calc is pure functions over the model.
# Bundle: gns_property_calc.bundle.js + gns_property_calc_cli.js (this dir).
# ---------------------------------------------------------------------------
def _node_bin():
import shutil, glob
n = shutil.which("node")
if n:
return n
cands = sorted(glob.glob("/home/frappe/.nvm/versions/node/*/bin/node"))
return cands[-1] if cands else "node"
@frappe.whitelist()
def compute_via_gns(payload):
"""Compute property-tax indicators with the GNS cabinet's own JS calc.
payload: dict (or JSON string) shaped as
{
"objectActivity": "OBJECT_FULL_ACTIVITY" | "OBJECT_ESTABLISHED" | "LIQUIDATION",
"calculation": {"monthCountFromStartPeriod": int, "monthCountToLiquidation": int, ...},
"appendix1": {"periodStartTotal","endYearTotal","overTotal","removedTotal","createdTotal"},
"appendix2": {"periodStartTotal","periodEndTotal","excessInsuredTotal","onCreateDateTotal","onCancelDateTotal"}
}
Returns dict {"<step>.<group>.<indicatorCode>": value, ...} exactly as the cabinet computes.
"""
import os, subprocess
if isinstance(payload, str):
payload = json.loads(payload)
cli = os.path.join(os.path.dirname(os.path.abspath(__file__)), "gns_property_calc_cli.js")
try:
proc = subprocess.run(
[_node_bin(), cli],
input=json.dumps(payload),
capture_output=True, text=True, timeout=30,
)
except Exception as e:
frappe.throw(f"GNS calc invocation failed: {e}")
if proc.returncode != 0:
frappe.throw(f"GNS calc error: {(proc.stderr or '')[:800]}")
return json.loads(proc.stdout or "{}")
@frappe.whitelist()
def populate_property_tax_tables(company, year, from_date, to_date, calculation_mode, existing_elave_1, existing_elave_2):
"""
Main method to populate Property Tax Gov child tables from Asset data
Args:
company: Company name
year: Tax year (integer)
from_date: Start date (YYYY-MM-DD)
to_date: End date (YYYY-MM-DD)
calculation_mode: 'tam_il' or 'il_erzinde'
existing_elave_1: Existing Əlavə 1 rows (JSON array)
existing_elave_2: Existing Əlavə 2 rows (JSON array)
Returns:
Dictionary with elave_1_data and elave_2_data mappings
"""
try:
# Parse JSON if needed
if isinstance(existing_elave_1, str):
existing_elave_1 = json.loads(existing_elave_1)
if isinstance(existing_elave_2, str):
existing_elave_2 = json.loads(existing_elave_2)
# Get aggregated asset data
taxable_aggregated = get_taxable_assets_aggregated(company, from_date, to_date)
tax_exempt_aggregated = get_tax_exempt_assets_aggregated(company, from_date, to_date)
# Map to rows with proper field names based on calculation_mode
# Use fuzzy matching for Əlavə 2 (Taxable Assets)
elave_2_data = {}
for category, data in taxable_aggregated.items():
# Find matching row by partial match (e.g., "Mənzillər" matches "1.5 Mənzillər")
matching_key = find_matching_category(category, existing_elave_2)
if matching_key:
if calculation_mode == 'tam_il':
elave_2_data[matching_key] = {
'hesabatilininəvvəlinəəsasvəsaitlərinqalıqdəyəri': data['value_as_on_from_date'],
'hesabatilinsonunaəsasvəsaitlərinqalıqdəyəri': data['net_asset_value_as_on_to_date'],
'hesabatilierzindeuçotaalınan': 0,
'artıqqiymətəəsasvəsaitlərindəyəri505': data['insurance_value']
}
else: # il_erzinde
# Бизнес-правило: Для компаний, созданных в течение года (İl Ərzində),
# если нет новых покупок (value_of_new_purchase < 0.01), то все поля = 0
if flt(data.get('value_of_new_purchase', 0)) >= 0.01:
elave_2_data[matching_key] = {
'hesabatilierzindeuçotaalınan': data['value_of_new_purchase'],
'hesabatilinsonunaəsasvəsaitlərinqalıqdəyəri': data['net_asset_value_as_on_to_date'],
'hesabatilininəvvəlinəəsasvəsaitlərinqalıqdəyəri': 0,
'artıqqiymətəəsasvəsaitlərindəyəri505': data['insurance_value']
}
else:
# Нет новых покупок - очистить все поля
elave_2_data[matching_key] = {
'hesabatilierzindeuçotaalınan': 0,
'hesabatilinsonunaəsasvəsaitlərinqalıqdəyəri': 0,
'hesabatilininəvvəlinəəsasvəsaitlərinqalıqdəyəri': 0,
'artıqqiymətəəsasvəsaitlərindəyəri505': 0
}
# Map to rows with fuzzy matching for Əlavə 1 (Tax Exempt Assets)
elave_1_data = {}
for article_number, data in tax_exempt_aggregated.items():
# Find matching row by article number in "Azadolma səbəbi"
matching_key = find_matching_azadolma_sebeb(article_number, existing_elave_1)
if matching_key:
if calculation_mode == 'tam_il':
elave_1_data[matching_key] = {
'hesabatilininəvvəlinəəsasvəsaitlərinqalıqdəyərimanatla5012': data['value_as_on_from_date'],
'ilinsonunaəsasvəsaitlərinqalıqdəyəri': data['net_asset_value_as_on_to_date'],
'hesabatiliərzindəəsasvəsaitlərinqalıqdəyəri': 0,
'artıqqiymətəəsasvəsaitlərindəyəri': data['insurance_value']
}
else: # il_erzinde
# Бизнес-правило: Для компаний, созданных в течение года (İl Ərzində),
# если нет новых покупок (value_of_new_purchase < 0.01), то все поля = 0
if flt(data.get('value_of_new_purchase', 0)) >= 0.01:
elave_1_data[matching_key] = {
'hesabatiliərzindəəsasvəsaitlərinqalıqdəyəri': data['value_of_new_purchase'],
'ilinsonunaəsasvəsaitlərinqalıqdəyəri': data['net_asset_value_as_on_to_date'],
'hesabatilininəvvəlinəəsasvəsaitlərinqalıqdəyərimanatla5012': 0,
'artıqqiymətəəsasvəsaitlərindəyəri': data['insurance_value']
}
else:
# Нет новых покупок - очистить все поля
elave_1_data[matching_key] = {
'hesabatiliərzindəəsasvəsaitlərinqalıqdəyəri': 0,
'ilinsonunaəsasvəsaitlərinqalıqdəyəri': 0,
'hesabatilininəvvəlinəəsasvəsaitlərinqalıqdəyərimanatla5012': 0,
'artıqqiymətəəsasvəsaitlərindəyəri': 0
}
return {
'success': True,
'elave_1_data': elave_1_data,
'elave_2_data': elave_2_data
}
except Exception as e:
frappe.log_error(f"Error in populate_property_tax_tables: {str(e)}", "Property Tax Gov")
return {
'success': False,
'error': str(e)
}
def get_taxable_assets_aggregated(company, from_date, to_date):
"""
Get aggregated data for taxable assets grouped by taxable_asset_type
Returns:
Dictionary: {
'taxable_asset_type_value': {
'value_as_on_from_date': float,
'value_of_new_purchase': float,
'net_asset_value_as_on_to_date': float
}
}
"""
# Get all assets with taxable_asset_type populated
assets_with_taxable_type = frappe.db.sql("""
SELECT
name,
taxable_asset_type
FROM
`tabAsset`
WHERE
docstatus = 1
AND company = %(company)s
AND taxable_asset_type IS NOT NULL
AND taxable_asset_type != ''
AND purchase_date <= %(to_date)s
""", {
'company': company,
'to_date': to_date
}, as_dict=True)
if not assets_with_taxable_type:
return {}
# Get asset balances
asset_names = [asset['name'] for asset in assets_with_taxable_type]
asset_balances = get_asset_balances_using_standard_logic(company, from_date, to_date, asset_names)
# Aggregate by taxable_asset_type
aggregated = {}
for asset in assets_with_taxable_type:
asset_type = asset['taxable_asset_type']
# Find balance for this asset
balance = next(
(b for b in asset_balances if b['asset'] == asset['name']),
{}
)
# Initialize if not exists
if asset_type not in aggregated:
aggregated[asset_type] = {
'value_as_on_from_date': 0.0,
'value_of_new_purchase': 0.0,
'net_asset_value_as_on_to_date': 0.0,
'insurance_value': 0.0
}
# Accumulate values
aggregated[asset_type]['value_as_on_from_date'] += flt(balance.get('value_as_on_from_date', 0))
aggregated[asset_type]['value_of_new_purchase'] += flt(balance.get('value_of_new_purchase', 0))
aggregated[asset_type]['net_asset_value_as_on_to_date'] += flt(balance.get('net_asset_value_as_on_to_date', 0))
aggregated[asset_type]['insurance_value'] += flt(balance.get('insurance_value', 0))
return aggregated
def get_tax_exempt_assets_aggregated(company, from_date, to_date):
"""
Get aggregated data for tax exempt assets grouped by tax article
Returns:
Dictionary: {
'tax_article_number': { # e.g., '199.1', '207.3'
'value_as_on_from_date': float,
'value_of_new_purchase': float,
'net_asset_value_as_on_to_date': float
}
}
"""
# Get all assets with industrial_tax_article or tax_exempt_tax_article
# Exclude agricultural_tax_article as per requirements
assets_with_tax_articles = frappe.db.sql("""
SELECT
a.name,
a.industrial_tax_article,
a.tax_exempt_tax_article,
COALESCE(NULLIF(a.industrial_tax_article, ''), a.tax_exempt_tax_article) as tax_article
FROM
`tabAsset` a
WHERE
a.docstatus = 1
AND a.company = %(company)s
AND (
(a.industrial_tax_article IS NOT NULL AND a.industrial_tax_article != '')
OR (a.tax_exempt_tax_article IS NOT NULL AND a.tax_exempt_tax_article != '')
)
AND a.purchase_date <= %(to_date)s
""", {
'company': company,
'to_date': to_date
}, as_dict=True)
if not assets_with_tax_articles:
return {}
# Get asset balances
asset_names = [asset['name'] for asset in assets_with_tax_articles]
asset_balances = get_asset_balances_using_standard_logic(company, from_date, to_date, asset_names)
# Aggregate by tax article number
aggregated = {}
for asset in assets_with_tax_articles:
# Extract article number from Tax Article name
tax_article_full = asset['tax_article']
article_number = extract_article_number(tax_article_full)
if not article_number:
continue
# Find balance for this asset
balance = next(
(b for b in asset_balances if b['asset'] == asset['name']),
{}
)
# Initialize if not exists
if article_number not in aggregated:
aggregated[article_number] = {
'value_as_on_from_date': 0.0,
'value_of_new_purchase': 0.0,
'net_asset_value_as_on_to_date': 0.0,
'insurance_value': 0.0
}
# Accumulate values
aggregated[article_number]['value_as_on_from_date'] += flt(balance.get('value_as_on_from_date', 0))
aggregated[article_number]['value_of_new_purchase'] += flt(balance.get('value_of_new_purchase', 0))
aggregated[article_number]['net_asset_value_as_on_to_date'] += flt(balance.get('net_asset_value_as_on_to_date', 0))
aggregated[article_number]['insurance_value'] += flt(balance.get('insurance_value', 0))
return aggregated
def extract_article_number(tax_article_name):
"""
Extract article number from Tax Article name
Examples:
"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"
Returns:
String: Article number or None if not found
"""
if not tax_article_name:
return None
# Pattern to match article numbers like 199.1, 207.3, 199.4.1-1, 227.1
pattern = r'(\d+(?:\.\d+)*(?:-\d+)?)'
match = re.search(pattern, tax_article_name)
if match:
return match.group(1)
return None
def find_matching_azadolma_sebeb(article_number, existing_rows):
"""
Find the "Azadolma səbəbi" value that contains the given article number
Args:
article_number: String like "199.1" or "207.3"
existing_rows: List of existing Əlavə 1 rows
Returns:
The matching "Azadolma səbəbi" value or None
"""
if not article_number:
return None
for row in existing_rows:
azadolma_sebeb = row.get('azadolmasəbəbi', '')
if article_number in azadolma_sebeb:
return azadolma_sebeb
return None
def find_matching_category(asset_category, existing_rows):
"""
Find matching category in Əlavə 2 rows using partial match
Examples:
Asset has: "Mənzillər"
Row has: "1.5 Mənzillər"
Result: Match found
Asset has: "Qeyri-yaşayış binaları (sahələri)"
Row has: "1.2 Qeyri-yaşayış binaları (sahələri)"
Result: Match found
Args:
asset_category: Category from Asset's taxable_asset_type field
existing_rows: List of existing Əlavə 2 rows
Returns:
The matching "Vergiyə cəlb olunan əmlakların kateqoriyası" value or None
"""
if not asset_category:
return None
for row in existing_rows:
row_category = row.get('vergiyəcəlbolunanəmlaklarınkateqoriyası', '')
# Check if asset_category is contained in row_category (e.g., "Mənzillər" in "1.5 Mənzillər")
if asset_category in row_category:
return row_category
# Also check reverse - if row_category is contained in asset_category
# (in case asset has full name with prefix)
if row_category in asset_category:
return row_category
return None
def get_asset_balances_using_standard_logic(company, from_date, to_date, asset_names):
"""
Calculate asset balances using ERPNext's Asset Depreciations and Balances report logic
Returns:
List of dictionaries with asset balances
"""
if not asset_names:
return []
# Check ERPNext version for field compatibility
version_info = check_erpnext_version()
purchase_amount_field = version_info['purchase_amount_field']
has_capitalization = version_info['has_capitalization']
# Get asset details (gross values)
asset_details = get_asset_cost_details(
company, from_date, to_date, asset_names,
purchase_amount_field, has_capitalization
)
# Get depreciation details
asset_depreciation = get_asset_depreciation_details(
company, from_date, to_date, asset_names
)
# Get value adjustments
asset_adjustments = get_asset_value_adjustments(
company, from_date, to_date, asset_names
)
# Combine and calculate net values
result = []
for asset_detail in asset_details:
asset_name = asset_detail.get('name')
# Find depreciation
depreciation = next(
(dep for dep in asset_depreciation if dep['asset'] == asset_name),
{}
)
# Find adjustments
adjustments = asset_adjustments.get(asset_name, {
'adjustment_before_from_date': 0.0,
'adjustment_till_to_date': 0.0
})
# Calculate values following ERPNext standard report logic
value_as_on_from_date = flt(asset_detail.get('cost_as_on_from_date', 0))
value_as_on_from_date += adjustments['adjustment_before_from_date']
value_of_new_purchase = flt(asset_detail.get('cost_of_new_purchase', 0))
adjustment_during_period = (
adjustments['adjustment_till_to_date'] -
adjustments['adjustment_before_from_date']
)
value_as_on_to_date = (
value_as_on_from_date +
value_of_new_purchase -
flt(asset_detail.get('cost_of_sold_asset', 0)) -
flt(asset_detail.get('cost_of_scrapped_asset', 0)) -
flt(asset_detail.get('cost_of_capitalized_asset', 0)) +
adjustment_during_period
)
accumulated_depreciation_as_on_from_date = flt(
depreciation.get('accumulated_depreciation_as_on_from_date', 0)
)
accumulated_depreciation_as_on_to_date = (
accumulated_depreciation_as_on_from_date +
flt(depreciation.get('depreciation_amount_during_the_period', 0)) -
flt(depreciation.get('depreciation_eliminated_during_the_period', 0)) -
flt(depreciation.get('depreciation_eliminated_via_reversal', 0))
)
net_asset_value_as_on_from_date = (
value_as_on_from_date - accumulated_depreciation_as_on_from_date
)
net_asset_value_as_on_to_date = (
value_as_on_to_date - accumulated_depreciation_as_on_to_date
)
# Calculate insurance value (Insured value - Gross Purchase Amount)
# Version-compat: ERPNext v15 renamed Asset.gross_purchase_amount -> net_purchase_amount
# (patch v15_0/rename_gross_purchase_amount_to_net_purchase_amount). Use the same field
# the rest of this cost logic uses (purchase_amount_field), with explicit fallback.
_asset_cols = frappe.db.get_table_columns('Asset')
if 'gross_purchase_amount' in _asset_cols:
_gross_field = 'gross_purchase_amount'
elif 'net_purchase_amount' in _asset_cols:
_gross_field = 'net_purchase_amount'
else:
_gross_field = 'purchase_amount'
insured_value = flt(frappe.db.get_value('Asset', asset_name, 'insured_value') or 0)
gross_purchase_amount = flt(frappe.db.get_value('Asset', asset_name, _gross_field) or 0)
# Only calculate difference if insured_value is actually set (> 0)
insurance_difference = (insured_value - gross_purchase_amount) if insured_value > 0 else 0
balance_result = {
'asset': asset_name,
'value_as_on_from_date': value_as_on_from_date,
'value_of_new_purchase': value_of_new_purchase,
'net_asset_value_as_on_from_date': net_asset_value_as_on_from_date,
'net_asset_value_as_on_to_date': net_asset_value_as_on_to_date,
'insurance_value': insurance_difference
}
result.append(balance_result)
return result
def check_erpnext_version():
"""Check ERPNext version for field compatibility"""
columns = frappe.db.get_table_columns("Asset")
has_net_purchase_amount = "net_purchase_amount" in columns
has_capitalization = "Asset Capitalization" in frappe.get_all("DocType", pluck="name")
return {
"purchase_amount_field": "net_purchase_amount" if has_net_purchase_amount else "gross_purchase_amount",
"has_capitalization": has_capitalization
}
def get_asset_cost_details(company, from_date, to_date, asset_names, purchase_amount_field, has_capitalization):
"""Get asset cost details (mimics ERPNext standard report)"""
asset_placeholders = ", ".join(["%s"] * len(asset_names))
capitalization_check = ""
if has_capitalization:
capitalization_check = """
AND NOT EXISTS(
SELECT 1 FROM `tabAsset Capitalization Asset Item` acai
JOIN `tabAsset Capitalization` ac ON acai.parent = ac.name
WHERE acai.asset = a.name
AND ac.posting_date < %s
AND ac.docstatus = 1
)
"""
else:
# В версии 15 просто исключаем активы где есть запись в Asset Capitalization Asset Item
capitalization_check = " AND NOT EXISTS(SELECT name FROM `tabAsset Capitalization Asset Item` WHERE asset = a.name)"
query = f"""
SELECT
a.name,
IFNULL(SUM(
CASE
WHEN a.purchase_date < %s THEN
CASE
WHEN IFNULL(a.disposal_date, 0) = 0 OR a.disposal_date >= %s
THEN a.{purchase_amount_field}
ELSE 0
END
ELSE 0
END
), 0) as cost_as_on_from_date,
IFNULL(SUM(
CASE
WHEN a.purchase_date >= %s
THEN a.{purchase_amount_field}
ELSE 0
END
), 0) as cost_of_new_purchase,
IFNULL(SUM(
CASE
WHEN IFNULL(a.disposal_date, 0) != 0
AND a.disposal_date >= %s
AND a.disposal_date <= %s
THEN
CASE WHEN a.status = 'Sold' THEN a.{purchase_amount_field} ELSE 0 END
ELSE 0
END
), 0) as cost_of_sold_asset,
IFNULL(SUM(
CASE
WHEN IFNULL(a.disposal_date, 0) != 0
AND a.disposal_date >= %s
AND a.disposal_date <= %s
THEN
CASE WHEN a.status = 'Scrapped' THEN a.{purchase_amount_field} ELSE 0 END
ELSE 0
END
), 0) as cost_of_scrapped_asset,
IFNULL(SUM(
CASE
WHEN IFNULL(a.disposal_date, 0) != 0
AND a.disposal_date >= %s
AND a.disposal_date <= %s
THEN
CASE WHEN a.status = 'Capitalized' THEN a.{purchase_amount_field} ELSE 0 END
ELSE 0
END
), 0) as cost_of_capitalized_asset
FROM
`tabAsset` a
WHERE
a.docstatus = 1
AND a.company = %s
AND a.purchase_date <= %s
AND a.name IN ({asset_placeholders})
{capitalization_check}
GROUP BY a.name
"""
values = [
from_date, # cost_as_on_from_date condition 1
from_date, # cost_as_on_from_date condition 2
from_date, # cost_of_new_purchase
from_date, # cost_of_sold_asset condition 1
to_date, # cost_of_sold_asset condition 2
from_date, # cost_of_scrapped_asset condition 1
to_date, # cost_of_scrapped_asset condition 2
from_date, # cost_of_capitalized_asset condition 1
to_date, # cost_of_capitalized_asset condition 2
company, # company filter
to_date, # purchase_date filter
*asset_names # asset names for IN clause
]
if has_capitalization:
values.append(from_date)
return frappe.db.sql(query, values, as_dict=True)
def get_asset_depreciation_details(company, from_date, to_date, asset_names):
"""Get asset depreciation details (mimics ERPNext standard report)"""
asset_placeholders = ", ".join(["%s"] * len(asset_names))
query = f"""
SELECT
results.name as asset,
SUM(results.accumulated_depreciation_as_on_from_date) as accumulated_depreciation_as_on_from_date,
SUM(results.depreciation_eliminated_during_the_period) as depreciation_eliminated_during_the_period,
SUM(results.depreciation_amount_during_the_period) as depreciation_amount_during_the_period,
SUM(results.depreciation_eliminated_via_reversal) as depreciation_eliminated_via_reversal
FROM (
SELECT
a.name as name,
IFNULL(SUM(
CASE
WHEN gle.posting_date < %s
AND (IFNULL(a.disposal_date, 0) = 0 OR a.disposal_date >= %s)
THEN gle.debit
ELSE 0
END
), 0) as accumulated_depreciation_as_on_from_date,
IFNULL(SUM(
CASE
WHEN gle.posting_date <= %s
AND IFNULL(a.disposal_date, 0) = 0
THEN gle.credit
ELSE 0
END
), 0) as depreciation_eliminated_via_reversal,
IFNULL(SUM(
CASE
WHEN IFNULL(a.disposal_date, 0) != 0
AND a.disposal_date >= %s
AND a.disposal_date <= %s
AND gle.posting_date <= a.disposal_date
THEN gle.debit
ELSE 0
END
), 0) as depreciation_eliminated_during_the_period,
IFNULL(SUM(
CASE
WHEN gle.posting_date >= %s
AND gle.posting_date <= %s
AND (IFNULL(a.disposal_date, 0) = 0 OR gle.posting_date <= a.disposal_date)
THEN gle.debit
ELSE 0
END
), 0) as depreciation_amount_during_the_period
FROM
`tabGL Entry` gle
JOIN
`tabAsset` a ON gle.against_voucher = a.name
JOIN
`tabAsset Category Account` aca ON aca.parent = a.asset_category
AND aca.company_name = %s
JOIN
`tabCompany` company ON company.name = %s
WHERE
a.docstatus = 1
AND a.company = %s
AND a.purchase_date <= %s
AND gle.is_cancelled = 0
AND gle.account = IFNULL(aca.depreciation_expense_account, company.depreciation_expense_account)
AND a.name IN ({asset_placeholders})
GROUP BY a.name
UNION
SELECT
a.name as name,
IFNULL(SUM(
CASE
WHEN IFNULL(a.disposal_date, 0) != 0
AND a.disposal_date < %s
THEN 0
ELSE a.opening_accumulated_depreciation
END
), 0) as accumulated_depreciation_as_on_from_date,
0 as depreciation_eliminated_via_reversal,
IFNULL(SUM(
CASE
WHEN a.disposal_date >= %s
AND a.disposal_date <= %s
THEN a.opening_accumulated_depreciation
ELSE 0
END
), 0) as depreciation_eliminated_during_the_period,
0 as depreciation_amount_during_the_period
FROM
`tabAsset` a
WHERE
a.docstatus = 1
AND a.company = %s
AND a.purchase_date <= %s
AND a.name IN ({asset_placeholders})
GROUP BY a.name
) as results
GROUP BY results.name
"""
values = [
from_date, # accumulated_depreciation_as_on_from_date condition 1
from_date, # accumulated_depreciation_as_on_from_date condition 2
to_date, # depreciation_eliminated_via_reversal
from_date, # depreciation_eliminated_during_the_period condition 1
to_date, # depreciation_eliminated_during_the_period condition 2
from_date, # depreciation_amount_during_the_period condition 1
to_date, # depreciation_amount_during_the_period condition 2
company, # aca.company_name
company, # company.name
company, # a.company
to_date, # a.purchase_date
*asset_names, # asset names for IN clause (first SELECT)
from_date, # disposal_date condition (second SELECT)
from_date, # disposal_date condition (second SELECT)
to_date, # disposal_date condition (second SELECT)
company, # a.company (second SELECT)
to_date, # a.purchase_date (second SELECT)
*asset_names # asset names for IN clause (second SELECT)
]
return frappe.db.sql(query, values, as_dict=True)
def get_asset_value_adjustments(company, from_date, to_date, asset_names):
"""Get asset value adjustments (mimics ERPNext standard report)"""
asset_placeholders = ", ".join(["%s"] * len(asset_names))
query = f"""
SELECT
a.name AS asset,
IFNULL(
SUM(
CASE
WHEN gle.posting_date < %s
AND (a.disposal_date IS NULL OR a.disposal_date >= %s)
THEN gle.debit - gle.credit
ELSE 0
END
),
0) AS value_adjustment_before_from_date,
IFNULL(
SUM(
CASE
WHEN gle.posting_date <= %s
AND (a.disposal_date IS NULL OR a.disposal_date >= %s)
THEN gle.debit - gle.credit
ELSE 0
END
),
0) AS value_adjustment_till_to_date
FROM
`tabGL Entry` gle
JOIN
`tabAsset` a ON gle.against_voucher = a.name
JOIN
`tabAsset Category Account` aca ON aca.parent = a.asset_category
AND aca.company_name = %s
WHERE
gle.is_cancelled = 0
AND a.docstatus = 1
AND a.company = %s
AND a.purchase_date <= %s
AND gle.account = aca.fixed_asset_account
AND a.name IN ({asset_placeholders})
GROUP BY a.name
"""
values = [
from_date, # value_adjustment_before_from_date condition 1
from_date, # value_adjustment_before_from_date condition 2
to_date, # value_adjustment_till_to_date condition 1
to_date, # value_adjustment_till_to_date condition 2
company, # aca.company_name
company, # a.company
to_date, # a.purchase_date
*asset_names # asset names for IN clause
]
result = frappe.db.sql(query, values, as_dict=True)
# Convert to dictionary
adjustment_map = {}
for r in result:
adjustment_map[r['asset']] = {
'adjustment_before_from_date': flt(r.get('value_adjustment_before_from_date', 0)),
'adjustment_till_to_date': flt(r.get('value_adjustment_till_to_date', 0))
}
return adjustment_map
@frappe.whitelist()
def calculate_months_for_vergi_hesab_4cu_1(company, year):
"""
Находит самый ранний Asset по available_for_use_date в указанном году
и возвращает количество месяцев от этого месяца до конца года (включительно)
Args:
company: Название компании
year: Год для поиска (integer)
Returns:
Integer: Количество месяцев (1-12) или 0 если нет Assets
"""
try:
# Найти самый ранний Asset в году
# docstatus = 1 означает статус "Submitted" (не Draft и не Cancelled)
earliest_asset = frappe.db.sql("""
SELECT MIN(available_for_use_date) as earliest_date
FROM `tabAsset`
WHERE company = %(company)s
AND docstatus = 1
AND available_for_use_date IS NOT NULL
AND YEAR(available_for_use_date) = %(year)s
""", {
'company': company,
'year': year
}, as_dict=True)
if not earliest_asset or not earliest_asset[0].get('earliest_date'):
return 0
earliest_date = earliest_asset[0]['earliest_date']
# Получить номер месяца (1-12)
from datetime import datetime
if isinstance(earliest_date, str):
earliest_date = datetime.strptime(earliest_date, '%Y-%m-%d')
month = earliest_date.month
# Вычислить количество месяцев от этого месяца до конца года (не включая этот месяц)
# Январь (1) → 12-1=11 месяцев, Март (3) → 12-3=9 месяцев, Сентябрь (9) → 12-9=3 месяца
months_count = 12 - month
return months_count
except Exception as e:
frappe.log_error(f"Error in calculate_months_for_vergi_hesab_4cu_1: {str(e)}", "Property Tax Gov")
return 0

View File

@ -1,9 +0,0 @@
# Copyright (c) 2025, Jey Soft and Contributors
# See license.txt
# import frappe
from frappe.tests.utils import FrappeTestCase
class TestPropertyTaxGov(FrappeTestCase):
pass

View File

@ -1,76 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-01-13 15:04:47.107017",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"azadolmasəbəbi",
"hesabatilininəvvəlinəəsasvəsaitlərinqalıqdəyərimanatla5012",
"ləğvolunmatarixinəəsasvəsaitlərinqalıqdəyəri",
"hesabatiliərzindəəsasvəsaitlərinqalıqdəyəri",
"ilinsonunaəsasvəsaitlərinqalıqdəyəri",
"artıqqiymətəəsasvəsaitlərindəyəri"
],
"fields": [
{
"fieldname": "azadolmasəbəbi",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Azadolma səbəbi",
"options": "Vergi Məcəlləsinin 199.1-ci maddəsinə əsasən:\nVergi Məcəlləsinin 199.4.1-ci maddəsinə əsasən:\nVergi Məcəlləsinin 199.4.2-ci maddəsinə əsasən:\nVergi Məcəlləsinin 199.4.3-cü maddəsinə əsasən:\nVergi Məcəlləsinin 199.4.4-cü maddəsinə əsasən:\nVergi Məcəlləsinin 199.4.1-1-ci maddəsinə əsasən:\nVergi Məcəlləsinin 199.5-ci maddəsinə əsasən:\nVergi Məcəlləsinin 199.7-ci maddəsinə əsasən:\nVergi Məcəlləsinin 199.8-ci maddəsinə əsasən:\nVergi Məcəlləsinin 199.9-cu maddəsinə əsasən:\nVergi Məcəlləsinin 199.11-cu maddəsinə əsasən:\nVergi Məcəlləsinin 199.14-cu maddəsinə əsasən:\nVergi Məcəlləsinin 199.15-cu maddəsinə əsasən:\nVergi Məcəlləsinin 199.16-cı maddəsinə əsasən:\nVergi Məcəlləsinin 199.17-ci maddəsinə əsasən:\nVergi Məcəlləsinin 199.18-ci maddəsinə əsasən:\nVergi Məcəlləsinin 199.19-cu maddəsinə əsasən:\nVergi Məcəlləsinin 227.1-ci maddəsinə əsasən:\nQanunla təsdiq olunmuş hasilatın pay bölgüsü haqqında, əsas boru kəməri haqqında və digər bu qəbildən olan sazişlərdə və ya qanunlarda, o cümlədən neft və qaz haqqında, ixrac məqsədli neft-qaz fəaliyyəti üzrə:\nXüsusi iqtisadi zonalar haqqında qanunlarda nəzərdə tutulan əmlaklar üzrə:\nAzərbaycan Respublikasının tərəfdar çıxdığı beynəlxalq müqavilələr üzrə:\nVergidən azad olunan əmlakın CƏMİ dəyəri:",
"read_only": 1,
"length": 255
},
{
"fieldname": "hesabatiliərzindəəsasvəsaitlərinqalıqdəyəri",
"fieldtype": "Float",
"precision": "2",
"in_list_view": 1,
"label": "Yeni yaradıldığı (uçota alındığı) və ya əmlak vergisi ödəyicisi olma tarixinə əsas vəsaitlərin qalıq dəyəri (manatla) (503.2)\t",
"read_only": 1
},
{
"fieldname": "ləğvolunmatarixinəəsasvəsaitlərinqalıqdəyəri",
"fieldtype": "Float",
"precision": "2",
"in_list_view": 1,
"label": "Vergi ödəyicisinin ləğv olunma və ya uçotdan çıxarılma tarixinə əsas vəsaitlərin qalıq dəyəri (manatla) (502.2)",
"read_only": 1
},
{
"fieldname": "ilinsonunaəsasvəsaitlərinqalıqdəyəri",
"fieldtype": "Float",
"precision": "2",
"in_list_view": 1,
"label": "Vergi ödəyicisinin ilin sonuna əsas vəsaitlərinin qalıq dəyəri (manatla) (504.2)"
},
{
"fieldname": "artıqqiymətəəsasvəsaitlərindəyəri",
"fieldtype": "Float",
"precision": "2",
"in_list_view": 1,
"label": "Artıq qiymətə sığortalanan əsas vəsaitlərin dəyəri (manatla) (505.2)"
},
{
"fieldname": "hesabatilininəvvəlinəəsasvəsaitlərinqalıqdəyərimanatla5012",
"fieldtype": "Float",
"precision": "2",
"in_list_view": 1,
"label": "Hesabat ilinin əvvəlinə əsas vəsaitlərin qalıq dəyəri (manatla) (501.2)"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-08-05 14:25:59.341379",
"modified_by": "Administrator",
"module": "Taxes Az",
"name": "Property Tax Gov Elave 1",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2025, Jey Soft and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PropertyTaxGovElave1(Document):
pass

View File

@ -1,74 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-01-13 16:36:30.780093",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"vergiy\u0259c\u0259lbolunan\u0259mlaklar\u0131nkateqoriyas\u0131",
"hesabatilinin\u0259vv\u0259lin\u0259\u0259sasv\u0259saitl\u0259rinqal\u0131qd\u0259y\u0259ri",
"l\u0259\u011fvolunmatarixin\u0259\u0259sasv\u0259saitl\u0259rinqal\u0131qd\u0259y\u0259ri",
"hesabatilierzindeu\u00e7otaal\u0131nan",
"hesabatilinsonuna\u0259sasv\u0259saitl\u0259rinqal\u0131qd\u0259y\u0259ri",
"art\u0131qqiym\u0259t\u0259\u0259sasv\u0259saitl\u0259rind\u0259y\u0259ri505"
],
"fields": [
{
"fieldname": "l\u0259\u011fvolunmatarixin\u0259\u0259sasv\u0259saitl\u0259rinqal\u0131qd\u0259y\u0259ri",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Vergi \u00f6d\u0259yicisinin l\u0259\u011fv olunma v\u0259 ya u\u00e7otdan \u00e7\u0131xar\u0131lma tarixin\u0259 \u0259sas v\u0259saitl\u0259rin qal\u0131q d\u0259y\u0259ri (manatla) (502.1)",
"precision": "2"
},
{
"fieldname": "vergiy\u0259c\u0259lbolunan\u0259mlaklar\u0131nkateqoriyas\u0131",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Vergiy\u0259 c\u0259lb olunan \u0259mlaklar\u0131n kateqoriyas\u0131",
"options": "1. Binalar, tikilil\u0259r v\u0259 qur\u011fular\n1.1 \u00c7oxm\u0259rt\u0259b\u0259li (\u00e7oxm\u0259nzilli) ya\u015fay\u0131\u015f binalar\u0131\n1.2 Qeyri-ya\u015fay\u0131\u015f binalar\u0131 (sah\u0259l\u0259ri)\n1.3 \u018fmlak kompleksi kimi m\u00fc\u0259ssis\u0259l\u0259r\n1.4 Qur\u011fular\n1.5 M\u0259nzill\u0259r\n1.6 F\u0259rdi ya\u015fay\u0131\u015f v\u0259 ba\u011f evl\u0259ri\n2 Ma\u015f\u0131nlar v\u0259 avadanl\u0131qlar\n3 Y\u00fcks\u0259k texnologiyalar m\u0259hsulu olan hesablama texnikas\u0131\n4 N\u0259qliyyat vasit\u0259l\u0259ri\n5 Dig\u0259r \u0259sas v\u0259saitl\u0259r\nVergiy\u0259 c\u0259lb olunan \u0259mlak\u0131n C\u018fM\u0130 d\u0259y\u0259ri:",
"read_only": 1
},
{
"fieldname": "hesabatilinin\u0259vv\u0259lin\u0259\u0259sasv\u0259saitl\u0259rinqal\u0131qd\u0259y\u0259ri",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Hesabat ilinin \u0259vv\u0259lin\u0259 \u0259sas v\u0259saitl\u0259rin qal\u0131q d\u0259y\u0259ri (manatla) (501.1)",
"precision": "2"
},
{
"fieldname": "hesabatilierzindeu\u00e7otaal\u0131nan",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Hesabat ili \u0259rzind\u0259 yarand\u0131\u011f\u0131 (u\u00e7ota al\u0131nd\u0131\u011f\u0131) v\u0259 ya \u0259mlak vergisi \u00f6d\u0259yicisi olma tarixin\u0259 \u0259sas v\u0259saitl\u0259rin qal\u0131q d\u0259y\u0259ri (manatla) (503.1)",
"precision": "2",
"read_only": 1
},
{
"fieldname": "hesabatilinsonuna\u0259sasv\u0259saitl\u0259rinqal\u0131qd\u0259y\u0259ri",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Hesabat ilinin sonuna \u0259sas v\u0259saitl\u0259rinin qal\u0131q d\u0259y\u0259ri (manatla) (504.1)",
"precision": "2"
},
{
"fieldname": "art\u0131qqiym\u0259t\u0259\u0259sasv\u0259saitl\u0259rind\u0259y\u0259ri505",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Art\u0131q qiym\u0259t\u0259 s\u0131\u011fotalanan \u0259sas v\u0259saitl\u0259rin d\u0259y\u0259ri (manatla) (505.1)",
"precision": "2"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2026-01-08 18:48:57.656460",
"modified_by": "Administrator",
"module": "Taxes Az",
"name": "Property Tax Gov Elave 2",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2025, Jey Soft and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PropertyTaxGovElave2(Document):
pass

View File

@ -1,41 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-01-13 14:28:57.994528",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"g\u00f6st\u0259ricil\u0259r",
"manatla"
],
"fields": [
{
"fieldname": "g\u00f6st\u0259ricil\u0259r",
"fieldtype": "Select",
"in_list_view": 1,
"label": "G\u00f6st\u0259ricil\u0259r",
"options": "501. \u018fmlak\u0131n \u00fcmumi qal\u0131q d\u0259y\u0259ri\n501.1 Vergiy\u0259 c\u0259lb olunan \u0259mlak\u0131n qal\u0131q d\u0259y\u0259ri\n501.1.1 Qeyri-kommersiya f\u0259aliyy\u0259tind\u0259 istifad\u0259 olunan \u0259mlak\u0131n qal\u0131q d\u0259y\u0259ri\n501.2 Vergid\u0259n azad olunan \u0259mlak\u0131n qal\u0131q d\u0259y\u0259ri",
"read_only": 1
},
{
"fieldname": "manatla",
"fieldtype": "Float",
"precision": "2",
"in_list_view": 1,
"label": "Manatla"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-08-04 19:47:26.620548",
"modified_by": "Administrator",
"module": "Taxes Az",
"name": "Property Tax Gov Emlak vergi hesablamasi 1ci cedvel",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2025, Jey Soft and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PropertyTaxGovEmlakvergihesablamasi1cicedvel(Document):
pass

View File

@ -1,41 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-08-04 12:02:18.835114",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"g\u00f6st\u0259ricil\u0259r",
"manatla"
],
"fields": [
{
"fieldname": "g\u00f6st\u0259ricil\u0259r",
"fieldtype": "Select",
"in_list_view": 1,
"label": "G\u00f6st\u0259ricil\u0259r",
"options": "503. \u018fmlak\u0131n \u00fcmumi d\u0259y\u0259ri\n503.1 Vergiy\u0259 c\u0259lb olunan \u0259mlak\u0131n d\u0259y\u0259ri\n503.1.1 Qeyri-kommersiya f\u0259aliyy\u0259tind\u0259 istifad\u0259 olunan \u0259mlak\u0131n d\u0259y\u0259ri\n503.2 Vergid\u0259n azad olunan \u0259mlak\u0131n d\u0259y\u0259ri",
"read_only": 1
},
{
"fieldname": "manatla",
"fieldtype": "Float",
"precision": "2",
"in_list_view": 1,
"label": "Manatla"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-08-04 19:38:26.382915",
"modified_by": "Administrator",
"module": "Taxes Az",
"name": "Property Tax Gov Emlak vergi hesablamasi 1ci cedvel 1",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2025, Jey Soft and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PropertyTaxGovEmlakvergihesablamasi1cicedvel1(Document):
pass

View File

@ -1,41 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-01-13 14:36:20.467665",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"g\u00f6st\u0259ricil\u0259r",
"manatla"
],
"fields": [
{
"fieldname": "g\u00f6st\u0259ricil\u0259r",
"fieldtype": "Select",
"in_list_view": 1,
"label": "G\u00f6st\u0259ricil\u0259r",
"options": "504. \u018fmlak\u0131n \u00fcmumi qal\u0131q d\u0259y\u0259ri\n504.1 Vergiy\u0259 c\u0259lb olunan \u0259mlak\u0131n qal\u0131q d\u0259y\u0259ri\n504.1.1 Qeyri-kommersiya f\u0259aliyy\u0259tind\u0259 istifad\u0259 olunan \u0259mlak\u0131n qal\u0131q d\u0259y\u0259ri\n504.2 Vergid\u0259n azad olunan \u0259mlak\u0131n qal\u0131q d\u0259y\u0259ri",
"read_only": 1
},
{
"fieldname": "manatla",
"fieldtype": "Float",
"precision": "2",
"in_list_view": 1,
"label": "Manatla"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-08-04 12:00:07.915973",
"modified_by": "Administrator",
"module": "Taxes Az",
"name": "Property Tax Gov Emlak vergi hesablamasi 2ci cedvel",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2025, Jey Soft and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PropertyTaxGovEmlakvergihesablamasi2cicedvel(Document):
pass

View File

@ -1,41 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-01-13 14:35:10.099838",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"g\u00f6st\u0259ricil\u0259r",
"manatla"
],
"fields": [
{
"fieldname": "g\u00f6st\u0259ricil\u0259r",
"fieldtype": "Select",
"in_list_view": 1,
"label": "G\u00f6st\u0259ricil\u0259r",
"options": "505 Art\u0131q qiym\u0259t\u0259 s\u0131\u011fortalanan \u0259mlak\u0131n d\u0259y\u0259ri\n505.1 Vergiy\u0259 c\u0259lb olunan art\u0131q qiym\u0259t\u0259 s\u0131\u011fortalanan \u0259mlak\u0131n d\u0259y\u0259ri\n505.2 Vergid\u0259n azad olunan art\u0131q qiym\u0259t\u0259 s\u0131\u011fortalanan \u0259mlak\u0131n d\u0259y\u0259ri",
"read_only": 1
},
{
"fieldname": "manatla",
"fieldtype": "Float",
"precision": "2",
"in_list_view": 1,
"label": "Manatla"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-08-04 12:00:44.910640",
"modified_by": "Administrator",
"module": "Taxes Az",
"name": "Property Tax Gov Emlak vergi hesablamasi 3cu cedvel",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2025, Jey Soft and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PropertyTaxGovEmlakvergihesablamasi3cucedvel(Document):
pass

View File

@ -1,42 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-01-13 14:36:07.154586",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"g\u00f6st\u0259ricil\u0259r",
"faizl\u0259"
],
"fields": [
{
"fieldname": "g\u00f6st\u0259ricil\u0259r",
"fieldtype": "Select",
"in_list_view": 1,
"label": "G\u00f6st\u0259ricil\u0259r",
"options": "506 Verginin d\u0259r\u0259c\u0259si",
"read_only": 1
},
{
"fieldname": "faizl\u0259",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Faizl\u0259 %",
"precision": "2",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-12-29 18:09:10.263087",
"modified_by": "Administrator",
"module": "Taxes Az",
"name": "Property Tax Gov Emlak vergi hesablamasi 4cu cedvel",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2025, Jey Soft and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PropertyTaxGovEmlakvergihesablamasi4cucedvel(Document):
pass

View File

@ -1,41 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-08-04 19:40:22.377464",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"g\u00f6st\u0259ricil\u0259r",
"ayla"
],
"fields": [
{
"fieldname": "g\u00f6st\u0259ricil\u0259r",
"fieldtype": "Select",
"in_list_view": 1,
"label": "G\u00f6st\u0259ricil\u0259r",
"options": "507 M\u00fc\u0259ssis\u0259 yarand\u0131\u011f\u0131 aydan sonra ilin sonuna q\u0259d\u0259r olan aylar\u0131n say\u0131",
"read_only": 1
},
{
"fieldname": "ayla",
"fieldtype": "Float",
"precision": "2",
"in_list_view": 1,
"label": "Ayla"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-08-04 19:41:48.738524",
"modified_by": "Administrator",
"module": "Taxes Az",
"name": "Property Tax Gov Emlak vergi hesablamasi 4cu cedvel 1",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2025, Jey Soft and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PropertyTaxGovEmlakvergihesablamasi4cucedvel1(Document):
pass

View File

@ -1,40 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-01-13 15:00:15.158446",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"g\u00f6st\u0259ricil\u0259r",
"manatla"
],
"fields": [
{
"fieldname": "g\u00f6st\u0259ricil\u0259r",
"fieldtype": "Select",
"in_list_view": 1,
"label": "G\u00f6st\u0259ricil\u0259r",
"options": "509.1 Vergi \u00f6d\u0259yicisi il \u0259rzind\u0259 tam f\u0259aliyy\u0259t g\u00f6st\u0259rdiyi halda:\n509.2 Hesabat ili \u0259rzind\u0259 yarad\u0131ld\u0131\u011f\u0131 (u\u00e7ota al\u0131nd\u0131\u011f\u0131) v\u0259 ya \u0259mlak vergisi \u00f6d\u0259yicisi oldu\u011fu halda:\n510 Vergi m\u0259c\u0259ll\u0259sinin 199.21-ci madd\u0259sin\u0259 \u0259sas\u0259n azald\u0131lmal\u0131 \u0259mlak vergisinin m\u0259bl\u0259\u011fi"
},
{
"fieldname": "manatla",
"fieldtype": "Float",
"in_list_view": 1,
"label": "Manatla",
"precision": "2"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2026-01-07 14:25:22.271312",
"modified_by": "Administrator",
"module": "Taxes Az",
"name": "Property Tax Gov Emlak vergi hesablamasi 5ci cedvel",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2025, Jey Soft and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PropertyTaxGovEmlakvergihesablamasi5cicedvel(Document):
pass

View File

@ -1,43 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-08-04 14:47:33.216880",
"default_view": "List",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"g\u00f6st\u0259ricil\u0259r",
"manatla"
],
"fields": [
{
"fieldname": "g\u00f6st\u0259ricil\u0259r",
"fieldtype": "Select",
"in_list_view": 1,
"label": "G\u00f6st\u0259ricil\u0259r",
"options": "511.1 M\u00fc\u0259ssis\u0259 il \u0259rzind\u0259 tam f\u0259aliyy\u0259t g\u00f6st\u0259rdiyi halda\n511.2 M\u00fc\u0259ssis\u0259 il \u0259rzind\u0259 yarand\u0131\u011f\u0131 halda",
"read_only": 1
},
{
"fieldname": "manatla",
"fieldtype": "Float",
"precision": "2",
"in_list_view": 1,
"label": "Manatla",
"read_only": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-08-04 21:25:48.999866",
"modified_by": "Administrator",
"module": "Taxes Az",
"name": "Property Tax Gov Emlak vergi hesablamasi 6ci cedvel",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}

View File

@ -1,9 +0,0 @@
# Copyright (c) 2025, Jey Soft and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class PropertyTaxGovEmlakvergihesablamasi6cicedvel(Document):
pass