Search the OSCAR Documentation
< All Topics
Print

RingCentral Fax Gateway

Share this

Preface

This is a basic installation of an encrypted secure delivery to the RingCentral fax server for use with OSCAR.

Document Version History

  • v1.0 – initial public release to worldoscar.org with python – Dec 20, 2023

Copyright © 2023 by Peter Hutten-Czapski MD under the Creative Commons Attribution-Share Alike 3.0 Unported License.

Portions © 2023 by Tom Lee and other sources as indicated

Errors corrected and updated by Adrian Starzynski 2023 and 2024

Preamble

OSCAR drops files to a directory identified in oscar.properties as fax_file_location= .  Failing that it uses the system property for java io tmp directory which usually resolves to the tmp directory to enable faxing.  The three types are a text file with the fax number(s), the corresponding pdf and an optional signature.jpg.  The .txt filename is one of the following patterns

  1. Prescription:prescription_<prescription_provider_no><serial>.txt
  2. eForm:EForm-<eform_data.fdid>.<serial>.txt
  3. Consult request form:CRF-<consultationRequests.requestId>.0.<serial>.txt

An Internet Fax Gateway is a commercial subscription service that allows for conversion of email to fax and vice versa, fax to email.  The main advantage of this service over using a method to fax locally is that the phone line and the modem are provided. The costs are the need for internet connectivity and the gateway subscription cost. 

Obtain a RingCentral account with the healthcare provider OSCAR EMR discount by contacting WorldOSCAR here.

The Bash Script

Use your favorite text editor and load the following into /usr/share/oscar-emr/RCFax_gateway.sh

#!/bin/bash
#
# Fax Gateway cron
# Picks up the files dropped by OSCAR for faxing
# and uploads them to Ring Central using the RCfax.py script
#

ARCH=/root/allfax_backup/
FAX_TEMP_FOLDER=/usr/share/oscar-emr/OscarDocument/fax

# Uncommented the FAX_TEMP_FOLDER and change it to correct path if neccessary
if [ -f /usr/share/tomcat9/bin/version.sh ] ; then
	TOMCAT=tomcat9
	#FAX_TEMP_FOLDER=
fi

if [ -f /usr/share/tomcat8/bin/version.sh ] ; then
    TOMCAT=tomcat8
	#FAX_TEMP_FOLDER=
fi


if [ -f $FAX_TEMP_FOLDER/faxlock.pid ] ; then
        echo "Fax in progress --- EXIT"
        exit;
fi

if [ ! -f $FAX_TEMP_FOLDER/prescription_*.pdf ] && [ ! -f $FAX_TEMP_FOLDER/CRF-*.pdf ] ; then
		echo `date` " : NOTHING to FAX OUT"
        exit;
fi

if test -n "$(find $FAX_TEMP_FOLDER -maxdepth 1 -name '*.txt' -print -quit)"; then 
	touch $FAX_TEMP_FOLDER/faxlock.pid
	for f in `ls $FAX_TEMP_FOLDER/*.txt`; do 
		echo `date` " : START SENDING FAX"
		t=`echo $f | sed -e s"/[._][0-9]*.txt//" -e s"/prescription_/Rx-/"`
		#t=`echo $f | sed -e s"/\/tmp\/${TOMCAT}-${TOMCAT}-tmp\///" -e s"/prescription_/Rx-/" -e s"/[0-9]\{13\}\.txt//"`
		/usr/local/bin/RCfax.py -s "Oscar Fax $t" -n `sed s"/ *//g" $f|tr -d "\n"` -f `echo $f | sed s"/txt/pdf/"` -b "$ARCH" < /dev/null
		echo `date` " : END SENDING FAX"
		echo "" 
	done  
fi


if [ -f $FAX_TEMP_FOLDER/faxlock.pid ] ; then
        rm $FAX_TEMP_FOLDER/faxlock.pid
fi


if test -n "$(find $FAX_TEMP_FOLDER -maxdepth 1 -name 'form*' -print -quit)"; then 
    rm $FAX_TEMP_FOLDER/form*
fi
if test -n "$(find $FAX_TEMP_FOLDER -maxdepth 1 -name 'sign*' -print -quit)"; then 
    rm $FAX_TEMP_FOLDER/sign*
fi
if test -n "$(find $FAX_TEMP_FOLDER -maxdepth 1 -name 'lab*' -print -quit)"; then 
    rm $FAX_TEMP_FOLDER/lab*
fi
if test -n "$(find $FAX_TEMP_FOLDER -maxdepth 1 -name '*.tmp' -print -quit)"; then 
    rm $FAX_TEMP_FOLDER/*.tmp
fi
if test -n "$(find $FAX_TEMP_FOLDER -maxdepth 1 -name 'pdfser*' -print -quit)"; then 
    rm $FAX_TEMP_FOLDER/pdfser*
fi

Of course you will need to provide an appropriate entry for $FAX_TEMP_FOLDER.

Note: 1) You may need to add a ‘;’ before the ‘then’, depending on your version of bash. 2) The script deletes the .txt and .pdf files in the /tmp folder, but the signature.jpg will remain. These get deleted when the server is restarted.

Now make it executable

chmod 710 RCFax_gateway.sh

Now a cron job

And set it up as a cron job (you will need to run it as root or the tomcat user to open the files that are dropped by Oscar into the tmp directory.)  The following example has the root user sending the files

sudo crontab -e

And add an entry like the following that executes every 2 minutes

*/2 * * * * /usr/share/oscar-emr/RCFax_gateway.sh> /dev/null

