manageCRF.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. import labkeyInterface
  2. import labkeyInterface
  3. import labkeyDatabaseBrowser
  4. # interact with the database (connect, get handle, getRows, uploadRows)
  5. def connectDB(server):
  6. net=labkeyInterface.labkeyInterface()
  7. fconfig=os.path.join(os.path.expanduser('~'),'.labkey',f'{server}.json')
  8. net.init(fconfig)
  9. return net,labkeyDatabaseBrowser.labkeyDB(net)
  10. def getDB(pars):
  11. try:
  12. return pars['db']
  13. except KeyError:
  14. pass
  15. pars['net'],pars['db']=connectDB(pars['server'])
  16. return pars['db']
  17. def getRows(pars):
  18. db=getDB(pars)
  19. qFilter=pars.get('qFilter',[])
  20. return db.selectRows(pars['project'],pars['schema'],
  21. pars['query'],qFilter)['rows']
  22. def modifyRows(pars,mode,rows):
  23. db=getDB(pars)
  24. return db.modifyRows(mode,pars['project'],pars['schema'],pars['query'],rows)
  25. # helper function
  26. #very generic variable splitting routine
  27. def parseVariables(q):
  28. if q==None:
  29. return []
  30. arr=q.split(';')
  31. v=[x.split('=') for x in arr]
  32. return [{'varName':x[0],'varValue':x[1]} for x in v]
  33. # get snapshot of the data layout
  34. #this should really look at FormStatus on layout and do the conversion
  35. def toStatus(x):
  36. if x=='Submitted':
  37. return 2
  38. if x=='InProgress':
  39. return 1
  40. if x=='Approved':
  41. return 5
  42. #get dataset names
  43. def getInputLists(pars):
  44. try:
  45. return pars['inputLists']
  46. except KeyError:
  47. pass
  48. parServerLayout={'db':pars['db'],'project':'crfLayout/hypoAfrica'}
  49. parInputLists={'schema':'lists','query':'inputLists'}
  50. rows=getRows(parServerLayout|parInputLists)
  51. pars['inputLists']={r['Key']:r['queryName'] for r in rows}
  52. return pars['inputLists']
  53. #get datasets for form
  54. def getDatasets(pars,form):
  55. try:
  56. return pars['datasets'][form]
  57. except KeyError:
  58. pass
  59. parServerLayout={'db':pars['db'],'project':'crfLayout/hypoAfrica'}
  60. # set datasets for forms
  61. formFilter={'variable':'formName','value':f'{form}','oper':'eq'}
  62. parFormSetup={'schema':'lists','query':'FormSetup'}
  63. parFilter={'qFilter':[formFilter]}
  64. rows=getRows(parServerLayout|parFormSetup|parFilter)
  65. #ignore show query since 15 has all set to NONE
  66. #keep variable definition
  67. inputLists=getInputLists(pars)
  68. datasets={r['Key']:r|{'query':inputLists[r['queryName']]} for r in rows}
  69. try:
  70. pars['datasets'][form]=datasets
  71. except KeyError:
  72. pars['datasets']={form:datasets}
  73. return datasets
  74. #manager CRF master entries (get, modify, upload)
  75. def getCrfEntry(pars,crf):
  76. crfFilter={'variable':'entryId','value':crf,'oper':'eq'}
  77. parFilter={'qFilter':[crfFilter]}
  78. parCrf={'schema':'lists','query':'crfEntry'}
  79. rows=getRows(pars|parCrf|parFilter)
  80. if len(rows)!=1:
  81. print('Fail crfEntry')
  82. return None
  83. return rows[0]
  84. def changeFormStatus(pars,crfEntry,targetStatus):
  85. crfEntry['FormStatus']=toStatus(targetStatus)
  86. uploadCrfEntry(pars,crfEntry)
  87. def uploadCrfEntry(pars,crfEntry):
  88. parCrf={'schema':'lists','query':'crfEntry'}
  89. outcome=modifyRows(pars|parCrf,'update',[crfEntry])
  90. try:
  91. print(outcome['exception'])
  92. except KeyError:
  93. pass
  94. #manage DATA (set, verify, upload)
  95. def setData(pars,crfEntry,schema):
  96. datasets=getDatasets(pars,crfEntry['Form'])
  97. for k in datasets:
  98. d=datasets[k]
  99. crf=crfEntry['entryId']
  100. #print('Setting [{}:{}/{}]'.format(schema,d['query'],d['variableDefinition']))
  101. crfFilter={'variable':'crfRef','value':crf,'oper':'eq'}
  102. qFilter=[crfFilter]
  103. qvar=parseVariables(d['variableDefinition'])
  104. qvarFilter=[{'variable':x['varName'],'value':x['varValue'],'oper':'eq'} for x in qvar]
  105. qFilter.extend(qvarFilter)
  106. parD={'schema':schema,'query':d['query'],'qFilter':qFilter}
  107. rows=getRows(pars|parD)
  108. try:
  109. pars['data'][schema][k]=rows
  110. except KeyError:
  111. try:
  112. pars['data'][schema]={k:rows}
  113. except KeyError:
  114. pars['data']={schema:{k:rows}}
  115. def verifyData(pars,crfEntry,schema):
  116. ok=True
  117. datasets=getDatasets(pars,crfEntry['Form'])
  118. for k in datasets:
  119. d=datasets[k]
  120. rows=pars['data'][schema][k]
  121. testFailed={'lists':len(rows)!=1,'study':len(rows)>1}
  122. if testFailed[schema]:
  123. print('[{} {}/{}]: {}'.format(schema,d['query'],
  124. d['variableDefinition'],len(rows)))
  125. #at least one fail
  126. ok=False
  127. continue
  128. return ok
  129. def uploadData(pars,crfEntry):
  130. status=True
  131. datasets=getDatasets(pars,crfEntry['Form'])
  132. for k in datasets:
  133. listRow=pars['data']['lists'][k][0]
  134. studyRows=pars['data']['study'][k]
  135. try:
  136. outRow=studyRows[0]
  137. outRow.update(listRow)
  138. mode='update'
  139. except IndexError:
  140. outRow={x:listRow[x] for x in listRow}
  141. mode='insert'
  142. outRow['ParticipantId']=crfEntry['participantStudyId']
  143. outRow['SequenceNum']=(int(crfEntry['entryId']) % 1000000000 )
  144. d=datasets[k]
  145. parD={'schema':'study','query':d['query']}
  146. outcome=modifyRows(pars|parD,mode,[outRow])
  147. try:
  148. print(outcome['exception'])
  149. status=False
  150. except KeyError:
  151. pass
  152. return status
  153. ## mimic CRF actions
  154. def onSubmitedToInProgress(pars,crf):
  155. crfEntry=getCrfEntry(pars,crf)
  156. statusIn=crfEntry['FormStatus']
  157. if statusIn!=toStatus('Submitted'):
  158. print(f'[{crf}]: Inappropriate status({statusIn})')
  159. return
  160. changeFormStatus(pars,crfEntry,'InProgress')
  161. def onApprovedToSubmited(pars,crf):
  162. crfEntry=getCrfEntry(pars,crf)
  163. statusIn=crfEntry['FormStatus']
  164. if statusIn!=toStatus('Approved'):
  165. print(f'[{crf}]: Inappropriate status({statusIn})')
  166. return
  167. changeFormStatus(pars,crfEntry,'Submitted')
  168. def onSubmit(pars,crf):
  169. crfEntry=getCrfEntry(pars,crf)
  170. statusIn=crfEntry['FormStatus']
  171. if statusIn!=toStatus('InProgress'):
  172. print(f'[{crf}]: Inappropriate status({statusIn})')
  173. return
  174. form=crfEntry['Form']
  175. setData(pars,crfEntry,'lists')
  176. status=verifyData(pars,crfEntry,'lists')
  177. crf=crfEntry['entryId']
  178. if not status:
  179. print(f'[{crf}/{form}] verification failed')
  180. return
  181. changeFormStatus(pars,crfEntry,'Submitted')
  182. def onDatabaseUpload(pars,crf):
  183. crfEntry=getCrfEntry(pars,crf)
  184. statusIn=crfEntry['FormStatus']
  185. if statusIn!=toStatus('Submitted'):
  186. print(f'[{crf}]: Inappropriate status({statusIn})')
  187. return
  188. form=crfEntry['Form']
  189. setData(pars,crfEntry,'lists')
  190. setData(pars,crfEntry,'study')
  191. dataOK=verifyData(pars,crfEntry,'study')
  192. if not dataOK:
  193. print(f'[{crf}]: verification failed')
  194. return
  195. print(f'[{crf}]: verification OK')
  196. uploadOK=uploadData(pars,crfEntry)
  197. if not uploadOK:
  198. print(f'[{crf}]: upload failed')
  199. return
  200. print(f'[{crf}]: upload OK')
  201. changeFormStatus(pars,crfEntry,'Approved')