2026-10-09 12:16:48 +05:30

116 lines
10 KiB
JSON

[
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Insert",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-10-09 09:01:23.304086",
"module": "Sidrah Business",
"name": "attendance",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": null,
"script": "dates = frappe.db.sql(\"\"\"\r\n SELECT DISTINCT DATE(time) as d\r\n FROM `tabEmployee Checkin`\r\n ORDER BY d\r\n\"\"\", as_dict=True)\r\n\r\ndates = [str(d[\"d\"]) for d in dates]\r\n\r\nfor d in dates:\r\n\r\n employees = frappe.db.sql(\"\"\"\r\n SELECT DISTINCT employee\r\n FROM `tabEmployee Checkin`\r\n WHERE DATE(time) = %s\r\n \"\"\", (d,), as_dict=True)\r\n\r\n for e in employees:\r\n emp = e[\"employee\"]\r\n\r\n frappe.errprint(\"Processing: \" + emp + \" | \" + d)\r\n\r\n # =========================\r\n # SKIP DUPLICATE\r\n # =========================\r\n if frappe.db.exists(\"Attendance\", {\r\n \"employee\": emp,\r\n \"attendance_date\": d\r\n }):\r\n continue\r\n\r\n # =========================\r\n # SHIFT\r\n # =========================\r\n shift_row = frappe.db.sql(\"\"\"\r\n SELECT shift_type\r\n FROM `tabShift Assignment`\r\n WHERE employee = %s\r\n AND start_date <= %s\r\n AND (end_date IS NULL OR end_date >= %s)\r\n LIMIT 1\r\n \"\"\", (emp, d, d))\r\n\r\n if not shift_row:\r\n frappe.errprint(\"❌ No shift\")\r\n continue\r\n\r\n shift_name = shift_row[0][0]\r\n shift = frappe.get_doc(\"Shift Type\", shift_name)\r\n\r\n shift_start = frappe.utils.get_datetime(d + \" \" + str(shift.start_time))\r\n shift_end = frappe.utils.get_datetime(d + \" \" + str(shift.end_time))\r\n\r\n if shift_end < shift_start:\r\n shift_end = frappe.utils.add_days(shift_end, 1)\r\n\r\n before = shift.begin_check_in_before_shift_start_time or 0\r\n after = shift.allow_check_out_after_shift_end_time or 0\r\n\r\n start_window = frappe.utils.add_to_date(shift_start, minutes=-before)\r\n end_window = frappe.utils.add_to_date(shift_end, minutes=after)\r\n\r\n # =========================\r\n # FETCH LOGS\r\n # =========================\r\n logs = frappe.db.sql(\"\"\"\r\n SELECT time\r\n FROM `tabEmployee Checkin`\r\n WHERE employee = %s\r\n AND time BETWEEN %s AND %s\r\n ORDER BY time\r\n \"\"\", (emp, start_window, end_window), as_dict=True)\r\n\r\n if not logs:\r\n frappe.errprint(\"❌ No logs\")\r\n continue\r\n\r\n # =========================\r\n # IN / OUT CALCULATION\r\n # =========================\r\n in_time = None\r\n out_time = None\r\n total_seconds = 0\r\n\r\n if shift.working_hours_calculation_based_on == \"First Check-in and Last Check-out\":\r\n in_time = logs[0][\"time\"]\r\n out_time = logs[-1][\"time\"]\r\n total_seconds = (out_time - in_time).total_seconds()\r\n\r\n else:\r\n # Alternating logic (pairing)\r\n pairs = []\r\n temp_in = None\r\n\r\n for l in logs:\r\n if not temp_in:\r\n temp_in = l[\"time\"]\r\n else:\r\n pairs.append((temp_in, l[\"time\"]))\r\n temp_in = None\r\n\r\n # calculate total\r\n for p in pairs:\r\n total_seconds += (p[1] - p[0]).total_seconds()\r\n\r\n if pairs:\r\n in_time = pairs[0][0]\r\n out_time = pairs[-1][1]\r\n\r\n if not in_time or not out_time:\r\n frappe.errprint(\"❌ Invalid IN/OUT\")\r\n continue\r\n\r\n hours = total_seconds / 3600\r\n\r\n # =========================\r\n # LATE ENTRY\r\n # =========================\r\n late_entry = 0\r\n if shift.enable_late_entry_marking:\r\n grace = shift.late_entry_grace_period or 0\r\n late_minutes = (in_time - shift_start).total_seconds() / 60\r\n\r\n if late_minutes > grace:\r\n late_entry = 1\r\n\r\n # =========================\r\n # EARLY EXIT\r\n # =========================\r\n early_exit = 0\r\n if shift.enable_early_exit_marking:\r\n grace = shift.early_exit_grace_period or 0\r\n early_minutes = (shift_end - out_time).total_seconds() / 60\r\n\r\n if early_minutes > grace:\r\n early_exit = 1\r\n\r\n # =========================\r\n # STATUS\r\n # =========================\r\n half_day = shift.working_hours_threshold_for_half_day\r\n absent = shift.working_hours_threshold_for_absent\r\n\r\n if absent and hours < absent:\r\n status = \"Absent\"\r\n\r\n elif half_day and hours <= half_day:\r\n status = \"Half Day\"\r\n\r\n else:\r\n status = \"Present\"\r\n\r\n # =========================\r\n # CREATE ATTENDANCE\r\n # =========================\r\n try:\r\n att = frappe.get_doc({\r\n \"doctype\": \"Attendance\",\r\n \"employee\": emp,\r\n \"attendance_date\": d,\r\n \"status\": status,\r\n \"shift\": shift_name,\r\n \"in_time\": in_time,\r\n \"out_time\": out_time,\r\n \"working_hours\": hours,\r\n \"late_entry\": late_entry,\r\n \"early_exit\": early_exit,\r\n \"skip_auto_attendance\": 0\r\n })\r\n \r\n att.insert(ignore_permissions=True)\r\n \r\n if att.docstatus == 0:\r\n att.submit()\r\n \r\n # ✅ ADD THIS LINE (IMPORTANT)\r\n frappe.db.set_value(\"Shift Type\", shift_name, \"last_sync_of_checkin\", frappe.utils.now())\r\n \r\n frappe.errprint(\"✅ \" + emp + \" → \" + status)\r\n\r\n except Exception as ex:\r\n frappe.errprint(\"❌ ERROR: \" + str(ex))\r\n\r\nfrappe.db.commit()",
"script_type": "Scheduler Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Save",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-10-09 09:01:22.964486",
"module": "Sidrah Business",
"name": "Category",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "User",
"script": "role_map = {\n \"Admin\": [\"SB Admin\"],\n \"Chairman\": [\"SB Owner\"],\n \"Auditor\": [\"SB Auditor\", \"SB Owner\"],\n \"X-Auditor\": [\"SB X-Auditor\"],\n \"Manager\": [\"SB Manager\"],\n \"Employee\": [\"SB Employee\"]\n}\n\ncategory_roles = [\n \"SB Admin\",\n \"SB Owner\",\n \"SB Auditor\",\n \"SB X-Auditor\",\n \"SB Manager\",\n \"SB Employee\"\n]\n\n# Remove existing category-based roles\nremaining_roles = []\n\nfor row in doc.roles:\n if row.role not in category_roles:\n remaining_roles.append(row)\n\ndoc.roles = remaining_roles\n\n# Add roles based on Category\nif doc.custom_category:\n existing = [row.role for row in doc.roles]\n\n for role in role_map.get(doc.custom_category, []):\n if role not in existing:\n doc.append(\"roles\", {\"role\": role})\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Insert",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-10-09 09:01:23.128829",
"module": "Sidrah Business",
"name": "Number S",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "SB Idea",
"script": "if doc.acronym:\r\n count = frappe.db.count(doc.doctype, {\r\n \"acronym\": doc.acronym\r\n }) + 1\r\n\r\n doc.number = f\"{doc.acronym}S{str(count).zfill(5)}\"",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Insert",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-10-09 09:01:23.275677",
"module": "Sidrah Business",
"name": "Number P",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "SB Process",
"script": "if doc.acronym:\r\n count = frappe.db.count(doc.doctype, {\r\n \"acronym\": doc.acronym\r\n }) + 1\r\n\r\n doc.number = f\"{doc.acronym}P{str(count).zfill(5)}\"",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Insert",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-10-09 09:01:23.161568",
"module": "Sidrah Business",
"name": "Number O",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "SB Order",
"script": "if doc.acronym:\r\n count = frappe.db.count(doc.doctype, {\r\n \"acronym\": doc.acronym\r\n }) + 1\r\n\r\n doc.number = f\"{doc.acronym}O{str(count).zfill(5)}\"",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Insert",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-10-09 09:01:23.239633",
"module": "Sidrah Business",
"name": "Number E",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "SB Order",
"script": "if doc.acronym:\r\n count = frappe.db.count(doc.doctype, {\r\n \"acronym\": doc.acronym\r\n }) + 1\r\n\r\n doc.number = f\"{doc.acronym}E{str(count).zfill(5)}\"",
"script_type": "DocType Event"
}
]