From d6488a68cf26c3edebe435bb5a5d2cf10637b0c4 Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Fri, 26 Jun 2026 11:10:30 +0000 Subject: [PATCH] feat(vat): auto-fill VAT declaration appendices from reports MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On selecting İl + Ay, the Declaration of value added tax fills three appendices from the source reports' get_data: - Əlavə 1 <- Purchase YGB VAT report - Əlavə 2 Hissə 1 <- Purchase invoice info report (act_type mapped to AZ) - Əlavə 2 Hissə 2 <- Agricultural goods stock report Adds a whitelisted populate_vat_tables method + form trigger, and a company filter to the purchase invoice info report. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../declaration_of_value_added_tax.js | 52 ++++++++++ .../declaration_of_value_added_tax.py | 98 ++++++++++++++++++- .../purchase_invoice_info_report.py | 3 + 3 files changed, 152 insertions(+), 1 deletion(-) diff --git a/taxes_az/taxes_az/doctype/declaration_of_value_added_tax/declaration_of_value_added_tax.js b/taxes_az/taxes_az/doctype/declaration_of_value_added_tax/declaration_of_value_added_tax.js index e69de29..b305a8c 100644 --- a/taxes_az/taxes_az/doctype/declaration_of_value_added_tax/declaration_of_value_added_tax.js +++ b/taxes_az/taxes_az/doctype/declaration_of_value_added_tax/declaration_of_value_added_tax.js @@ -0,0 +1,52 @@ +// Copyright (c) 2025, Your Company and contributors +// For license information, please see license.txt + +frappe.ui.form.on("Declaration of value added tax", { + il: function (frm) { + fill_from_reports(frm); + }, + ay: function (frm) { + fill_from_reports(frm); + }, +}); + +// Pull Əlavə 1 / Əlavə 2 Hissə 1 / Əlavə 2 Hissə 2 from the three source +// reports once both the year (İl) and month (Ay) are selected. +function fill_from_reports(frm) { + if (!frm.doc.il || !frm.doc.ay) { + return; + } + + frappe.dom.freeze(__("Hesabatlardan doldurulur...")); + frappe.call({ + method: "taxes_az.taxes_az.doctype.declaration_of_value_added_tax.declaration_of_value_added_tax.populate_vat_tables", + args: { year: frm.doc.il, month: frm.doc.ay }, + callback: function (r) { + frappe.dom.unfreeze(); + if (!r.message || !r.message.success) { + frappe.msgprint(__("Doldurma alınmadı: {0}", [(r.message && r.message.error) || ""])); + return; + } + + set_table(frm, "əlavə_1", r.message.elave_1); + set_table(frm, "əlavə_2", r.message.elave_2); + set_table(frm, "əlavə_2_2", r.message.elave_2_2); + + frm.refresh_fields(); + frappe.show_alert({ message: __("Əlavələr hesabatlardan dolduruldu"), indicator: "green" }); + }, + }); +} + +// Replace a child table's rows with the supplied data. +function set_table(frm, fieldname, rows) { + frm.clear_table(fieldname); + (rows || []).forEach(function (data) { + const child = frm.add_child(fieldname); + Object.keys(data).forEach(function (key) { + if (data[key] !== null && data[key] !== undefined) { + child[key] = data[key]; + } + }); + }); +} diff --git a/taxes_az/taxes_az/doctype/declaration_of_value_added_tax/declaration_of_value_added_tax.py b/taxes_az/taxes_az/doctype/declaration_of_value_added_tax/declaration_of_value_added_tax.py index c1fa5a8..90a3861 100644 --- a/taxes_az/taxes_az/doctype/declaration_of_value_added_tax/declaration_of_value_added_tax.py +++ b/taxes_az/taxes_az/doctype/declaration_of_value_added_tax/declaration_of_value_added_tax.py @@ -9,4 +9,100 @@ from datetime import datetime, date import calendar class Declarationofvalueaddedtax(Document): - pass \ No newline at end of file + pass + + +# Azərbaycan month names (matches the `ay` Select field), index 0 -> January. +MONTHS_AZ = [ + "Yanvar", "Fevral", "Mart", "Aprel", "May", "İyun", + "İyul", "Avqust", "Sentyabr", "Oktyabr", "Noyabr", "Dekabr", +] + +# Report act_type -> the declaration's "sənəd növü" Select option. +ACT_TYPE_MAP = { + "EQF": "EQF", + "Purchase Act": "Alış aktı", + "Import": "İdxal", +} + + +def _period_filters(year, month): + """Build report filters (company + month date range) from year + month.""" + from frappe.utils import get_last_day + + company = (frappe.defaults.get_user_default("Company") + or frappe.db.get_single_value("Global Defaults", "default_company")) + + month_idx = MONTHS_AZ.index(month) + 1 + from_date = f"{cint(year):04d}-{month_idx:02d}-01" + to_date = str(get_last_day(from_date)) + + return {"company": company, "from_date": from_date, "to_date": to_date} + + +@frappe.whitelist() +def populate_vat_tables(year, month): + """Build the VAT declaration appendix rows from the three source reports. + + Returns row dicts for: + - Əlavə 1 (əlavə_1) <- Purchase YGB VAT report + - Əlavə 2 Hissə 1 (əlavə_2) <- Purchase invoice info report + - Əlavə 2 Hissə 2 (əlavə_2_2) <- Agricultural goods stock report + """ + from taxes_az.taxes_az.report.purchase_ygb_vat_report.purchase_ygb_vat_report import ( + get_data as ygb_get_data, + ) + from taxes_az.taxes_az.report.purchase_invoice_info_report.purchase_invoice_info_report import ( + get_data as purchase_info_get_data, + ) + from taxes_az.taxes_az.report.agricultural_goods_stock_report.agricultural_goods_stock_report import ( + get_data as agri_get_data, + ) + + if not month or not year: + return {"success": False, "error": "Year and month are required"} + + filters = _period_filters(year, month) + + # Əlavə 1 — one row per YGB purchase document. + # (ygbnintarixi is a Float field on the declaration, so the date is not + # mapped here — see the note returned to the client.) + elave_1 = [] + for r in (ygb_get_data(filters) or []): + elave_1.append({ + "sətirkodu": r.get("line_code"), + "ygbninnömrəsi": r.get("ygb"), + "ygbüzrəalınmışmalınədvsizdəyərimanatla": r.get("amount_without_vat"), + "ygbüzrəalınmışmalınədvməbləğimanatla": r.get("vat_amount"), + }) + + # Əlavə 2 Hissə 1 — one row per agricultural purchase document. + elave_2 = [] + for r in (purchase_info_get_data(filters) or []): + elave_2.append({ + "malalışınıtəsdiqedənsənədnövününadı": ACT_TYPE_MAP.get(r.get("act_type"), r.get("act_type")), + "adı": r.get("counterparty"), + "vöen": r.get("voen") or None, + "fin": r.get("fin"), + "hesabatdövrüərzindəalınmışmallarınalışqiymətiiləməbləği": r.get("amount"), + }) + + # Əlavə 2 Hissə 2 — single summary row (agricultural goods movement). + elave_2_2 = [] + for r in (agri_get_data(filters) or []): + elave_2_2.append({ + "hesabatdövrününəvvəlinəsatılmamışmallarınalışqiymətiiləməbləği": r.get("opening_balance"), + "dövrərzindəalınmışmallarınalışqiymətiiləməbləği": r.get("purchased"), + "dövrərzindəsatılmışmallarınsatışqiymətiiləməbləği": r.get("sold"), + "dövrsonunamallarınalışqiymətiiləqalıqməbləği": r.get("closing_balance"), + "carihesabatdövründəsatılmışmallaragörəticarətəlavəsi": r.get("trade_markup"), + "hesabatdövründəsatılmışmallaragörəticarətəlavəsininədvməbləği": r.get("trade_markup_vat"), + }) + + return { + "success": True, + "elave_1": elave_1, + "elave_2": elave_2, + "elave_2_2": elave_2_2, + "period": filters, + } \ No newline at end of file diff --git a/taxes_az/taxes_az/report/purchase_invoice_info_report/purchase_invoice_info_report.py b/taxes_az/taxes_az/report/purchase_invoice_info_report/purchase_invoice_info_report.py index 1b01f2d..7dbdf21 100644 --- a/taxes_az/taxes_az/report/purchase_invoice_info_report/purchase_invoice_info_report.py +++ b/taxes_az/taxes_az/report/purchase_invoice_info_report/purchase_invoice_info_report.py @@ -61,6 +61,9 @@ def get_data(filters=None): filters = filters or {} conditions = "" + if filters.get("company"): + conditions += " AND pi.company = %(company)s" + if filters.get("from_date"): conditions += " AND pi.posting_date >= %(from_date)s"