feat(property-tax-gov): rework property_tax_gov client script; add RU architecture doc
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6d6ff50afe
commit
d370d74e32
|
|
@ -0,0 +1,218 @@
|
||||||
|
# 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. Расчётный движок (клиент)
|
||||||
|
|
||||||
|
Здесь самое тонкое место. Файл содержит **два поколения кода расчёта**, и работает только второе.
|
||||||
|
|
||||||
|
### Старый код (строки 269–919)
|
||||||
|
Ручные функции: `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 = число месяцев).
|
||||||
|
|
||||||
|
### Новый код (строки 1042–1264) — **активный**
|
||||||
|
|
||||||
|
В конце файла все шесть `calculate_*` **переопределены заново** как тонкие делегаторы:
|
||||||
|
|
||||||
|
```js
|
||||||
|
function calculate_509_1(frm) { gns_property_recalc(frm); }
|
||||||
|
// ... и т.д.
|
||||||
|
```
|
||||||
|
|
||||||
|
Это работает за счёт **hoisting функций в JS: последнее объявление побеждает**. То есть все
|
||||||
|
старые триггеры (обработчики дочерних таблиц на строках 924–1040) теперь незаметно вызывают
|
||||||
|
новый единый движок `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. Сейчас же, как явно сказано в
|
||||||
|
комментарии (строки 1103–1107), **формулы переписаны нативно в 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`) сейчас не в рантайме, а как эталон формул.
|
||||||
|
|
@ -1097,53 +1097,67 @@ function gns_property_recalc(frm) {
|
||||||
_ptgov_timer = setTimeout(function () { _gns_property_recalc_now(frm); }, 250);
|
_ptgov_timer = setTimeout(function () { _gns_property_recalc_now(frm); }, 250);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// half-up rounding to 2 decimals (matches the cabinet's decimal rounding)
|
||||||
|
function ptgov_round2(x) { return Math.round((flt(x) + Number.EPSILON) * 100) / 100; }
|
||||||
|
|
||||||
|
// LOCAL implementation of the property-tax formulas. The formulas/logic were extracted &
|
||||||
|
// verified from the GNS cabinet (new.e-taxes.gov.az) — see .etaxes_notes/scratch/calc_extract.
|
||||||
|
// Only the +,-,*,/ run here (locally, offline). The cabinet is the SOURCE of the formulas,
|
||||||
|
// not a runtime dependency; compute_via_gns + the extracted bundle stay in the repo as the
|
||||||
|
// reference from which these were derived.
|
||||||
|
// a1 = appendix1 (taxFree) totals, a2 = appendix2 (taxable) totals, full = Tam İl
|
||||||
|
function ptgov_calc_byArticle(a1, a2, full, months) {
|
||||||
|
const RATE = 0.01; // 506 taxDegree = 1% for legal entities
|
||||||
|
const by = {};
|
||||||
|
if (full) {
|
||||||
|
// 501 prePeriod (beginning of year): total = taxable + tax-exempt
|
||||||
|
by['501.1'] = a2.periodStart; // taxable residual
|
||||||
|
by['501.2'] = a1.periodStart; // tax-exempt residual
|
||||||
|
by['501'] = a2.periodStart + a1.periodStart;
|
||||||
|
} else {
|
||||||
|
// 503 createDate (newly established during the year)
|
||||||
|
by['503.1'] = a2.onCreate;
|
||||||
|
by['503.2'] = a1.created;
|
||||||
|
by['503'] = a2.onCreate + a1.created;
|
||||||
|
}
|
||||||
|
// 504 endYear
|
||||||
|
by['504.1'] = a2.periodEnd;
|
||||||
|
by['504.2'] = a1.endYear;
|
||||||
|
by['504'] = a2.periodEnd + a1.endYear;
|
||||||
|
// 505 excess-insured
|
||||||
|
by['505.1'] = a2.excess;
|
||||||
|
by['505.2'] = a1.over;
|
||||||
|
by['505'] = a2.excess + a1.over;
|
||||||
|
// 509 calculated tax — only taxable (appendix2) is taxed; 511 shouldBePaid mirrors it
|
||||||
|
let tax;
|
||||||
|
if (full) {
|
||||||
|
tax = ptgov_round2((a2.periodStart + a2.periodEnd) / 2 * RATE + a2.excess * RATE);
|
||||||
|
by['509.1'] = tax; by['511.1'] = tax;
|
||||||
|
} else {
|
||||||
|
tax = ptgov_round2((a2.onCreate + a2.periodEnd) / 24 * flt(months) * RATE + a2.excess * RATE);
|
||||||
|
by['509.2'] = tax; by['511.2'] = tax;
|
||||||
|
}
|
||||||
|
return by;
|
||||||
|
}
|
||||||
|
|
||||||
function _gns_property_recalc_now(frm) {
|
function _gns_property_recalc_now(frm) {
|
||||||
const e1 = ptgov_sum(frm.doc.elave_1, PTGOV_E1);
|
const a1 = ptgov_sum(frm.doc.elave_1, PTGOV_E1);
|
||||||
const e2 = ptgov_sum(frm.doc.elave_2, PTGOV_E2, ptgov_is_excluded_e2);
|
const a2 = ptgov_sum(frm.doc.elave_2, PTGOV_E2, ptgov_is_excluded_e2);
|
||||||
|
const full = !frm.doc.il_erzinde;
|
||||||
const activity = frm.doc.il_erzinde ? 'OBJECT_ESTABLISHED' : 'OBJECT_FULL_ACTIVITY';
|
let months = 0;
|
||||||
|
|
||||||
// months (507): read from the 4cu cedvel 1 (ayla) row, used only for OBJECT_ESTABLISHED
|
|
||||||
let months = null;
|
|
||||||
(frm.doc.vergi_hesab_4cu_1 || []).forEach(function (r) {
|
(frm.doc.vergi_hesab_4cu_1 || []).forEach(function (r) {
|
||||||
if (ptgov_article(r.göstəricilər) === '507') months = flt(r.ayla);
|
if (ptgov_article(r.göstəricilər) === '507') months = flt(r.ayla);
|
||||||
});
|
});
|
||||||
|
const byArt = ptgov_calc_byArticle(a1, a2, full, months);
|
||||||
|
|
||||||
const payload = {
|
|
||||||
objectActivity: activity,
|
|
||||||
calculation: {
|
|
||||||
monthCountFromStartPeriod: activity === 'OBJECT_ESTABLISHED' ? months : null,
|
|
||||||
monthCountToLiquidation: null,
|
|
||||||
},
|
|
||||||
appendix1: {
|
|
||||||
periodStartTotal: e1.periodStart, createdTotal: e1.created,
|
|
||||||
removedTotal: e1.removed, endYearTotal: e1.endYear, overTotal: e1.over,
|
|
||||||
},
|
|
||||||
appendix2: {
|
|
||||||
periodStartTotal: e2.periodStart, onCreateDateTotal: e2.onCreate,
|
|
||||||
onCancelDateTotal: e2.onCancel, periodEndTotal: e2.periodEnd,
|
|
||||||
excessInsuredTotal: e2.excess,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
frappe.call({
|
|
||||||
method: 'taxes_az.taxes_az.doctype.property_tax_gov.property_tax_gov.compute_via_gns',
|
|
||||||
args: { payload: JSON.stringify(payload) },
|
|
||||||
callback: function (r) {
|
|
||||||
if (!r.message || !r.message.byArticle) return;
|
|
||||||
const byArt = r.message.byArticle;
|
|
||||||
frm.__ptgov_writing = true; // guard: our set_value writes retrigger manatla handlers
|
frm.__ptgov_writing = true; // guard: our set_value writes retrigger manatla handlers
|
||||||
try {
|
try {
|
||||||
// write computed values into the calculation cedvel rows (manatla) by article number
|
|
||||||
PTGOV_OUT_TABLES.forEach(function (tbl) {
|
PTGOV_OUT_TABLES.forEach(function (tbl) {
|
||||||
(frm.doc[tbl] || []).forEach(function (row) {
|
(frm.doc[tbl] || []).forEach(function (row) {
|
||||||
const art = ptgov_article(row.göstəricilər);
|
const art = ptgov_article(row.göstəricilər);
|
||||||
if (art != null && byArt[art] != null) {
|
frappe.model.set_value(row.doctype, row.name, 'manatla', flt(byArt[art] || 0));
|
||||||
frappe.model.set_value(row.doctype, row.name, 'manatla', flt(byArt[art]));
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// tax rate (506) is the constant 1% for legal entities
|
|
||||||
(frm.doc.vergi_hesab_4cu || []).forEach(function (row) {
|
(frm.doc.vergi_hesab_4cu || []).forEach(function (row) {
|
||||||
if (ptgov_article(row.göstəricilər) === '506') {
|
if (ptgov_article(row.göstəricilər) === '506') {
|
||||||
frappe.model.set_value(row.doctype, row.name, 'faizlə', 1);
|
frappe.model.set_value(row.doctype, row.name, 'faizlə', 1);
|
||||||
|
|
@ -1153,8 +1167,6 @@ function _gns_property_recalc_now(frm) {
|
||||||
PTGOV_OUT_TABLES.concat(['vergi_hesab_4cu']).forEach(function (t) { frm.refresh_field(t); });
|
PTGOV_OUT_TABLES.concat(['vergi_hesab_4cu']).forEach(function (t) { frm.refresh_field(t); });
|
||||||
setTimeout(function () { frm.__ptgov_writing = false; }, 0); // release after sync triggers flush
|
setTimeout(function () { frm.__ptgov_writing = false; }, 0); // release after sync triggers flush
|
||||||
}
|
}
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---- delegators: override the old hand-coded calc (hoisting: these win) ----
|
// ---- delegators: override the old hand-coded calc (hoisting: these win) ----
|
||||||
|
|
@ -1165,41 +1177,85 @@ function calculate_vergi_hesab_3cu_totals(frm) { gns_property_recalc(frm); }
|
||||||
function calculate_509_1(frm) { gns_property_recalc(frm); }
|
function calculate_509_1(frm) { gns_property_recalc(frm); }
|
||||||
function calculate_509_2(frm) { gns_property_recalc(frm); }
|
function calculate_509_2(frm) { gns_property_recalc(frm); }
|
||||||
|
|
||||||
// ---- template rows: create one row per Select option for empty tables ----
|
// ---- template rows: identical to the original doctype's Default Client Scripts ----
|
||||||
// (the form shipped without default rows for elave_1/2 and most cedvel tables;
|
// elave_1/elave_2 use the exact curated row sets; cedvel tables use their göstərici options.
|
||||||
// autofill matches asset data to these rows and the calc writes results into them)
|
const PTGOV_E1_ROWS = [
|
||||||
const PTGOV_ROW_TEMPLATES = [
|
"Vergi Məcəlləsinin 199.1-ci maddəsinə əsasən azaldılmalı əmlak vergisinin məbləği",
|
||||||
['elave_1', 'azadolmasəbəbi'],
|
"Vergi Məcəlləsinin 199.4.1-ci maddəsinə əsasən:",
|
||||||
['elave_2', 'vergiyəcəlbolunanəmlaklarınkateqoriyası'],
|
"Vergi Məcəlləsinin 199.4.2-ci maddəsinə əsasən:",
|
||||||
['vergi_hesab_1ci', 'göstəricilər'],
|
"Vergi Məcəlləsinin 199.4.3-cü maddəsinə əsasən:",
|
||||||
['vergi_hesab_1ci_1', 'göstəricilər'],
|
"Vergi Məcəlləsinin 199.4.4-cü maddəsinə əsasən:",
|
||||||
['vergi_hesab_2ci', 'göstəricilər'],
|
"Vergi Məcəlləsinin 199.4.1-1-ci maddəsinə əsasən:",
|
||||||
['vergi_hesab_3cu', 'göstəricilər'],
|
"Vergi Məcəlləsinin 199.5-ci maddəsinə əsasən:",
|
||||||
['vergi_hesab_4cu', 'göstəricilər'],
|
"Vergi Məcəlləsinin 199.7-ci maddəsinə əsasən:",
|
||||||
['vergi_hesab_4cu_1', 'göstəricilər'],
|
"Vergi Məcəlləsinin 199.8-ci maddəsinə əsasən:",
|
||||||
['vergi_hesab_5ci', 'göstəricilər'],
|
"Vergi Məcəlləsinin 199.9-cu maddəsinə əsasən:",
|
||||||
['vergi_hesab_6ci', 'göstəricilər'],
|
"Vergi Məcəlləsinin 199.11-cu maddəsinə əsasən:",
|
||||||
|
"Vergi Məcəlləsinin 199.14-cu maddəsinə əsasən:",
|
||||||
|
"Vergi Məcəlləsinin 199.15-cu maddəsinə əsasən:",
|
||||||
|
"Vergi Məcəlləsinin 199.16-cı maddəsinə əsasən:",
|
||||||
|
"Vergi Məcəlləsinin 199.17-ci maddəsinə əsasən:",
|
||||||
|
"Vergi Məcəlləsinin 199.18-ci maddəsinə əsasən:",
|
||||||
|
"Vergi Məcəlləsinin 199.19-cu maddəsinə əsasən:",
|
||||||
|
"Vergi Məcəlləsinin 199.20-ci maddəsinə əsasən:",
|
||||||
|
"Vergi Məcəlləsinin 227.1-ci maddəsinə əsasən:",
|
||||||
|
"Qanunla 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ə:",
|
||||||
|
"Xüsusi iqtisadi zonalar haqqında qanunlarda nəzərdə tutulan əmlaklar üzrə:",
|
||||||
|
"Azərbaycan Respublikasının tərəfdar çıxdığı beynəlxalq müqavilələr üzrə:",
|
||||||
|
"Vergidən azad olunan əmlakın CƏMİ dəyəri:",
|
||||||
];
|
];
|
||||||
|
const PTGOV_E2_ROWS = [
|
||||||
|
"1. Binalar, tikililər və qurğular",
|
||||||
|
"1.1 Çoxmərtəbəli (çoxmənzilli) yaşayış binaları",
|
||||||
|
"1.2 Qeyri-yaşayış binaları (sahələri)",
|
||||||
|
"1.3 Əmlak kompleksi kimi müəssisələr",
|
||||||
|
"1.4 Qurğular",
|
||||||
|
"1.5 Mənzillər",
|
||||||
|
"1.6 Fərdi yaşayış və bağ evləri",
|
||||||
|
"2 Maşınlar və avadanlıqlar",
|
||||||
|
"3 Yüksək texnologiyalar məhsulu olan hesablama texnikası",
|
||||||
|
"4 Nəqliyyat vasitələri",
|
||||||
|
"5 Digər əsas vəsaitlər",
|
||||||
|
"Vergiyə cəlb olunan əmlakın CƏMİ dəyəri:",
|
||||||
|
];
|
||||||
|
const PTGOV_CEDVEL_TABLES = ['vergi_hesab_1ci', 'vergi_hesab_1ci_1', 'vergi_hesab_2ci', 'vergi_hesab_3cu',
|
||||||
|
'vergi_hesab_4cu', 'vergi_hesab_4cu_1', 'vergi_hesab_5ci', 'vergi_hesab_6ci'];
|
||||||
|
|
||||||
function ptgov_ensure_rows(frm) {
|
function ptgov_ensure_rows(frm) {
|
||||||
let added = false;
|
let added = false;
|
||||||
PTGOV_ROW_TEMPLATES.forEach(function (pair) {
|
function fill(tbl, fld, vals) {
|
||||||
const tbl = pair[0], fld = pair[1];
|
|
||||||
if ((frm.doc[tbl] || []).length) return; // already has rows -> skip
|
if ((frm.doc[tbl] || []).length) return; // already has rows -> skip
|
||||||
|
vals.forEach(function (v) { frm.add_child(tbl)[fld] = v; });
|
||||||
|
if (vals.length) { frm.refresh_field(tbl); added = true; }
|
||||||
|
}
|
||||||
|
fill('elave_1', 'azadolmasəbəbi', PTGOV_E1_ROWS);
|
||||||
|
fill('elave_2', 'vergiyəcəlbolunanəmlaklarınkateqoriyası', PTGOV_E2_ROWS);
|
||||||
|
PTGOV_CEDVEL_TABLES.forEach(function (tbl) {
|
||||||
const field = frm.get_field(tbl);
|
const field = frm.get_field(tbl);
|
||||||
if (!field) return;
|
if (!field) return;
|
||||||
const childDt = field.df.options;
|
const df = frappe.meta.get_docfield(field.df.options, 'göstəricilər');
|
||||||
const df = frappe.meta.get_docfield(childDt, fld);
|
|
||||||
const opts = ((df && df.options) || '').split('\n').filter(function (x) { return x.trim(); });
|
const opts = ((df && df.options) || '').split('\n').filter(function (x) { return x.trim(); });
|
||||||
opts.forEach(function (opt) { frm.add_child(tbl)[fld] = opt; });
|
fill(tbl, 'göstəricilər', opts);
|
||||||
if (opts.length) { frm.refresh_field(tbl); added = true; }
|
|
||||||
});
|
});
|
||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make computed output columns read-only (the cedvel manatla/faizlə are calc results)
|
||||||
|
function ptgov_set_readonly(frm) {
|
||||||
|
const cols = [['vergi_hesab_1ci', 'manatla'], ['vergi_hesab_1ci_1', 'manatla'], ['vergi_hesab_2ci', 'manatla'],
|
||||||
|
['vergi_hesab_3cu', 'manatla'], ['vergi_hesab_5ci', 'manatla'], ['vergi_hesab_6ci', 'manatla'],
|
||||||
|
['vergi_hesab_4cu', 'faizlə']];
|
||||||
|
cols.forEach(function (pair) {
|
||||||
|
const f = frm.get_field(pair[0]);
|
||||||
|
if (f && f.grid) f.grid.update_docfield_property(pair[1], 'read_only', 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// manual recalc button (autofill runs automatically on İl / Tam İl / İl Ərzində change)
|
// manual recalc button (autofill runs automatically on İl / Tam İl / İl Ərzində change)
|
||||||
frappe.ui.form.on('Property Tax Gov', {
|
frappe.ui.form.on('Property Tax Gov', {
|
||||||
refresh: function (frm) {
|
refresh: function (frm) {
|
||||||
ptgov_ensure_rows(frm); // populate empty child tables with their template rows
|
ptgov_ensure_rows(frm); // populate empty child tables with their template rows
|
||||||
|
ptgov_set_readonly(frm); // lock computed cedvel columns
|
||||||
frm.add_custom_button('Şablon sətirləri yarat', function () {
|
frm.add_custom_button('Şablon sətirləri yarat', function () {
|
||||||
if (ptgov_ensure_rows(frm)) frappe.show_alert({ message: 'Şablon sətirləri yaradıldı', indicator: 'green' });
|
if (ptgov_ensure_rows(frm)) frappe.show_alert({ message: 'Şablon sətirləri yaradıldı', indicator: 'green' });
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue