FDBPGController.php 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782
  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\Models\Client;
  4. use Illuminate\Http\Request;
  5. use Illuminate\Support\Facades\DB;
  6. class FDBPGController extends Controller
  7. {
  8. public function rx(Request $request)
  9. {
  10. return view('app.fdb-pg.fdb-rx');
  11. }
  12. // 1. medication suggest
  13. public function medSuggest(Request $request)
  14. {
  15. $term = $request->input('term') ? trim($request->input('term')) : '';
  16. if (empty($term)) return '';
  17. $matches = DB::connection('pgsql_fdb')->select(
  18. "SELECT med_name_id, med_name FROM rminmid1_med_name WHERE med_status_cd = '0' AND med_name ILIKE :term ORDER BY med_name",
  19. ['term' => '%' . $term . '%']
  20. );
  21. return view('app.fdb-pg.fdb-med-suggest', compact('matches'));
  22. }
  23. // 1.1 medication suggest (json response)
  24. public function medSuggestJSON(Request $request)
  25. {
  26. $term = $request->input('term') ? trim($request->input('term')) : '';
  27. if (empty($term)) return '';
  28. $matches = DB::connection('pgsql_fdb')->select(
  29. "SELECT med_name_id, med_name as text FROM rminmid1_med_name WHERE med_status_cd = '0' AND med_name ILIKE :term ORDER BY med_name",
  30. ['term' => '%' . $term . '%']
  31. );
  32. return json_encode([
  33. "success" => true,
  34. "data" => $matches
  35. ]);
  36. }
  37. // 2. routed meds from men name
  38. public function routedMeds(Request $request)
  39. {
  40. $medNameID = $request->input('med-name-id') ? trim($request->input('med-name-id')) : '';
  41. if (empty($medNameID)) return '';
  42. $matches = DB::connection('pgsql_fdb')->select(
  43. "SELECT routed_med_id, med_routed_med_id_desc FROM rmirmid1_routed_med WHERE med_status_cd = '0' AND med_name_id = :medNameID ORDER BY med_routed_med_id_desc",
  44. ['medNameID' => $medNameID]
  45. );
  46. return json_encode($matches);
  47. }
  48. // 3. routed dosage from routed med
  49. public function routedDosages(Request $request)
  50. {
  51. $routedMedID = $request->input('routed-med-id') ? trim($request->input('routed-med-id')) : '';
  52. if (empty($routedMedID)) return '';
  53. $matches = DB::connection('pgsql_fdb')->select(
  54. "SELECT routed_dosage_form_med_id, med_routed_df_med_id_desc FROM rmidfid1_routed_dose_form_med WHERE med_status_cd = '0' AND routed_med_id = :routedMedID ORDER BY med_routed_df_med_id_desc",
  55. ['routedMedID' => $routedMedID]
  56. );
  57. return json_encode($matches);
  58. }
  59. // 4. strengths from routed med
  60. public function meds(Request $request)
  61. {
  62. $dosageFormMedId = $request->input('dosage-form-med-id') ? trim($request->input('dosage-form-med-id')) : '';
  63. if (empty($dosageFormMedId)) return '';
  64. $matches = DB::connection('pgsql_fdb')->select(
  65. "SELECT medid, med_medid_desc, gcn_seqno FROM rmiid1_med WHERE med_status_cd = '0' AND routed_dosage_form_med_id = :dosageFormMedId ORDER BY med_medid_desc",
  66. ['dosageFormMedId' => $dosageFormMedId]
  67. );
  68. return json_encode($matches);
  69. }
  70. // ** med suggest V2 ** //
  71. public function medSuggestV2JSON(Request $request)
  72. {
  73. $term = $request->input('term') ? trim($request->input('term')) : '';
  74. if (empty($term)) return '';
  75. $matches = DB::connection('pgsql_fdb')->select("
  76. SELECT r_med.medid,
  77. r_med.med_medid_desc as text,
  78. r_med.gcn_seqno,
  79. r_dosage_form.routed_dosage_form_med_id,
  80. r_route.routed_med_id,
  81. SIMILARITY(r_med.med_medid_desc, :term) as sim1
  82. FROM rmiid1_med r_med
  83. JOIN rmidfid1_routed_dose_form_med r_dosage_form
  84. ON r_med.routed_dosage_form_med_id = r_dosage_form.routed_dosage_form_med_id
  85. JOIN rmirmid1_routed_med r_route ON r_dosage_form.routed_med_id = r_route.routed_med_id
  86. WHERE r_med.med_status_cd = '0'
  87. AND SIMILARITY(r_med.med_medid_desc, :term) >= " . config('stag.fuzzySearchMinimumSimilarityScore')['medication'] . "
  88. ORDER BY sim1 DESC",
  89. ['term' => $term]
  90. );
  91. return json_encode([
  92. "success" => true,
  93. "data" => $matches
  94. ]);
  95. }
  96. // side effects for a given rx
  97. public function sideEffects(Request $request)
  98. {
  99. $gcnSeqNo = $request->input('gcn-seq-no') ? trim($request->input('gcn-seq-no')) : '';
  100. if (empty($gcnSeqNo)) return '';
  101. $sides = DB::connection('pgsql_fdb')->select("
  102. SELECT r1.side, sm.side_freq, sm.side_sev, sm.dxid, dx.dxid_desc56
  103. FROM rsidegc0_gcnseqno_link r1
  104. JOIN rsidema3_mstr sm ON r1.side = sm.side
  105. JOIN rfmldx0_dxid dx ON sm.dxid = dx.dxid
  106. WHERE r1.gcn_seqno = :gcnSeqNo
  107. ORDER BY sm.side_sev DESC, sm.side_freq ASC
  108. ",
  109. ['gcnSeqNo' => $gcnSeqNo]
  110. );
  111. return view('app.fdb-pg.fdb-side-effects', compact('sides'));
  112. }
  113. // ger prec for a given rx
  114. public function geriatricPrecautions(Request $request)
  115. {
  116. $gcnSeqNo = $request->input('gcn-seq-no') ? trim($request->input('gcn-seq-no')) : '';
  117. if (empty($gcnSeqNo)) return '';
  118. $precautions = DB::connection('pgsql_fdb')->select("
  119. SELECT r1.geri_code, gm.geri_sl, gm.geri_desc, gm.geri_narrative
  120. FROM rgerigc0_geri_gcnseqno_link r1
  121. JOIN rgerima1_geri_mstr gm ON r1.geri_code = gm.geri_code
  122. WHERE r1.gcn_seqno = :gcnSeqNo
  123. ORDER BY gm.geri_desc
  124. ",
  125. ['gcnSeqNo' => $gcnSeqNo]
  126. );
  127. return view('app.fdb-pg.fdb-geriatric-precautions', compact('precautions'));
  128. }
  129. // indication of a given rx
  130. public function indications(Request $request)
  131. {
  132. $gcnSeqNo = $request->input('gcn-seq-no') ? trim($request->input('gcn-seq-no')) : '';
  133. if (empty($gcnSeqNo)) return '';
  134. $indications = DB::connection('pgsql_fdb')->select("
  135. SELECT r1.indcts, r2.indcts_sn, r2.indcts_lbl, r2.dxid, r2.proxy_ind, r3.dxid_desc56
  136. FROM rindmgc0_indcts_gcnseqno_link r1
  137. JOIN rindmma2_indcts_mstr r2 ON r1.indcts = r2.indcts
  138. JOIN rfmldx0_dxid r3 ON r2.dxid = r3.dxid
  139. WHERE r1.gcn_seqno = :gcnSeqNo
  140. ORDER BY r3.dxid_desc56
  141. ",
  142. ['gcnSeqNo' => $gcnSeqNo]
  143. );
  144. return view('app.fdb-pg.fdb-indications', compact('indications'));
  145. }
  146. // contra-indications of a given rx
  147. public function contraindications(Request $request)
  148. {
  149. $routedMedID = $request->input('routed-med-id') ? trim($request->input('routed-med-id')) : '';
  150. if (empty($routedMedID)) return '';
  151. $contraindications = DB::connection('pgsql_fdb')->select("
  152. SELECT r1.ddxcn, r2.dxid, r2.ddxcn_sl, r3.dxid_desc56
  153. FROM rddcmrm0_routed_med_link r1
  154. JOIN rddcmma1_contra_mstr r2 ON r1.ddxcn = r2.ddxcn
  155. JOIN rfmldx0_dxid r3 ON r2.dxid = r3.dxid
  156. WHERE r1.routed_med_id = :routedMedID
  157. ORDER BY r2.ddxcn_sl
  158. ",
  159. ['routedMedID' => $routedMedID]
  160. );
  161. return view('app.fdb-pg.fdb-contraindications', compact('contraindications'));
  162. }
  163. // dx suggest
  164. public function dxSuggest(Request $request)
  165. {
  166. $term = $request->input('term') ? trim($request->input('term')) : '';
  167. if (empty($term)) return '';
  168. $matches = DB::connection('pgsql_fdb')->select("
  169. SELECT distinct(r1.dxid), r1.dxid_desc56
  170. FROM rfmldx0_dxid r1
  171. JOIN rfmlsyn0_dxid_syn r2 ON r1.dxid = r2.dxid
  172. WHERE (r1.dxid_desc56 ILIKE :term OR r1.dxid_desc100 ILIKE :term OR r2.dxid_syn_desc56 ILIKE :term OR r2.dxid_syn_desc100 ILIKE :term)
  173. ORDER BY r1.dxid_desc56
  174. ",
  175. ['term' => '%' . $term . '%']
  176. );
  177. return view('app.fdb-pg.fdb-dx-suggest', compact('matches'));
  178. }
  179. public function dxSuggestJSON(Request $request)
  180. {
  181. $term = $request->input('term') ? trim($request->input('term')) : '';
  182. if (empty($term)) return '';
  183. $matches = DB::connection('pgsql_fdb')->select("
  184. SELECT distinct(r1.dxid), r1.dxid_desc56 as text
  185. FROM rfmldx0_dxid r1
  186. JOIN rfmlsyn0_dxid_syn r2 ON r1.dxid = r2.dxid
  187. WHERE (r1.dxid_desc56 ILIKE :term OR r1.dxid_desc100 ILIKE :term OR r2.dxid_syn_desc56 ILIKE :term OR r2.dxid_syn_desc100 ILIKE :term)
  188. ORDER BY r1.dxid_desc56
  189. ",
  190. ['term' => '%' . $term . '%']
  191. );
  192. return response()->json(['success'=>true, 'data'=>$matches]);
  193. }
  194. public function dxICDsForDxID(Request $request) {
  195. $matches = DB::connection('pgsql_fdb')->select("
  196. select r1.search_icd_cd, r1.icd_cd_type, r2.icd_desc
  197. from RFMLISR1_ICD_SEARCH r1
  198. left join RFMLINM1_ICD_DESC r2 on r1.search_icd_cd = r2.icd_cd
  199. where r1.related_dxid = :dxid
  200. and (/*r1.icd_cd_type = '01' or */r1.icd_cd_type = '05')
  201. and r1.fml_clin_code = '01'
  202. /*and fml_nav_code = '01'*/
  203. ",
  204. ['dxid' => $request->input('dxid')]
  205. );
  206. return response()->json($matches);
  207. }
  208. // dx suggest v2 - from ICD tables
  209. public function dxSuggestV2JSON(Request $request)
  210. {
  211. $term = $request->input('term') ? trim($request->input('term')) : '';
  212. if (empty($term)) return '';
  213. $customProblems = get_custom_problems();
  214. $customResults = [];
  215. foreach($customProblems as $p){
  216. if(str_contains(strtolower($p['text']), strtolower($term))){
  217. $customResults[] = $p;
  218. }
  219. }
  220. $matches = DB::connection('pgsql_fdb')->select("
  221. SELECT distinct on (sim1) SIMILARITY(r2.icd_desc, :term) as sim1,
  222. search_icd_cd as sub_text,
  223. r1.icd_cd_type,
  224. r2.icd_desc as text,
  225. r1.related_dxid as dxid,
  226. r1.fml_clin_code,
  227. r1.fml_nav_code,
  228. r3.dxid_desc56
  229. FROM RFMLISR1_ICD_SEARCH r1
  230. JOIN RFMLINM1_ICD_DESC r2 ON r1.search_icd_cd = r2.icd_cd
  231. LEFT OUTER JOIN RFMLDX0_DXID r3 ON r1.related_dxid = r3.dxid
  232. WHERE r1.icd_cd_type = '05'
  233. AND r1.fml_clin_code = '01'
  234. AND (SIMILARITY(r2.icd_desc, :term) >= " . config('stag.fuzzySearchMinimumSimilarityScore')['problem'] . " OR
  235. r1.search_icd_cd ILIKE :term2)
  236. ORDER BY sim1 DESC
  237. ",
  238. ['term' => $term, 'term2' => $term . '%']
  239. );
  240. $matches = array_merge($customResults, $matches);
  241. return response()->json(['success'=>true, 'data'=>$matches]);
  242. }
  243. // allergy suggest
  244. public function allergySuggest(Request $request)
  245. {
  246. $term = $request->input('term') ? trim($request->input('term')) : '';
  247. if (empty($term)) return '';
  248. $matches = DB::connection('pgsql_fdb')->select("
  249. SELECT r1.dam_concept_id, r1.dam_concept_id_typ, r1.dam_concept_id_desc
  250. FROM rdamca0_concept r1
  251. WHERE (r1.dam_concept_id_desc ILIKE :term)
  252. ORDER BY r1.dam_concept_id_desc
  253. ",
  254. ['term' => $term . '%']
  255. );
  256. return view('app.fdb-pg.fdb-allergy-suggest', compact('matches'));
  257. }
  258. // allergy suggest (json response)
  259. public function allergySuggestJSON(Request $request)
  260. {
  261. $term = $request->input('term') ? trim($request->input('term')) : '';
  262. if (empty($term)) return '';
  263. $matches = DB::connection('pgsql_fdb')->select("
  264. SELECT distinct on (sim1) SIMILARITY(r1.dam_concept_id_desc, :term) as sim1,
  265. r1.dam_concept_id, r1.dam_concept_id_typ, r1.dam_concept_id_desc as text
  266. FROM rdamca0_concept r1 join rdamcd0_picklist_con_typ_desc r2 on r1.dam_concept_id_typ = r2.dam_concept_id_typ
  267. WHERE SIMILARITY(r1.dam_concept_id_desc, :term) >= " . config('stag.fuzzySearchMinimumSimilarityScore')['allergy'] . "
  268. ORDER BY sim1 DESC
  269. ",
  270. ['term' => $term]
  271. );
  272. return json_encode([
  273. "success" => true,
  274. "data" => $matches
  275. ]);
  276. }
  277. // drug <-> allergy match making
  278. public function drugAllergies(Request $request) {
  279. // override
  280. if($request->input('test')) {
  281. $x = new \stdClass();
  282. $x->allergen = 'Pollen';
  283. $x->dam_concept_id_typ = 6;
  284. $allergies = [$x];
  285. $y = new \stdClass();
  286. $y->rx = 'Brufen';
  287. $rx = [$y];
  288. }
  289. else {
  290. $input = json_decode($request->input('data'));
  291. $allergies = $input->allergies;
  292. $rx = $input->rx;
  293. }
  294. $output = [];
  295. /*
  296. for each allergy
  297. if dam_concept_id_typ = 1 // allergen-group-id
  298. // https://docs.fdbhealth.com/display/MKDOCUS/Screening+an+NDC+for+a+DAM_ALRGN_GRP+Allergen+-+Illustration+of+Scenario+C
  299. ...
  300. elseif dam_concept_id_typ = 2 // medication-name-id
  301. // https://docs.fdbhealth.com/display/MKDOCUS/Screening+an+NDC+for+a+MED_NAME_ID+Allergen+-+Illustration+of+Scenario+B
  302. ...
  303. elseif dam_concept_id_typ = 6 // base-ingredient-id
  304. // https://docs.fdbhealth.com/display/MKDOCUS/Screening+an+NDC+for+an+Ingredient+Allergen+-+Illustration+of+Scenario+A
  305. ...
  306. endif
  307. endfor
  308. */
  309. foreach ($allergies as $allergy) {
  310. foreach ($rx as $rxItem) {
  311. if($allergy->dam_concept_id_typ == 6) { // ingredient
  312. if ($this->drugAllergyIngredientAllergenVsSingleRx($allergy, $rxItem)) {
  313. $output[] = "<b>{$rxItem->rx}</b> can cause allergic reactions since the patient is allergic to <b>{$allergy->allergen}</b>.";
  314. }
  315. }
  316. else if($allergy->dam_concept_id_typ == 2) { // medication
  317. if ($this->drugAllergyMedicationAllergenVsSingleRx($allergy, $rxItem)) {
  318. $output[] = "<b>{$rxItem->rx}</b> can cause allergic reactions since the patient is allergic to <b>{$allergy->allergen}</b>.";
  319. }
  320. }
  321. else if($allergy->dam_concept_id_typ == 1) { // allergen group
  322. if ($this->drugAllergyGroupAllergenVsSingleRx($allergy, $rxItem)) {
  323. $output[] = "<b>{$rxItem->rx}</b> can cause allergic reactions since the patient is allergic to <b>{$allergy->allergen}</b>.";
  324. }
  325. }
  326. }
  327. }
  328. return implode("<br>", $output);
  329. }
  330. private function drugAllergyIngredientAllergenVsSingleRx($_allergen, $_rx) {
  331. $matches = DB::connection('pgsql_fdb')->select("
  332. (
  333. -- ingredients from medication
  334. SELECT R1.related_hic_seqn as hic_seqn, R2.hic_desc
  335. FROM RHICHCR0_HIC_HIC_LINK R1
  336. JOIN RHICD5_HIC_DESC R2 ON R1.related_hic_seqn = R2.hic_seqn
  337. WHERE R1.hic_seqn IN (
  338. SELECT S2.dam_alrgn_hic_seqn
  339. FROM RMEDMHL0_MED_HICLSEQNO_LINK S1
  340. JOIN RDAMHHA0_HIC_HICL_ALG_LINK S2 ON S1.hicl_seqno = S2.hicl_seqno
  341. WHERE S1.med_concept_id = :medid
  342. AND S1.med_concept_id_typ = 3
  343. )
  344. )
  345. INTERSECT
  346. (
  347. -- all ingredients directly and related from allergens
  348. (
  349. SELECT R1.related_hic_seqn as hic_seqn, R2.hic_desc
  350. FROM RHICHCR0_HIC_HIC_LINK R1
  351. JOIN RHICD5_HIC_DESC R2 ON R1.related_hic_seqn = R2.hic_seqn
  352. WHERE R1.hic_seqn = :allergenConceptID
  353. )
  354. UNION
  355. -- all ingredients via related dam allergen groups
  356. (
  357. SELECT r3.hic_seqn, r4.hic_desc
  358. FROM RDAMGHC0_HIC_ALRGN_GRP_LINK R1
  359. JOIN rdamagd1_alrgn_grp_desc R2 on R1.dam_alrgn_grp = R2.dam_alrgn_grp
  360. JOIN RDAMGHC0_HIC_ALRGN_GRP_LINK R3 on R1.dam_alrgn_grp = R3.dam_alrgn_grp
  361. JOIN RHICD5_HIC_DESC R4 on r3.hic_seqn = r4.hic_seqn
  362. WHERE R1.hic_seqn = :allergenConceptID
  363. AND R2.dam_alrgn_grp_status_cd = 0
  364. ORDER BY r3.hic_seqn
  365. )
  366. )
  367. ",
  368. ['medid' => $_rx->medid, 'allergenConceptID' => $_allergen->dam_concept_id]
  369. );
  370. return !!count($matches);
  371. }
  372. private function drugAllergyMedicationAllergenVsSingleRx($_allergen, $_rx) {
  373. $matches = DB::connection('pgsql_fdb')->select("
  374. (
  375. -- ingredients from medication
  376. SELECT R1.related_hic_seqn as hic_seqn
  377. FROM RHICHCR0_HIC_HIC_LINK R1
  378. JOIN RHICD5_HIC_DESC R2 ON R1.related_hic_seqn = R2.hic_seqn
  379. WHERE R1.hic_seqn IN (
  380. SELECT S2.dam_alrgn_hic_seqn
  381. FROM RMEDMHL0_MED_HICLSEQNO_LINK S1
  382. JOIN RDAMHHA0_HIC_HICL_ALG_LINK S2 ON S1.hicl_seqno = S2.hicl_seqno
  383. WHERE S1.med_concept_id = :medid
  384. AND S1.med_concept_id_typ = 3
  385. )
  386. )
  387. INTERSECT
  388. (
  389. -- all ingredients directly and related from allergens
  390. SELECT R1.dam_alrgn_hic_seqn as hic_seqn
  391. FROM RDAMHHA0_HIC_HICL_ALG_LINK R1
  392. WHERE R1.hicl_seqno IN (
  393. SELECT R1.hicl_seqno
  394. FROM RMEDMHL0_MED_HICLSEQNO_LINK R1
  395. WHERE R1.med_concept_id_typ = 1
  396. AND R1.med_concept_id = :allergenConceptID
  397. AND MED_CONCEPT_HICL_SRC_CD = 0
  398. )
  399. )
  400. ",
  401. ['medid' => $_rx->medid, 'allergenConceptID' => $_allergen->dam_concept_id]
  402. );
  403. return !!count($matches);
  404. }
  405. private function drugAllergyGroupAllergenVsSingleRx($_allergen, $_rx) {
  406. $matches = DB::connection('pgsql_fdb')->select("
  407. (
  408. -- ingredients from medication
  409. SELECT R1.related_hic_seqn as hic_seqn
  410. FROM RHICHCR0_HIC_HIC_LINK R1
  411. JOIN RHICD5_HIC_DESC R2 ON R1.related_hic_seqn = R2.hic_seqn
  412. WHERE R1.hic_seqn IN (
  413. SELECT S2.dam_alrgn_hic_seqn
  414. FROM RMEDMHL0_MED_HICLSEQNO_LINK S1
  415. JOIN RDAMHHA0_HIC_HICL_ALG_LINK S2 ON S1.hicl_seqno = S2.hicl_seqno
  416. WHERE S1.med_concept_id = :medid
  417. AND S1.med_concept_id_typ = 3
  418. )
  419. )
  420. INTERSECT
  421. (
  422. -- ingredients from medication allergen
  423. (
  424. SELECT R1.hic_seqn as hic_seqn
  425. FROM RDAMGHC0_HIC_ALRGN_GRP_LINK R1
  426. WHERE R1.DAM_ALRGN_GRP = :allergenConceptID
  427. )
  428. UNION
  429. (
  430. SELECT distinct s1.hic_seqn
  431. FROM RDAMXHC0_HIC_ALRGN_XSENSE_LINK S1
  432. WHERE S1.dam_alrgn_xsense IN (
  433. SELECT R1.dam_alrgn_xsense
  434. FROM RDAMGX0_ALRGN_GRP_XSENSE_LINK R1
  435. JOIN RDAMCSD1_XSENSIT_ALLERGY_DESC R2 on R1.dam_alrgn_xsense = R2.dam_alrgn_xsense
  436. WHERE R1.dam_alrgn_grp = :allergenConceptID
  437. AND R2.dam_alrgn_xsense_status_cd = 0
  438. )
  439. )
  440. )
  441. ",
  442. ['medid' => $_rx->medid, 'allergenConceptID' => $_allergen->dam_concept_id]
  443. );
  444. return !!count($matches);
  445. }
  446. // drug <-> drug match making
  447. public function drugDrugInteraction(Request $request) {
  448. if($request->input('test')) {
  449. // override
  450. $rx = json_decode(json_encode([
  451. [
  452. "gcn_seqno" => "45190",
  453. "med_name_id" => "18604",
  454. "medid" => "234539",
  455. "routed_dosage_form_med_id" => "95130",
  456. "routed_med_id" => "19876",
  457. "rx" => "Zyprexa Zydis",
  458. ],
  459. [
  460. "gcn_seqno" => "49853",
  461. "med_name_id" => "26164",
  462. "medid" => "400058",
  463. "routed_dosage_form_med_id" => "36194",
  464. "routed_med_id" => "32562",
  465. "rx" => "Orfadin",
  466. ],
  467. ]));
  468. }
  469. else {
  470. $input = json_decode($request->input('data'));
  471. $rx = $input->rx;
  472. }
  473. if(count($rx) < 2) return "";
  474. $leftIndex = 0;
  475. $output = [];
  476. for ($i=$leftIndex; $i<count($rx) - 1; $i++) {
  477. for ($j=$i + 1; $j<count($rx); $j++) {
  478. $output[] = $this->drugDrugInteractionSinglePair($rx[$i], $rx[$j]);
  479. }
  480. }
  481. $output = array_filter($output, function($_x) {
  482. return !!$_x;
  483. });
  484. return implode("<br>", $output);
  485. }
  486. private function drugDrugInteractionSinglePair($_rx1, $_rx2) {
  487. $output = [];
  488. // get active ingredient DDI_CODEX values for drug 1 and 2
  489. $rx1ActiveDdiCodex = $this->getActiveDdiCodexFromGcnSeqNo($_rx1->gcn_seqno);
  490. $rx2ActiveDdiCodex = $this->getActiveDdiCodexFromGcnSeqNo($_rx2->gcn_seqno);
  491. if(!$rx1ActiveDdiCodex || !$rx2ActiveDdiCodex || !count($rx1ActiveDdiCodex) || !count($rx2ActiveDdiCodex)) return "";
  492. // dump($rx1_DDI_CODEX);
  493. // dump($rx2_DDI_CODEX);
  494. // get inactive ingredient DDI_CODEX values for drug 1 and 2
  495. // to get this we need to first get the NDCs of the drugs
  496. $rx1Ndc = $this->getNdcFromMedId($_rx1->medid);
  497. $rx2Ndc = $this->getNdcFromMedId($_rx2->medid);
  498. // dump($rx1Ndc);
  499. // dump($rx2Ndc);
  500. $rx1InactiveDdiCodex = $this->getInactiveDdiCodexFromNdc($rx1Ndc);
  501. $rx2InactiveDdiCodex = $this->getInactiveDdiCodexFromNdc($rx2Ndc);
  502. // if(!$rx1InactiveDdiCodex || !$rx2InactiveDdiCodex || !count($rx1InactiveDdiCodex) || !count($rx2InactiveDdiCodex)) return "";
  503. // dump($rx1InactiveDdiCodex);
  504. // dump($rx2InactiveDdiCodex);
  505. // get ddi codex - monox pairs for drug 1 & 2
  506. $rx1ActiveDdiCodexMonoxPairs = $this->getDdiCodexMonoxPairs($rx1ActiveDdiCodex);
  507. $rx1InactiveDdiCodexMonoxPairs = $this->getDdiCodexMonoxPairs($rx1InactiveDdiCodex);
  508. $rx2ActiveDdiCodexMonoxPairs = $this->getDdiCodexMonoxPairs($rx2ActiveDdiCodex);
  509. $rx2InactiveDdiCodexMonoxPairs = $this->getDdiCodexMonoxPairs($rx2InactiveDdiCodex);
  510. // dump($rx1ActiveDdiCodexMonoxPairs);
  511. // dump($rx1InactiveDdiCodexMonoxPairs);
  512. // dump($rx2ActiveDdiCodexMonoxPairs);
  513. // dump($rx2InactiveDdiCodexMonoxPairs);
  514. // compare 1-active to 2-active and 2-inactive
  515. $activeCatches = [];
  516. foreach ($rx1ActiveDdiCodexMonoxPairs as $compareLeft) {
  517. foreach ($rx2ActiveDdiCodexMonoxPairs as $compareRight) {
  518. if($compareLeft->ddi_monox == $compareRight->ddi_monox && $compareLeft->ddi_codex != $compareRight->ddi_codex) {
  519. $activeCatches[] = $compareLeft->ddi_codex;
  520. }
  521. }
  522. foreach ($rx2InactiveDdiCodexMonoxPairs as $compareRight) {
  523. if($compareLeft->ddi_monox == $compareRight->ddi_monox && $compareLeft->ddi_codex != $compareRight->ddi_codex) {
  524. $activeCatches[] = $compareLeft->ddi_codex;
  525. }
  526. }
  527. }
  528. // compare 1-inactive to 2-active and 2-inactive
  529. $inactiveCatches = [];
  530. foreach ($rx1InactiveDdiCodexMonoxPairs as $compareLeft) {
  531. foreach ($rx2ActiveDdiCodexMonoxPairs as $compareRight) {
  532. if($compareLeft->ddi_monox == $compareRight->ddi_monox && $compareLeft->ddi_codex != $compareRight->ddi_codex) {
  533. $inactiveCatches[] = $compareLeft->ddi_codex;
  534. }
  535. }
  536. foreach ($rx2InactiveDdiCodexMonoxPairs as $compareRight) {
  537. if($compareLeft->ddi_monox == $compareRight->ddi_monox && $compareLeft->ddi_codex != $compareRight->ddi_codex) {
  538. $inactiveCatches[] = $compareLeft->ddi_codex;
  539. }
  540. }
  541. }
  542. if(count($activeCatches)) {
  543. $output[] = "<b>{$_rx2->rx}</b> interacts with one or more active ingredients in <b>{$_rx1->rx}</b>.";
  544. }
  545. if(count($inactiveCatches)) {
  546. $output[] = "<b>{$_rx2->rx}</b> interacts with one or more inactive ingredients in <b>{$_rx1->rx}</b>.";
  547. }
  548. // TODO: find out and show the names of the actual ingredients causing interaction
  549. return implode("<br>", $output);
  550. }
  551. private function getActiveDdiCodexFromGcnSeqNo($_gcnSeqNo) {
  552. $ddiCodexArray = [];
  553. $query = DB::connection('pgsql_fdb')->select("
  554. SELECT r1.ddi_codex
  555. FROM RADIMGC4_GCNSEQNO_LINK r1
  556. WHERE r1.gcn_seqno = :gcnSeqNo
  557. ",
  558. ['gcnSeqNo' => $_gcnSeqNo]
  559. );
  560. if(count($query)) {
  561. $ddiCodexArray = array_map(function($_x) {
  562. return $_x->ddi_codex;
  563. }, $query);
  564. }
  565. return $ddiCodexArray;
  566. }
  567. private function getNdcFromMedId($_medId) {
  568. $ndcArray = [];
  569. $query = DB::connection('pgsql_fdb')->select("
  570. select ndc from rmindc1_ndc_medid where medid = :medId
  571. ",
  572. ['medId' => $_medId]
  573. );
  574. if(count($query)) {
  575. $ndcArray = array_map(function($_x) {
  576. return $_x->ndc;
  577. }, $query);
  578. }
  579. return $ndcArray;
  580. }
  581. private function getInactiveDdiCodexFromNdc($_ndc) {
  582. $ddiCodexArray = [];
  583. $query = DB::connection('pgsql_fdb')->select("
  584. SELECT distinct r1.ddi_codex
  585. FROM RDDIMIN0_NDC_INACTV_DDIM_LINK r1
  586. WHERE r1.ddi_ndc IN (" . implode(',', array_map(function($_x) {return "'" . $_x . "'";}, $_ndc)) . ")
  587. "
  588. );
  589. if(count($query)) {
  590. $ddiCodexArray = array_map(function($_x) {
  591. return $_x->ddi_codex;
  592. }, $query);
  593. }
  594. return $ddiCodexArray;
  595. }
  596. private function getDdiCodexMonoxPairs($_ddiCodexArray) {
  597. $ddiCodexMonoxPairsArray = [];
  598. if(count($_ddiCodexArray)) {
  599. $ddiCodexMonoxPairsArray = DB::connection('pgsql_fdb')->select("
  600. SELECT r1.ddi_codex, r1.ddi_monox
  601. FROM RADIMMA5_MSTR r1
  602. WHERE r1.ddi_codex IN (" . implode(',', array_map(function($_x) {return "'" . $_x . "'";}, $_ddiCodexArray)) . ")
  603. "
  604. );
  605. }
  606. return $ddiCodexMonoxPairsArray;
  607. }
  608. // drug <-> drug coadministration notes
  609. public function drugCoadministration(Request $request) {
  610. $gcnSeqnos = $request->input('gcn-seqnos') ? trim($request->input('gcn-seqnos')) : '';
  611. if (empty($gcnSeqnos)) return '';
  612. //$gcnSeqnos = explode(",", $gcnSeqnos);
  613. $coadministration = DB::connection('pgsql_fdb')->select("
  614. SELECT distinct r1.coadmin_dosing_text
  615. FROM radige0_ddi_gcnseqno_except r1
  616. WHERE r1.side_a_gcn_seqno in ($gcnSeqnos) AND r1.side_b_gcn_seqno in ($gcnSeqnos)
  617. "
  618. );
  619. return view('app.fdb-pg.fdb-coadministration', compact('coadministration'));
  620. }
  621. // duplicate therapy indications
  622. public function duplicateTherapy(Request $request) {
  623. if($request->input('test')) {
  624. // override
  625. $rx = json_decode(json_encode([
  626. [
  627. "gcn_seqno" => "4376",
  628. "med_name_id" => "1076",
  629. "medid" => "172480",
  630. "routed_dosage_form_med_id" => "5870",
  631. "routed_med_id" => "1082",
  632. "rx" => "aspirin 325",
  633. ],
  634. [
  635. "gcn_seqno" => "4377",
  636. "med_name_id" => "1076",
  637. "medid" => "216092",
  638. "routed_dosage_form_med_id" => "5870",
  639. "routed_med_id" => "1082",
  640. "rx" => "aspirin 500",
  641. ],
  642. ]));
  643. }
  644. else {
  645. $input = json_decode($request->input('data'));
  646. $rx = $input->rx;
  647. }
  648. $dptClasses = [];
  649. foreach ($rx as $rxItem) {
  650. $rxItem->dpt = $this->getDptClassFromGcnSeqNo($rxItem->gcn_seqno);
  651. }
  652. // dd($rx);
  653. $leftIndex = 0;
  654. $matches = [];
  655. for ($i=$leftIndex; $i<count($rx) - 1; $i++) {
  656. for ($j=$i + 1; $j<count($rx); $j++) {
  657. $compareResult = $this->compareDPTs($rx[$i]->dpt, $rx[$j]->dpt);
  658. foreach ($compareResult as $c) {
  659. $matches[] = "<b>{$rx[$i]->rx}</b> and <b>{$rx[$j]->rx}</b> both participate in the duplicate therapy class <b>{$c->dpt_class_desc}</b> (duplicates allowed: {$c->dpt_allowance})";
  660. }
  661. }
  662. }
  663. return "<ol class='pl-0 ml-3'>" . implode("", array_map(function($_x) {
  664. return "<li class='mb-2'>" . $_x . "</li>";
  665. }, $matches)) . "</ol>";
  666. }
  667. private function getDptClassFromGcnSeqNo($_gcnSeqNo) {
  668. return DB::connection('pgsql_fdb')->select("
  669. SELECT distinct r1.dpt_class_id, r2.dpt_allowance, r2.dpt_class_desc
  670. FROM RDPTGC0_GCNSEQNO_LINK r1
  671. JOIN RDPTCL0_CLASS_ID r2 on r1.dpt_class_id = r2.dpt_class_id
  672. WHERE r1.gcn_seqno = :gcnSeqNo
  673. ",
  674. ['gcnSeqNo' => $_gcnSeqNo]
  675. );
  676. }
  677. private function compareDPTs($_dptArray1, $_dptArray2) {
  678. $output = [];
  679. for ($i = 0; $i < count($_dptArray1); $i++) {
  680. for ($j = 0; $j < count($_dptArray2); $j++) {
  681. if ($_dptArray1[$i]->dpt_class_id == $_dptArray2[$j]->dpt_class_id) {
  682. $output[] = json_decode(json_encode([
  683. "dpt_allowance" => $_dptArray1[$i]->dpt_allowance,
  684. "dpt_class_desc" => $_dptArray1[$i]->dpt_class_desc
  685. ]));
  686. }
  687. }
  688. }
  689. return $output;
  690. }
  691. public function rxVigilance(Request $request, Client $patient) {
  692. return view('app.fdb-pg.rx-vigilance', compact('patient'));
  693. }
  694. public function dxVigilance(Request $request, Client $patient) {
  695. return view('app.fdb-pg.dx-vigilance', compact('patient'));
  696. }
  697. public function allergyVigilance(Request $request, Client $patient) {
  698. return view('app.fdb-pg.allergy-vigilance', compact('patient'));
  699. }
  700. }