__main__.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. #!/usr/bin/env python
  2. """
  3. (c) 2019 EDI Parser Toolkit,
  4. Health Information Privacy Lab, Vanderbilt University Medical Center
  5. Steve L. Nyemba <steve.l.nyemba@vanderbilt.edu>
  6. Khanhly Nguyen <khanhly.t.nguyen@gmail.com>
  7. This code is intended to process and parse healthcare x12 837 (claims) and x12 835 (remittances) into human readable JSON format.
  8. The claims/outpout can be forwarded to a NoSQL Data store like couchdb and mongodb
  9. Usage :
  10. Commandline :
  11. # parse {x12}
  12. healthcare-io parse <x12_folder>
  13. # export {x12}
  14. healthcare-io export
  15. -
  16. Embedded :
  17. """
  18. # import healthcareio
  19. import typer
  20. from typing import Optional
  21. from typing_extensions import Annotated
  22. import uuid
  23. import os
  24. import meta
  25. import json
  26. import time
  27. from healthcareio import x12
  28. from healthcareio.x12.parser import X12Parser
  29. import requests
  30. import pandas as pd
  31. import numpy as np
  32. # import healthcareio
  33. # import healthcareio.x12.util
  34. # from healthcareio.x12.parser import X12Parser
  35. app = typer.Typer()
  36. CONFIG_FOLDER = os.sep.join([os.environ['HOME'],'.healthcareio'])
  37. HOST = "https://healthcareio.the-phi.com" if 'PARSER_HOST_URL' not in os.environ else os.environ['PARSER_HOST_URL']
  38. @app.command(name='init')
  39. def config(email:str,provider:str='sqlite',auth_file:str=None) :
  40. """\b
  41. Generate configuration file needed with default data store. For supported data-store providers visit https://hiplab.mc.vanderbilt.edu/git/hiplab/data-transport.git
  42. :email your email
  43. :provider data store provider (visit https://hiplab.mc.vanderbilt.edu/git/hiplab/data-transport.git)
  44. """
  45. _db = "healthcareio"
  46. global CONFIG_FOLDER
  47. # _PATH = os.sep.join([os.environ['HOME'],'.healthcareio'])
  48. if not os.path.exists(CONFIG_FOLDER) :
  49. os.mkdir(CONFIG_FOLDER)
  50. #
  51. # NOTE:
  52. # if a provider is setup as an environment variable, we override the parameter
  53. # This is designed for developement and containers
  54. #
  55. if 'X12_DATABASE' in os.environ :
  56. provider = os.environ['X12_DATABASE']
  57. if provider in ['sqlite','sqlite3'] :
  58. _db = os.sep.join([CONFIG_FOLDER,_db+'.db3'])
  59. _config = {
  60. "store":{
  61. "provider":provider,"database":_db,"context":"write"
  62. },
  63. "plugins":None,
  64. "system":{
  65. "uid":str(uuid.uuid4()),
  66. "email":email,
  67. "version":meta.__version__,
  68. "copyright":meta.__author__
  69. }
  70. }
  71. if auth_file and os.path.exists(auth_file) and provider not in ['sqlite','sqlite3'] :
  72. f = open(auth_file)
  73. _auth = json.loads(f.read())
  74. f.close()
  75. _config['store'] = dict(_config['store'],**_auth)
  76. #
  77. # Let create or retrieve a user's key/token to make sure he/she has access to features they need
  78. # This would also allow us to allow the users to be informed of new versions
  79. #
  80. try:
  81. global HOST
  82. # HOST = "https://healthcareio.the-phi.com" if 'PARSER_HOST_URL' not in os.environ else os.environ['PARSER_HOST']
  83. url = f"{HOST}/api/users/signup"
  84. _body = {"email":email,"version":meta.__version__}
  85. _headers = {"content-type":"application/json"}
  86. resp = requests.post(url,headers=_headers,data=json.dumps(_body))
  87. if resp.ok :
  88. _config['system'] = dict(_config['system'],**resp.json())
  89. except Exception as e:
  90. print (e)
  91. pass
  92. # store this on disk
  93. f = open(os.sep.join([CONFIG_FOLDER,'config.json']),'w')
  94. f.write(json.dumps(_config))
  95. f.close()
  96. _msg = f"""
  97. Thank you for considering using our {{x12}} parser verion {meta.__version__}
  98. The generatted configuration file found at {CONFIG_FOLDER}
  99. The database provider is {provider}
  100. visit {HOST} to learn more about the features,
  101. """
  102. print (_msg)
  103. @app.command(name='about')
  104. def copyright():
  105. f"""
  106. This function will return information about the {meta.__name__}
  107. """
  108. for note in [meta.__name__,meta.__author__,meta.__license__]:
  109. print (note)
  110. pass
  111. @app.command()
  112. def parse (claim_folder:str,plugin_folder:str = None,config_path:str = None):
  113. """
  114. This function will parse 837 and or 835 claims given a location of parsing given claim folder and/or plugin folder.
  115. plugin_folder folder containing user defined plugins (default are loaded)
  116. config_path default configuration path
  117. """
  118. _plugins,_parents = x12.plugins.instance(path=plugin_folder)
  119. _files = x12.util.file.Location.get(path=claim_folder,chunks=10)
  120. _path = config_path if config_path else os.sep.join([CONFIG_FOLDER,'config.json'])
  121. if os.path.exists(_path) :
  122. f = open(_path)
  123. _config = json.loads(f.read())
  124. f.close()
  125. _store = _config['store']
  126. # # print (len(_files))
  127. jobs = []
  128. for _chunks in _files:
  129. pthread = X12Parser(plugins=_plugins,parents=_parents,files=_chunks, store=_store)
  130. pthread.start()
  131. jobs.append(pthread)
  132. while jobs :
  133. jobs = [pthread for pthread in jobs if pthread.is_alive()]
  134. time.sleep(1)
  135. # pass
  136. # else:
  137. # pass
  138. print ()
  139. print (" PARSED ")
  140. print ("...................... FINISHED .........................")
  141. #
  142. #
  143. @app.command()
  144. def check():
  145. """
  146. This function checks for the version running against the current version
  147. """
  148. _info = [meta.__version__,None]
  149. url = f'{HOST}/api/store/version'
  150. try:
  151. resp= requests.post(url)
  152. _info[1] = resp.text if resp.status_code == 200 else "NA"
  153. except Exception as e:
  154. _info[1] = "NA"
  155. pass
  156. if _info[1] == "NA" :
  157. _msg = "Unavailable server (unreachable)"
  158. else:
  159. _msg = ""
  160. print ()
  161. _info =pd.DataFrame(_info,columns=["versions"],index=["Yours","Current"])
  162. print (_info)
  163. print (_msg)
  164. @app.command(name="export-schema")
  165. def export_schema (file_type:str):
  166. """
  167. This function will display the schema in JSON format of a given file/type
  168. """
  169. _plugins,_parents = x12.plugins.instance()
  170. if file_type not in ['835','837'] and file_type in ['claims','remits']:
  171. file_type = '835' if file_type == 'remits' else '837'
  172. _template = x12.publish.build(x12=file_type,plugins=_plugins)
  173. print ( json.dumps(_template))
  174. @app.command(name="export")
  175. def publish (file_type:str,path:str):
  176. """
  177. This function will export to a different database
  178. file_type values are either claims or remits
  179. path path to export configuration (data transport file)
  180. file_type claims or remits (835 or 837)
  181. """
  182. _type = None
  183. if file_type.strip() in ['837','claims'] :
  184. _type = 'claims'
  185. _x12 = '837'
  186. elif file_type.strip() in ['835','remits']:
  187. _type = 'remits'
  188. _x12 = '835'
  189. if _type :
  190. _store = {'source':os.sep.join([CONFIG_FOLDER,'config.json']),'target':path}
  191. for _key in _store :
  192. f = open(_store[_key])
  193. _store[_key] = json.loads(f.read())
  194. f.close()
  195. _store['source'] = _store['source']['store']
  196. _plugins,_parents = x12.plugins.instance()
  197. x12.publish.init(plugins=_plugins,x12=_x12,store=_store)
  198. else:
  199. print ("Can not determine type, (837 or 835)")
  200. print ()
  201. print (" EXPORT ")
  202. print ("...................... FINISHED .........................")
  203. if __name__ == '__main__' :
  204. app()