[ { "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

\"+doc.subject+\"

Regards,
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 {item_code} in warehouse {warehouse}. \"\n f\"Available: {available_qty}, Required: {required_qty}.\"\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
\n Please provide your feedback for Work Order {doc.name}. \n Click here to provide your feedback.\n
\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 # Day‑based 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 # Month‑based 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

Dear {user_doc.full_name},

\r\n

This is the Planned PM Report for your hospital: {user_hospital}

\r\n

Period: {start_date} to {end_date}

\r\n

You can view the report here: {report_link}

\r\n

Regards,
Maintenance Team

\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

Dear Team,

\r\n

This is the Planned PM Report for the period: {start_date} to {end_date}.

\r\n

You can view the report here: {report_link1}

\r\n

Regards,
Maintenance Team

\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" } ]