feat: add Monthly Present Report and bolme2_hisse1 row 2 (actual headcount)
New report counts days present (Present + Half Day) per employee. bolme2_hisse1 row 2 counts unique employees who showed up per month. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
86b219a31e
commit
6ed4c94213
|
|
@ -210,13 +210,16 @@ def get_bolme2_hisse1_data(company, year, 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 = []
|
||||
total_counts = []
|
||||
present_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("""
|
||||
# Row 1: total employees on payroll
|
||||
total = frappe.db.sql("""
|
||||
SELECT COUNT(*) FROM `tabEmployee`
|
||||
WHERE company = %(company)s
|
||||
AND status != 'Inactive'
|
||||
|
|
@ -226,17 +229,34 @@ def get_bolme2_hisse1_data(company, year, quarter):
|
|||
OR (relieving_date IS NULL AND status != 'Left')
|
||||
)
|
||||
""", {"company": company, "month_start": month_start, "month_end": month_end})[0][0]
|
||||
total_counts.append(total)
|
||||
|
||||
monthly_counts.append(count)
|
||||
# Row 2: unique employees who actually showed up
|
||||
present = frappe.db.sql("""
|
||||
SELECT COUNT(DISTINCT a.employee) FROM `tabAttendance` a
|
||||
WHERE a.company = %(company)s
|
||||
AND a.docstatus = 1
|
||||
AND a.status IN ('Present', 'Half Day')
|
||||
AND a.attendance_date >= %(month_start)s
|
||||
AND a.attendance_date <= %(month_end)s
|
||||
""", {"company": company, "month_start": month_start, "month_end": month_end})[0][0]
|
||||
present_counts.append(present)
|
||||
|
||||
avg = round(sum(monthly_counts) / 3) if monthly_counts else 0
|
||||
total_avg = round(sum(total_counts) / 3) if total_counts else 0
|
||||
present_avg = round(sum(present_counts) / 3) if present_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,
|
||||
"1ciay": total_counts[0] if len(total_counts) > 0 else 0,
|
||||
"2ciay": total_counts[1] if len(total_counts) > 1 else 0,
|
||||
"3cüay": total_counts[2] if len(total_counts) > 2 else 0,
|
||||
"rübüzrəortasay": total_avg,
|
||||
},
|
||||
"Faktiki işə cəlb olunan işçilərin sayı": {
|
||||
"1ciay": present_counts[0] if len(present_counts) > 0 else 0,
|
||||
"2ciay": present_counts[1] if len(present_counts) > 1 else 0,
|
||||
"3cüay": present_counts[2] if len(present_counts) > 2 else 0,
|
||||
"rübüzrəortasay": present_avg,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright (c) 2026, Jey Soft and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
function get_quarter_dates(year, quarter) {
|
||||
const quarters = {
|
||||
"1": { from: year + "-01-01", to: year + "-03-31" },
|
||||
"2": { from: year + "-04-01", to: year + "-06-30" },
|
||||
"3": { from: year + "-07-01", to: year + "-09-30" },
|
||||
"4": { from: year + "-10-01", to: year + "-12-31" }
|
||||
};
|
||||
return quarters[String(quarter)];
|
||||
}
|
||||
|
||||
frappe.query_reports["Monthly Present Report"] = {
|
||||
"filters": [
|
||||
{
|
||||
fieldname: "company",
|
||||
label: __("Şirkət"),
|
||||
fieldtype: "Link",
|
||||
options: "Company",
|
||||
reqd: 1,
|
||||
default: frappe.defaults.get_user_default("Company")
|
||||
},
|
||||
{
|
||||
fieldname: "year",
|
||||
label: __("İl"),
|
||||
fieldtype: "Int",
|
||||
reqd: 1,
|
||||
default: new Date().getFullYear(),
|
||||
on_change: function() {
|
||||
const year = frappe.query_report.get_filter_value("year");
|
||||
const quarter = frappe.query_report.get_filter_value("quarter");
|
||||
if (year && quarter) {
|
||||
const dates = get_quarter_dates(year, quarter);
|
||||
frappe.query_report.set_filter_value("from_date", dates.from);
|
||||
frappe.query_report.set_filter_value("to_date", dates.to);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldname: "quarter",
|
||||
label: __("Rüb"),
|
||||
fieldtype: "Select",
|
||||
options: "1\n2\n3\n4",
|
||||
reqd: 1,
|
||||
default: String(Math.ceil((new Date().getMonth() + 1) / 3)),
|
||||
on_change: function() {
|
||||
const year = frappe.query_report.get_filter_value("year");
|
||||
const quarter = frappe.query_report.get_filter_value("quarter");
|
||||
if (year && quarter) {
|
||||
const dates = get_quarter_dates(year, quarter);
|
||||
frappe.query_report.set_filter_value("from_date", dates.from);
|
||||
frappe.query_report.set_filter_value("to_date", dates.to);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
fieldname: "from_date",
|
||||
label: __("Tarixdən"),
|
||||
fieldtype: "Date",
|
||||
hidden: 1
|
||||
},
|
||||
{
|
||||
fieldname: "to_date",
|
||||
label: __("Tarixə qədər"),
|
||||
fieldtype: "Date",
|
||||
hidden: 1
|
||||
}
|
||||
],
|
||||
|
||||
"onload": function() {
|
||||
const year = frappe.query_report.get_filter_value("year");
|
||||
const quarter = frappe.query_report.get_filter_value("quarter");
|
||||
if (year && quarter) {
|
||||
const dates = get_quarter_dates(year, quarter);
|
||||
frappe.query_report.set_filter_value("from_date", dates.from);
|
||||
frappe.query_report.set_filter_value("to_date", dates.to);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"add_total_row": 0,
|
||||
"columns": [],
|
||||
"creation": "2026-04-03 00:00:00.000000",
|
||||
"disabled": 0,
|
||||
"docstatus": 0,
|
||||
"doctype": "Report",
|
||||
"filters": [],
|
||||
"idx": 0,
|
||||
"is_standard": "Yes",
|
||||
"modified": "2026-04-03 00:00:00.000000",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Taxes Az",
|
||||
"name": "Monthly Present Report",
|
||||
"owner": "Administrator",
|
||||
"ref_doctype": "Attendance",
|
||||
"report_name": "Monthly Present Report",
|
||||
"report_type": "Script Report",
|
||||
"roles": []
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
# Copyright (c) 2026, Jey Soft and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
||||
|
||||
def execute(filters=None):
|
||||
columns = get_columns()
|
||||
data = get_data(filters)
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_columns():
|
||||
return [
|
||||
{
|
||||
"label": _("Soyad"),
|
||||
"fieldname": "last_name",
|
||||
"fieldtype": "Data",
|
||||
"width": 140,
|
||||
},
|
||||
{
|
||||
"label": _("Ad"),
|
||||
"fieldname": "first_name",
|
||||
"fieldtype": "Data",
|
||||
"width": 120,
|
||||
},
|
||||
{
|
||||
"label": _("FİN"),
|
||||
"fieldname": "fin",
|
||||
"fieldtype": "Data",
|
||||
"width": 110,
|
||||
},
|
||||
{
|
||||
"label": _("İşçinin faktiki işə cəlb olunduğu iş günlərinin sayı"),
|
||||
"fieldname": "days_present",
|
||||
"fieldtype": "Int",
|
||||
"width": 160,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def get_data(filters):
|
||||
if not filters:
|
||||
filters = {}
|
||||
|
||||
return frappe.db.sql("""
|
||||
SELECT
|
||||
e.last_name,
|
||||
e.first_name,
|
||||
e.passport_number AS fin,
|
||||
COUNT(*) AS days_present
|
||||
FROM `tabAttendance` a
|
||||
LEFT JOIN `tabEmployee` e ON e.name = a.employee
|
||||
WHERE
|
||||
a.docstatus = 1
|
||||
AND a.status IN ('Present', 'Half Day')
|
||||
AND a.company = %(company)s
|
||||
AND a.attendance_date >= %(from_date)s
|
||||
AND a.attendance_date <= %(to_date)s
|
||||
GROUP BY a.employee
|
||||
ORDER BY e.last_name ASC, e.first_name ASC
|
||||
""", filters, as_dict=1)
|
||||
Loading…
Reference in New Issue