Kaynağa Gözat

added debit bills

= 3 yıl önce
ebeveyn
işleme
c8d90a6d4b

+ 671 - 0
app/Http/Controllers/FDBPGController.php

@@ -0,0 +1,671 @@
+<?php
+
+namespace App\Http\Controllers;
+
+use Illuminate\Http\Request;
+use Illuminate\Support\Facades\DB;
+
+class FDBPGController extends Controller
+{
+
+    public function rx(Request $request)
+    {
+        return view('app.fdb-pg.fdb-rx');
+    }
+
+    // 1. medication suggest
+    public function medSuggest(Request $request)
+    {
+        $term = $request->input('term') ? trim($request->input('term')) : '';
+        if (empty($term)) return '';
+        $matches = DB::connection('pgsql_fdb')->select(
+            "SELECT med_name_id, med_name FROM rminmid1_med_name WHERE med_status_cd = '0' AND med_name ILIKE :term ORDER BY med_name",
+            ['term' => '%' . $term . '%']
+        );
+        return view('app.fdb-pg.fdb-med-suggest', compact('matches'));
+    }
+
+    // 1.1 medication suggest (json response)
+    public function medSuggestJSON(Request $request)
+    {
+        $term = $request->input('term') ? trim($request->input('term')) : '';
+        if (empty($term)) return '';
+        $matches = DB::connection('pgsql_fdb')->select(
+            "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",
+            ['term' => '%' . $term . '%']
+        );
+        return json_encode([
+            "success" => true,
+            "data" => $matches
+        ]);
+    }
+
+    // 2. routed meds from men name
+    public function routedMeds(Request $request)
+    {
+        $medNameID = $request->input('med-name-id') ? trim($request->input('med-name-id')) : '';
+        if (empty($medNameID)) return '';
+        $matches = DB::connection('pgsql_fdb')->select(
+            "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",
+            ['medNameID' => $medNameID]
+        );
+        return json_encode($matches);
+    }
+
+    // 3. routed dosage from routed med
+    public function routedDosages(Request $request)
+    {
+        $routedMedID = $request->input('routed-med-id') ? trim($request->input('routed-med-id')) : '';
+        if (empty($routedMedID)) return '';
+        $matches = DB::connection('pgsql_fdb')->select(
+            "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",
+            ['routedMedID' => $routedMedID]
+        );
+        return json_encode($matches);
+    }
+
+    // 4. strengths from routed med
+    public function meds(Request $request)
+    {
+        $dosageFormMedId = $request->input('dosage-form-med-id') ? trim($request->input('dosage-form-med-id')) : '';
+        if (empty($dosageFormMedId)) return '';
+        $matches = DB::connection('pgsql_fdb')->select(
+            "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",
+            ['dosageFormMedId' => $dosageFormMedId]
+        );
+        return json_encode($matches);
+    }
+
+    // side effects for a given rx
+    public function sideEffects(Request $request)
+    {
+        $gcnSeqNo = $request->input('gcn-seq-no') ? trim($request->input('gcn-seq-no')) : '';
+        if (empty($gcnSeqNo)) return '';
+        $sides = DB::connection('pgsql_fdb')->select("
+SELECT r1.side, sm.side_freq, sm.side_sev, sm.dxid, dx.dxid_desc56
+FROM rsidegc0_gcnseqno_link r1
+    JOIN rsidema3_mstr sm ON r1.side = sm.side
+    JOIN rfmldx0_dxid dx ON sm.dxid = dx.dxid
+WHERE r1.gcn_seqno = :gcnSeqNo
+ORDER BY sm.side_sev DESC, sm.side_freq ASC
+            ",
+            ['gcnSeqNo' => $gcnSeqNo]
+        );
+        return view('app.fdb-pg.fdb-side-effects', compact('sides'));
+    }
+
+    // ger prec for a given rx
+    public function geriatricPrecautions(Request $request)
+    {
+        $gcnSeqNo = $request->input('gcn-seq-no') ? trim($request->input('gcn-seq-no')) : '';
+        if (empty($gcnSeqNo)) return '';
+        $precautions = DB::connection('pgsql_fdb')->select("
+SELECT r1.geri_code, gm.geri_sl, gm.geri_desc, gm.geri_narrative
+FROM rgerigc0_geri_gcnseqno_link r1
+    JOIN rgerima1_geri_mstr gm ON r1.geri_code = gm.geri_code
+WHERE r1.gcn_seqno = :gcnSeqNo
+ORDER BY gm.geri_desc
+            ",
+            ['gcnSeqNo' => $gcnSeqNo]
+        );
+        return view('app.fdb-pg.fdb-geriatric-precautions', compact('precautions'));
+    }
+
+    // indication of a given rx
+    public function indications(Request $request)
+    {
+        $gcnSeqNo = $request->input('gcn-seq-no') ? trim($request->input('gcn-seq-no')) : '';
+        if (empty($gcnSeqNo)) return '';
+        $indications = DB::connection('pgsql_fdb')->select("
+SELECT r1.indcts, r2.indcts_sn, r2.indcts_lbl, r2.dxid, r2.proxy_ind, r3.dxid_desc56
+FROM rindmgc0_indcts_gcnseqno_link r1
+    JOIN rindmma2_indcts_mstr r2 ON r1.indcts = r2.indcts
+    JOIN rfmldx0_dxid r3 ON r2.dxid = r3.dxid
+WHERE r1.gcn_seqno = :gcnSeqNo
+ORDER BY r3.dxid_desc56
+            ",
+            ['gcnSeqNo' => $gcnSeqNo]
+        );
+        return view('app.fdb-pg.fdb-indications', compact('indications'));
+    }
+
+    // contra-indications of a given rx
+    public function contraindications(Request $request)
+    {
+        $routedMedID = $request->input('routed-med-id') ? trim($request->input('routed-med-id')) : '';
+        if (empty($routedMedID)) return '';
+        $contraindications = DB::connection('pgsql_fdb')->select("
+SELECT r1.ddxcn, r2.dxid, r2.ddxcn_sl, r3.dxid_desc56
+FROM rddcmrm0_routed_med_link r1
+    JOIN rddcmma1_contra_mstr r2 ON r1.ddxcn = r2.ddxcn
+    JOIN rfmldx0_dxid r3 ON r2.dxid = r3.dxid
+WHERE r1.routed_med_id = :routedMedID
+ORDER BY r2.ddxcn_sl
+            ",
+            ['routedMedID' => $routedMedID]
+        );
+        return view('app.fdb-pg.fdb-contraindications', compact('contraindications'));
+    }
+
+    // dx suggest
+    public function dxSuggest(Request $request)
+    {
+        $term = $request->input('term') ? trim($request->input('term')) : '';
+        if (empty($term)) return '';
+        $matches = DB::connection('pgsql_fdb')->select("
+SELECT distinct(r1.dxid), r1.dxid_desc56
+FROM rfmldx0_dxid r1
+JOIN rfmlsyn0_dxid_syn r2 ON r1.dxid = r2.dxid
+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)
+ORDER BY r1.dxid_desc56
+",
+            ['term' => '%' . $term . '%']
+        );
+        return view('app.fdb-pg.fdb-dx-suggest', compact('matches'));
+    }
+
+    public function dxSuggestJSON(Request $request)
+    {
+        $term = $request->input('term') ? trim($request->input('term')) : '';
+        //sample
+        $matches = [
+             ['icd' => '384',  "text" =>"juvenile diabetes"],
+             ['icd' => '387',  "text" =>"insulin-dependent DM"],
+             ['icd' => '388',  "text" =>"insulin-dependent diabetes mellitus"],
+             ['icd' => '389',  "text" =>"ketosis-prone diabetes mellitus"],
+             ['icd' => '390',  "text" =>"ketosis-prone diabetes"],
+             ['icd' => '391',  "text" =>"juvenile-onset diabetes"],
+             ['icd' => '392',  "text" =>"juvenile-onset diabetes mellitus"],
+             ['icd' => '393',  "text" =>"juvenile onset DM"],
+             ['icd' => '394',  "text" =>"type I diabetes mellitus"],
+             ['icd' => '395',  "text" =>"diabetes mellitus type"],
+             ['icd' => '396',  "text" =>"ketosis-prone DM"],
+           ['icd' => '58331',  "text" =>"insulin dependent diabetes mellitus"],
+           ['icd' => '58407',  "text" =>"immune mediated diabetes mellitus"],
+        ];
+        return response()->json(['success'=>true, 'data'=>$matches]);
+    }
+
+    // allergy suggest
+    public function allergySuggest(Request $request)
+    {
+        $term = $request->input('term') ? trim($request->input('term')) : '';
+        if (empty($term)) return '';
+        $matches = DB::connection('pgsql_fdb')->select("
+SELECT r1.dam_concept_id, r1.dam_concept_id_typ, r1.dam_concept_id_desc
+FROM rdamca0_concept r1
+WHERE (r1.dam_concept_id_desc ILIKE :term)
+ORDER BY r1.dam_concept_id_desc
+",
+            ['term' => '%' . $term . '%']
+        );
+        return view('app.fdb-pg.fdb-allergy-suggest', compact('matches'));
+    }
+
+    // drug <-> allergy match making
+    public function drugAllergies(Request $request) {
+
+        // override
+        if($request->input('test')) {
+            $x = new \stdClass();
+            $x->allergen = 'Pollen';
+            $x->dam_concept_id_typ = 6;
+            $allergies = [$x];
+            $y = new \stdClass();
+            $y->rx = 'Brufen';
+            $rx = [$y];
+        }
+        else {
+            $input = json_decode($request->input('data'));
+            $allergies = $input->allergies;
+            $rx = $input->rx;
+        }
+
+        $output = [];
+
+        /*
+        for each allergy
+            if dam_concept_id_typ = 1 // allergen-group-id
+                // https://docs.fdbhealth.com/display/MKDOCUS/Screening+an+NDC+for+a+DAM_ALRGN_GRP+Allergen+-+Illustration+of+Scenario+C
+                ...
+            elseif dam_concept_id_typ = 2 // medication-name-id
+                // https://docs.fdbhealth.com/display/MKDOCUS/Screening+an+NDC+for+a+MED_NAME_ID+Allergen+-+Illustration+of+Scenario+B
+                ...
+            elseif dam_concept_id_typ = 6 // base-ingredient-id
+                // https://docs.fdbhealth.com/display/MKDOCUS/Screening+an+NDC+for+an+Ingredient+Allergen+-+Illustration+of+Scenario+A
+                ...
+            endif
+        endfor
+        */
+
+        foreach ($allergies as $allergy) {
+            foreach ($rx as $rxItem) {
+                if($allergy->dam_concept_id_typ == 6) { // ingredient
+                    if ($this->drugAllergyIngredientAllergenVsSingleRx($allergy, $rxItem)) {
+                        $output[] = "<b>{$rxItem->rx}</b> can cause allergic reactions since the patient is allergic to <b>{$allergy->allergen}</b>.";
+                    }
+                }
+                else if($allergy->dam_concept_id_typ == 2) { // medication
+                    if ($this->drugAllergyMedicationAllergenVsSingleRx($allergy, $rxItem)) {
+                        $output[] = "<b>{$rxItem->rx}</b> can cause allergic reactions since the patient is allergic to <b>{$allergy->allergen}</b>.";
+                    }
+                }
+                else if($allergy->dam_concept_id_typ == 1) { // allergen group
+                    if ($this->drugAllergyGroupAllergenVsSingleRx($allergy, $rxItem)) {
+                        $output[] = "<b>{$rxItem->rx}</b> can cause allergic reactions since the patient is allergic to <b>{$allergy->allergen}</b>.";
+                    }
+                }
+            }
+        }
+
+        return implode("<br>", $output);
+
+    }
+
+        private function drugAllergyIngredientAllergenVsSingleRx($_allergen, $_rx) {
+
+            $matches = DB::connection('pgsql_fdb')->select("
+    (
+        -- ingredients from medication
+        SELECT R1.related_hic_seqn as hic_seqn, R2.hic_desc
+        FROM RHICHCR0_HIC_HIC_LINK R1
+                 JOIN RHICD5_HIC_DESC R2 ON R1.related_hic_seqn = R2.hic_seqn
+        WHERE R1.hic_seqn IN (
+            SELECT S2.dam_alrgn_hic_seqn
+            FROM RMEDMHL0_MED_HICLSEQNO_LINK S1
+                     JOIN RDAMHHA0_HIC_HICL_ALG_LINK S2 ON S1.hicl_seqno = S2.hicl_seqno
+            WHERE S1.med_concept_id = :medid
+              AND S1.med_concept_id_typ = 3
+        )
+    )
+    INTERSECT
+    (
+        -- all ingredients directly and related from allergens
+        (
+            SELECT R1.related_hic_seqn as hic_seqn, R2.hic_desc
+            FROM RHICHCR0_HIC_HIC_LINK R1
+                     JOIN RHICD5_HIC_DESC R2 ON R1.related_hic_seqn = R2.hic_seqn
+            WHERE R1.hic_seqn = :allergenConceptID
+        )
+        UNION
+        -- all ingredients via related dam allergen groups
+        (
+            SELECT r3.hic_seqn, r4.hic_desc
+            FROM RDAMGHC0_HIC_ALRGN_GRP_LINK R1
+                     JOIN rdamagd1_alrgn_grp_desc R2 on R1.dam_alrgn_grp = R2.dam_alrgn_grp
+                     JOIN RDAMGHC0_HIC_ALRGN_GRP_LINK R3 on R1.dam_alrgn_grp = R3.dam_alrgn_grp
+                     JOIN RHICD5_HIC_DESC R4 on r3.hic_seqn = r4.hic_seqn
+            WHERE R1.hic_seqn = :allergenConceptID
+              AND R2.dam_alrgn_grp_status_cd = 0
+            ORDER BY r3.hic_seqn
+        )
+    )
+    ",
+                ['medid' => $_rx->medid, 'allergenConceptID' => $_allergen->dam_concept_id]
+            );
+
+            return !!count($matches);
+        }
+
+        private function drugAllergyMedicationAllergenVsSingleRx($_allergen, $_rx) {
+
+            $matches = DB::connection('pgsql_fdb')->select("
+    (
+        -- ingredients from medication
+        SELECT R1.related_hic_seqn as hic_seqn
+        FROM RHICHCR0_HIC_HIC_LINK R1
+                 JOIN RHICD5_HIC_DESC R2 ON R1.related_hic_seqn = R2.hic_seqn
+        WHERE R1.hic_seqn IN (
+            SELECT S2.dam_alrgn_hic_seqn
+            FROM RMEDMHL0_MED_HICLSEQNO_LINK S1
+                     JOIN RDAMHHA0_HIC_HICL_ALG_LINK S2 ON S1.hicl_seqno = S2.hicl_seqno
+            WHERE S1.med_concept_id = :medid
+              AND S1.med_concept_id_typ = 3
+        )
+    )
+    INTERSECT
+    (
+        -- all ingredients directly and related from allergens
+        SELECT R1.dam_alrgn_hic_seqn as hic_seqn
+        FROM RDAMHHA0_HIC_HICL_ALG_LINK R1
+        WHERE R1.hicl_seqno IN (
+            SELECT R1.hicl_seqno
+            FROM RMEDMHL0_MED_HICLSEQNO_LINK R1
+            WHERE R1.med_concept_id_typ = 1
+              AND R1.med_concept_id = :allergenConceptID
+              AND MED_CONCEPT_HICL_SRC_CD = 0
+        )
+    )
+    ",
+                ['medid' => $_rx->medid, 'allergenConceptID' => $_allergen->dam_concept_id]
+            );
+
+            return !!count($matches);
+        }
+
+        private function drugAllergyGroupAllergenVsSingleRx($_allergen, $_rx) {
+
+        $matches = DB::connection('pgsql_fdb')->select("
+(
+    -- ingredients from medication
+    SELECT R1.related_hic_seqn as hic_seqn
+    FROM RHICHCR0_HIC_HIC_LINK R1
+             JOIN RHICD5_HIC_DESC R2 ON R1.related_hic_seqn = R2.hic_seqn
+    WHERE R1.hic_seqn IN (
+        SELECT S2.dam_alrgn_hic_seqn
+        FROM RMEDMHL0_MED_HICLSEQNO_LINK S1
+                 JOIN RDAMHHA0_HIC_HICL_ALG_LINK S2 ON S1.hicl_seqno = S2.hicl_seqno
+        WHERE S1.med_concept_id = :medid
+          AND S1.med_concept_id_typ = 3
+    )
+)
+INTERSECT
+(
+    -- ingredients from medication allergen
+    (
+        SELECT R1.hic_seqn as hic_seqn
+        FROM RDAMGHC0_HIC_ALRGN_GRP_LINK R1
+        WHERE R1.DAM_ALRGN_GRP = :allergenConceptID
+    )
+    UNION
+    (
+        SELECT distinct s1.hic_seqn
+        FROM RDAMXHC0_HIC_ALRGN_XSENSE_LINK S1
+        WHERE S1.dam_alrgn_xsense IN (
+            SELECT R1.dam_alrgn_xsense
+            FROM RDAMGX0_ALRGN_GRP_XSENSE_LINK R1
+                     JOIN RDAMCSD1_XSENSIT_ALLERGY_DESC R2 on R1.dam_alrgn_xsense = R2.dam_alrgn_xsense
+            WHERE R1.dam_alrgn_grp = :allergenConceptID
+              AND R2.dam_alrgn_xsense_status_cd = 0
+        )
+    )
+)
+",
+            ['medid' => $_rx->medid, 'allergenConceptID' => $_allergen->dam_concept_id]
+        );
+
+        return !!count($matches);
+    }
+
+    // drug <-> drug match making
+    public function drugDrugInteraction(Request $request) {
+
+        if($request->input('test')) {
+            // override
+            $rx = json_decode(json_encode([
+                [
+                    "gcn_seqno" => "45190",
+                    "med_name_id" => "18604",
+                    "medid" => "234539",
+                    "routed_dosage_form_med_id" => "95130",
+                    "routed_med_id" => "19876",
+                    "rx" => "Zyprexa Zydis",
+                ],
+                [
+                    "gcn_seqno" => "49853",
+                    "med_name_id" => "26164",
+                    "medid" => "400058",
+                    "routed_dosage_form_med_id" => "36194",
+                    "routed_med_id" => "32562",
+                    "rx" => "Orfadin",
+                ],
+            ]));
+        }
+        else {
+            $input = json_decode($request->input('data'));
+            $rx = $input->rx;
+        }
+
+        if(count($rx) < 2) return "";
+
+        $leftIndex = 0;
+
+        $output = [];
+
+        for ($i=$leftIndex; $i<count($rx) - 1; $i++) {
+            for ($j=$i + 1; $j<count($rx); $j++) {
+                $output[] = $this->drugDrugInteractionSinglePair($rx[$i], $rx[$j]);
+            }
+        }
+
+        $output = array_filter($output, function($_x) {
+            return !!$_x;
+        });
+
+        return implode("<br>", $output);
+    }
+
+        private function drugDrugInteractionSinglePair($_rx1, $_rx2) {
+
+            $output = [];
+
+            // get active ingredient DDI_CODEX values for drug 1 and 2
+            $rx1ActiveDdiCodex = $this->getActiveDdiCodexFromGcnSeqNo($_rx1->gcn_seqno);
+            $rx2ActiveDdiCodex = $this->getActiveDdiCodexFromGcnSeqNo($_rx2->gcn_seqno);
+            if(!$rx1ActiveDdiCodex || !$rx2ActiveDdiCodex || !count($rx1ActiveDdiCodex) || !count($rx2ActiveDdiCodex)) return "";
+
+    //        dump($rx1_DDI_CODEX);
+    //        dump($rx2_DDI_CODEX);
+
+            // get inactive ingredient DDI_CODEX values for drug 1 and 2
+            // to get this we need to first get the NDCs of the drugs
+            $rx1Ndc = $this->getNdcFromMedId($_rx1->medid);
+            $rx2Ndc = $this->getNdcFromMedId($_rx2->medid);
+
+    //        dump($rx1Ndc);
+    //        dump($rx2Ndc);
+
+            $rx1InactiveDdiCodex = $this->getInactiveDdiCodexFromNdc($rx1Ndc);
+            $rx2InactiveDdiCodex = $this->getInactiveDdiCodexFromNdc($rx2Ndc);
+            // if(!$rx1InactiveDdiCodex || !$rx2InactiveDdiCodex || !count($rx1InactiveDdiCodex) || !count($rx2InactiveDdiCodex)) return "";
+
+    //        dump($rx1InactiveDdiCodex);
+    //        dump($rx2InactiveDdiCodex);
+
+            // get ddi codex - monox pairs for drug 1 & 2
+            $rx1ActiveDdiCodexMonoxPairs = $this->getDdiCodexMonoxPairs($rx1ActiveDdiCodex);
+            $rx1InactiveDdiCodexMonoxPairs = $this->getDdiCodexMonoxPairs($rx1InactiveDdiCodex);
+            $rx2ActiveDdiCodexMonoxPairs = $this->getDdiCodexMonoxPairs($rx2ActiveDdiCodex);
+            $rx2InactiveDdiCodexMonoxPairs = $this->getDdiCodexMonoxPairs($rx2InactiveDdiCodex);
+
+    //        dump($rx1ActiveDdiCodexMonoxPairs);
+    //        dump($rx1InactiveDdiCodexMonoxPairs);
+    //        dump($rx2ActiveDdiCodexMonoxPairs);
+    //        dump($rx2InactiveDdiCodexMonoxPairs);
+
+            // compare 1-active to 2-active and 2-inactive
+            $activeCatches = [];
+            foreach ($rx1ActiveDdiCodexMonoxPairs as $compareLeft) {
+                foreach ($rx2ActiveDdiCodexMonoxPairs as $compareRight) {
+                    if($compareLeft->ddi_monox == $compareRight->ddi_monox && $compareLeft->ddi_codex != $compareRight->ddi_codex) {
+                        $activeCatches[] = $compareLeft->ddi_codex;
+                    }
+                }
+                foreach ($rx2InactiveDdiCodexMonoxPairs as $compareRight) {
+                    if($compareLeft->ddi_monox == $compareRight->ddi_monox && $compareLeft->ddi_codex != $compareRight->ddi_codex) {
+                        $activeCatches[] = $compareLeft->ddi_codex;
+                    }
+                }
+            }
+
+            // compare 1-inactive to 2-active and 2-inactive
+            $inactiveCatches = [];
+            foreach ($rx1InactiveDdiCodexMonoxPairs as $compareLeft) {
+                foreach ($rx2ActiveDdiCodexMonoxPairs as $compareRight) {
+                    if($compareLeft->ddi_monox == $compareRight->ddi_monox && $compareLeft->ddi_codex != $compareRight->ddi_codex) {
+                        $inactiveCatches[] = $compareLeft->ddi_codex;
+                    }
+                }
+                foreach ($rx2InactiveDdiCodexMonoxPairs as $compareRight) {
+                    if($compareLeft->ddi_monox == $compareRight->ddi_monox && $compareLeft->ddi_codex != $compareRight->ddi_codex) {
+                        $inactiveCatches[] = $compareLeft->ddi_codex;
+                    }
+                }
+            }
+
+            if(count($activeCatches)) {
+                $output[] = "<b>{$_rx2->rx}</b> interacts with one or more active ingredients in <b>{$_rx1->rx}</b>.";
+            }
+            if(count($inactiveCatches)) {
+                $output[] = "<b>{$_rx2->rx}</b> interacts with one or more inactive ingredients in <b>{$_rx1->rx}</b>.";
+            }
+
+            // TODO: find out and show the names of the actual ingredients causing interaction
+
+            return implode("<br>", $output);
+        }
+
+        private function getActiveDdiCodexFromGcnSeqNo($_gcnSeqNo) {
+            $ddiCodexArray = [];
+            $query = DB::connection('pgsql_fdb')->select("
+    SELECT r1.ddi_codex
+    FROM RADIMGC4_GCNSEQNO_LINK r1
+    WHERE r1.gcn_seqno = :gcnSeqNo
+                ",
+                ['gcnSeqNo' => $_gcnSeqNo]
+            );
+            if(count($query)) {
+                $ddiCodexArray = array_map(function($_x) {
+                    return $_x->ddi_codex;
+                }, $query);
+            }
+            return $ddiCodexArray;
+        }
+
+        private function getNdcFromMedId($_medId) {
+            $ndcArray = [];
+            $query = DB::connection('pgsql_fdb')->select("
+    select ndc from rmindc1_ndc_medid where medid = :medId
+                ",
+                ['medId' => $_medId]
+            );
+            if(count($query)) {
+                $ndcArray = array_map(function($_x) {
+                    return $_x->ndc;
+                }, $query);
+            }
+            return $ndcArray;
+        }
+
+        private function getInactiveDdiCodexFromNdc($_ndc) {
+            $ddiCodexArray = [];
+            $query = DB::connection('pgsql_fdb')->select("
+    SELECT distinct r1.ddi_codex
+    FROM RDDIMIN0_NDC_INACTV_DDIM_LINK r1
+    WHERE r1.ddi_ndc IN (" . implode(',', array_map(function($_x) {return "'" . $_x . "'";}, $_ndc)) . ")
+                "
+            );
+            if(count($query)) {
+                $ddiCodexArray = array_map(function($_x) {
+                    return $_x->ddi_codex;
+                }, $query);
+            }
+            return $ddiCodexArray;
+        }
+
+        private function getDdiCodexMonoxPairs($_ddiCodexArray) {
+        $ddiCodexMonoxPairsArray = [];
+        if(count($_ddiCodexArray)) {
+            $ddiCodexMonoxPairsArray = DB::connection('pgsql_fdb')->select("
+SELECT r1.ddi_codex, r1.ddi_monox
+FROM RADIMMA5_MSTR r1
+WHERE r1.ddi_codex IN (" . implode(',', array_map(function($_x) {return "'" . $_x . "'";}, $_ddiCodexArray)) . ")
+            "
+            );
+        }
+        return $ddiCodexMonoxPairsArray;
+    }
+
+    // drug <-> drug coadministration notes
+    public function drugCoadministration(Request $request) {
+        $gcnSeqnos = $request->input('gcn-seqnos') ? trim($request->input('gcn-seqnos')) : '';
+        if (empty($gcnSeqnos)) return '';
+        //$gcnSeqnos = explode(",", $gcnSeqnos);
+
+        $coadministration = DB::connection('pgsql_fdb')->select("
+SELECT distinct r1.coadmin_dosing_text
+FROM radige0_ddi_gcnseqno_except r1
+WHERE r1.side_a_gcn_seqno in ($gcnSeqnos) AND r1.side_b_gcn_seqno in ($gcnSeqnos)
+            "
+        );
+        return view('app.fdb-pg.fdb-coadministration', compact('coadministration'));
+    }
+
+    // duplicate therapy indications
+    public function duplicateTherapy(Request $request) {
+
+        if($request->input('test')) {
+            // override
+            $rx = json_decode(json_encode([
+                [
+                    "gcn_seqno" => "4376",
+                    "med_name_id" => "1076",
+                    "medid" => "172480",
+                    "routed_dosage_form_med_id" => "5870",
+                    "routed_med_id" => "1082",
+                    "rx" => "aspirin 325",
+                ],
+                [
+                    "gcn_seqno" => "4377",
+                    "med_name_id" => "1076",
+                    "medid" => "216092",
+                    "routed_dosage_form_med_id" => "5870",
+                    "routed_med_id" => "1082",
+                    "rx" => "aspirin 500",
+                ],
+            ]));
+        }
+        else {
+            $input = json_decode($request->input('data'));
+            $rx = $input->rx;
+        }
+
+        $dptClasses = [];
+        foreach ($rx as $rxItem) {
+            $rxItem->dpt = $this->getDptClassFromGcnSeqNo($rxItem->gcn_seqno);
+        }
+
+        // dd($rx);
+
+        $leftIndex = 0;
+        $matches = [];
+        for ($i=$leftIndex; $i<count($rx) - 1; $i++) {
+            for ($j=$i + 1; $j<count($rx); $j++) {
+                $compareResult = $this->compareDPTs($rx[$i]->dpt, $rx[$j]->dpt);
+                foreach ($compareResult as $c) {
+                    $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})";
+                }
+            }
+        }
+
+        return "<ol class='pl-0 ml-3'>" . implode("", array_map(function($_x) {
+                return "<li class='mb-2'>" . $_x . "</li>";
+            }, $matches)) . "</ol>";
+    }
+
+        private function getDptClassFromGcnSeqNo($_gcnSeqNo) {
+            return DB::connection('pgsql_fdb')->select("
+    SELECT distinct r1.dpt_class_id, r2.dpt_allowance, r2.dpt_class_desc
+    FROM RDPTGC0_GCNSEQNO_LINK r1
+    JOIN RDPTCL0_CLASS_ID r2 on r1.dpt_class_id = r2.dpt_class_id
+    WHERE r1.gcn_seqno = :gcnSeqNo
+                ",
+                ['gcnSeqNo' => $_gcnSeqNo]
+            );
+        }
+
+        private function compareDPTs($_dptArray1, $_dptArray2) {
+        $output = [];
+        for ($i=0; $i<count($_dptArray1); $i++) {
+            for ($j=0; $j<count($_dptArray2); $j++) {
+                if($_dptArray1[$i]->dpt_class_id == $_dptArray2[$j]->dpt_class_id) {
+                    $output[] = json_decode(json_encode([
+                        "dpt_allowance" => $_dptArray1[$i]->dpt_allowance,
+                        "dpt_class_desc" => $_dptArray1[$i]->dpt_class_desc
+                    ]));
+                }
+            }
+        }
+        return $output;
+    }
+}

