KFSH/asset_lite/fixtures/server_script.json
2025-12-11 13:37:26 +05:30

667 lines
70 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters

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": "2025-08-26 13:50:56.568464",
"module": "Asset Lite",
"name": "Auto Set User Names",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Work_Order",
"script": "amount = 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 \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\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": "2025-08-26 13:49:25.456532",
"module": "Asset Lite",
"name": "Location",
"rate_limit_count": 5,
"rate_limit_seconds": 86400,
"reference_doctype": "Asset",
"script": "# Server Script for Asset Doctype\r\nif 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": "2025-08-26 13:48:52.603499",
"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\": \"Bio Medical\",\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\": \"Biomedical\",\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": 0,
"docstatus": 0,
"doctype": "Server Script",
"doctype_event": "After Save",
"enable_rate_limit": 0,
"event_frequency": "All",
"modified": "2025-04-22 12:40:36.725618",
"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"
}
]