### Install Biograph Application via Bench Source: https://github.com/tacten/biograph/blob/biograph-fh/README.md These commands are used to fetch the Biograph repository into the bench environment and install the healthcare module onto a specific site. Ensure that ERPNext is already installed and configured before executing these commands. ```bash bench get-app https://github.com/Tacten/biograph bench --site demo.com install-app healthcare ``` -------------------------------- ### Batch Create Lab Tests Source: https://context7.com/tacten/biograph/llms.txt Allows for the bulk creation of lab tests from source documents like Sales Invoices or Patient Encounters. Includes both the backend Python implementation and a frontend JavaScript call example. ```python from healthcare.healthcare.doctype.lab_test.lab_test import create_multiple @frappe.whitelist() def create_multiple(doctype, docname): if not doctype or not docname: frappe.throw(_("Sales Invoice or Patient Encounter is required to create Lab Tests"), title=_("Insufficient Data")) lab_test_created = False if doctype == "Sales Invoice": lab_test_created = create_lab_test_from_invoice(docname) elif doctype == "Patient Encounter": lab_test_created = create_lab_test_from_encounter(docname) if lab_test_created: frappe.msgprint(_("Lab Test(s) {0} created successfully").format(lab_test_created), indicator="green") ``` ```javascript frappe.call({ method: "healthcare.healthcare.doctype.lab_test.lab_test.create_multiple", args: { doctype: "Sales Invoice", docname: "SINV-00001" } }); ``` -------------------------------- ### Process Task Options and Insert Document in Python Source: https://github.com/tacten/biograph/wiki/In‐Patient-Management-Workflows:-Gaps-and-Areas-for-Enhancements This Python code snippet processes task options, calculates the requested start time based on time offsets, and inserts a new document into the system. It handles conditional logic for time offsets and filters out empty values before document insertion. Dependencies include the 'frappe' library and a helper function 'add_to_date'. ```python options = { "mandatory": task.mandatory, "duration": task.task_duration, "task_doctype": task.task_doctype, } if task.time_offset: time_offset = task.time_offset if not post_event else 0 - task.time_offset requested_start_time = add_to_date(start_time, seconds=time_offset) else: requested_start_time = start_time options.update({"requested_start_time": requested_start_time}) options = {key: value for (key, value) in options.items() if value} frappe.get_doc(options).insert() ``` -------------------------------- ### Get Healthcare Services to Invoice (Python) Source: https://context7.com/tacten/biograph/llms.txt Retrieves all billable healthcare services for a patient that have not yet been invoiced. It aggregates services from appointments, encounters, lab tests, clinical procedures, inpatient services, therapy plans/sessions, service requests, observations, and package subscriptions. ```python from healthcare.healthcare.utils import get_healthcare_services_to_invoice @frappe.whitelist() def get_healthcare_services_to_invoice(patient, customer, company, link_customer=False): """Get all uninvoiced healthcare services for a patient""" patient = frappe.get_doc("Patient", patient) if not customer: customer = patient.customer items_to_invoice = [] if patient: # Collect all billable services items_to_invoice += get_appointments_to_invoice(patient, company) items_to_invoice += get_encounters_to_invoice(patient, company) items_to_invoice += get_lab_tests_to_invoice(patient, company) items_to_invoice += get_clinical_procedures_to_invoice(patient, company) items_to_invoice += get_inpatient_services_to_invoice(patient, company) items_to_invoice += get_therapy_plans_to_invoice(patient, company) items_to_invoice += get_therapy_sessions_to_invoice(patient, company) items_to_invoice += get_service_requests_to_invoice(patient, company) items_to_invoice += get_observations_to_invoice(patient, company) items_to_invoice += get_package_subscriptions_to_invoice(patient, company) validate_customer_created(patient, customer, link_customer) return items_to_invoice # Returns list of dicts with: reference_type, reference_name, service, rate, date ``` -------------------------------- ### Create and Retrieve Patient Record in Biograph Source: https://context7.com/tacten/biograph/llms.txt Demonstrates how to create a new patient record, retrieve an existing patient's details, and get a patient's age using the Frappe framework's API. It requires the 'Patient' DocType to be defined. ```python import frappe # Create a new patient patient = frappe.new_doc("Patient") patient.first_name = "John" patient.last_name = "Doe" patient.sex = "Male" patient.dob = "1985-03-15" patient.mobile = "+1234567890" patient.email = "john.doe@example.com" patient.save() # Retrieve a patient patient = frappe.get_doc("Patient", "HLC-PAT-00001") # Get patient age age = patient.get_age() ``` -------------------------------- ### Get Pending Invoices for Inpatient Record (Python) Source: https://github.com/tacten/biograph/wiki/In‐Patient-Management-Workflows:-Gaps-and-Areas-for-Enhancements Retrieves a dictionary of pending invoices related to an inpatient record, checking for unbilled inpatient occupancies and other document types like appointments and encounters. It aggregates pending items. ```python def get_pending_invoices(inpatient_record): pending_invoices = {} if inpatient_record.inpatient_occupancies: service_unit_names = False for inpatient_occupancy in inpatient_record.inpatient_occupancies: if not inpatient_occupancy.invoiced: if is_service_unit_billable(inpatient_occupancy.service_unit): if service_unit_names: service_unit_names += ", " + inpatient_occupancy.service_unit else: service_unit_names = inpatient_occupancy.service_unit if service_unit_names: pending_invoices["Inpatient Occupancy"] = service_unit_names docs = ["Patient Appointment", "Patient Encounter", "Lab Test", "Clinical Procedure"] for doc in docs: doc_name_list = get_unbilled_inpatient_docs(doc, inpatient_record) if doc_name_list: pending_invoices = get_pending_doc(doc, doc_name_list, pending_invoices) return pending_invoices def get_pending_doc(doc, doc_name_list, pending_invoices): if doc_name_list: doc_ids = False for doc_name in doc_name_list: doc_link = get_link_to_form(doc, doc_name.name) if doc_ids: doc_ids += ", " + doc_link else: doc_ids = doc_link if doc_ids: pending_invoices[doc] = doc_ids return pending_invoices ``` -------------------------------- ### Get Service Unit Tree Children (Python) Source: https://context7.com/tacten/biograph/llms.txt Retrieves children nodes for the Healthcare Service Unit tree view. It supports fetching root nodes or nodes based on a parent and company, and includes occupancy counts for group nodes. Dependencies include frappe modules. ```python from healthcare.healthcare.utils import get_children @frappe.whitelist() def get_children(doctype, parent=None, company=None, is_root=False): """Get children nodes for Healthcare Service Unit tree""" parent_fieldname = "parent_" + doctype.lower().replace(" ", "_") fields = ["name as value", "is_group as expandable", "lft", "rgt"] if is_root: filters = [[parent_fieldname, "in", [None, ""]]] filters.append(["company", "=", company]) else: filters = [[parent_fieldname, "=", parent]] fields += ["service_unit_type", "allow_appointments", "inpatient_occupancy", "occupancy_status"] service_units = frappe.get_list(doctype, fields=fields, filters=filters) # Add occupancy counts for group nodes for each in service_units: if each["expandable"] == 1: available_count = frappe.db.count( "Healthcare Service Unit", filters={"parent_healthcare_service_unit": each["value"], "inpatient_occupancy": 1}, ) if available_count > 0: occupied_count = frappe.db.count( "Healthcare Service Unit", filters={ "parent_healthcare_service_unit": each["value"], "inpatient_occupancy": 1, "occupancy_status": "Occupied", }, ) each["occupied_of_available"] = f"{occupied_count} Occupied of {available_count}" return service_units ``` -------------------------------- ### Create Patient Encounters Source: https://context7.com/tacten/biograph/llms.txt Demonstrates how to programmatically create a Patient Encounter document. It includes linking to an appointment, adding symptoms, recording diagnoses, and prescribing lab tests. ```python import frappe # Create an encounter from an appointment encounter = frappe.new_doc("Patient Encounter") encounter.patient = "HLC-PAT-00001" encounter.practitioner = "HLC-PRAC-00001" encounter.encounter_date = frappe.utils.today() encounter.appointment = "HLC-APP-00001" # Add symptoms encounter.append("symptoms", { "complaint": "Chest pain", "duration": 2, "duration_in": "Days" }) # Add diagnosis encounter.append("diagnosis", { "diagnosis": "Angina Pectoris", "medical_code": "I20.9" }) # Prescribe lab tests via Service Request encounter.append("lab_test_prescription", { "lab_test_code": "CBC", "lab_test_name": "Complete Blood Count" }) encounter.save() encounter.submit() ``` -------------------------------- ### GET /api/method/get_lab_test_prescribed Source: https://context7.com/tacten/biograph/llms.txt Retrieves a list of pending lab test orders for a specific patient. ```APIDOC ## GET /api/method/get_lab_test_prescribed ### Description Fetches all lab tests prescribed to a patient that have not yet been completed. ### Method GET ### Endpoint /api/method/get_lab_test_prescribed ### Parameters #### Query Parameters - **patient** (string) - Required - The ID of the patient to query. ### Request Example GET /api/method/get_lab_test_prescribed?patient=HLC-PAT-00001 ### Response #### Success Response (200) - **template_dn** (string) - Lab test template name - **order_group** (string) - Grouping identifier - **billing_status** (string) - Current billing status - **practitioner** (string) - Prescribing practitioner - **order_date** (date) - Date of order - **name** (string) - Unique identifier of the service request #### Response Example [ { "template_dn": "Complete Blood Count", "order_group": "GRP-001", "billing_status": "Unbilled", "practitioner": "Dr. Smith", "order_date": "2023-10-27", "name": "HLC-SR-00001" } ] ``` -------------------------------- ### Get Lab Tests to Invoice (Python) Source: https://context7.com/tacten/biograph/llms.txt Retrieves a list of uninvoiced lab tests for a given patient and company. It filters for completed lab tests that have an associated billable item and have not yet been invoiced. ```python from healthcare.healthcare.utils import get_lab_tests_to_invoice def get_lab_tests_to_invoice(patient, company): """Get all uninvoiced lab tests""" lab_tests_to_invoice = [] lab_tests = frappe.get_list( "Lab Test", fields=["name", "template", "date"], filters={ "patient": patient.name, "company": company, "invoiced": False, "docstatus": 1, "service_request": "", }, order_by="date desc", ) for lab_test in lab_tests: item, is_billable = frappe.get_cached_value( "Lab Test Template", lab_test.template, ["item", "is_billable"] ) if is_billable: lab_tests_to_invoice.append({ "reference_type": "Lab Test", "reference_name": lab_test.name, "service": item, "date": lab_test.date }) return lab_tests_to_invoice ``` -------------------------------- ### Create Stock Entry for Medication Orders (Python) Source: https://github.com/tacten/biograph/wiki/In‐Patient-Management-Workflows:-Gaps-and-Areas-for-Enhancements Generates a new 'Stock Entry' document for issuing materials related to medication orders. It populates the stock entry with item details, quantities, and cost information, then submits it. ```python def make_stock_entry(self): stock_entry = frappe.new_doc("Stock Entry") stock_entry.purpose = "Material Issue" stock_entry.set_stock_entry_type() stock_entry.from_warehouse = self.warehouse stock_entry.company = self.company stock_entry.inpatient_medication_entry = self.name cost_center = frappe.get_cached_value("Company", self.company, "cost_center") expense_account = get_account(None, "expense_account", "Healthcare Settings", self.company) for entry in self.medication_orders: se_child = stock_entry.append("items") se_child.item_code = entry.drug_code se_child.item_name = entry.drug_name se_child.uom = frappe.db.get_value("Item", entry.drug_code, "stock_uom") se_child.stock_uom = se_child.uom se_child.qty = flt(entry.dosage) # in stock uom se_child.conversion_factor = 1 se_child.cost_center = cost_center se_child.expense_account = expense_account # references se_child.patient = entry.patient se_child.inpatient_medication_entry_child = entry.name stock_entry.submit() return stock_entry.name ``` -------------------------------- ### Create Healthcare Service Units (Python) Source: https://github.com/tacten/biograph/wiki/Patient-Inpatient-Admission-Flow This Python script generates multiple Healthcare Service Unit documents. It calculates the next available suffix for service unit names and inserts new documents into the database, logging any failures. Dependencies include the 'frappe' framework. ```python capacity = cint(data.get("service_unit_capacity") or 1) service_unit = { "doctype": "Healthcare Service Unit", "parent_healthcare_service_unit": parent if parent != company else None, "service_unit_type": data.get("service_unit_type") or None, "service_unit_capacity": capacity if capacity > 0 else 1, "warehouse": data.get("warehouse") or None, "company": company, } service_unit_name = "{}".format(data.get("healthcare_service_unit_name").strip(" -")) last_suffix = frappe.db.sql( """ SELECT IFNULL(MAX(CAST(SUBSTRING(name FROM %(start)s FOR 4) AS UNSIGNED)), 0) FROM `tabHealthcare Service Unit` WHERE name like %(prefix)s AND company=%(company)s """, { "start": len(service_unit_name) + 2, "prefix": "{}-%".format(service_unit_name), "company": company, }, as_list=1, )[0][0] start_suffix = cint(last_suffix) + 1 failed_list = [] for i in range(start_suffix, count + start_suffix): # name to be in the form WARD-#### service_unit["healthcare_service_unit_name"] = "{}-{}".format( service_unit_name, cstr("%0*d" % (4, i)) ) service_unit_doc = frappe.get_doc(service_unit) try: service_unit_doc.insert() except Exception: failed_list.append(service_unit["healthcare_service_unit_name"]) return failed_list ``` -------------------------------- ### Frappe Static Data Middleware Path Resolution (Python) Source: https://github.com/tacten/biograph/wiki/Error-on-submit This snippet from Frappe's middleware demonstrates how it resolves file paths for static data, incorporating the site name to ensure correct directory access. It uses `os.path.join` for path construction. ```Python site = get_site_name(frappe.app._site or self.environ.get("HTTP_HOST")) path = os.path.join(directory, site, "public", "files", cstr(path)) ``` -------------------------------- ### Get Medical Codes from Templates Source: https://context7.com/tacten/biograph/llms.txt Retrieves medical codes (e.g., ICD, SNOMED) from 'Codification Table' entries associated with a specific template. It can filter codes by a given code standard. Useful for extracting structured medical data. ```python from healthcare.healthcare.utils import get_medical_codes @frappe.whitelist() def get_medical_codes(template_dt, template_dn, code_standard=None): """Get codification table entries from templates""" filters = {"parent": template_dn, "parenttype": template_dt} if code_standard: filters["code_system"] = code_standard return frappe.db.get_all( "Codification Table", filters=filters, fields=["code_value", "code", "system", "definition", "code_system"], ) # Usage: # codes = get_medical_codes("Lab Test Template", "CBC", "ICD-10") ``` -------------------------------- ### Constructing a Duplicate Check Filter Object Source: https://github.com/tacten/biograph/blob/biograph-fh/wiki/PATIENT-DUPLICATE-CHECKER-USAGE-DOC.md This JSON example illustrates how the system filters out empty fields. When a patient record is missing a value for a field like 'Mobile', the resulting filter object only contains the fields that have valid data. ```json { "first_name": "John", "last_name": "Smith" } ``` -------------------------------- ### Create Sample Collection and Observations Source: https://context7.com/tacten/biograph/llms.txt Automatically creates sample collection and observation records when a sales invoice is submitted. It checks for associated observation templates for invoice items and generates the necessary healthcare documents. ```python from healthcare.healthcare.utils import create_sample_collection_and_observation def create_sample_collection_and_observation(doc): """Create sample collections and observations from sales invoice items""" # Triggered by Healthcare Settings: create_observation_on_si_submit for item in doc.items: template_id = frappe.db.exists("Observation Template", {"item": item.item_code}) if template_id: # Creates Sample Collection document sample_collection = create_sample_collection(doc, patient) # Creates Observation documents based on template # Handles grouped templates with components recursively insert_observation_and_sample_collection( doc, patient, obs, sample_collection, child ) # Creates Diagnostic Report to group observations if diag_report_required: insert_diagnostic_report(doc, patient, sample_collection.name) ``` -------------------------------- ### Nursing Task Status Updates - Python Source: https://github.com/tacten/biograph/wiki/Patient-Inpatient-Admission-Flow Manages the status updates for Nursing Tasks. It includes validation for completing tasks, setting start and end times, and calculating task duration. It also handles notifications upon updates. ```python def on_update_after_submit(self): if self.status == "Completed" and self.task_doctype and not self.task_document_name: frappe.throw(_("Not Allowed to 'Complete' Nursing Task without linking Task Document")) if self.status == "Draft": frappe.throw(_("Nursing Task cannot be 'Draft' after submission")) if self.status == "In Progress": if not self.task_start_time: self.db_set("task_start_time", now_datetime()) elif self.status == "Completed": task_end_time = now_datetime() self.db_set( { "task_end_time": task_end_time, "task_duration": time_diff_in_seconds(task_end_time, self.task_start_time), } ) self.notify_update() ``` -------------------------------- ### Create Nursing Tasks from Template - Python Source: https://github.com/tacten/biograph/wiki/Patient-Inpatient-Admission-Flow A class method to create multiple nursing tasks based on a provided template. It fetches tasks from a 'Nursing Checklist Template Task' and uses another method to create them, optionally posting an event. ```python @classmethod def create_nursing_tasks_from_template(cls, template, doc, start_time=None, post_event=True): tasks = frappe.get_all( "Nursing Checklist Template Task", filters={"parent": template}, fields=["*"] ) start_time = start_time or now_datetime() NursingTask.create_nursing_tasks(tasks, doc, start_time, post_event) ``` -------------------------------- ### Create Therapy Session from Service Request Source: https://github.com/tacten/biograph/wiki/Link-Between-Therapy-Session-and-Service-Request-of-Therapy-Plan Handles the creation of a Therapy Session based on a Service Request. It includes checks for existing sessions and payment status, and populates the new session with relevant data from the service request. ```python def make_therapy_session(service_request): if isinstance(service_request, string_types): service_request = json.loads(service_request) service_request = frappe._dict(service_request) if ( frappe.db.get_single_value("Healthcare Settings", "process_service_request_only_if_paid") and service_request.billing_status != "Invoiced" ): frappe.throw( _("Service Request need to be invoiced before proceeding"), title=_("Payment Required") ) doc = frappe.new_doc("Therapy Session") doc.therapy_type = service_request.template_dn doc.service_request = service_request.name doc.company = service_request.company doc.patient = service_request.patient doc.patient_name = service_request.patient_name doc.gender = service_request.patient_gender doc.patient_age = service_request.patient_age_data doc.practitioner = service_request.practitioner doc.department = service_request.medical_department doc.start_date = service_request.occurrence_date doc.start_time = service_request.occurrence_time doc.invoiced = service_request.invoiced return doc ``` ```javascript } else if (frm.doc.template_dt === 'Therapy Type') { frm.add_custom_button(__("Therapy Session"), function() { frappe.db.get_value("Therapy Session", {"service_request":frm.doc.name, "docstatus":["!=", 2]}, "name") .then(r => { if (Object.keys(r.message).length == 0) { frm.trigger('make_therapy_session'); } else { if (r.message && r.message.name) { frappe.set_route("Form", "Therapy Session", r.message.name); frappe.show_alert({ message: __(`Therapy Session is already created`), indicator: "info", }); } } }) }, __('Create')); ``` -------------------------------- ### Python Frappe API Request Handling Source: https://github.com/tacten/biograph/wiki/Error-on-submit Illustrates the request handling pipeline for Frappe's API endpoints. It covers routing API requests, executing commands, and building responses, including handling specific exceptions like DoesNotExistError. ```python File "/workspace/development/frappe-bench/apps/frappe/frappe/app.py", line 114, in application ) frappe.handler.handle() response = frappe.utils.response.build_response("json") elif request.path.startswith("/api/"): response = frappe.api.handle(request) ^^^^^^^^^^^^^^^^^^^^^^^ elif request.path.startswith("/backups"): response = frappe.utils.response.download_backup(request.path) elif request.path.startswith("/private/files/") File "/workspace/development/frappe-bench/apps/frappe/frappe/api/__init__.py", line 49, in handle try: endpoint, arguments = API_URL_MAP.bind_to_environ(request.environ).match() except NotFound: # Wrap 404 - backward compatiblity raise frappe.DoesNotExistError data = endpoint(**arguments) ^^^^^^^^^^^^^^^^^^^^^ if isinstance(data, Response): return data if data is not None: frappe.response["data"] = data File "/workspace/development/frappe-bench/apps/frappe/frappe/api/v1.py", line 36, in handle_rpc_call import frappe.handler method = method.split("/")[0] # for backward compatiblity frappe.form_dict.cmd = method return frappe.handler.handle() ^^^^^^^^^^^^^^^^^^^^^^^ def create_doc(doctype: str): data = get_request_form_data() data.pop("doctype", None) ``` -------------------------------- ### Manage Nursing Task Status Updates (Python) Source: https://github.com/tacten/biograph/wiki/In‐Patient-Management-Workflows:-Gaps-and-Areas-for-Enhancements This method handles updates to a nursing task after it has been submitted. It enforces rules such as requiring a linked task document for 'Completed' tasks and disallowing 'Draft' status post-submission. It also records start and end times and calculates task duration. ```python def on_update_after_submit(self): if self.status == "Completed" and self.task_doctype and not self.task_document_name: frappe.throw(_("Not Allowed to 'Complete' Nursing Task without linking Task Document")) if self.status == "Draft": frappe.throw(_("Nursing Task cannot be 'Draft' after submission")) if self.status == "In Progress": if not self.task_start_time: self.db_set("task_start_time", now_datetime()) elif self.status == "Completed": task_end_time = now_datetime() self.db_set( { "task_end_time": task_end_time, "task_duration": time_diff_in_seconds(task_end_time, self.task_start_time), } ) self.notify_update() ``` -------------------------------- ### Create Nursing Tasks from Template (Python) Source: https://github.com/tacten/biograph/wiki/In‐Patient-Management-Workflows:-Gaps-and-Areas-for-Enhancements This class method facilitates the creation of nursing tasks based on a predefined template. It retrieves tasks from a 'Nursing Checklist Template Task', determines the relevant service unit and medical department, and then calls another method to create the actual 'Nursing Task' documents. ```python @classmethod def create_nursing_tasks_from_template(cls, template, doc, start_time=None, post_event=True): tasks = frappe.get_all( "Nursing Checklist Template Task", filters={"parent": template}, fields=["*"], ) start_time = start_time or now_datetime() NursingTask.create_nursing_tasks(tasks, doc, start_time, post_event) @classmethod def create_nursing_tasks(cls, tasks, doc, start_time, post_event=True): for task in tasks: medical_department = ( doc.get("department") if doc.get("department") else doc.get("medical_department") ) if doc.get("doctype") == "Inpatient Record": service_unit = ( frappe.db.get_value("Inpatient Occupancy", {"parent": doc.name, "left": 0}, "service_unit"), ) else: service_unit = ( doc.get("service_unit") if doc.get("service_unit") else doc.get("healthcare_service_unit") ) options = { "doctype": "Nursing Task", "status": "Requested", "company": doc.get("company", get_default_company()), "service_unit": service_unit, "medical_department": medical_department, "reference_doctype": doc.get("doctype"), "reference_name": doc.get("name"), "patient": doc.get("patient"), "activity": task.activity, ``` -------------------------------- ### Admit Patient to Inpatient Record (Python) Source: https://github.com/tacten/biograph/wiki/In‐Patient-Management-Workflows:-Gaps-and-Areas-for-Enhancements Handles patient admission by setting admission datetime, status to 'Admitted', and expected discharge date. It also initializes inpatient occupancies and transfers the patient to a service unit. ```python def admit_patient(inpatient_record, service_unit, check_in, expected_discharge=None): validate_nursing_tasks(inpatient_record) inpatient_record.admitted_datetime = check_in inpatient_record.status = "Admitted" inpatient_record.expected_discharge = expected_discharge inpatient_record.set("inpatient_occupancies", []) transfer_patient(inpatient_record, service_unit, check_in) frappe.db.set_value( "Patient", inpatient_record.patient, {"inpatient_status": "Admitted", "inpatient_record": inpatient_record.name}, ) ``` -------------------------------- ### Python Frappe Command Execution Source: https://github.com/tacten/biograph/wiki/Error-on-submit Details the process of executing commands within the Frappe framework. This includes validating whitelisted methods, checking HTTP method compatibility, and ultimately calling the specified function with provided arguments. ```python File "/workspace/development/frappe-bench/apps/frappe/frappe/handler.py", line 50, in handle cmd = frappe.local.form_dict.cmd data = None if cmd != "login": data = execute_cmd(cmd) ^^^^^^^^^^^^ # data can be an empty string or list which are valid responses if data is not None: if isinstance(data, Response): # method returns a response object, pass it on File "/workspace/development/frappe-bench/apps/frappe/frappe/handler.py", line 86, in execute_cmd if method != run_doc_method: is_whitelisted(method) is_valid_http_method(method) return frappe.call(method, **frappe.form_dict) ^^^^^^^^^^^^^^^^^^^^^^^^^^^ def run_server_script(server_script): ``` -------------------------------- ### Handle Incoming WSGI Application Request - Python Source: https://github.com/tacten/biograph/wiki/Error-on-submit This code snippet demonstrates how a WSGI application handles incoming requests within the Werkzeug framework. It wraps the application call in a 'ClosingIterator' to ensure cleanup tasks like rate limiting, recorder dumping, and session destruction are performed. It also catches HTTP exceptions and returns appropriate responses. ```python def application(environ, start_response): return ClosingIterator( app(environ, start_response), ( frappe.rate_limiter.update, frappe.recorder.dump, frappe.request.after_response.run, frappe.destroy, ) ) ``` -------------------------------- ### Create Service Requests for Healthcare Documents (Python) Source: https://github.com/tacten/biograph/wiki/In‐Patient-Management-Workflows:-Gaps-and-Areas-for-Enhancements This function iterates through lab tests, clinical procedures, and therapies, creating service requests if they don't already exist. It fetches relevant templates, retrieves order details, and submits the orders, linking them back to the original document. ```python template = "observation_template" elif lab_test.lab_test_code: template_doc = "Lab Test Template" template = "lab_test_code" else: continue if not lab_test.service_request: lab_template = frappe.get_doc(template_doc, lab_test.get(template)) order = self.get_order_details(lab_template, lab_test) order.insert(ignore_permissions=True, ignore_mandatory=True) order.submit() lab_test.service_request = order.name if self.procedure_prescription: for procedure in self.procedure_prescription: if not procedure.service_request: procedure_template = frappe.get_doc("Clinical Procedure Template", procedure.procedure) order = self.get_order_details(procedure_template, procedure) order.insert(ignore_permissions=True, ignore_mandatory=True) order.submit() procedure.service_request = order.name if self.therapies: for therapy in self.therapies: if not therapy.service_request: therapy_type = frappe.get_doc("Therapy Type", therapy.therapy_type) order = self.get_order_details(therapy_type, therapy) order.insert(ignore_permissions=True, ignore_mandatory=True) order.submit() therapy.service_request = order.name ``` -------------------------------- ### Frappe Message Printing and Real-time Updates (Python) Source: https://github.com/tacten/biograph/wiki/Error-on-submit This snippet details how messages are handled in Frappe, including appending them to a log or publishing them in real-time if the `realtime` flag is set. It also includes a call to `_raise_exception`. ```Python if realtime: publish_realtime(event="msgprint", message=out) else: message_log.append(out) _raise_exception() ``` -------------------------------- ### Process Stock Entry for Inpatient Medication (Python) Source: https://github.com/tacten/biograph/wiki/In‐Patient-Management-Workflows:-Gaps-and-Areas-for-Enhancements Handles the creation and submission of a stock entry for inpatient medication. It validates medication orders, updates stock if necessary, and generates success messages. ```python def on_submit(self): self.validate_medication_orders() success_msg = "" if self.update_stock: stock_entry = self.process_stock() success_msg += _("Stock Entry {0} created and ").format( frappe.bold(get_link_to_form("Stock Entry", stock_entry)) ) self.update_medication_orders() success_msg += _("Inpatient Medication Orders updated successfully") frappe.msgprint(success_msg, title=_("Success"), indicator="green") ``` -------------------------------- ### Admit Patient Dialog Implementation Source: https://github.com/tacten/biograph/wiki/In‐Patient-Management-Workflows:-Gaps-and-Areas-for-Enhancements This JavaScript function creates a modal dialog for admitting patients. It handles input fields for service units and dates, and triggers a server-side method call to process the admission. ```javascript let admit_patient_dialog = function(frm) { let dialog = new frappe.ui.Dialog({ title: 'Admit Patient', width: 100, fields: [ {fieldtype: 'Link', label: 'Service Unit Type', fieldname: 'service_unit_type', options: 'Healthcare Service Unit Type', default: frm.doc.admission_service_unit_type }, {fieldtype: 'Link', label: 'Service Unit', fieldname: 'service_unit', options: 'Healthcare Service Unit', reqd: 1 }, {fieldtype: 'Datetime', label: 'Admission Datetime', fieldname: 'check_in', reqd: 1, default: frappe.datetime.now_datetime() }, {fieldtype: 'Date', label: 'Expected Discharge', fieldname: 'expected_discharge', default: frm.doc.expected_length_of_stay ? frappe.datetime.add_days(frappe.datetime.now_datetime(), frm.doc.expected_length_of_stay) : '' } ], primary_action_label: __('Admit'), primary_action : function(){ let service_unit = dialog.get_value('service_unit'); let check_in = dialog.get_value('check_in'); let expected_discharge = null; if (dialog.get_value('expected_discharge')) { expected_discharge = dialog.get_value('expected_discharge'); } if (!service_unit && !check_in) { return; } frappe.call({ doc: frm.doc, method: 'admit', args:{ 'service_unit': service_unit, 'check_in': check_in, 'expected_discharge': expected_discharge }, callback: function(data) { if (!data.exc) { frm.reload_doc(); } }, freeze: true, freeze_message: __('Processing Patient Admission') }); frm.refresh_fields(); dialog.hide(); } }); dialog.show(); }; ``` -------------------------------- ### Python Safe Evaluation with Frappe Source: https://github.com/tacten/biograph/wiki/Error-on-submit Demonstrates Frappe's implementation of a safer evaluation mechanism for Python code, preventing execution of unsafe operations. It utilizes a restricted compilation policy and whitelists specific built-ins. ```python def safe_eval(code, eval_globals=None, eval_locals=None): """A safer `eval`""" from frappe.utils.safe_exec import safe_eval return safe_eval(code, eval_globals, eval_locals) def get_website_settings(key): if not hasattr(local, "website_settings"): try: File "/workspace/development/frappe-bench/apps/frappe/frappe/utils/safe_exec.py", line 136, in safe_eval eval_globals = {} eval_globals["__builtins__"] = {} eval_globals.update(WHITELISTED_SAFE_EVAL_GLOBALS) return eval( compile_restricted(code, filename="", policy=FrappeTransformer, mode="eval"), eval_globals, eval_locals, ) File "", line 1, in File "/workspace/development/frappe-bench/apps/frappe/frappe/utils/safe_exec.py", line 537, in _get_attr_for_eval def _get_attr_for_eval(object, name, default=ARGUMENT_NOT_SET): _validate_attribute_read(object, name) # Use vanilla getattr to raise correct attribute error. Safe exec has been supressing attribute # error which is bad for DX/UX in general. return getattr(object, name) if default is ARGUMENT_NOT_SET else getattr(object, name, default) ^^^^^^^^^^^^^^^^^^^^^ def _validate_attribute_read(object, name): if isinstance(name, str) and (name in UNSAFE_ATTRIBUTES): raise SyntaxError(f"{name} is an unsafe attribute") ``` -------------------------------- ### Frappe Notification Evaluation Logic (Python) Source: https://github.com/tacten/biograph/wiki/Error-on-submit This code demonstrates the logic for evaluating alerts and notifications within the Frappe framework. It checks if a notification has already been executed and evaluates it based on the event type and method name. ```Python def _evaluate_alert(alert): if alert.name in self.flags.notifications_executed: return evaluate_alert(self, alert.name, alert.event) self.flags.notifications_executed.append(alert.name) event_map = { "on_update": "Save", "after_insert": "New", } ``` -------------------------------- ### Manage Laboratory Tests Source: https://context7.com/tacten/biograph/llms.txt Provides functions to retrieve lab test templates and initialize new Lab Test documents. These utilities ensure that patient demographics and test configurations are correctly mapped. ```python from healthcare.healthcare.doctype.lab_test.lab_test import create_lab_test_doc, get_lab_test_template def get_lab_test_template(item): """Get Lab Test Template from item code""" template_id = frappe.db.exists("Lab Test Template", {"item": item}) if template_id: return frappe.get_doc("Lab Test Template", template_id) return False def create_lab_test_doc(practitioner, patient, template, company, invoiced=False, service_unit=None): """Create a Lab Test document from template""" lab_test = frappe.new_doc("Lab Test") lab_test.invoiced = invoiced lab_test.practitioner = practitioner lab_test.patient = patient.name lab_test.patient_age = patient.get_age() lab_test.patient_sex = patient.sex lab_test.email = patient.email lab_test.mobile = patient.mobile lab_test.report_preference = patient.report_preference lab_test.department = template.department lab_test.template = template.name lab_test.lab_test_group = template.lab_test_group lab_test.result_date = getdate() lab_test.company = company lab_test.service_unit = service_unit return lab_test ``` -------------------------------- ### Configure Healthcare Service Unit Properties - Python Source: https://github.com/tacten/biograph/wiki/Patient-Inpatient-Admission-Flow Sets properties for a Healthcare Service Unit based on whether it's a group or a specific type. It configures appointment settings, occupancy, and capacity, fetching details from 'Healthcare Service Unit Type' if applicable. ```python sdef set_service_unit_properties(self): if cint(self.is_group): self.allow_appointments = False self.overlap_appointments = False self.inpatient_occupancy = False self.service_unit_capacity = 0 self.occupancy_status = "" self.service_unit_type = "" elif self.service_unit_type != "": service_unit_type = frappe.get_doc("Healthcare Service Unit Type", self.service_unit_type) self.allow_appointments = service_unit_type.allow_appointments self.inpatient_occupancy = service_unit_type.inpatient_occupancy if self.inpatient_occupancy and self.occupancy_status != "": self.occupancy_status = "Vacant" if service_unit_type.overlap_appointments: self.overlap_appointments = True else: self.overlap_appointments = False self.service_unit_capacity = 0 ``` -------------------------------- ### Create Inpatient Record from Order Source: https://github.com/tacten/biograph/wiki/In‐Patient-Management-Workflows:-Gaps-and-Areas-for-Enhancements This Python function initializes a new Inpatient Record document based on an admission order. It maps patient details and clinical encounter data such as symptoms, diagnoses, and prescriptions to the new record. ```python def create_inpatient_record(admission_order): if isinstance(admission_order, str): admission_order = json.loads(admission_order) if not admission_order or not admission_order["patient"] or not admission_order["admission_encounter"]: frappe.throw(_("Missing required details, did not create Inpatient Record")) inpatient_record = frappe.new_doc("Inpatient Record") set_details_from_ip_order(inpatient_record, admission_order) patient = frappe.get_doc("Patient", admission_order["patient"]) inpatient_record.patient = patient.name inpatient_record.patient_name = patient.patient_name inpatient_record.gender = patient.sex inpatient_record.blood_group = patient.blood_group inpatient_record.dob = patient.dob inpatient_record.mobile = patient.mobile inpatient_record.email = patient.email inpatient_record.phone = patient.phone inpatient_record.scheduled_date = today() encounter = frappe.get_doc("Patient Encounter", admission_order["admission_encounter"]) if encounter and encounter.symptoms: set_ip_child_records(inpatient_record, "chief_complaint", encounter.symptoms) if encounter and encounter.diagnosis: set_ip_child_records(inpatient_record, "diagnosis", encounter.diagnosis) if encounter and encounter.drug_prescription: set_ip_child_records(inpatient_record, "drug_prescription", encounter.drug_prescription) if encounter and encounter.lab_test_prescription: set_ip_child_records(inpatient_record, "lab_test_prescription", encounter.lab_test_prescription) if encounter and encounter.procedure_prescription: set_ip_child_records(inpatient_record, "procedure_prescription", encounter.procedure_prescription) if encounter and encounter.therapies: inpatient_record.therapy_plan = encounter.therapy_plan set_ip_child_records(inpatient_record, "therapies", encounter.therapies) inpatient_record.status = "Admission Scheduled" ``` -------------------------------- ### Schedule Inpatient Record Creation (Python) Source: https://github.com/tacten/biograph/wiki/The-inpatient-flow Python function 'schedule_inpatient' that creates a new 'Inpatient Record' document. It parses admission order details from the provided arguments, validates required fields, and populates the new record with patient information and admission details. ```python def schedule_inpatient(args): admission_order = json.loads(args) # admission order via Encounter if ( not admission_order or not admission_order["patient"] or not admission_order["admission_encounter"] ): frappe.throw(_("Missing required details, did not create Inpatient Record")) inpatient_record = frappe.new_doc("Inpatient Record") # Admission order details set_details_from_ip_order(inpatient_record, admission_order) # Patient details patient = frappe.get_doc("Patient", admission_order["patient"]) inpatient_record.patient = patient.name inpatient_record.patient_name = patient.patient_name inpatient_record.gender = patient.sex inpatient_record.blood_group = patient.blood_group inpatient_record.dob = patient.dob inpatient_record.mobile = patient.mobile inpatient_record.email = patient.email inpatient_record.phone = patient.phone ``` -------------------------------- ### Define Workspace Shortcuts and Filters Source: https://github.com/tacten/biograph/wiki/Insurance-Module-Functional-Coverage Configures shortcut links for the workspace, including specific stats filters for DocTypes like Insurance Claim and Sales Invoice. These filters determine which records appear in the dashboard views. ```json { "shortcuts": [ { "label": "Insurance Claim", "link_to": "Insurance Claim", "stats_filter": "[[\"Insurance Claim\",\"status\",\"in\",[\"Draft\",\"Submitted\",null]],[\"Insurance Claim\",\"docstatus\",\"=\",\"1\"]]", "type": "DocType" } ] } ``` -------------------------------- ### Handle Post-Insert Inpatient Record Logic Source: https://github.com/tacten/biograph/wiki/Patient-Inpatient-Admission-Flow The after_insert method updates the patient status, links medication and service requests associated with the admission encounter, and initializes nursing tasks from a template. ```python def after_insert(self): frappe.db.set_value("Patient", self.patient, "inpatient_record", self.name) frappe.db.set_value("Patient", self.patient, "inpatient_status", self.status) if self.admission_encounter: frappe.db.set_value( "Patient Encounter", self.admission_encounter, {"inpatient_record": self.name, "inpatient_status": self.status}, ) filters = {"order_group": self.admission_encounter, "docstatus": 1} medication_requests = frappe.get_all("Medication Request", filters, ["name"]) service_requests = frappe.get_all("Service Request", filters, ["name"]) for service_request in service_requests: frappe.db.set_value( "Service Request", service_request.name, {"inpatient_record": self.name, "inpatient_status": self.status}, ) for medication_request in medication_requests: frappe.db.set_value( "Medication Request", medication_request.name, {"inpatient_record": self.name, "inpatient_status": self.status}, ) if self.admission_nursing_checklist_template: NursingTask.create_nursing_tasks_from_template( template=self.admission_nursing_checklist_template, doc=self, ) ``` -------------------------------- ### Configure Service Unit Query (JavaScript) Source: https://github.com/tacten/biograph/wiki/Patient-Inpatient-Admission-Flow This JavaScript code configures the query for the 'service_unit' field in a frontend dialog. It sets filters based on company, service unit type, and occupancy status, ensuring only relevant and vacant service units are displayed. This is typically used within a Frappe framework application. ```javascript dialog.fields_dict['service_unit'].get_query = function() { return { filters: { 'is_group': 0, 'company': frm.doc.company, 'service_unit_type': dialog.get_value('service_unit_type'), 'occupancy_status' : 'Vacant' } }; }; ``` -------------------------------- ### Create Service Request from Lab Test Prescription (Python) Source: https://github.com/tacten/biograph/wiki/In‐Patient-Management-Workflows:-Gaps-and-Areas-for-Enhancements Initiates the creation of a service request based on a lab test prescription within a patient encounter. It iterates through lab tests and checks for associated observation templates. ```python def make_service_request(self): if self.lab_test_prescription: for lab_test in self.lab_test_prescription: if lab_test.observation_template: template_doc = "Observation Template" ``` -------------------------------- ### Werkzeug Shared Data Middleware File Handling (Python) Source: https://github.com/tacten/biograph/wiki/Error-on-submit This code is part of the Werkzeug library's Shared Data Middleware. It shows the logic for determining whether to serve a file directly or pass the request to the underlying application, based on file existence and permissions. ```Python if file_loader is None or not self.is_allowed(real_filename): # type: ignore return self.app(environ, start_response) guessed_type = mimetypes.guess_type(real_filename) # type: ignore ``` -------------------------------- ### Healthcare Service Unit Initialization - Python Source: https://github.com/tacten/biograph/wiki/Patient-Inpatient-Admission-Flow Initializes a Healthcare Service Unit. It sets the parent field for nested set model and loads address and contact information on load. It also validates service unit properties. ```python class HealthcareServiceUnit(NestedSet): nsm_parent_field = "parent_healthcare_service_unit" sdef onload(self): """Load address and contacts in `__onload`""" load_address_and_contact(self) sdef validate(self): self.set_service_unit_properties() ```