From 2b0426de0b61c5da7a5aa3828aa0e89147172649 Mon Sep 17 00:00:00 2001 From: Ali <010109ali@gmail.com> Date: Thu, 2 Apr 2026 19:50:16 +0400 Subject: [PATCH] feat: auto-populate bolme2_hisse1 row 1 (employee count per month) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Count employees per month using date_of_joining + relieving_date logic. Safety net: status=Left without relieving_date excluded from count. Updates existing pre-created rows by matching göstəricilər field. Co-Authored-By: Claude Opus 4.6 (1M context) --- ...lated_to_salaried_and_non_salaried_work.js | 15 +++++++ ...lated_to_salaried_and_non_salaried_work.py | 40 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.js b/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.js index 96e5352..8553fdc 100644 --- a/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.js +++ b/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.js @@ -90,6 +90,7 @@ function reload_hisse_1_data(frm) { populate_hisse_1(frm, r.message.hisse_1_data || []); populate_child_table(frm, 'hissə_2', r.message.hisse_2_data || []); populate_child_table(frm, 'hissə_3', r.message.hisse_3_data || []); + update_existing_rows(frm, 'bolme2_hisse1', r.message.bolme2_hisse1_data || {}); frm.dirty(); frm.refresh_fields(); @@ -120,6 +121,20 @@ function populate_hisse_1(frm, data) { populate_child_table(frm, 'hissə_1', data); } +function update_existing_rows(frm, table_name, data) { + // Update existing rows by matching göstəricilər field + (frm.doc[table_name] || []).forEach(function(row) { + let key = row.göstəricilər; + if (key && data[key]) { + let values = data[key]; + Object.keys(values).forEach(function(field) { + frappe.model.set_value(row.doctype, row.name, field, values[field]); + }); + } + }); + frm.refresh_field(table_name); +} + function populate_child_table(frm, table_name, data) { frm.clear_table(table_name); diff --git a/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.py b/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.py index 356f4ca..2f96e28 100644 --- a/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.py +++ b/taxes_az/taxes_az/doctype/single_declaration_related_to_salaried_and_non_salaried_work/single_declaration_related_to_salaried_and_non_salaried_work.py @@ -1,6 +1,8 @@ # Copyright (c) 2025, Jey Soft and contributors # For license information, please see license.txt +import calendar + import frappe from frappe.model.document import Document from frappe.utils import flt, getdate @@ -66,12 +68,14 @@ def populate_declaration_tables(company, year, quarter): hisse_1_data = build_hisse_1(payroll) hisse_2_data = build_hisse_2(payroll) hisse_3_data = get_absence_data(company, from_date, to_date) + bolme2_hisse1_data = get_bolme2_hisse1_data(company, year, quarter) return { "success": True, "hisse_1_data": hisse_1_data, "hisse_2_data": hisse_2_data, "hisse_3_data": hisse_3_data, + "bolme2_hisse1_data": bolme2_hisse1_data, } except Exception as e: @@ -201,6 +205,42 @@ def build_hisse_2(payroll): return result +def get_bolme2_hisse1_data(company, year, quarter): + """Build data for bolme2_hisse1: employee counts per month of quarter.""" + quarter_num = int(quarter[0]) # "1. Rüb" -> 1 + months = [(quarter_num - 1) * 3 + i for i in range(1, 4)] # e.g. Q1 -> [1, 2, 3] + + monthly_counts = [] + for month in months: + last_day = calendar.monthrange(year, month)[1] + month_start = f"{year}-{month:02d}-01" + month_end = f"{year}-{month:02d}-{last_day:02d}" + + count = frappe.db.sql(""" + SELECT COUNT(*) FROM `tabEmployee` + WHERE company = %(company)s + AND status != 'Inactive' + AND date_of_joining <= %(month_end)s + AND ( + (relieving_date >= %(month_start)s) + OR (relieving_date IS NULL AND status != 'Left') + ) + """, {"company": company, "month_start": month_start, "month_end": month_end})[0][0] + + monthly_counts.append(count) + + avg = round(sum(monthly_counts) / 3, 2) if monthly_counts else 0 + + return { + "İşçilərin ümumi sayı": { + "1ciay": monthly_counts[0] if len(monthly_counts) > 0 else 0, + "2ciay": monthly_counts[1] if len(monthly_counts) > 1 else 0, + "3cüay": monthly_counts[2] if len(monthly_counts) > 2 else 0, + "rübüzrəortasay": avg, + }, + } + + def get_absence_data(company, from_date, to_date): """Fetch absence data from Monthly Absence Report for hissə_3.""" from taxes_az.taxes_az.report.monthly_absence_report.monthly_absence_report import get_data