Notification sound on send

Hi, I have the below code
It’s send notifcation succeffuly but I want to play sound when send it, how I can do this, also show it in the screen not just in the notification icon

Py

def check_flow_board():
    # Get today patient appointment
    today_date = getdate(today())

    appointments = frappe.db.sql("""
        SELECT
            pa.name,
            pa.patient_name,
            MAX(CASE WHEN pah.status = 'In Exam Room' THEN pah.update_at END) as in_exam_room_time,
            pa.duration
        FROM
            `tabPatient Appointment` pa
        JOIN
            `tabPatient Appointment History` pah ON pah.parent = pa.name
        WHERE
            DATE(pa.appointment_date) = %s
            AND pa.appointment_status = 'In Exam Room'
        GROUP BY
            pa.name
    """, (today_date), as_dict=1)

    # Get current time
    current_time = datetime.now()

    # Format the time to just show the time part and check duration
    formatted_appointments = []
    for appointment in appointments:
        if appointment.in_exam_room_time:
            # Convert in_exam_room_time to datetime
            in_exam_room_datetime = get_datetime(appointment.in_exam_room_time)
            
            # Since duration is already in seconds, we directly use it
            duration_seconds = appointment.duration
            
            # Calculate the expected end time
            expected_end_time = add_to_date(in_exam_room_datetime, seconds=duration_seconds)
            
            # Check if current time exceeds expected end time
            if current_time > expected_end_time:
                alarm_status = "لقد تأخر المريض في الغرفة اكثر من الحد المسموح به"
            else:
                alarm_status = "Within time limit"
            
            # Format the in_exam_room_time
            appointment['in_exam_room_time'] = format_datetime(appointment.in_exam_room_time, 'HH:mm:ss')
            appointment['alarm_status'] = alarm_status
            
        formatted_appointments.append(appointment)

    # Loop through formatted_appointments to send notifications
    for appointment in formatted_appointments:
        if appointment['alarm_status'] == "لقد تأخر المريض في الغرفة اكثر من الحد المسموح به":
            # Send system notification to all users
            send_notification(appointment['patient_name'], appointment['name'], appointment['alarm_status'])
            # Trigger an alarm on the client side
            trigger_alarm(appointment['name'], appointment['patient_name'])

    # Log the list of formatted appointments with alarm status
    frappe.log(f"Appointment : {formatted_appointments}")

def send_notification(patient, appointment_name, status):
    # Get all system users
    users = frappe.get_all('User', filters={'enabled': 1, 'user_type': 'System User'}, pluck='name')
    
    # Create and send notification for each user
    for user in users:
        doc = frappe.get_doc({
            'doctype': 'Notification Log',
            'subject': f'تبقى اكثر من وقت الجلسة: {appointment_name} - {patient}',
            'email_content': f'The appointment {appointment_name} has exceeded its time limit. Status: {status}',
            'for_user': user,
            'type': 'Alert',
            'document_type': 'Patient Appointment',
            'document_name': appointment_name
        })
        doc.insert(ignore_permissions=True)
        frappe.log(f"Notification sent for user {user} for appointment {appointment_name}")

def trigger_alarm(appointment_name, patient_name):
    # Emit a real-time event to trigger the alarm on the client side
    frappe.publish_realtime('trigger_alarm', {'appointment_name': appointment_name, 'patient_name': patient_name}, after_commit=True)

JS

// Path: /home/frappe/Frappe-Projects/camb/apps/clinic_system/clinic_system/public/js/alarm_notification.js

frappe.realtime.on("trigger_alarm", function(data) {
  if (data.appointment_name && data.patient_name) {
      // Create a visual alarm
      frappe.show_alert({
          message: __('Appointment Time Limit Exceeded: {0} - {1}', [data.appointment_name, data.patient_name]),
          indicator: 'red',
          primary_action: {
              label: __('Acknowledge'),
              action: function() {
                  // Action to take when acknowledged, could be to dismiss the alarm
                  frappe.hide_alert();
              }
          }
      });
      
      // Optionally, play a sound
      frappe.utils.play_sound('alert');
      
      // Manually add to the notification area if needed
      add_to_notification_area(data.appointment_name, data.patient_name);
  }
});

function add_to_notification_area(appointment_name, patient_name) {
  let notification_html = `
      <div class="notification-content">
          <span class="indicator-pill blue">🕐</span>
          <span class="notification-message">
              ${__("تبقى اكثر من وقت الجلسة: {0} - {1}", [appointment_name, patient_name])}
          </span>
          <span class="notification-time">${__("Just now")}</span>
      </div>
  `;
  
  let notification_list = document.querySelector('.notification-list');
  if (notification_list) {
      let new_notification = document.createElement('div');
      new_notification.clas// Path: /home/frappe/Frappe-Projects/camb/apps/clinic_system/clinic_system/public/js/alarm_notification.js

frappe.realtime.on("trigger_alarm", function(data) {
  if (data.appointment_name && data.patient_name) {
      // Create a visual alarm
      frappe.show_alert({
          message: __('Appointment Time Limit Exceeded: {0} - {1}', [data.appointment_name, data.patient_name]),
          indicator: 'red',
          primary_action: {
              label: __('Acknowledge'),
              action: function() {
                  // Action to take when acknowledged, could be to dismiss the alarm
                  frappe.hide_alert();
              }
          }
      });
      
      // Optionally, play a sound
      frappe.utils.play_sound('alert');
      
      // Manually add to the notification area if needed
      add_to_notification_area(data.appointment_name, data.patient_name);
  }
});

function add_to_notification_area(appointment_name, patient_name) {
  let notification_html = `
      <div class="notification-content">
          <span class="indicator-pill blue">🕐</span>
          <span class="notification-message">
              ${__("تبقى اكثر من وقت الجلسة: {0} - {1}", [appointment_name, patient_name])}
          </span>
          <span class="notification-time">${__("Just now")}</span>
      </div>
  `;
  
  let notification_list = document.querySelector('.notification-list');
  if (notification_list) {
      let new_notification = document.createElement('div');
      new_notification.className = 'notification';
      new_notification.innerHTML = notification_html;
      notification_list.insertBefore(new_notification, notification_list.firstChild);
  }
}sName = 'notification';
      new_notification.innerHTML = notification_html;
      notification_list.insertBefore(new_notification, notification_list.firstChild);
  }
}

Maybe you want frappe.confirm() or directly use new frappe.ui.Dialog()?

@corentin
no, I mean the python file is not called js file, because that I want to send notification sound from python file

To be sure I understand everything correctly: what is NOT working? Just the sound?

Exactly the sound is not working, becuase the JS file is not called by Py file,

To understand everything,
this python file is a cron job every 5 minutes in Tasks.py and is setup in hook file,
then I create JS file in public folder to play sound when sned notification, and setup in hook file

hooks.py

app_include_js = [“public/js/alarm_notification.js”]

now my python file is send notification successfully but I can’t called this js file in py file to play the sound this is first issue

:x:

I think the issue is here. Try the following:

app_include_js = ["/assets/clinic_system/js/alarm_notification.js"]

:white_check_mark:

Further reading

https://docs.frappe.io/framework/user/en/basics/asset-bundling