feat(vat): auto-fill VAT declaration appendices from reports

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) <noreply@anthropic.com>
This commit is contained in:
Ali 2026-06-26 11:10:30 +00:00
parent 8a430ae1b0
commit d6488a68cf
3 changed files with 152 additions and 1 deletions

View File

@ -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];
}
});
});
}

View File

@ -9,4 +9,100 @@ from datetime import datetime, date
import calendar
class Declarationofvalueaddedtax(Document):
pass
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,
}

View File

@ -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"