2026-03-23 17:34:51 +05:30

914 lines
93 KiB
JSON
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Insert",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-09-02 18:08:19.628822",
"module": "Asset Lite",
"name": "Issue",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Issue",
"script": "recipients = [\r\n 'support@seeraarabia.com','hussein.albeshri@seeraarabia.com','mohamed.elhawary@seeraarabia.com'\r\n \r\n]\r\n\r\nfrappe.sendmail(\r\n recipients=recipients,\r\n subject=doc.subject,\r\n message=\"Dear Sir/Madam <br><br>\"+doc.subject+\"<br><br>Regards,<br>Support Team\",\r\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": "Daily",
"modified": "2024-10-17 15:40:12.770634",
"module": "Asset Lite",
"name": "Support Plan status set",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": null,
"script": "# Get today's date as a datetime.date object\r\ntoday = frappe.utils.today()\r\ntoday_date = frappe.utils.getdate(today)\r\n\r\n# Fetch all documents from the 'Support Plans' doctype\r\nsupport_plans = frappe.get_all('Asset', fields=['name','custom_warranty_start_date', 'custom_warranty_end_date', 'custom_warranty_status','custom_service_contract_start'\r\n,'custom_service_contract_end','custom_service_contract_status'])\r\n# warrantys = frappe.get_all('Warranty', fields=['name','warranty_start_date', 'warranty_end_date', 'warranty_status'])\r\n\r\nfor plan in support_plans:\r\n doc = frappe.get_doc('Asset', plan.name)\r\n\r\n # Convert service contract date objects if they are not None\r\n start_date = frappe.utils.getdate(doc.custom_service_contract_start) if doc.custom_service_contract_start else None\r\n end_date = frappe.utils.getdate(doc.custom_service_contract_end) if doc.custom_service_contract_end else None\r\n \r\n\r\n # Check and update service contract status\r\n if start_date and end_date:\r\n if start_date <= today_date <= end_date:\r\n doc.custom_service_contract_status = 'Active'\r\n elif today_date > end_date:\r\n doc.custom_service_contract_status = 'Expired'\r\n else:\r\n doc.custom_service_contract_status = ''\r\n \r\n \r\n # Get the regular warranty start and end dates\r\n war_start_date = frappe.utils.getdate(doc.custom_warranty_start_date) if doc.custom_warranty_start_date else None\r\n war_end_date = frappe.utils.getdate(doc.custom_warranty_end_date) if doc.custom_warranty_end_date else None\r\n \r\n # Get the extended warranty start and end dates\r\n extended_war_start_date = frappe.utils.getdate(doc.custom_extended_start_date) if doc.custom_extended_start_date else None\r\n extended_war_end_date = frappe.utils.getdate(doc.custom_extended_end_date) if doc.custom_extended_end_date else None\r\n \r\n # Set the status based on the warranty period and extended warranty\r\n if war_start_date and war_end_date:\r\n if war_start_date <= today_date <= war_end_date:\r\n doc.custom_warranty_status = 'Active'\r\n elif extended_war_start_date and extended_war_end_date and extended_war_start_date <= today_date <= extended_war_end_date:\r\n doc.custom_warranty_status = 'Active'\r\n elif today_date > war_end_date:\r\n doc.custom_warranty_status = 'Expired'\r\n else:\r\n doc.custom_warranty_status = ''\r\n\r\n # Save the updated document\r\n doc.save()\r\n \r\n# for warranty in warrantys:\r\n# doc1 = frappe.get_doc('Warranty', warranty.name)\r\n \r\n# # Convert warranty_start and warranty_end to date objects if they are not None\r\n# warranty_start = frappe.utils.getdate(doc1.warranty_start_date) if doc1.warranty_start_date else None\r\n# warranty_end = frappe.utils.getdate(doc1.warranty_end_date) if doc1.warranty_end_date else None\r\n \r\n# # Check and update warranty status\r\n# if warranty_start and warranty_end:\r\n# if warranty_start <= today_date <= warranty_end:\r\n# doc1.warranty_status = 'Active'\r\n# elif today_date > warranty_end:\r\n# doc1.warranty_status = 'Expired'\r\n# else:\r\n# doc1.warranty_status = ''\r\n \r\n# # Save the updated document\r\n# doc1.save()\r\n",
"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-02-10 12:20:31.335591",
"module": "Asset Lite",
"name": "Auto Set User Names",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "if doc.first_responded_on and doc.completion_date:\n \n first_response = frappe.utils.get_datetime(doc.first_responded_on)\n completion = frappe.utils.get_datetime(doc.completion_date)\n \n # Remove seconds and microseconds\n first_response = first_response.replace(second=0, microsecond=0)\n completion = completion.replace(second=0, microsecond=0)\n \n if completion >= first_response:\n diff_seconds = (completion - first_response).total_seconds()\n total_hours = diff_seconds / 3600\n \n if doc.total_hours_spent != round(total_hours, 2):\n doc.total_hours_spent = round(total_hours, 2)\n else:\n doc.total_hours_spent = 0\n\namount = 0\nif doc and doc.invoice_table:\n for row in doc.invoice_table:\n amount = amount + row.cost\n \n doc.repair_cost = amount\n \nstock_amt = 0 \nif doc and doc.stock_items:\n for row in doc.stock_items:\n if row.total_value:\n stock_amt = stock_amt + row.total_value\n \n doc.total_repair_cost = stock_amt\n \ndoc.total_repair_cost = amount + stock_amt\n \n # Block workflow action if Assigned Technician is missing\n# Block workflow action if Assigned Technician is missing\n# if (doc.workflow_state == \"Sent to Work Control\" and not doc.assigned_technician):\n# frappe.throw(\"Assigned Technician is mandatory before proceeding.\")\n\n \n \n\n\n# user = frappe.get_doc('User', frappe.session.user)\n# for role in user.roles:\n# if((role.role ==\"End user\" or role.role ==\"PHCC End User\")and role.role !=\"Technician\" and role.role !=\"Maintenance Manager\" \n# and role.role !=\"PHCC Site Manager\"):\n# doc.end_user = user.full_name\n\n \nuser = frappe.get_doc(\"User\", frappe.session.user)\n\n# Collect roles into a set\nroles = {r.role for r in user.roles}\n\n# Allowed vs excluded\nallowed = {\"End user\", \"PHCC End User\"}\nexcluded = {\"Technician\", \"Maintenance Manager\", \"PHCC Site Manager\",\"System Manager\",\"General WOA\",\"General Contractor\"}\n\n# Logic\nif roles.intersection(allowed) and not roles.intersection(excluded):\n if not doc.end_user:\n doc.end_user = user.full_name\n \n\n\nif doc.custom_assign_to_contractor and not doc.serviced_by:\n tech_user = frappe.get_doc(\"User\", doc.custom_assign_to_contractor)\n doc.serviced_by = tech_user.full_name\n \nif doc.custom_assigned_supervisor and not doc.bio_med_dept:\n sup_user = frappe.get_doc(\"User\", doc.custom_assigned_supervisor)\n doc.bio_med_dept = sup_user.full_name\n \nif doc.custom_technician_name and not doc.serviced_by:\n doc.serviced_by = doc.custom_technician_name\n\n \n# if(role.role ==\"Technician\"):\n# doc.serviced_by = user.full_name\n \n# if(role.role ==\"Maintenance Manager\"):\n# doc.bio_med_dept = user.full_name\n \n\n\n# Stock availability check \nif doc.stock_items:\n \n for item in doc.stock_items: # Loop through all stock items in Work Order\n item_code = item.item_code\n required_qty = float(item.consumed_quantity or 0)\n # required_qty = float(item.consumed_quantity) or 0\n warehouse = item.warehouse # Make sure you have a warehouse field in your stock table\n \n if not item_code or not warehouse:\n continue # Skip if no item or warehouse is set\n\n # ✅ Fetch Available Stock from Stock Ledger\n available_qty = frappe.db.get_value(\"Bin\", \n {\"item_code\": item_code, \"warehouse\": warehouse}, \"actual_qty\") or 0\n \n available_qty = float(available_qty)\n\n # ✅ompare Available vs Required Quantity\n if required_qty > available_qty:\n frappe.throw(\n f\"❌ Insufficient stock for <b>{item_code}</b> in warehouse <b>{warehouse}</b>. \"\n f\"Available: <b>{available_qty}</b>, Required: <b>{required_qty}</b>.\"\n )\n \n \n \n# # Script to auto assign technician to PHCC site Work orders\n\n# if doc.site_name:\n# site = doc.site_name\n\n# # Check if ToDo already exists for this Work Order\n# existing_todo = frappe.db.exists(\"ToDo\", {\n# \"reference_type\": \"Work_Order\",\n# \"reference_name\": doc.name\n# })\n# print(existing_todo)\n# if not existing_todo:\n \n# # Step 1: Get users with permission to this Mobile Team Site\n# permitted_users = frappe.get_all(\n# \"User Permission\",\n# filters={\n# \"allow\": \"Mobile Team Site\",\n# \"for_value\": site\n# },\n# fields=[\"user\"]\n# )\n# print(permitted_users)\n# if permitted_users:\n \n# # Step 2: Filter users with 'Technician' role\n# technician_users = []\n# for entry in permitted_users:\n# user_roles = frappe.get_all(\"Has Role\", filters={\"parent\": entry.user}, fields=[\"role\"])\n# if any(r[\"role\"] == \"Technician\" for r in user_roles):\n# technician_users.append(entry.user)\n# print(technician_users)\n# if technician_users:\n# # Step 3: Assign to first technician user found (or apply logic to choose)\n# assigned_user = technician_users[0]\n# print(assigned_user)\n \n# # Create the ToDo\n# frappe.get_doc({\n# \"doctype\": \"ToDo\",\n# \"allocated_to\": assigned_user,\n# \"description\": f\"Work Order Assigned: {doc.name}\",\n# \"reference_type\": \"Work_Order\",\n# \"reference_name\": doc.name,\n# \"status\": \"Open\"\n# }).insert(ignore_permissions=True)\n \n# frappe.msgprint(f\"Assigned Work Order {doc.name} to Technician: {assigned_user}\")\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 1,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Insert",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-04-22 12:40:36.864716",
"module": "Asset Lite",
"name": "Auto creation of asset from Item",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Item",
"script": "if doc.is_fixed_asset == 1:\r\n new_asset = frappe.get_doc({\r\n \"doctype\": \"Asset\",\r\n \"item_code\": doc.item_code,\r\n \"location\": doc.custom_location,\r\n \"asset_name\": doc.item_code,\r\n \"asset_category\":doc.asset_category,\r\n \"gross_purchase_amount\":doc.custom_gross_purchase_amount,\r\n \"available_for_use_date\":doc.custom_available_for_use_date,\r\n \"is_existing_asset\":1,\r\n \"custom_asset_type\":doc.custom_asset_type,\r\n \"company\":\"King Fahad Specialist Hospital-Dammam\"\r\n })\r\n new_asset.insert()\r\n frappe.msgprint(\"Fixed Asset has been created\")",
"script_type": "DocType 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": "2024-10-17 15:44:33.022436",
"module": "Asset Lite",
"name": "Auto set warranty status",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Support Plans",
"script": "# Get today's date as a datetime.date object\ntoday = frappe.utils.today()\ntoday_date = frappe.utils.getdate(today)\n\nstart_date = frappe.utils.getdate(doc.custom_service_contract_start) if doc.custom_service_contract_start else None\nend_date = frappe.utils.getdate(doc.custom_service_contract_end) if doc.custom_service_contract_end else None\n\n\n# Check and update service contract status\nif start_date and end_date:\n if start_date <= today_date <= end_date:\n doc.custom_service_contract_status = 'Active'\n elif today_date > end_date:\n doc.custom_service_contract_status = 'Expired'\n else:\n doc.custom_service_contract_status = ''\n \n\n# Get the regular warranty start and end dates\nwar_start_date = frappe.utils.getdate(doc.custom_warranty_start_date) if doc.custom_warranty_start_date else None\nwar_end_date = frappe.utils.getdate(doc.custom_warranty_end_date) if doc.custom_warranty_end_date else None\n\n# Get the extended warranty start and end dates\nextended_war_start_date = frappe.utils.getdate(doc.custom_extended_start_date) if doc.custom_extended_start_date else None\nextended_war_end_date = frappe.utils.getdate(doc.custom_extended_end_date) if doc.custom_extended_end_date else None\n\n# Set the status based on the warranty period and extended warranty\nif war_start_date and war_end_date:\n if war_start_date <= today_date <= war_end_date:\n doc.custom_warranty_status = 'Active'\n elif extended_war_start_date and extended_war_end_date and extended_war_start_date <= today_date <= extended_war_end_date:\n doc.custom_warranty_status = 'Active'\n elif today_date > war_end_date:\n doc.custom_warranty_status = 'Expired'\n else:\n doc.custom_warranty_status = ''\n \n",
"script_type": "DocType 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": "2024-09-17 13:26:06.877577",
"module": "Asset Lite",
"name": "Warranty status Set",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Warranty",
"script": "# Get today's date as a datetime.date object\ntoday = frappe.utils.today()\ntoday_date = frappe.utils.getdate(today)\n\n # Convert warranty_start and warranty_end to date objects if they are not None\nwarranty_start = frappe.utils.getdate(doc.warranty_start_date) if doc.warranty_start_date else None\nwarranty_end = frappe.utils.getdate(doc.warranty_end_date) if doc.warranty_end_date else None\n\n# Check and update warranty status\nif warranty_start and warranty_end:\n if warranty_start <= today_date <= warranty_end:\n doc.warranty_status = 'Active'\n elif today_date > warranty_end:\n doc.warranty_status = 'Expired'\n else:\n doc.warranty_status = ''",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Insert",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2024-09-24 11:48:59.674584",
"module": "Asset Lite",
"name": "PPM autocreation",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Asset Maintenance Log",
"script": "# Check if maintenance status is \"Planned\" and custom asset type is provided\r\nif doc.maintenance_status == \"Planned\" and doc.custom_asset_type:\r\n\r\n # Fetch the PPM Template based on the asset type in the Asset Maintenance Log\r\n ppm_template = frappe.db.get_value('PPM Templates', {'asset_type': doc.custom_asset_type}, 'name')\r\n\r\n if ppm_template:\r\n # Create a new PPM document using the fetched template and asset maintenance log details\r\n ppm_doc = frappe.get_doc({\r\n \"doctype\": \"PPM\",\r\n \"asset_maintenance_log\": doc.name, \r\n \"data\": ppm_template, \r\n })\r\n\r\n # Insert the PPM document into the database\r\n ppm_doc.insert() \r\n\r\n frappe.msgprint(f\"Planned Preventive Maintenance created for Asset {doc.asset_name}\")\r\n else:\r\n ppm_doc1 = frappe.get_doc({\r\n \"doctype\": \"PPM\",\r\n \"asset_maintenance_log\": doc.name, \r\n \"data\": \"CT Scan\", \r\n })\r\n\r\n # Insert the PPM document into the database\r\n ppm_doc1.insert()\r\n \r\n frappe.msgprint(f\"Planned Preventive Maintenance created for Asset {doc.asset_name}\")\r\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Save",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-08-18 12:28:26.236597",
"module": "Asset Lite",
"name": "Asset status Update",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "\r\n# Fetch all work orders with status 'Open' or 'Work In Progress'\r\nwork_orders = frappe.get_all(\"Work_Order\", filters={\"repair_status\": [\"in\", [\"Open\", \"Work In Progress\",\"Pending Review\"]]}, fields=[\"name\", \"asset\"])\r\n\r\n# Create a set of assets that are linked to work orders with status 'Open' or 'Work In Progress'\r\ndown_assets = set()\r\nfor wo in work_orders:\r\n if wo.asset:\r\n down_assets.add(wo.asset)\r\n\r\n# Fetch all assets\r\nassets = frappe.get_all(\"Asset\", fields=[\"name\", \"custom_device_status\", \"docstatus\"])\r\n\r\nfor asset in assets:\r\n # Skip if the asset is cancelled\r\n if asset[\"docstatus\"] == 2: # 2 means the document is cancelled\r\n continue\r\n \r\n # Determine the new status based on the work orders\r\n new_status = \"Down\" if asset[\"name\"] in down_assets else \"Up\"\r\n if asset[\"custom_device_status\"] != new_status:\r\n # Update the asset status if it has changed\r\n asset_doc = frappe.get_doc(\"Asset\", asset[\"name\"])\r\n asset_doc.custom_device_status = new_status\r\n asset_doc.save(ignore_permissions=True)\r\n\r\n\r\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": "2025-04-22 12:40:37.019545",
"module": "Asset Lite",
"name": "PPM Update",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Asset Maintenance Log",
"script": "# Check if maintenance status is \"Planned\" and custom asset type is provided\r\nif doc.maintenance_status == \"Planned\" and doc.custom_asset_type:\r\n\r\n # Fetch the PPM Template based on the asset type in the Asset Maintenance Log\r\n ppm_template = frappe.db.get_value('PPM Templates', {'asset_type': doc.custom_asset_type}, 'name')\r\n if ppm_template:\r\n \r\n if not doc.custom_table:\r\n doc.custom_template = ppm_template\r\n template_data = frappe.get_doc(\"PPM Templates\", ppm_template)\r\n\r\n for item in template_data.ppm_template_table:\r\n doc.append(\"custom_table\", {\r\n \"maintenance_name\": item.maintenance_name,\r\n })\r\n \r\n else:\r\n if not doc.custom_table:\r\n template_data = frappe.get_doc(\"PPM Templates\", \"CT Scan\")\r\n\r\n for item in template_data.ppm_template_table:\r\n doc.append(\"custom_table\", {\r\n \"maintenance_name\": item.maintenance_name,\r\n })\r\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 1,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Save",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-04-22 12:40:36.994832",
"module": "Asset Lite",
"name": "Plus Button",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "\nif doc.workflow_state == \"Repair InProgress\":\n # Inject link in Connections when the state is \"Repair InProgress\"\n doc.add_comment(\"Comment\", \"Connections enabled for Repair InProgress state.\")\n \nelse:\n # Return false or remove links as needed for other states\n pass",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Save (Submitted Document)",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-04-22 12:40:36.903945",
"module": "Asset Lite",
"name": "Asset warranty end date addition",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "penalty_value = int(float(doc.penalty))\r\n\r\nif penalty_value> 0:\r\n # Ensure an asset is linked to the work order\r\n if not doc.asset:\r\n frappe.throw(_(\"No Asset is linked to this Work Order.\"))\r\n \r\n # Fetch the asset document\r\n asset = frappe.get_doc(\"Asset\", doc.asset)\r\n \r\n # Get the current warranty end date (default to today if not set)\r\n current_warranty_end_date = asset.custom_warranty_end_date or frappe.utils.nowdate()\r\n \r\n # Calculate the new warranty end date by adding penalty days\r\n new_warranty_end_date = frappe.utils.add_days(current_warranty_end_date, penalty_value)\r\n \r\n # Update the asset with the new warranty end date\r\n asset.custom_warranty_end_date = new_warranty_end_date\r\n asset.save(ignore_permissions=True)\r\n \r\n # Notify the user about the update\r\n frappe.msgprint(\r\n \"The warranty end date for Asset \" \r\n + str(asset.name) \r\n + \" has been updated \" \r\n \r\n )\r\n",
"script_type": "DocType 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-01-28 15:26:02.616652",
"module": "Asset Lite",
"name": "Location",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Asset",
"script": "# # Server Script for Asset Doctype\r\n# if not doc.location:\r\n# doc.location = \"Ohud\"\r\n \r\n# # if doc and doc.custom_serial_number:\r\n# # if frappe.db.exists(\"Asset\", {\"custom_serial_number\": doc.custom_serial_number,\"name\": [\"!=\", doc.name]}):\r\n# # frappe.throw(f\"Serial Number: {doc.custom_serial_number} is already exists. Please enter a unique Serial Number.\")\r\n\r\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 1,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Submit",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-04-22 12:40:36.959715",
"module": "Asset Lite",
"name": "Depreciation post date",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Asset",
"script": "assets = frappe.get_all('Asset', filters={'calculate_depreciation': 1}, fields=['name'])\r\n\r\nfor asset in assets:\r\n # Get the full asset document\r\n asset_doc = frappe.get_doc(\"Asset\", asset.name)\r\n# Ensure the child table 'finance_books' exists in the asset document\r\n if asset_doc.finance_books:\r\n for row in asset_doc.finance_books:\r\n # Get the depreciation start date from the child table row\r\n depreciation_start_date = frappe.utils.getdate(row.depreciation_start_date)\r\n today = frappe.utils.getdate(frappe.utils.today())\r\n \r\n # Check if the depreciation start date matches today's date\r\n if depreciation_start_date == today:\r\n \r\n # Email subject and message\r\n subject = f\"Reminder: Depreciation is Posted\"\r\n message = f\"\"\"\r\n This is a reminder that the depreciation for Asset starts today.\r\n \r\n Depreciation Start Date: {row.depreciation_start_date}\r\n \r\n \"\"\"\r\n \r\n email_recipients = []\r\n users = frappe.get_all(\"User\")\r\n for user in users:\r\n userdoc = frappe.get_doc(\"User\", user.name)\r\n # print(doc.roles)\r\n for row in userdoc.roles:\r\n # print(row.role)\r\n if row.role == \"Maintenance Manager\":\r\n print(userdoc.email)\r\n email_recipients.append(userdoc.email)\r\n # email_recipients = [\"maintenancemanager@gmail.com\"] # Replace with actual manager emails\r\n \r\n # Send the email notification\r\n frappe.sendmail(\r\n recipients=email_recipients,\r\n subject=subject,\r\n message=message\r\n )\r\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Save",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-04-22 12:40:36.937380",
"module": "Asset Lite",
"name": "Work_order email",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "if doc.workflow_state == \"Completed\":\n # Fetch the user's roles\n user_roles = frappe.db.get_all(\n 'Has Role',\n filters={'parent': doc.owner},\n fields=['role'],\n pluck='role'\n )\n\n # Check if the user does NOT have the 'Asset Manager' role\n if \"Asset Manager\" not in user_roles:\n # Create the notification message with a link\n subject = f\"Feedback Required for Work Order {doc.name}\"\n quality_feedback_link = f\"/app/quality-feedback/new-quality-feedback-1\"\n message = f\"\"\"\n Hello {doc.owner},\n <br>\n Please provide your feedback for Work Order <b>{doc.name}</b>. \n Click <a href=\"{quality_feedback_link}\">here</a> to provide your feedback.\n <br>\n Thank you!\n \"\"\"\n\n # Send notification\n frappe.sendmail(\n recipients=[doc.owner],\n subject=subject,\n message=message,\n )",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Submit",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-04-22 12:40:36.924935",
"module": "Asset Lite",
"name": "Work order",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work Job Order",
"script": "if doc:\n doc.completion_date = frappe.utils.now_datetime()\n doc.job_completed = \"Yes\"",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 1,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Submit",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-04-22 12:40:36.880055",
"module": "Asset Lite",
"name": "Auto Create Feedback",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Feedback",
"script": "new_feedback = frappe.get_doc({\r\n \"doctype\": \"Feedback\",\r\n \"work_order\": doc.name,\r\n\r\n})\r\nnew_feedback.insert()\r\nfrappe.msgprint('Feedback Created')",
"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-02-26 10:25:55.264211",
"module": "Asset Lite",
"name": "Create Item on Asset",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Asset",
"script": "# Check if an item already exists\r\nitem_exists = frappe.db.exists(\"Item\", doc.asset_name)\r\n\r\nif not item_exists:\r\n # Create new item since it does not exist\r\n new_item = frappe.get_doc({\r\n \"doctype\": \"Item\",\r\n \"item_code\": doc.asset_name,\r\n \"item_name\": doc.asset_name,\r\n \"asset_category\": \"General\",\r\n \"custom_gross_purchase_amount\": doc.gross_purchase_amount,\r\n \"custom_available_for_use_date\": doc.available_for_use_date,\r\n \"is_fixed_asset\": 1,\r\n \"is_stock_item\":0,\r\n \"custom_asset_type\": doc.custom_asset_type,\r\n \"item_group\": \"General\",\r\n \"stock_uom\": \"Nos\",\r\n \"custom_hospital_name\":doc.company\r\n })\r\n new_item.insert(ignore_permissions=True) # Ignore permission issues\r\n # frappe.msgprint(f\"Item {doc.asset_name} has been created\")\r\n\r\n # Assign newly created item to asset's item_code field\r\n doc.item_code = doc.asset_name\r\n\r\nelse:\r\n # If item exists, fetch the document and assign the name\r\n item_doc = frappe.get_doc(\"Item\", item_exists)\r\n doc.item_code = item_doc.name\r\n\r\n\r\n# if doc.custom_local_id:\r\n# if frappe.db.exists(\"Asset\", {\"custom_local_id\": doc.custom_local_id}):\r\n# frappe.throw(f\"Local ID: {doc.custom_local_id} is already exists. Please enter a unique LOCAL ID.\")\r\nif doc.custom_serial_number:\r\n if frappe.db.exists(\"Asset\", {\"custom_serial_number\": doc.custom_serial_number}):\r\n frappe.throw(f\"Serial Number: {doc.custom_serial_number} is already exists. Please enter a unique Serial Number.\")\r\n",
"script_type": "DocType 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": "2025-04-24 14:17:13.388211",
"module": "Asset Lite",
"name": "Purchase Invoice",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Purchase Invoice",
"script": "if doc.custom_purchase_order and not doc.custom_work_order:\r\n po = frappe.get_doc(\"Purchase Order\", doc.custom_purchase_order)\r\n \r\n if po.name and po.items:\r\n first_item = po.items[0] # Get the first row\r\n material_request = first_item.material_request # Get the Material Request from first row\r\n\r\n if material_request:\r\n mr_doc = frappe.get_doc(\"Material Request\", material_request)\r\n if mr_doc.custom_work_order: # Ensure the Work Order field exists\r\n doc.custom_work_order = mr_doc.custom_work_order\r\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Save (Submitted Document)",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-04-22 12:40:36.801438",
"module": "Asset Lite",
"name": "Asset Down Time Updation from WO",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "if doc.asset:\r\n ast = frappe.get_doc(\"Asset\", doc.asset)\r\n \r\n if doc.failure_date and doc.completion_date:\r\n failure_datetime = frappe.utils.get_datetime(doc.failure_date)\r\n completed_datetime = frappe.utils.get_datetime(doc.completion_date)\r\n\r\n # Calculate the difference in hours\r\n downtime = (completed_datetime - failure_datetime).total_seconds() / 3600\r\n\r\n # If there's already a downtime recorded, add to it\r\n existing_downtime = ast.custom_down_time or 0\r\n total_downtime = round(existing_downtime + downtime, 2)\r\n\r\n # Update the Asset's downtime\r\n frappe.db.set_value(\"Asset\", ast.name, \"custom_down_time\", total_downtime)\r\n \r\n if doc.first_responded_on and doc.completion_date:\r\n first_datetime = frappe.utils.get_datetime(doc.first_responded_on)\r\n completed_datetime = frappe.utils.get_datetime(doc.completion_date)\r\n \r\n # Calculate the difference in hours\r\n hrs_spent = (completed_datetime - first_datetime).total_seconds() / 3600\r\n \r\n doc.total_hours_spent = hrs_spent\r\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Submit",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-08-26 13:51:21.606837",
"module": "Asset Lite",
"name": "Update Spares from WO to Asset",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "if doc.stock_items:\r\n \r\n \r\n\r\n stock_entry = frappe.new_doc(\"Stock Entry\")\r\n stock_entry.stock_entry_type = \"Material Issue\" # Reduces stock\r\n stock_entry.purpose = \"Material Issue\"\r\n # stock_entry.company = doc.company\r\n stock_entry.custom_job_order = doc.name # Link Work Order\r\n \r\n company = doc.company\r\n \r\n for item in doc.stock_items:\r\n item_rate = frappe.db.get_value(\"Item\", item.item_code, \"valuation_rate\") or 0\r\n company = frappe.db.get_value(\"Item Default\", {\"parent\": item.item_code}, \"company\")\r\n \r\n stock_entry.append(\"items\", {\r\n \"s_warehouse\": item.warehouse, # Warehouse to deduct from\r\n \"item_code\": item.item_code,\r\n \"qty\": item.consumed_quantity,\r\n \"uom\": frappe.db.get_value(\"Item\", item.item_code, \"stock_uom\"),\r\n \"basic_rate\": item.valuation_rate or item_rate,\r\n })\r\n stock_entry.company = company\r\n # Save and submit Stock Entry\r\n stock_entry.insert()\r\n stock_entry.submit()\r\n frappe.msgprint(f\"Stock deducted successfully via Stock Entry {stock_entry.name}\")\r\n\r\n \r\n \r\n\r\n\r\n\r\n\r\n\r\n# if not doc.asset:\r\n# frappe.throw(\"Asset ID is required to update spare parts.\")\r\n \r\nif doc.asset:\r\n # Fetch the Asset document linked to this Work Order\r\n asset_doc = frappe.get_doc(\"Asset\", doc.asset)\r\n total_amount = 0\r\n for item in doc.stock_items:\r\n total_amount = total_amount +item.total_value\r\n asset_doc.append(\"custom_spare_parts\", {\r\n \"work_order\":doc.name,\r\n \"item_code\": item.item_code,\r\n \"item_name\": item.item_code,\r\n \"qty\": item.consumed_quantity,\r\n \"rate\": item.valuation_rate,\r\n \"amount\": item.total_value\r\n })\r\n \r\n # if doc.repair_cost:\r\n # total_amount = total_amount +doc.repair_cost\r\n \r\n for row in doc.invoice_table:\r\n pi = frappe.get_doc(\"Purchase Invoice\", row.purchase_invoice)\r\n for pi_row in pi.items:\r\n asset_doc.append(\"custom_spare_parts\", {\r\n \"work_order\":doc.name,\r\n \"item_code\": pi_row.item_code,\r\n \"item_name\": pi_row.item_name,\r\n \"qty\": pi_row.qty,\r\n \"rate\": pi_row.rate,\r\n \"amount\": pi_row.amount\r\n })\r\n \r\n asset_doc.custom_total_spare_parts_amount = asset_doc.custom_total_spare_parts_amount + doc.total_repair_cost\r\n \r\n # Save the Asset document\r\n asset_doc.save()\r\n # frappe.msgprint(f\"Spare parts updated for Asset {doc.asset}\")\r\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 1,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Save",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-04-22 12:40:36.699028",
"module": "Asset Lite",
"name": "To calculate No of PMs",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Asset Maintenance",
"script": "# if doc.custom_start_date and doc.custom_end_date:\r\n# start_date = frappe.utils.getdate(doc.custom_start_date)\r\n# end_date = frappe.utils.getdate(doc.custom_end_date)\r\n# total_amount = doc.custom_total_amount or 0 # Ensure it's not None\r\n# total_pm_count = 0 # Initialize total PM count\r\n\r\n# # Mapping Periodicity to Date Increment Functions\r\n# periodicity_mapping = {\r\n# \"Daily\": lambda date: frappe.utils.add_days(date, 1),\r\n# \"Weekly\": lambda date: frappe.utils.add_days(date, 7),\r\n# \"Monthly\": lambda date: frappe.utils.add_months(date, 1),\r\n# \"Quarterly\": lambda date: frappe.utils.add_months(date, 3),\r\n# \"Half-yearly\": lambda date: frappe.utils.add_months(date, 6),\r\n# \"Yearly\": lambda date: frappe.utils.add_years(date, 1),\r\n# \"2 Yearly\": lambda date: frappe.utils.add_years(date, 2),\r\n# \"3 Yearly\": lambda date: frappe.utils.add_years(date, 3),\r\n# }\r\n\r\n# # Loop through the child table to process each periodicity\r\n# for task in doc.get(\"asset_maintenance_tasks\"):\r\n# periodicity = task.periodicity # Assuming the field is named \"periodicity\"\r\n\r\n# if not periodicity or periodicity not in periodicity_mapping:\r\n# continue # Skip invalid periodicities\r\n\r\n# increment_function = periodicity_mapping[periodicity]\r\n\r\n# # First maintenance happens after the first periodic interval\r\n# temp_date = increment_function(start_date)\r\n# pm_count = 0 # PM count for this periodicity\r\n\r\n# # Count PM occurrences between start and end date\r\n# while temp_date <= end_date:\r\n# pm_count =pm_count + 1\r\n# temp_date = increment_function(temp_date)\r\n\r\n# total_pm_count =total_pm_count + pm_count # Add to total count\r\n\r\n# # Update the document fields\r\n# doc.custom_no_of_pms = total_pm_count\r\n\r\n# # Calculate Price Per PM\r\n# doc.custom_price_per_pm = (total_amount / total_pm_count) if total_pm_count > 0 else 0\r\n\r\n\r\nif (doc.custom_start_date and doc.custom_end_date):\r\n # frappe.throw(\"Start Date and End Date are required.\")\r\n\r\n start_date = frappe.utils.getdate(doc.custom_start_date)\r\n end_date = frappe.utils.getdate(doc.custom_end_date)\r\n total_amount = doc.custom_total_amount\r\n total_pm_count = 0 # Initialize total PM count\r\n \r\n # Mapping Periodicity to Date Increment Functions\r\n periodicity_mapping = {\r\n \"Daily\": lambda date: frappe.utils.add_days(date, 1),\r\n \"Weekly\": lambda date: frappe.utils.add_days(date, 7),\r\n \"Monthly\": lambda date: frappe.utils.add_months(date, 1),\r\n \"Quarterly\": lambda date: frappe.utils.add_months(date, 3),\r\n \"Half-yearly\": lambda date: frappe.utils.add_months(date, 6),\r\n \"Yearly\": lambda date: frappe.utils.add_years(date, 1),\r\n \"2 Yearly\": lambda date: frappe.utils.add_years(date, 2),\r\n \"3 Yearly\": lambda date: frappe.utils.add_years(date, 3),\r\n }\r\n \r\n # Loop through the child table to process each periodicity\r\n for task in doc.get(\"asset_maintenance_tasks\"):\r\n periodicity = task.periodicity # Assuming the field is named \"periodicity\"\r\n \r\n if not periodicity or periodicity not in periodicity_mapping:\r\n continue # Skip invalid periodicities\r\n \r\n increment_function = periodicity_mapping[periodicity]\r\n temp_date = start_date\r\n pm_count = 0 # PM count for this periodicity\r\n \r\n # Count PM occurrences between start and end date\r\n while temp_date <= end_date:\r\n pm_count =pm_count + 1\r\n temp_date = increment_function(temp_date)\r\n \r\n total_pm_count =total_pm_count + pm_count # Add to total count\r\n \r\n # Update the document fields\r\n doc.custom_no_of_pms = total_pm_count\r\n \r\n # Calculate Price Per PM\r\n if total_amount and total_pm_count > 0:\r\n doc.custom_price_per_pm = total_amount / total_pm_count\r\n else:\r\n doc.custom_price_per_pm = 0",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 1,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Save",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-02-05 16:31:47.631399",
"module": "Asset Lite",
"name": "To Set Rating in WO",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Feedback",
"script": "if doc.work_order and doc.overall:\r\n frappe.db.set_value(\"Work_Order\", doc.work_order, \"feedback_rating\", doc.overall)\r\n # frappe.db.commit()",
"script_type": "DocType 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": "2025-05-22 18:30:29.780919",
"module": "Asset Lite",
"name": "To set Proce Per PMS and Total No of PMs",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Asset Maintenance",
"script": "if doc.custom_service_coverage_table:\r\n total_pms = 0\r\n total_pms_exclude_warranty = 0\r\n\r\n for row in doc.custom_service_coverage_table:\r\n # Ensure no_of_pms is at least 0\r\n no_of_pms = int(row.no_of_pms or 0)\r\n total_pms =total_pms + int(no_of_pms or 0)\r\n\r\n # Ensure service_agreement is not None before checking\r\n if row.service_agreement and row.service_agreement != \"Warranty\":\r\n total_pms_exclude_warranty =total_pms_exclude_warranty + no_of_pms\r\n\r\n # Assign calculated values\r\n doc.custom_no_of_pms = total_pms\r\n # doc.total_pms_exclude_warranty = total_pms_exclude_warranty # Ensure it's updated\r\n\r\n # Avoid division by zero\r\n if total_pms_exclude_warranty > 0:\r\n doc.custom_price_per_pm = doc.custom_total_amount / total_pms_exclude_warranty\r\n else:\r\n doc.custom_price_per_pm = 0 # Set a fallback value\r\n \r\n \r\n \r\nif doc.custom_service_coverage_table:\r\n today_date = frappe.utils.getdate(frappe.utils.today())\r\n\r\n for row in doc.custom_service_coverage_table:\r\n if row.start_date and row.end_date:\r\n start = frappe.utils.getdate(row.start_date)\r\n end = frappe.utils.getdate(row.end_date)\r\n\r\n # Check if today's date is within the start and end date range\r\n if start <= today_date <= end:\r\n if row.active != 'Yes':\r\n row.active = 'Yes'\r\n else:\r\n if row.active != 'No':\r\n row.active = 'No'\r\n\r\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": "Hourly",
"modified": "2024-10-17 14:13:14.465565",
"module": "Asset Lite",
"name": "Asset Update in Support Plan",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": null,
"script": "try:\r\n # Get all support plans\r\n support_plans = frappe.get_all(\"Support Plans\", fields=[\"name\"])\r\n\r\n for plan in support_plans:\r\n # Fetch all assets linked to this support plan\r\n assets = frappe.get_all(\"Asset\", filters={\"custom_support_plan\": plan.name}, fields=[\"name\", \"asset_name\", \"status\"])\r\n\r\n # Fetch the support plan document\r\n support_plan_doc = frappe.get_doc(\"Support Plans\", plan.name)\r\n\r\n # Clear the existing asset list table\r\n support_plan_doc.set(\"asset_list\", [])\r\n\r\n # Populate the asset list table with assets linked to this support plan\r\n for asset in assets:\r\n support_plan_doc.append(\"asset_list\", {\r\n \"asset_name\": asset.asset_name,\r\n \"asset_id\": asset.name,\r\n \r\n })\r\n\r\n # Save the updated support plan document\r\n support_plan_doc.save(ignore_permissions=True)\r\n\r\nexcept Exception as e:\r\n frappe.log_error(f\"Error updating support plans: {str(e)}\", \"Support Plan Update Error\")\r\n\r\n\r\n",
"script_type": "Scheduler Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 1,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Insert",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-04-22 12:40:37.040174",
"module": "Asset Lite",
"name": "Asset Total Hours",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Asset",
"script": "# Fetch all assets where 'current_datetime' is set\r\nassets = frappe.get_all(\"Asset\", filters={\"custom_installation_date\": [\"is\", \"set\"]}, fields=[\"name\", \"custom_installation_date\"])\r\n \r\n# Iterate over each asset to calculate and update the total hours\r\nfor asset in assets:\r\n # Parse the 'current_datetime' value as a datetime object\r\n installation_datetime = frappe.utils.get_datetime(asset.custom_installation_date)\r\n current_datetime = frappe.utils.now_datetime()\r\n\r\n # Calculate the time difference in hours\r\n time_diff = (current_datetime - installation_datetime).total_seconds() / 3600\r\n \r\n # Update the 'total_hours' field for the asset\r\n frappe.db.set_value(\"Asset\", asset.name, \"custom_total_hours\", round(time_diff, 2))\r\n frappe.db.commit()\r\n\r\n\r\n",
"script_type": "Scheduler Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": "* */5 * * * ",
"disabled": 1,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Insert",
"enable_rate_limit": 0,
"event_frequency": "Cron",
"modified": "2025-04-22 12:40:36.818236",
"module": "Asset Lite",
"name": "Asset Down Time",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Asset",
"script": "# Fetch all assets\r\nassets = frappe.get_all(\"Asset\", fields=[\"name\",\"available_for_use_date\"])\r\n\r\n# Iterate over each asset\r\nfor asset in assets:\r\n total_up_time = 0.0\r\n total_hrs = 0.0\r\n \r\n total_downtime = 0.0\r\n \r\n\r\n # Fetch all work orders related to this asset with both failure and completion datetimes set\r\n work_orders = frappe.get_all(\r\n \"Work_Order\",\r\n filters={\r\n \"asset\": asset.name,\r\n \"failure_date\": [\"is\", \"set\"],\r\n \"completion_date\": [\"is\", \"set\"]\r\n },\r\n fields=[\"name\", \"failure_date\", \"completion_date\"]\r\n )\r\n\r\n # Calculate total downtime for all work orders of the asset\r\n for wo in work_orders:\r\n failure_datetime = frappe.utils.get_datetime(wo.failure_date)\r\n completed_datetime = frappe.utils.get_datetime(wo.completion_date)\r\n\r\n # Calculate the difference in hours\r\n downtime = (completed_datetime - failure_datetime).total_seconds() / 3600\r\n\r\n # Debug: Log the asset, work order, and calculated downtime\r\n log_message = (\r\n f\"Asset: {asset.name}, Work Order: {wo.name}, \"\r\n f\"Failure datetime: {failure_datetime}, Completion datetime: {completed_datetime}, \"\r\n f\"Calculated downtime: {downtime} hours\"\r\n )\r\n if len(log_message) > 140:\r\n log_message = log_message[:137] + '...'\r\n frappe.log_error(log_message, \"Work Order Downtime Debug\")\r\n\r\n total_downtime =total_downtime+ downtime\r\n\r\n # Update the 'custom_down_time' field in the Asset doctype\r\n if total_downtime > 0: # Only update if downtime is greater than zero\r\n frappe.db.set_value(\"Asset\", asset.name, \"custom_down_time\", round(total_downtime, 2))\r\n \r\n asset_doc = frappe.get_doc(\"Asset\", asset.name)\r\n if asset_doc.available_for_use_date:\r\n # Convert available_for_use_date to datetime object\r\n available_date = frappe.utils.get_datetime(asset_doc.available_for_use_date)\r\n \r\n # Get the current date and time\r\n current_date = frappe.utils.now_datetime()\r\n \r\n # Calculate the time difference in days\r\n day_diff = (current_date - available_date).days\r\n \r\n # Convert days to hours\r\n total_hours = day_diff * 24\r\n \r\n frappe.db.set_value(\"Asset\", asset_doc.name, \"custom_total_hours\", round(total_hours, 2))\r\n \r\n total_up_time = total_hours - total_downtime\r\n frappe.db.set_value(\"Asset\", asset_doc.name, \"custom_up_time\", round(total_up_time, 2))\r\n \r\n \r\n\r\n# Commit the transaction after processing all assets\r\nfrappe.db.commit()\r\n",
"script_type": "Scheduler Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 1,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Insert",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-06-06 13:28:02.658953",
"module": "Asset Lite",
"name": "Auto create the permission",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "User",
"script": "if doc.custom_site_name and doc.name:\r\n if not frappe.db.exists(\"User Permission\", {\"user\": doc.name, \"allow\": \"Hospital\", \"for_value\": doc.custom_site_name}):\r\n user_per = frappe.get_doc({\r\n \"doctype\": \"User Permission\",\r\n \"user\": doc.name,\r\n \"allow\": \"Hospital\",\r\n \"for_value\": doc.custom_site_name,\r\n \"apply_to_all_doctypes\": 1\r\n })\r\n user_per.flags.ignore_validate_links = True\r\n user_per.flags.ignore_validate = True\r\n user_per.insert(ignore_permissions=True)",
"script_type": "DocType Event"
},
{
"allow_guest": 1,
"api_method": "get_assets",
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Insert",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-09-18 13:11:11.122120",
"module": "Asset Lite",
"name": "Asset Fetching",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": null,
"script": "# @frappe.whitelist()\r\ndef get_assets(company=None, custom_modality=None, custom_manufacturer=None, custom_device_status=None, custom_model=None):\r\n try:\r\n filters = {}\r\n \r\n filters[\"docstatus\"] = 1\r\n # Build filters dictionary (only add non-empty values)\r\n if company:\r\n filters[\"company\"] = company\r\n \r\n # if asset_name:\r\n # filters[\"asset_name\"] = asset_name\r\n if custom_modality:\r\n filters[\"custom_modality\"] = custom_modality\r\n if custom_manufacturer:\r\n filters[\"custom_manufacturer\"] = custom_manufacturer\r\n if custom_device_status:\r\n filters[\"custom_device_status\"] = custom_device_status\r\n if custom_model:\r\n filters[\"custom_model\"] = custom_model\r\n \r\n # Fetch assets\r\n assets = frappe.get_all(\r\n \"Asset\", \r\n filters=filters, \r\n fields=[\"name\", \"asset_name\",\"custom_modality\", \"company\", \"custom_manufacturer\", \"custom_device_status\",\"custom_model\"]\r\n )\r\n \r\n \r\n # Get assets that already have Asset Maintenance entries\r\n existing_maintenance_assets = frappe.get_all(\r\n \"Asset Maintenance\",\r\n filters={\r\n \"docstatus\": [\"<\", 2] # Not cancelled (0=Draft, 1=Submitted)\r\n },\r\n fields=[\"name\"],\r\n pluck=\"name\" # Returns only the asset values as a list\r\n )\r\n \r\n \r\n \r\n # Filter out assets that already have maintenance\r\n filtered_assets = []\r\n excluded_count = 0\r\n \r\n for asset in assets:\r\n if asset.name not in existing_maintenance_assets:\r\n filtered_assets.append(asset)\r\n else:\r\n excluded_count =excluded_count + 1\r\n frappe.errprint(f\"Excluded asset {asset.name} - already has maintenance\")\r\n \r\n \r\n \r\n # Return the filtered results\r\n frappe.response['message'] = filtered_assets\r\n \r\n except Exception as e:\r\n frappe.errprint(f\"Error in get_assets: {str(e)}\")\r\n frappe.response['message'] = []\r\n frappe.throw(f\"Error fetching assets: {str(e)}\")\r\n\r\n# Get parameters from form_dict\r\ncompany = frappe.form_dict.get(\"company\")\r\n# asset_name = frappe.form_dict.get(\"asset_name\") \r\ncustom_modality = frappe.form_dict.get(\"custom_modality\")\r\ncustom_manufacturer = frappe.form_dict.get(\"custom_manufacturer\")\r\ncustom_device_status = frappe.form_dict.get(\"custom_device_status\")\r\ncustom_model = frappe.form_dict.get(\"custom_model\")\r\n\r\n\r\n# Call the function\r\nget_assets(\r\n company=company,\r\n # asset_name=asset_name,\r\n custom_modality = custom_modality,\r\n custom_manufacturer=custom_manufacturer,\r\n custom_device_status=custom_device_status,\r\n custom_model = custom_model\r\n \r\n)",
"script_type": "API"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Submit",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-07-10 11:53:36.704632",
"module": "Asset Lite",
"name": "Auto Creation Of Asset maintenance",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "PM Schedule Generator",
"script": "for row in doc.maintenance_entries:\r\n # Get values from Asset Doc\r\n asset_doc = frappe.get_doc(\"Asset\", row.asset)\r\n\r\n # ---------- create Asset Maintenance ----------\r\n am = frappe.get_doc({\r\n \"doctype\": \"Asset Maintenance\",\r\n\r\n # --- top-level fields ---\r\n \"custom_pm_schedule\":doc.name,\r\n \"asset_name\": row.asset,\r\n \"hospital\": doc.company,\r\n \"maintenance_team\": doc.maintenance_team,\r\n \"maintenance_manager_name\": doc.maintenance_manager,\r\n\r\n \"custom_site_contractor\": asset_doc.custom_site_contractor,\r\n \"custom_subcontractor\": asset_doc.custom_subcontractor,\r\n \"custom_service_coverage\": asset_doc.custom_service_coverage,\r\n \"custom_total_amount\": asset_doc.custom_total_amount,\r\n\r\n # --- service-coverage child table ---\r\n \"custom_service_coverage_table\": [{\r\n \"service_agreement\": \"Contract\",\r\n \"start_date\": doc.start_date,\r\n \"end_date\": doc.end_date\r\n }],\r\n\r\n # --- maintenance-tasks child table ---\r\n \"asset_maintenance_tasks\": [{\r\n \"maintenance_task\": \"Maintenance Task\",\r\n \"maintenance_status\": \"Planned\",\r\n \"periodicity\": doc.periodicity,\r\n \"assign_to\": doc.assign_to,\r\n \"start_date\": doc.start_date,\r\n \"next_due_date\": doc.due_date\r\n }]\r\n })\r\n\r\n am.insert(ignore_permissions=True)\r\n # am.submit() # Uncomment if you want to auto-submit\r\n",
"script_type": "DocType 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": "2025-07-10 11:53:55.583984",
"module": "Asset Lite",
"name": "Update Due Date",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "PM Schedule Generator",
"script": "\r\nmapping_days = {\r\n \"Daily\": 1,\r\n \"Weekly\": 7,\r\n}\r\n\r\nmapping_months = {\r\n \"Monthly\": 1,\r\n \"Quarterly\": 3,\r\n \"Half-yearly\": 6,\r\n \"Yearly\": 12,\r\n \"2 Yearly\": 24,\r\n \"3 Yearly\": 36,\r\n}\r\n\r\n\r\nif doc.start_date and doc.periodicity:\r\n # Daybased intervals\r\n if doc.periodicity in mapping_days:\r\n doc.due_date = frappe.utils.add_days(doc.start_date, mapping_days[doc.periodicity])\r\n\r\n # Monthbased intervals\r\n elif doc.periodicity in mapping_months:\r\n doc.due_date = frappe.utils.add_months(doc.start_date, mapping_months[doc.periodicity])\r\n\r\n\r\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": "2025-07-10 11:54:34.343111",
"module": "Asset Lite",
"name": "Asset Maintenance PM nos",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Asset Maintenance",
"script": "# Calculates no_of_pms for each row in custom_service_coverage_table\r\n# based on the first maintenance task's periodicity.\r\n\r\n# import math\r\n# from frappe.utils import getdate\r\n\r\nif doc.asset_maintenance_tasks:\r\n\r\n periodicity = doc.asset_maintenance_tasks[0].periodicity # first task only\r\n \r\n periodicity_mapping = {\r\n \"Daily\": 1,\r\n \"Weekly\": 7,\r\n \"Monthly\": 30,\r\n \"Quarterly\": 90,\r\n \"Half-yearly\": 180,\r\n \"Yearly\": 365,\r\n \"2 Yearly\": 730,\r\n \"3 Yearly\": 1095,\r\n }\r\n\r\n days_per_period = periodicity_mapping.get(periodicity)\r\n if days_per_period:\r\n for row in doc.custom_service_coverage_table:\r\n if row.start_date and row.end_date:\r\n start = frappe.utils.getdate(row.start_date)\r\n end = frappe.utils.getdate(row.end_date)\r\n diff_days = (end - start).days\r\n \r\n # floor division gives whole periods\r\n row.no_of_pms = diff_days // days_per_period\r\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": "0 0 * * 0",
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Insert",
"enable_rate_limit": 0,
"event_frequency": "Cron",
"modified": "2025-09-03 16:18:34.270759",
"module": "Asset Lite",
"name": "Planned PM Report Script",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": null,
"script": "\r\ndef send_planned_pm_mail():\r\n # Get start and end of current month\r\n today = frappe.utils.nowdate()\r\n # start_date = frappe.utils.get_first_day(frappe.utils.add_months(today, 1))\r\n # end_date = frappe.utils.get_last_day(frappe.utils.add_months(today, 1))\r\n \r\n start_date = frappe.utils.nowdate()\r\n end_date = frappe.utils.get_last_day(today)\r\n\r\n # Get users with role \"Maintenance Manager\"\r\n role_users = frappe.get_all(\r\n \"Has Role\",\r\n filters={\"role\": \"Maintenance Manager\"},\r\n fields=[\"parent\"],\r\n distinct=True\r\n )\r\n \r\n \r\n for user in role_users:\r\n user_id = user[\"parent\"]\r\n\r\n # Skip Administrator & disabled users\r\n if user_id.lower() == \"administrator\":\r\n continue\r\n if frappe.db.get_value(\"User\", user_id, \"enabled\") != 1:\r\n continue\r\n\r\n # Get user details\r\n user_doc = frappe.get_doc(\"User\", user_id)\r\n user_email = user_doc.email\r\n if user_doc.custom_site_name:\r\n user_hospital = user_doc.get(\"custom_site_name\") # 👈 your custom hospital field\r\n print(user_hospital)\r\n \r\n if not user_email or not user_hospital:\r\n continue\r\n \r\n # Encode hospital filter in report URL\r\n # Example: https://site/app/report/Planned%20PM?hospital=Hospital%20Name\r\n report_base = \"https://asm-aljouf.seeraarabia.com/app/query-report/Planned%20PM\"\r\n report_link = f\"{report_base}?hospital={user_hospital}\"\r\n \r\n # Prepare email\r\n subject = f\"Planned PM Report for {user_hospital}: {start_date} to {end_date}\"\r\n message = f\"\"\"\r\n <p>Dear {user_doc.full_name},</p>\r\n <p>This is the Planned PM Report for your hospital: <b>{user_hospital}</b></p>\r\n <p>Period: <b>{start_date} to {end_date}</b></p>\r\n <p>You can view the report here: <a href=\"{report_link}\">{report_link}</a></p>\r\n <p>Regards,<br>Maintenance Team</p>\r\n \"\"\"\r\n print(message)\r\n \r\n # Send email\r\n frappe.sendmail(\r\n recipients=[user_email],\r\n subject=subject,\r\n message=message\r\n )\r\n \r\n\r\n pm_recipient = \"projectmanager@gmail.com\"\r\n if pm_recipient:\r\n \r\n # Prepare email content\r\n subject = f\"Planned PM Report: {start_date} to {end_date}\"\r\n report_link1 = \"https://asm-aljouf.seeraarabia.com/app/report/Planned%20PM\"\r\n message = f\"\"\"\r\n <p>Dear Team,</p>\r\n <p>This is the Planned PM Report for the period: <b>{start_date} to {end_date}</b>.</p>\r\n <p>You can view the report here: <a href=\"{report_link1}\">{report_link1}</a></p>\r\n <p>Regards,<br>Maintenance Team</p>\r\n \"\"\"\r\n \r\n # Send the email\r\n frappe.sendmail(\r\n # recipients=recipients,\r\n recipients=pm_recipient,\r\n subject=subject,\r\n message=message\r\n )\r\n\r\n# Call the function\r\nsend_planned_pm_mail()\r\n",
"script_type": "Scheduler Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 1,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Save",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-08-26 13:50:01.482363",
"module": "Asset Lite",
"name": "Auto Assign PHCC Work_Order",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "# Script to auto assign technician to PHCC site Work orders\n\nif doc.name and doc.site_name and doc.asset_type and doc.asset_type == \"Non Biomedical\":\n site = doc.site_name\n \n # name = doc.name\n\n # Check if ToDo already exists for this Work Order\n existing_todo = frappe.db.exists(\"ToDo\", {\n \"reference_type\": \"Work_Order\",\n \"reference_name\": doc.name\n })\n print(existing_todo)\n if not existing_todo:\n \n # Step 1: Get users with permission to this Mobile Team Site\n permitted_users = frappe.get_all(\n \"User Permission\",\n filters={\n \"allow\": \"Mobile Team Site\",\n \"for_value\": site\n },\n fields=[\"user\"]\n )\n print(permitted_users)\n if permitted_users:\n \n # Step 2: Filter users with 'Technician' role\n technician_users = []\n for entry in permitted_users:\n user_roles = frappe.get_all(\"Has Role\", filters={\"parent\": entry.user}, fields=[\"role\"])\n if any(r[\"role\"] == \"Technician\" for r in user_roles):\n technician_users.append(entry.user)\n print(technician_users)\n if technician_users:\n # Step 3: Assign to first technician user found (or apply logic to choose)\n assigned_user = technician_users[0]\n print(assigned_user)\n \n # Create the ToDo\n frappe.get_doc({\n \"doctype\": \"ToDo\",\n \"allocated_to\": assigned_user,\n \"description\": f\"Work Order Assigned: {doc.name}\",\n \"reference_type\": \"Work_Order\",\n \"reference_name\": doc.name,\n \"status\": \"Open\"\n }).insert(ignore_permissions=True)\n \n frappe.msgprint(f\"Assigned Work Order {doc.name} to Technician: {assigned_user}\")\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 1,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Save",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-08-26 13:49:53.175838",
"module": "Asset Lite",
"name": "Notifications",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "\r\ndef send_notification_on_workflow_change(doc, method):\r\n # Only run when workflow_state changes\r\n if not doc.has_value_changed(\"workflow_state\"):\r\n return\r\n\r\n hospital = getattr(doc, \"hospital\", None)\r\n if not hospital:\r\n frappe.log_error(f\"No hospital linked in {doc.name}\", \"Workflow Notification Error\")\r\n return\r\n\r\n recipients = set()\r\n\r\n # Step 1: Get all users with that hospital\r\n hospital_users = frappe.get_all(\"User\", filters={\"custom_site_name\": hospital}, pluck=\"name\")\r\n\r\n if not hospital_users:\r\n frappe.log_error(f\"No users found for hospital: {hospital}\", \"Workflow Notification Error\")\r\n return\r\n\r\n # Step 2: Get users with Maintenance Manager role\r\n mm_users = frappe.get_all(\r\n \"Has Role\",\r\n filters={\r\n \"role\": \"Maintenance Manager\",\r\n \"parent\": [\"in\", hospital_users]\r\n },\r\n pluck=\"parent\"\r\n )\r\n\r\n # Step 3: Get users with Technician role\r\n tech_users = frappe.get_all(\r\n \"Has Role\",\r\n filters={\r\n \"role\": \"Technician\",\r\n \"parent\": [\"in\", hospital_users]\r\n },\r\n pluck=\"parent\"\r\n )\r\n\r\n # Combine recipients\r\n recipients.update(mm_users)\r\n recipients.update(tech_users)\r\n\r\n # Step 4: Send notifications\r\n for user in recipients:\r\n frappe.new_doc(\"Notification Log\").update({\r\n \"type\": \"Alert\",\r\n \"document_type\": doc.doctype,\r\n \"document_name\": doc.name,\r\n \"subject\": f\"Workflow changed to {doc.workflow_state}\",\r\n \"from_user\": frappe.session.user,\r\n \"for_user\": user\r\n }).insert(ignore_permissions=True)\r\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": "assign_supervisor_or_technician",
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Insert",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-08-26 13:50:22.889014",
"module": "Asset Lite",
"name": "Assign Supervisor",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": null,
"script": "\r\ndef assign_supervisor_or_technician(work_order, action, asset_type):\r\n \"\"\"Assign Maintenance Manager or Technician depending on workflow action\"\"\"\r\n doc = frappe.get_doc(\"Work_Order\", work_order)\r\n\r\n if action == \"Apply\":\r\n if asset_type == \"Biomedical\":\r\n mm_user = frappe.db.sql(\"\"\"\r\n SELECT parent\r\n FROM `tabHas Role`\r\n WHERE role = 'Maintenance Manager'\r\n AND parent IN (SELECT name FROM `tabUser` WHERE enabled = 1 AND custom_site_name = %s)\r\n LIMIT 1\r\n \"\"\", (doc.company,), as_dict=True)\r\n if asset_type == \"Non Biomedical\":\r\n mm_user = frappe.db.sql(\"\"\"\r\n SELECT parent\r\n FROM `tabHas Role`\r\n WHERE role = 'General WOA'\r\n AND parent IN (\r\n SELECT name FROM `tabUser`\r\n WHERE enabled = 1 AND custom_site_name = %s\r\n )\r\n AND parent NOT IN (\r\n SELECT parent FROM `tabHas Role` WHERE role = 'System Manager'\r\n )\r\n LIMIT 1\r\n \"\"\", (doc.company,), as_dict=True) \r\n \r\n if mm_user and not doc.custom_assigned_supervisor:\r\n doc.custom_assigned_supervisor = mm_user[0].parent\r\n user_doc = frappe.get_doc(\"User\", mm_user[0].parent)\r\n doc.bio_med_dept = user_doc.full_name\r\n doc.save()\r\n return {\"assigned_to\": mm_user[0].parent}\r\n\r\n elif action == \"Send For Repair\" and asset_type == \"Biomedical\":\r\n tech_user = frappe.db.sql(\"\"\"\r\n SELECT parent\r\n FROM `tabHas Role`\r\n WHERE role = 'Technician'\r\n AND parent IN (\r\n SELECT name FROM `tabUser`\r\n WHERE enabled = 1 AND custom_site_name = %s\r\n )\r\n AND parent NOT IN (\r\n SELECT parent FROM `tabHas Role` WHERE role = 'Maintenance Manager'\r\n )\r\n LIMIT 1\r\n \"\"\", (doc.company,), as_dict=True)\r\n\r\n if tech_user and not doc.custom_assign_to_contractor:\r\n doc.custom_assign_to_contractor = tech_user[0].parent\r\n user_doc = frappe.get_doc(\"User\", tech_user[0].parent)\r\n doc.serviced_by = user_doc.full_name\r\n doc.save()\r\n return {\"assigned_to\": tech_user[0].parent}\r\n\r\n return {\"assigned_to\": None}\r\n\r\naction = frappe.form_dict.get(\"action\")\r\nwork_order = frappe.form_dict.get(\"work_order\")\r\nasset_type = frappe.form_dict.get(\"asset_type\")\r\n\r\n# Call the function\r\nassign_supervisor_or_technician(\r\n work_order=work_order,\r\n action=action,\r\n asset_type=asset_type\r\n \r\n)",
"script_type": "API"
},
{
"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": "2025-12-12 12:02:25.482488",
"module": "Asset Lite",
"name": "User Full Name",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "User",
"script": "parts = []\r\n\r\n# Add custom user id first (if present)\r\nif doc.custom_user_id:\r\n parts.append(str(doc.custom_user_id))\r\n\r\n# Then add first, middle, last name\r\nif doc.first_name:\r\n parts.append(doc.first_name)\r\n\r\nif doc.middle_name:\r\n parts.append(doc.middle_name)\r\n\r\nif doc.last_name:\r\n parts.append(doc.last_name)\r\n\r\n# Join all parts with space\r\ndoc.full_name = \" \".join(parts)\r\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Submit",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-01-19 12:44:25.790307",
"module": "Asset Lite",
"name": "Set Completion date",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "# if not doc.completion_date:\r\n# doc.completion_date = frappe.utils.now_datetime()\r\n\r\nif doc.first_responded_on and doc.completion_date:\r\n first_response = frappe.utils.get_datetime(doc.first_responded_on)\r\n completion = frappe.utils.get_datetime(doc.completion_date)\r\n \r\n # Remove seconds and microseconds\r\n first_response = first_response.replace(second=0, microsecond=0)\r\n completion = completion.replace(second=0, microsecond=0)\r\n\r\n if completion >= first_response:\r\n diff_seconds = (completion - first_response).total_seconds()\r\n total_hours = diff_seconds / 3600\r\n\r\n doc.total_hours_spent = round(total_hours, 2)\r\n else:\r\n doc.total_hours_spent = 0",
"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": "Daily",
"modified": "2026-01-16 18:05:39.628396",
"module": "Asset Lite",
"name": "Inspection corrective wo",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": null,
"script": "today = frappe.utils.nowdate()\r\n\r\ninspections = frappe.get_all(\r\n \"Inspection\",\r\n filters={\r\n \"target_closure_date\": [\"<\", today],\r\n \"linked_corrective_wo_no\": [\"is\", \"not set\"],\r\n \"status\": [\"!=\", \"Closed\"],\r\n \"workflow_state\": [\"in\", [\"Sent to technician\", \"Sent to Work Control\"]]\r\n },\r\n fields=[\"name\", \"requested_by\", \"status\", \"target_closure_date\",\"attachment\", \"extension_no\", \"work_order_type\",\r\n \"department\",\"location\",\"assigned_technician\"]\r\n)\r\n\r\nfor insp in inspections:\r\n if insp.target_closure_date:\r\n\r\n # Prevent duplicate Work Orders\r\n if frappe.db.exists(\"Work_Order\", {\"inspection\": insp.name}):\r\n continue\r\n \r\n wo = frappe.new_doc(\"Work_Order\")\r\n wo.repair_status = \"Open\"\r\n wo.inspection = insp.name\r\n wo.custom_requester = insp.requested_by or \"Administrator\"\r\n \r\n # ✅ Mandatory server-side fields\r\n wo.failure_date = frappe.utils.now()\r\n # wo.custom_extension_no = 0000\r\n \r\n # ✅ Use existing dummy attachment\r\n wo.custom_extension_no = insp.extension_no\r\n wo.custom_attachment = insp.attachment\r\n wo.work_order_type = insp.work_order_type\r\n wo.department = insp.department\r\n wo.custom_location = insp.location\r\n wo.assigned_technician = insp.assigned_technician\r\n wo.custom_technical_department = insp.technician_department\r\n \r\n # Insert Work Order\r\n wo.insert(ignore_permissions=True, ignore_mandatory=True)\r\n # wo.insert(ignore_permissions=True)\r\n \r\n # Link back to Inspection\r\n frappe.db.set_value(\r\n \"Inspection\",\r\n insp.name,\r\n \"linked_corrective_wo_no\",\r\n wo.name\r\n )\r\n",
"script_type": "Scheduler Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Save",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-03-06 07:21:59.710246",
"module": "Asset Lite",
"name": "wo inspection status update",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "# Proceed only if linked Inspection exists\r\nif doc.inspection and doc.workflow_state in [\"Approved\", \"Closed\"]:\r\n\r\n insp = frappe.get_doc(\"Inspection\", doc.inspection)\r\n\r\n # Do nothing if already closed\r\n if insp.workflow_state != \"Closed\":\r\n\r\n # Draft → Sent to Supervisor (Action: Apply)\r\n if insp.workflow_state == \"Sent to Work Control\":\r\n frappe.call(\r\n \"frappe.model.workflow.apply_workflow\",\r\n doc=insp,\r\n action=\"Send to Technician\"\r\n )\r\n \r\n if insp.workflow_state == \"Sent to technician\":\r\n frappe.call(\r\n \"frappe.model.workflow.apply_workflow\",\r\n doc=insp,\r\n action=\"Send to Supervisor\"\r\n )\r\n\r\n # Sent to Supervisor → Closed (Action: Approve)\r\n if insp.workflow_state == \"Sent to Supervisor\":\r\n frappe.call(\r\n \"frappe.model.workflow.apply_workflow\",\r\n doc=insp,\r\n action=\"Close\"\r\n )\r\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-02-13 08:56:08.582064",
"module": "Asset Lite",
"name": "Update Item Defaults",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Item",
"script": "row = doc.append(\"item_defaults\", {})\r\nrow.company = \"King Fahad Specialist Hospital - Dammam\"\r\nrow.default_warehouse = \"Stores - KFSH-D\"",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Insert",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-02-05 12:13:19.732385",
"module": "Asset Lite",
"name": "Notifications to all Supervisors based on Work order Type",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "\r\nif doc.work_order_type:\r\n \r\n # 1. Get all Asset Maintenance Teams matching expertise\r\n teams = frappe.get_all(\r\n \"Asset Maintenance Team\",\r\n filters={\r\n \"custom_expertise\": doc.work_order_type\r\n },\r\n fields=[\"maintenance_manager\"]\r\n )\r\n \r\n if teams:\r\n \r\n # 2. Collect unique email IDs\r\n manager_emails = list({\r\n t.maintenance_manager.strip()\r\n for t in teams\r\n if t.maintenance_manager\r\n })\r\n \r\n if manager_emails:\r\n \r\n # 3. Prepare email content\r\n subject = f\"New Work Order Created: {doc.name}\"\r\n message = f\"\"\"\r\n <p>A new <b>Work Order</b> has been created.</p>\r\n <p><b>Work Order:</b> {doc.name}</p>\r\n <p><b>Work Order Type:</b> {doc.work_order_type}</p>\r\n <p><b>Created By:</b> {doc.owner}</p>\r\n \r\n \"\"\"\r\n \r\n # 4. Send Email directly\r\n frappe.sendmail(\r\n recipients=manager_emails,\r\n subject=subject,\r\n message=message,\r\n delayed=True\r\n )\r\n \r\n # 5. ERPNext Notification (only if email matches a User)\r\n users = frappe.get_all(\r\n \"User\",\r\n filters={\r\n \"email\": [\"in\", manager_emails],\r\n \"enabled\": 1\r\n },\r\n fields=[\"name\"]\r\n )\r\n \r\n for user in users:\r\n frappe.get_doc({\r\n \"doctype\": \"Notification Log\",\r\n \"subject\": subject,\r\n \"email_content\": frappe.utils.strip_html(message),\r\n \"for_user\": user.name,\r\n \"type\": \"Alert\",\r\n \"document_type\": \"Work_Order\",\r\n \"document_name\": doc.name\r\n }).insert(ignore_permissions=True)\r\n \r\n # frappe.db.commit()\r\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 1,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "Before Save",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-01-29 17:18:56.439541",
"module": "Asset Lite",
"name": "Assigned Technician",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "# Only continue if existing document\r\nif not doc.is_new():\r\n\r\n # Only continue if technician NOT assigned\r\n if not doc.assigned_technician:\r\n\r\n # Detect workflow action click\r\n action = frappe.form_dict.get(\"action\")\r\n\r\n if action:\r\n\r\n # Get logged-in user\r\n user = frappe.session.user\r\n\r\n # Get roles safely\r\n roles = frappe.get_all(\r\n \"Has Role\",\r\n filters={\"parent\": user},\r\n pluck=\"role\"\r\n )\r\n\r\n # Block ONLY Work Control action\r\n if \"Work Control\" in roles:\r\n frappe.throw(_(\"Assigned Technician is mandatory before Work Control can proceed.\"))\r\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Save",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-03-06 07:21:59.690311",
"module": "Asset Lite",
"name": "Add technicians Notifications",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "if doc.custom_add_technicians:\r\n # Support comma and new line separated users\r\n users = doc.custom_add_technicians.replace('\\n', ',').split(',')\r\n for user in users:\r\n user = user.strip()\r\n if user:\r\n # Check existing ToDo FOR THIS SPECIFIC USER\r\n existing = frappe.get_all(\r\n \"ToDo\",\r\n filters={\r\n \"reference_type\": \"Work_Order\",\r\n \"reference_name\": doc.name,\r\n \"allocated_to\": user, # Check for THIS user specifically\r\n \"status\": [\"!=\", \"Cancelled\"]\r\n },\r\n limit=1\r\n )\r\n \r\n # Create only if not exists FOR THIS USER\r\n if not existing:\r\n # -------- CREATE TODO --------\r\n todo = frappe.new_doc(\"ToDo\")\r\n todo.allocated_to = user\r\n todo.assigned_by = frappe.session.user\r\n todo.reference_type = \"Work_Order\"\r\n todo.reference_name = doc.name\r\n todo.description = \"New Work_Order assigned: \" + doc.name\r\n todo.status = \"Open\"\r\n todo.insert(ignore_permissions=True)\r\n \r\n # -------- SEND SYSTEM NOTIFICATION --------\r\n notification = frappe.new_doc(\"Notification Log\")\r\n notification.subject = \"New Work_Order Assigned\"\r\n notification.email_content = \"Work_Order \" + doc.name + \" has been assigned to you.\"\r\n notification.for_user = user\r\n notification.type = \"Alert\"\r\n notification.document_type = \"Work_Order\"\r\n notification.document_name = doc.name\r\n notification.insert(ignore_permissions=True)\r\n \r\n # -------- SEND EMAIL --------\r\n frappe.sendmail(\r\n recipients=[user],\r\n subject=\"New Work_Order Assigned - \" + doc.name,\r\n message=\"Work_Order \" + doc.name + \" has been assigned to you. Please Take necessary action.\",\r\n reference_doctype=\"Work_Order\",\r\n reference_name=doc.name\r\n )",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Save",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-02-05 12:12:50.646975",
"module": "Asset Lite",
"name": "Asset notification To Supervisor",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Asset",
"script": "\r\nif doc.custom_technical_department and doc.workflow_state == \"Sent to Supervisor\":\r\n \r\n # 1. Get all Asset Maintenance Teams matching expertise\r\n teams = frappe.get_all(\r\n \"Asset Maintenance Team\",\r\n filters={\r\n \"custom_expertise\": doc.custom_technical_department\r\n },\r\n fields=[\"maintenance_manager\"]\r\n )\r\n \r\n if teams:\r\n \r\n # 2. Collect unique email IDs\r\n manager_emails = list({\r\n t.maintenance_manager.strip()\r\n for t in teams\r\n if t.maintenance_manager\r\n })\r\n \r\n if manager_emails:\r\n \r\n # 3. Prepare email content\r\n subject = f\"New Asset is Created: {doc.name}\"\r\n message = f\"\"\"\r\n <p>A new <b>Asset</b> has been created.</p>\r\n <p><b>Asset ID:</b> {doc.name}</p>\r\n <p><b>Technical Department Type:</b> {doc.custom_technical_department}</p>\r\n <p><b>Created By:</b> {doc.owner}</p>\r\n \r\n \"\"\"\r\n \r\n # 4. Send Email directly\r\n frappe.sendmail(\r\n recipients=manager_emails,\r\n subject=subject,\r\n message=message,\r\n delayed=True\r\n )\r\n \r\n # 5. ERPNext Notification (only if email matches a User)\r\n users = frappe.get_all(\r\n \"User\",\r\n filters={\r\n \"email\": [\"in\", manager_emails],\r\n \"enabled\": 1\r\n },\r\n fields=[\"name\"]\r\n )\r\n \r\n for user in users:\r\n frappe.get_doc({\r\n \"doctype\": \"Notification Log\",\r\n \"subject\": subject,\r\n \"email_content\": frappe.utils.strip_html(message),\r\n \"for_user\": user.name,\r\n \"type\": \"Alert\",\r\n \"document_type\": \"Asset\",\r\n \"document_name\": doc.name\r\n }).insert(ignore_permissions=True)\r\n \r\n # frappe.db.commit()\r\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-03-06 07:21:59.668954",
"module": "Asset Lite",
"name": "Location No logic",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Asset",
"script": "# room_no = (doc.custom_room_number or \"\")\r\n\r\n# # 1⃣ Mandatory check\r\n# if not room_no:\r\n# frappe.throw(\"Room Number is mandatory.\")\r\n\r\n# # 2⃣ Fetch Infrastructure Location\r\n# infra_list = frappe.get_all(\r\n# \"Infrastructure Location\",\r\n# filters={\"room_no\": room_no},\r\n# fields=[\"name\", \"building\", \"department\", \"location\"]\r\n# )\r\n\r\n# # 3⃣ Not found\r\n# if not infra_list:\r\n# frappe.throw(f\"No Infrastructure Location found for Room No: {room_no}\")\r\n\r\n# # 4⃣ Duplicate check\r\n# if len(infra_list) > 1:\r\n# names = \"\\n\".join([d[\"name\"] for d in infra_list])\r\n# frappe.throw(\r\n# f\"\"\"Duplicate Room Number '{room_no}' found:\r\n# {names}\r\n# Fix Infrastructure Location master first.\"\"\"\r\n# )\r\n\r\n# # 5⃣ Auto-fill Asset fields\r\n# infra = infra_list[0]\r\n# doc.custom_building = infra.get(\"building\")\r\n# doc.department = infra.get(\"department\")\r\n# doc.location = infra.get(\"location\")\r\n\r\n\r\nroom_no = (doc.custom_room_number or \"\")\r\n\r\n# If Room No is blank → allow import (skip validation)\r\nif not room_no:\r\n pass\r\n\r\nelse:\r\n # Fetch Infrastructure Location (ONLY check_xqxx = 0)\r\n infra_list = frappe.get_all(\r\n \"Infrastructure Location\",\r\n filters={\r\n \"room_no\": room_no,\r\n \"check_xqxx\": 0 # Only consider check_xqxx = 0\r\n },\r\n fields=[\"name\", \"building\", \"department\", \"location\"]\r\n )\r\n\r\n # Not found\r\n if not infra_list:\r\n frappe.throw(f\"No Infrastructure Location found for Room No: {room_no}\")\r\n\r\n # Duplicate check\r\n if len(infra_list) > 1:\r\n names = \"\\n\".join([d[\"name\"] for d in infra_list])\r\n frappe.throw(\r\n f\"\"\"Duplicate Room Number '{room_no}' found:\r\n{names}\r\nFix Infrastructure Location master first.\"\"\"\r\n )\r\n\r\n # Auto-fill Asset fields\r\n infra = infra_list[0]\r\n doc.custom_building = infra.get(\"building\")\r\n doc.department = infra.get(\"department\")\r\n doc.location = infra.get(\"location\")\r\n",
"script_type": "DocType Event"
},
{
"allow_guest": 0,
"api_method": null,
"cron_format": null,
"disabled": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Submit",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2026-02-18 15:22:06.045753",
"module": "Asset Lite",
"name": "Delete Request",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Delete Request",
"script": "# Server Script: Delete Request - on_update\r\nif doc.workflow_state == \"Approved\" and doc.status != \"Deleted\":\r\n try:\r\n target = frappe.get_doc(doc.target_doctype, doc.target_name)\r\n target.delete()\r\n doc.db_set(\"status\", \"Deleted\")\r\n frappe.msgprint(f\"Document {doc.target_name} has been deleted.\")\r\n except Exception as e:\r\n frappe.throw(f\"Could not delete: {str(e)}\")",
"script_type": "DocType 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-03-06 07:21:59.650638",
"module": "Asset Lite",
"name": "rejected_on",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "# Capture Rejected timestamp only when workflow state changes\r\n\r\nif doc.workflow_state == \"Rejected\" and doc.get_doc_before_save():\r\n\r\n previous = doc.get_doc_before_save()\r\n\r\n if previous.workflow_state != \"Rejected\":\r\n doc.custom_rejected_on = frappe.utils.now_datetime()\r\n",
"script_type": "DocType 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-03-06 07:21:59.593079",
"module": "Asset Lite",
"name": "For Time to repair",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "# Get previous document\r\nprevious_doc = doc.get_doc_before_save()\r\nprevious_state = previous_doc.workflow_state if previous_doc else None\r\n\r\n\r\n# 1⃣ When state becomes Sent to Work Control\r\nif doc.workflow_state == \"Sent to Work Control\":\r\n\r\n # Always update open time\r\n doc.custom_open_time = frappe.utils.now_datetime()\r\n\r\n # If NOT coming from Draft → clear first_responded_on\r\n if previous_state != \"Draft\":\r\n doc.first_responded_on = None\r\n\r\n\r\n# 2⃣ When state becomes Pending Approval\r\nif doc.workflow_state == \"Pending Approval\":\r\n\r\n # Always update pending approval time\r\n doc.custom_pending_approval_time = frappe.utils.now_datetime()\r\n\r\n\r\n# 3⃣ Calculate Repair Time\r\nif doc.custom_open_time and doc.custom_pending_approval_time:\r\n\r\n start = frappe.utils.get_datetime(doc.custom_open_time)\r\n end = frappe.utils.get_datetime(doc.custom_pending_approval_time)\r\n\r\n hours = (end - start).total_seconds() / 3600\r\n\r\n doc.custom_time_for_repair = round(hours, 2)",
"script_type": "DocType Event"
}
]