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
|
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]
|
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:
|
for month in months:
|
||||||
last_day = calendar.monthrange(year, month)[1]
|
last_day = calendar.monthrange(year, month)[1]
|
||||||
month_start = f"{year}-{month:02d}-01"
|
month_start = f"{year}-{month:02d}-01"
|
||||||
month_end = f"{year}-{month:02d}-{last_day:02d}"
|
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`
|
SELECT COUNT(*) FROM `tabEmployee`
|
||||||
WHERE company = %(company)s
|
WHERE company = %(company)s
|
||||||
AND status != 'Inactive'
|
AND status != 'Inactive'
|
||||||
|
|
@ -226,17 +229,34 @@ def get_bolme2_hisse1_data(company, year, quarter):
|
||||||
OR (relieving_date IS NULL AND status != 'Left')
|
OR (relieving_date IS NULL AND status != 'Left')
|
||||||
)
|
)
|
||||||
""", {"company": company, "month_start": month_start, "month_end": month_end})[0][0]
|
""", {"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 {
|
return {
|
||||||
"İşçilərin ümumi sayı": {
|
"İşçilərin ümumi sayı": {
|
||||||
"1ciay": monthly_counts[0] if len(monthly_counts) > 0 else 0,
|
"1ciay": total_counts[0] if len(total_counts) > 0 else 0,
|
||||||
"2ciay": monthly_counts[1] if len(monthly_counts) > 1 else 0,
|
"2ciay": total_counts[1] if len(total_counts) > 1 else 0,
|
||||||
"3cüay": monthly_counts[2] if len(monthly_counts) > 2 else 0,
|
"3cüay": total_counts[2] if len(total_counts) > 2 else 0,
|
||||||
"rübüzrəortasay": avg,
|
"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