Now install the Python Script

Install the dependencies

You should first install Python 3.11 then the pip package manager, and RingCentral SDK

sudo apt install python3-pip
pip3 install ringcentral

A python script should be installed in /usr/local/bin/RCfax.py.  You need to have Python 3 to run it and to provide credentials for your RingCentral account for SERVER_URL = CALLER = CLIENT_ID  CLIENT_SECRET  and JWT_TOKEN

#!/usr/bin/env python3

# https://developers.ringcentral.com/guide/messaging/fax/sending-faxes#python
# extended by Tom Le

import re
import json
import os.path
import base64
import logging
import shutil, os
import sys, getopt
import time
from ringcentral import SDK



#****************************
# Tom Le added the following to handle fax info., eg. fax #, filename to be fax,
#****************************
# get command line args
myopts, args = getopt.getopt(sys.argv[1:],"n:f:s:b:")

#*******
# o == option
# a == argument passed to the o
#*******
# process the options
for o, a in myopts:
    if o == '-n':
        fax_no=a
    elif o == '-f':
        fax_file=a
    elif o == '-s':
        cover_subject=a
    elif o == '-b':
        archDir=a
    else:
        print("Usage: %s -n faxnumber -f file -s subject -b archDir" % sys.argv[0])
    sys.exit

print (" ")
print("* Backup Dir. is : %s " % (archDir))
print("* Fax file is : %s " % (fax_file))
print ("* Fax number is : %s" % fax_no)

# Tom Le added this to get the fax number and pdf files to ready for archive
temp_filename = str(os.path.splitext(fax_file)[0])

print ("* Fax number filename is : %s" % temp_filename+".txt")
print ("* Fax PDF filename is : %s" % temp_filename+".pdf")
print (" ")

# should be the number in the filename in temp fax directory with .txt extension
RECIPIENT = fax_no
# should be the PDF filename that in temp fax directory with .pdf extension
FILE_TO_FAX = fax_file

#****************************

#****************************
# 1) uncomment the correct fax SERVER_URL
# 2) need to provide data for all variables in CAPITAL
#****************************
# For TESTING 
#SERVER_URL = "https://platform.devtest.ringcentral.com"
#
# For PRODUCTION 
#SERVER_URL = "https://platform.ringcentral.com"
#
CALLER = ""
CLIENT_ID = ""
CLIENT_SECRET = ""
JWT_TOKEN = ""
#****************************



# Send a high resolution fax message to a recipient number
def send_fax():
    try:
        builder = rcsdk.create_multipart_builder()
        builder.set_body({
            'to': [{ 'phoneNumber': RECIPIENT }],
            # To send fax to multiple recipients, add more 'phoneNumber' object. E.g.
            #
            # to: [
            #       { 'phoneNumber': "Recipient1-Phone-Number" },
            #       { 'phoneNumber': "Recipient2-Phone-Number" }
            # ],
            'faxResolution': "High",
            'coverPageText': ""
        })

        #with open('test.jpg', "rb") as f: #ORIGINAL CODE
        with open(FILE_TO_FAX, "rb") as f:
            content = f.read()
            #attachment = ('test.jpg', content)
            attachment = (FILE_TO_FAX, content)
            builder.add(attachment)
            request = builder.request('/restapi/v1.0/account/~/extension/~/fax')
        resp = platform.send_request(request)
        jsonObj = resp.json()
        print ("Fax sent. Message id: " + str(jsonObj.id))
        check_fax_message_status(jsonObj.id)
    except Exception as e:
        print (e)

# Check the sending message status until it's no longer in the queued status
def check_fax_message_status(messageId):
    try:
        endpoint = "/restapi/v1.0/account/~/extension/~/message-store/" + str(messageId)
        resp = platform.get(endpoint)
        jsonObj = resp.json()
        print ("Message status: " + jsonObj.messageStatus)
        if jsonObj.messageStatus == "Queued":
            time.sleep(30)
            check_fax_message_status(jsonObj.id)



#****************************
# Tom Le added this to move the fax to archive if fax successfully submitted,
# eg. got a messageStatus as Sent from RC
#****************************

        print (" ")
        if jsonObj.messageStatus == "Sent":
            print (" ")

            dst_txt_filename = archDir + os.path.basename(temp_filename)+".txt"
            dst_pdf_filename = archDir + os.path.basename(temp_filename)+".pdf"

            shutil.move(temp_filename+".txt", dst_txt_filename)
            outputStr1 = "- Moved fax_no File : " + temp_filename + ".txt TO " + dst_txt_filename
            print (outputStr1)

            shutil.move(temp_filename+".pdf", dst_pdf_filename)
            outputStr2 = "- Moved FAXED file : " + temp_filename + ".pdf TO " + dst_pdf_filename
            print (outputStr2)

#****************************



    except Exception as e:
        print (e)

# Authenticate a user using a personal JWT token
def login():
    try:
      #platform.login( jwt=os.environ.get('RC_JWT') ) #ORIGINAL CODE
        platform.login( jwt= JWT_TOKEN )
        send_fax()
    except Exception as e:
      print ("Unable to authenticate to platform. Check credentials." + str(e))

##########
# Instantiate the SDK and get the platform instance
##########
rcsdk = SDK(CLIENT_ID, CLIENT_SECRET, SERVER_URL)
platform = rcsdk.platform()
login()
##########
Table of Contents