+ 5 - 0
app/Models/Pro.php

@@ -32,6 +32,11 @@ class Pro extends Model
         return strtolower(implode("", $characters));
     }
 
+    public function debitBills()
+    {
+        return $this->hasMany(Bill::class, 'debit_pro_id');
+    }
+
     public function cmBills()
     {
         return $this->hasMany(Bill::class, 'cm_pro_id');

+ 95 - 0
resources/views/app/patient/segment-templates/intake_problems/edit.blade.php

@@ -0,0 +1,95 @@
+<?php
+
+use App\Models\Point;
+use \App\Models\Client;
+use \App\Models\Note;
+use \App\Models\Segment;
+
+/** @var Client $patient */
+/** @var Note $note */
+/** @var Segment $segment */
+
+$problems = Point::getIntakePointsOfCategory($patient, 'PROBLEM', $note);
+
+?>
+<div>
+
+    <div class="d-flex mb-2">
+        <table class="table table-sm table-bordered table-striped mb-0 bg-white">
+            <thead>
+            <tr class="">
+                <th class="border-bottom-0">Problem</th>
+                <th class="border-bottom-0">Last Review</th>
+                <th class="border-bottom-0">Review Today</th>
+            </tr>
+            </thead>
+            <?php foreach($problems as $problem): ?>
+                <tr>
+                    <td>
+                        <div class="d-flex align-items-baseline">
+                            <div class="<?= $problem->is_removed ? 'strike-through' : '' ?>">
+                                <b><?= !!@($problem->data->name) ? @($problem->data->name) : '-' ?></b>
+                                <?= !!@($problem->data->description) ? '/&nbsp;' . @($problem->data->description) : '' ?>
+                            </div>
+
+                            <!-- common actions -->
+                            <div class="ml-auto d-inline-flex align-items-baseline pr-2">
+                                <?php
+                                $point = $problem;
+                                $label = 'Problem';
+                                include resource_path('views/app/patient/segment-templates/_common_actions/remove-undo.php');
+                                ?>
+                            </div>
+                        </div>
+                    </td>
+                    <td>
+                        <?php
+                        $point = $problem;
+                        include resource_path('views/app/patient/segment-templates/_child_review/last-review.php');
+                        ?>
+                    </td>
+                    <td>
+                        <?php
+                        $point = $problem;
+                        include resource_path('views/app/patient/segment-templates/_child_review/edit-review.php');
+                        ?>
+                    </td>
+                </tr>
+            <?php endforeach; ?>
+        </table>
+    </div>
+
+    <div visit-moe class="mt-1">
+        <a href="#" start show class="btn btn-sm btn btn-outline-primary">+ Add Problem patient is ALREADY having, prior to this visit</a>
+        <form url="/api/visitPoint/addTopLevelOnIntake" class="mcp-theme-1">
+            <input type="hidden" name="segmentUid" value="<?= $segment->uid ?>">
+            <input type="hidden" name="category" value="PROBLEM">
+            <input type="hidden" name="data">
+
+            <p class="mb-2"><b>Add Problem (on intake)</b></p>
+
+            <div class="mb-2">
+                <label class="text-sm text-secondary mb-1">Name</label>
+                <input type="text" data-name="name" class="form-control form-control-sm"
+                       stag-suggest
+                       stag-suggest-ep="/fdb-dx-suggest/json">
+            </div>
+
+			<div class="mb-2">
+                <label class="text-sm text-secondary mb-1">ICD</label>
+                <input type="text" data-name="icd" class="form-control form-control-sm">
+            </div>
+
+            <div class="mb-2">
+                <label class="text-sm text-secondary mb-1">Description</label>
+                <input type="text" data-name="description" class="form-control form-control-sm">
+            </div>
+
+            <div>
+                <button submit class="btn btn-sm btn-primary mr-2">Submit</button>
+                <button cancel class="btn btn-sm btn-default border">Cancel</button>
+            </div>
+        </form>
+    </div>
+</div>
+

+ 97 - 3
resources/views/app/practice-management/pro-financials.blade.php

@@ -29,7 +29,8 @@
                     <tr>
                         <th>Pro</th>
                         <th>Balance Owed</th>
-                        <th class="w-75">Recent Debits</th>
+                        <th class="w-50">Recent Debits</th>
+                        <th class="w-50">Debit Bills</th>
                     </tr>
                     </thead>
                     <tbody>
@@ -51,12 +52,105 @@
                             <td>
                                 @foreach($row->recentDebits() as $debit)
                                     <div class="d-flex align-items-center mb-1">
-                                        <span class="width-90px">{{'$' . $debit->amount}}</span>
-                                        <span class="text-secondary width-90px">{{friendly_date_time($debit->created_at, false)}}</span>
+                                        <span class="">{{'$' . $debit->amount}}</span>
+                                        <span class="text-secondary">{{friendly_date_time($debit->created_at, false)}}</span>
                                         <span class="text-secondary">{{$debit->company ? $debit->company->name : ''}}</span>
                                     </div>
                                 @endforeach
                             </td>
+                            <td>
+                                <div>
+  
+                                    <div moe class="ml-1" relative>
+                                        <a class="text-danger" href="" show start>Create debit bill</a>
+                                        <form url="/api/bill/createForDebit" right>
+                                            <div class="form-group">
+                                                <label for="" class="control-label">Company</label>
+                                                <select name="debitCompanyProUid" class="form-control input-sm">
+                                                    <option value="">--select--</option>
+                                                    @foreach($row->companyPros as $companyPro)
+                                                        <option value="{{$companyPro->uid}}">{{$companyPro->company->name}}</option>
+                                                    @endforeach
+                                                </select>
+                                            </div>
+                                            <div class="form-group">
+                                                <label for="" class="control-label">Amount</label>
+                                                <input type="number" step=".01" name="amount" class="input-sm form-control">
+                                            </div>
+                                            <div class="form-group">
+                                                <label for="" class="control-label">Description</label>
+                                                <textarea name="description" class="input-sm form-control"></textarea>
+                                            </div>
+                                            <div class="form-group">
+                                                <label for="" class="control-label">Description Data</label>
+                                                <textarea name="descriptionData" class="input-sm form-control"></textarea>
+                                            </div>
+                                            <div class="form-group">
+                                                <label for="" class="control-label">Effective Date</label>
+                                                <input type="date" name="effectiveDate" class="input-sm form-control">
+                                            </div>
+                                            <div class="mb-0">
+                                                <button class="btn btn-primary btn-sm" submit>Submit</button>
+                                                <button class="btn btn-default border btn-sm" cancel>Cancel</button>
+                                            </div>
+                                        </form>
+                                    </div>
+                                    
+                                </div>
+                                <table class="table table-sm">
+                                    <thead>
+                                        <tr>
+                                            <th>Bill Amount</th>
+                                            <th>Debited?</th>
+                                            <th>Paid Amount</th>
+                                            <th></th>
+                                        </tr>
+                                        @foreach($row->debitBills as $debitBill)
+                                        <tr>
+                                            <td>{{$debitBill->debit_pro_expected_amount}}</td>
+                                            <td>{{$debitBill->has_debit_pro_been_debited}}</td>
+                                            <td>{{$debitBill->debit_pro_expected_amount?'Yes':'No'}}</td>
+                                            <td>
+                                                
+                                                <div moe class="ml-1" relative>
+                                                    <a class="text-danger" href="" show start>Debit expected amount</a>
+                                                    <form url="/api/bill/debitDebitProAmount" right>
+                                                        <input type="hidden" name="uid" value="{{$debitBill->uid}}">
+
+                                                        <div class="form-group">
+                                                            <label for="" class="control-label">Amount</label>
+                                                            <input type="number" stype=".01"  name="debitDebitProAmount" class="form-control input-sm">
+                                                        </div>
+                                                        
+                                                        <div class="mb-0">
+                                                            <button class="btn btn-primary btn-sm" submit>Submit</button>
+                                                            <button class="btn btn-default border btn-sm" cancel>Cancel</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+
+                                                <div moe class="ml-1" relative>
+                                                    <a class="text-danger" href="" show start>Debit different amount</a>
+                                                    <form url="/api/bill/debitDebitProDifferentAmount" right>
+                                                        <input type="hidden" name="uid" value="{{$debitBill->uid}}">
+                                                        
+                                                        <div class="form-group">
+                                                            <label for="" class="control-label">Amount</label>
+                                                            <input type="number" stype=".01"  name="differentDebitProAmount" class="form-control input-sm">
+                                                        </div>
+                                                        
+                                                        <div class="mb-0">
+                                                            <button class="btn btn-primary btn-sm" submit>Submit</button>
+                                                            <button class="btn btn-default border btn-sm" cancel>Cancel</button>
+                                                        </div>
+                                                    </form>
+                                                </div>
+                                            </td>
+                                        </tr>
+                                        @endforeach
+                                    </thead>
+                                </table>       
+                            </td>
                         </tr>
                     @endforeach
                     </tbody>

+ 34 - 9
routes/web.php

@@ -165,26 +165,26 @@ Route::middleware('pro.auth')->group(function () {
         });
         Route::name('statTrees.')->prefix('stat-trees')->group(function () {
             Route::get('', 'StatTreeController@list')->name('list');
-            Route::get('create', 'StatTreeController@createPage')->name('createPage');            
+            Route::get('create', 'StatTreeController@createPage')->name('createPage');
             Route::name('view.')->prefix('view/{statTree}')->group(function () {
                 Route::get('', 'StatTreeController@dashboard')->name('dashboard');
             });
         });
         Route::name('statTreeLines.')->prefix('stat-tree-lines/')->group(function () {
-            Route::get('', 'StatTreeLineController@list')->name('list');            
+            Route::get('', 'StatTreeLineController@list')->name('list');
             Route::name('view.')->prefix('view/{statTreeLine}')->group(function () {
                 Route::get('', 'StatTreeLineController@dashboard')->name('dashboard');
             });
         });
-        
-        
+
+
         // APIs
         Route::name('api.')->group(function () {
             //Clause
             Route::name('clause.')->prefix('clause/')->group(function () {
                 Route::post('replace-all', 'ClauseController@replaceAll')->name('replaceAll');
             });
-        
+
             //Stat Tree
             Route::name('statTree.')->prefix('stat-tree/')->group(function () {
                 Route::post('create', 'StatTreeController@create')->name('create');
@@ -192,13 +192,13 @@ Route::middleware('pro.auth')->group(function () {
                 Route::post('update-basic', 'StatTreeController@updateBasic')->name('updateBasic');
                 Route::post('refresh-count', 'StatTreeController@refreshCount')->name('refreshCount');
                 Route::post('replace-all-lines', 'StatTreeController@replaceAllLines')->name('replaceAllLines');
-                Route::post('refresh-tree-count-queries', 'StatTreeLineController@refreshTreeCountQueries')->name('refreshTreeCountQueries');              
+                Route::post('refresh-tree-count-queries', 'StatTreeLineController@refreshTreeCountQueries')->name('refreshTreeCountQueries');
             });
-        
+
             //Stat Tree Line
             Route::name('statTreeLine.')->prefix('stat-tree-line/')->group(function () {
-                Route::post('replace-all-report-columns', 'StatTreeLineController@replaceAllReportColumns')->name('replaceAllReportColumns'); 
-                Route::post('refresh-count-query', 'StatTreeLineController@refreshCountQuery')->name('refreshCountQuery');                
+                Route::post('replace-all-report-columns', 'StatTreeLineController@replaceAllReportColumns')->name('replaceAllReportColumns');
+                Route::post('refresh-count-query', 'StatTreeLineController@refreshCountQuery')->name('refreshCountQuery');
             });
         });
 
@@ -368,6 +368,31 @@ Route::middleware('pro.auth')->group(function () {
     Route::post("/back_to_admin_pro", 'HomeController@backToAdminPro')->name('back-to-admin-pro');
 
     Route::get('/remote-monitoring-measurements/{careMonth}', 'PracticeManagementController@remoteMonitoringMeasurements')->name('remote-monitoring-measurements');
+<<<<<<< HEAD
+=======
+
+    Route::get('/patient-care-month-matrix/{careMonth}', 'PatientController@careMonthMatrix')->name('patient-care-month-matrix');
+    Route::get('/pro-care-month-report', 'PracticeManagementController@careMonthReport')->name('pro-care-month-report');
+
+    // fdb playground
+    Route::get('/fdb-pg-rx', 'FDBPGController@rx')->name('fdb-pg-rx');
+    Route::get('/fdb-med-suggest', 'FDBPGController@medSuggest');
+    Route::get('/fdb-med-suggest/json', 'FDBPGController@medSuggestJSON');
+    Route::get('/fdb-routed-meds', 'FDBPGController@routedMeds');
+    Route::get('/fdb-routed-dosages', 'FDBPGController@routedDosages');
+    Route::get('/fdb-meds', 'FDBPGController@meds');
+    Route::get('/fdb-side-effects', 'FDBPGController@sideEffects');
+    Route::get('/fdb-geriatric-precautions', 'FDBPGController@geriatricPrecautions');
+    Route::get('/fdb-indications', 'FDBPGController@indications');
+    Route::get('/fdb-contraindications', 'FDBPGController@contraindications');
+    Route::get('/fdb-dx-suggest', 'FDBPGController@dxSuggest');
+    Route::get('/fdb-dx-suggest/json', 'FDBPGController@dxSuggestJSON');
+    Route::get('/fdb-allergy-suggest', 'FDBPGController@allergySuggest');
+    Route::any('/fdb-drug-allergies', 'FDBPGController@drugAllergies');
+    Route::any('/fdb-drug-drug-interaction', 'FDBPGController@drugDrugInteraction');
+    Route::any('/fdb-drug-coadministration', 'FDBPGController@drugCoadministration');
+    Route::any('/fdb-duplicate-therapy', 'FDBPGController@duplicateTherapy');
+>>>>>>> 102da0e5 (added debit bills)
 });
 
 Route::post("/process_form_submit", 'NoteController@processFormSubmit')->name('process_form_submit');