21 lines
8.4 KiB
JSON
21 lines
8.4 KiB
JSON
[
|
|
{
|
|
"allow_guest": 0,
|
|
"api_method": null,
|
|
"cron_format": null,
|
|
"disabled": 0,
|
|
"docstatus": 0,
|
|
"doctype": "Server Script",
|
|
"doctype_event": "Before Insert",
|
|
"enable_rate_limit": 0,
|
|
"event_frequency": "Daily",
|
|
"modified": "2026-06-09 13:40:45.248212",
|
|
"module": "SFDA Parser",
|
|
"name": "Check the Serial nos present from sfda parser",
|
|
"rate_limit_count": 5,
|
|
"rate_limit_seconds": 86400,
|
|
"reference_doctype": null,
|
|
"script": "def normalize_values(raw):\r\n if not raw:\r\n return []\r\n return [v.strip() for v in str(raw).split(\",\") if v.strip()]\r\n\r\n\r\n# Users having BOTH \"System Manager\" and \"Cluster Manager\"\r\nboth_roles = frappe.get_all(\r\n \"Has Role\",\r\n filters={\r\n \"role\": [\"in\", [\"System Manager\", \"Cluster Manager\"]],\r\n \"parenttype\": \"User\"\r\n },\r\n fields=[\"parent\", \"role\"],\r\n limit_page_length=0\r\n)\r\n\r\nrole_map = {}\r\nfor r in both_roles:\r\n role_map.setdefault(r.parent, set()).add(r.role)\r\n\r\nrecall_users = [\r\n u for u, roles in role_map.items()\r\n if {\"System Manager\", \"Cluster Manager\"}.issubset(roles)\r\n]\r\n\r\nrecall_users = frappe.get_all(\r\n \"User\",\r\n filters={\"name\": [\"in\", recall_users], \"enabled\": 1},\r\n pluck=\"name\",\r\n limit_page_length=0\r\n) if recall_users else []\r\n\r\nsite_url = frappe.utils.get_url()\r\n\r\nsfda_entries = frappe.get_all(\r\n \"SFDA Entries\",\r\n filters={\"passed\": 0},\r\n fields=[\"name\"],\r\n limit_page_length=0\r\n)\r\n\r\nfor entry in sfda_entries:\r\n doc = frappe.get_doc(\"SFDA Entries\", entry.name)\r\n\r\n entry_link = f\"{site_url}/asm_app/sfda-entries/{doc.name}\"\r\n\r\n # rows that matched (asset found) and rows that did NOT match\r\n matched_rows = [] # list of dicts: {ncmdr_ref, serial, asset}\r\n unmatched_refs = [] # list of ncmdr_ref values with no match\r\n\r\n for row in doc.device_list:\r\n catalog_numbers = normalize_values(row.catalog_number)\r\n serial_numbers = normalize_values(row.serial_no)\r\n all_values = list(set(catalog_numbers + serial_numbers))\r\n\r\n row_matched = False\r\n\r\n if all_values:\r\n matched_assets = frappe.get_all(\r\n \"Asset\",\r\n filters={\"custom_serial_number\": [\"in\", all_values]},\r\n fields=[\"name\", \"custom_serial_number\"],\r\n limit_page_length=0\r\n )\r\n\r\n for asset in matched_assets:\r\n frappe.db.set_value(\r\n \"Asset\", asset.name, \"custom_recalled\", \"Yes\"\r\n )\r\n matched_rows.append({\r\n \"ncmdr_ref\": row.ncmdr_ref or \"N/A\",\r\n \"serial\": asset.custom_serial_number,\r\n \"asset\": asset.name\r\n })\r\n row_matched = True\r\n\r\n # Set Serial No Matching on the child row\r\n row.serial_no_matching = \"Yes\" if row_matched else \"No\"\r\n\r\n if not row_matched:\r\n unmatched_refs.append(row.ncmdr_ref or \"N/A\")\r\n\r\n # Persist serial_no_matching changes on child rows\r\n doc.save(ignore_permissions=True)\r\n\r\n # ------------------------------------------------------------------\r\n # NOTIFICATION 1 -> Matching list (serial no + asset id)\r\n # ------------------------------------------------------------------\r\n if matched_rows:\r\n rows_html = \"\".join(\r\n f\"<tr>\"\r\n f\"<td style='padding:6px;border:1px solid #ddd;'>{m['ncmdr_ref']}</td>\"\r\n f\"<td style='padding:6px;border:1px solid #ddd;'>{m['serial']}</td>\"\r\n f\"<td style='padding:6px;border:1px solid #ddd;'>{m['asset']}</td>\"\r\n f\"</tr>\"\r\n for m in matched_rows\r\n )\r\n\r\n subject = f\"SFDA Recall Match Found: {doc.name}\"\r\n\r\n message = f\"\"\"\r\n <h3>Recall Match Found</h3>\r\n <p>The following assets matched a recall in SFDA Entry <b>{doc.name}</b>\r\n and have been marked as recalled.</p>\r\n\r\n <table style=\"border-collapse:collapse;border:1px solid #ddd;\">\r\n <tr style=\"background:#f4f4f4;\">\r\n <th style=\"padding:6px;border:1px solid #ddd;text-align:left;\">NCMDR Ref</th>\r\n <th style=\"padding:6px;border:1px solid #ddd;text-align:left;\">Serial / Catalog No</th>\r\n <th style=\"padding:6px;border:1px solid #ddd;text-align:left;\">Asset ID</th>\r\n </tr>\r\n {rows_html}\r\n </table>\r\n\r\n <p style=\"margin-top:15px;\">\r\n <a href=\"{entry_link}\"\r\n style=\"background:#0b5cff;color:#fff;padding:8px 14px;\r\n text-decoration:none;border-radius:4px;\">\r\n Open SFDA Entry\r\n </a>\r\n </p>\r\n \"\"\"\r\n\r\n for user in recall_users:\r\n frappe.get_doc({\r\n \"doctype\": \"Notification Log\",\r\n \"for_user\": user,\r\n \"type\": \"Alert\",\r\n \"subject\": subject,\r\n \"email_content\": message,\r\n \"document_type\": \"SFDA Entries\",\r\n \"document_name\": doc.name\r\n }).insert(ignore_permissions=True)\r\n\r\n if recall_users:\r\n frappe.sendmail(\r\n recipients=recall_users,\r\n subject=subject,\r\n message=message,\r\n reference_doctype=\"SFDA Entries\",\r\n reference_name=doc.name\r\n )\r\n\r\n frappe.log_error(\r\n title=f\"SFDA Recall Matched - {doc.name}\",\r\n message=(\r\n f\"SFDA Entry: {doc.name}\\n\"\r\n f\"Matched: {matched_rows}\\n\"\r\n f\"Recipients: {', '.join(recall_users)}\"\r\n )\r\n )\r\n\r\n # ------------------------------------------------------------------\r\n # NOTIFICATION 2 -> Non-matching list (NCMDR Ref values)\r\n # ------------------------------------------------------------------\r\n if unmatched_refs:\r\n # de-duplicate while preserving order\r\n seen = set()\r\n unique_refs = [\r\n r for r in unmatched_refs if not (r in seen or seen.add(r))\r\n ]\r\n\r\n refs_html = \"\".join(\r\n f\"<li style='margin-bottom:4px;'>{ref}</li>\" for ref in unique_refs\r\n )\r\n\r\n subject = f\"SFDA Manual Review Required: {doc.name}\"\r\n\r\n message = f\"\"\"\r\n <h3>Manual Review Required</h3>\r\n <p>No matching asset was found for the following recall references in\r\n SFDA Entry <b>{doc.name}</b>. Please review these manually.</p>\r\n\r\n <ul>\r\n {refs_html}\r\n </ul>\r\n\r\n <p style=\"margin-top:15px;\">\r\n <a href=\"{entry_link}\"\r\n style=\"background:#d9534f;color:#fff;padding:8px 14px;\r\n text-decoration:none;border-radius:4px;\">\r\n Open SFDA Entry\r\n </a>\r\n </p>\r\n \"\"\"\r\n\r\n for user in recall_users:\r\n frappe.get_doc({\r\n \"doctype\": \"Notification Log\",\r\n \"for_user\": user,\r\n \"type\": \"Alert\",\r\n \"subject\": subject,\r\n \"email_content\": message,\r\n \"document_type\": \"SFDA Entries\",\r\n \"document_name\": doc.name\r\n }).insert(ignore_permissions=True)\r\n\r\n if recall_users:\r\n frappe.sendmail(\r\n recipients=recall_users,\r\n subject=subject,\r\n message=message,\r\n reference_doctype=\"SFDA Entries\",\r\n reference_name=doc.name\r\n )\r\n\r\n frappe.log_error(\r\n title=f\"SFDA Manual Review Required - {doc.name}\",\r\n message=(\r\n f\"SFDA Entry: {doc.name}\\n\"\r\n f\"Unmatched Refs: {', '.join(unique_refs)}\\n\"\r\n f\"Recipients: {', '.join(recall_users)}\"\r\n )\r\n )\r\n\r\n # Mark entry as processed\r\n doc.passed = 1\r\n doc.passed_date = frappe.utils.now_datetime()\r\n doc.save(ignore_permissions=True)\r\n\r\nfrappe.db.commit()",
|
|
"script_type": "Scheduler Event"
|
|
}
|
|
] |