Ignore:
Timestamp:
Jan 4, 2012, 12:05:03 AM (12 years ago)
Author:
George Lilly
Message:

reset to certification routines with tabs

File:
1 edited

Legend:

Unmodified
Added
Removed
  • ccr/branches/ohum/p/C0CMED6.m

    r1330 r1332  
    1 C0CMED6 ; WV/CCDCCR/SMH - Meds from RPMS: Outpatient Meds;01/10/09
    2         ;;1.0;C0C;;May 19, 2009;Build 1
    3         ; Copyright 2008 WorldVistA.  Licensed under the terms of the GNU
    4         ; General Public License See attached copy of the License.
    5         ;
    6         ; This program is free software; you can redistribute it and/or modify
    7         ; it under the terms of the GNU General Public License as published by
    8         ; the Free Software Foundation; either version 2 of the License, or
    9         ; (at your option) any later version.
    10         ;
    11         ; This program is distributed in the hope that it will be useful,
    12         ; but WITHOUT ANY WARRANTY; without even the implied warranty of
    13         ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14         ; GNU General Public License for more details.
    15         ;
    16         ; You should have received a copy of the GNU General Public License along
    17         ; with this program; if not, write to the Free Software Foundation, Inc.,
    18         ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    19         ;
    20         W "NO ENTRY FROM TOP",!
    21         Q
    22         ;
    23 EXTRACT(MINXML,DFN,OUTXML,MEDCOUNT,FLAGS)        ; EXTRACT MEDICATIONS INTO PROVIDED XML TEMPLATE
    24         ;
    25         ; MINXML and OUTXML are passed by name so globals can be used
    26         ; MINXML will contain only the medications skeleton of the overall template
    27         ; MEDCOUNT is a counter passed by Reference.
    28         ; FLAGS are: MEDALL(bool)^MEDLIMIT(int)^MEDACTIVE(bool)^MEDPENDING(bool)
    29         ; FLAGS are set-up in C0CMED.
    30         ;
    31         ; MEDS is return array from RPC.
    32         ; MAP is a mapping variable map (store result) for each med
    33         ; MED is holds each array element from MEDS(J), one medicine
    34         ; J is a counter.
    35         ;
    36         ; GETRXS^BEHORXFN(ARRAYNAME,DFN,DAYS) will be the the API used.
    37         ; This API has been developed by Medsphere for IHS for getting
    38         ; Medications from RPMS. It has most of what we need.
    39         ; API written by Doug Martin when he worked for Medsphere (thanks Doug!)
    40         ; -- ARRAYNAME is passed by name (required)
    41         ; -- DFN is passed by value (required)
    42         ; -- DAYS is passed by value (optional; if not passed defaults to 365)
    43         ;
    44         ; Return:
    45         ; ~Type^PharmID^Drug^InfRate^StopDt^RefRem^TotDose^UnitDose^OrderID
    46         ; ^Status^LastFill^Chronic^Issued^Rx #^Provider^
    47         ; Status Reason^DEA Handling
    48         ;
    49         N MEDS,MEDS1,MAP
    50         D GETRXS^BEHORXFN("MEDS1",DFN,$P($P(FLAGS,U,2),"-",2)) ; 2nd piece of FLAGS is # of days to retrieve, which comes in the form "T-360"
    51         N ALL S ALL=+FLAGS
    52         N ACTIVE S ACTIVE=$P(FLAGS,U,3)
    53         N PENDING S PENDING=$P(FLAGS,U,4)
    54         S @OUTXML@(0)=0  ;By default, no meds
    55         ; If MEDS1 is not defined, then no meds
    56         I '$D(MEDS1) QUIT
    57         I DEBUG ZWR MEDS1,MINXML
    58         N MEDCNT S MEDCNT=0 ; Med Count
    59         ; The next line is a super line. It goes through the array return
    60         ; and if the first characters are ~OP, it grabs the line.
    61         ; This means that line is for a dispensed Outpatient Med.
    62         ; That line has the metadata about the med that I need.
    63         ; The next lines, however many, are the med and the sig.
    64         ; I won't be using those because I have to get the sig parsed exactly.
    65         N J S J="" F  S J=$O(MEDS1(J)) Q:J=""  I $E(MEDS1(J),1,3)="~OP" S MEDCNT=MEDCNT+1 S MEDS(MEDCNT)=MEDS1(J)
    66         K MEDS1
    67         S MEDCNT="" ; Initialize for $Order
    68         F  S MEDCNT=$O(MEDS(MEDCNT)) Q:MEDCNT=""  D  ; for each medication in the list
    69         . I 'ALL,ACTIVE,$P(MEDS(MEDCNT),U,10)'="ACTIVE" QUIT
    70         . I 'ALL,PENDING,$P(MEDS(MEDCNT),U,10)'="PENDING" QUIT
    71         . I DEBUG W "MEDCNT IS ",MEDCNT,!
    72         . S MAP=$NA(^TMP("C0CCCR",$J,"MEDMAP",MEDCNT))
    73         . ; K @MAP DO NOT KILL HERE, WAS CLEARED IN C0CMED
    74         . I DEBUG W "MAP= ",MAP,!
    75         . S @MAP@("MEDOBJECTID")="MED"_MEDCNT ; MEDCNT FOR ID
    76         . S @MAP@("MEDISSUEDATETXT")="Issue Date"
    77         . S @MAP@("MEDISSUEDATE")=$$FMDTOUTC^C0CUTIL($P(MEDS(MEDCNT),U,15),"DT")
    78         . S @MAP@("MEDLASTFILLDATETXT")="Last Fill Date"
    79         . S @MAP@("MEDLASTFILLDATE")=$$FMDTOUTC^C0CUTIL($P(MEDS(MEDCNT),U,11),"DT")
    80         . S @MAP@("MEDRXNOTXT")="Prescription Number"
    81         . S @MAP@("MEDRXNO")=$P(MEDS(MEDCNT),U,14)
    82         . S @MAP@("MEDTYPETEXT")="Medication"
    83         . S @MAP@("MEDDETAILUNADORNED")=""  ; Leave blank, field has its uses
    84         . S @MAP@("MEDSTATUSTEXT")=$P(MEDS(MEDCNT),U,10)
    85         . ; Provider only provided in API as text, not DUZ.
    86         . ; We need to get DUZ from filman file 52 (Prescription)
    87         . ; Field 4; IEN is Piece 2 of Meds stripped of trailing characters.
    88         . ; Note that I will use RXIEN several times later
    89         . N RXIEN S RXIEN=+$P(MEDS(MEDCNT),U,2)
    90         . S @MAP@("MEDSOURCEACTORID")="ACTORPROVIDER_"_$$GET1^DIQ(52,RXIEN,4,"I")
    91         . S @MAP@("MEDPRODUCTNAMETEXT")=$P(MEDS(MEDCNT),U,3)
    92         . ; --- RxNorm Stuff
    93         . ; 176.001 is the file for Concepts; 176.003 is the file for
    94         . ; sources (i.e. for RxNorm Version)
    95         . ;
    96         . ; I use 176.001 for the Vista version of this routine (files 1-3)
    97         . ; Since IHS does not have VUID's, I will be getting RxNorm codes
    98         . ; using NDCs. My specially crafted index (sounds evil) named "NDC"
    99         . ; is in file 176.002. The file is called RxNorm NDC to VUID.
    100         . ; Except that I don't need the VUID, but it's there if I need it.
    101         . ;
    102         . ; We obviously need the NDC. That is easily obtained from the prescription.
    103         . ; Field 27 in file 52
    104         . N NDC S NDC=$$GET1^DIQ(52,RXIEN,27,"I")
    105         . ; I discovered that file 176.002 might give you two codes for the NDC
    106         . ; One for the Clinical Drug, and one for the ingredient.
    107         . ; So the plan is to get the two RxNorm codes, and then find from
    108         . ; file 176.001 which one is the Clinical Drug.
    109         . ; ... I refactored this into GETRXN
    110         . N RXNORM,SRCIEN,RXNNAME,RXNVER
    111         . I +NDC,$D(^C0CRXN) D  ; $Data is for Systems that don't have our RxNorm file yet.
    112         . . S RXNORM=$$GETRXN(NDC)
    113         . . S SRCIEN=$$FIND1^DIC(176.003,,,"RXNORM","B")
    114         . . S RXNNAME=$$GET1^DIQ(176.003,SRCIEN,6)
    115         . . S RXNVER=$$GET1^DIQ(176.003,SRCIEN,7)
    116         . ;
    117         . E  S (RXNORM,RXNNAME,RXNVER)=""
    118         . ; End if/else block
    119         . S @MAP@("MEDPRODUCTNAMECODEVALUE")=RXNORM
    120         . S @MAP@("MEDPRODUCTNAMECODINGINGSYSTEM")=RXNNAME
    121         . S @MAP@("MEDPRODUCTNAMECODEVERSION")=RXNVER
    122         . ; --- End RxNorm section
    123         . ;
    124         . ; Brand name is 52 field 6.5
    125         . S @MAP@("MEDBRANDNAMETEXT")=$$GET1^DIQ(52,RXIEN,6.5)
    126         . ;
    127         . ; Next I need Med Form (tab, cap etc), strength (250mg)
    128         . ; concentration for liquids (250mg/mL)
    129         . ; Since IHS does not have any of the new calls that
    130         . ; Vista has, I will be doing a crosswalk:
    131         . ; File 52, field 6 is Drug IEN in file 50
    132         . ; File 50, field 22 is VA Product IEN in file 50.68
    133         . ; In file 50.68, I will get the following:
    134         . ; -- 1: Dosage Form
    135         . ; -- 2: Strength
    136         . ; -- 3: Units
    137         . ; -- 8: Dispense Units
    138         . ; -- Conc is 2 concatenated with 3
    139         . ;
    140         . ; *** If Drug is not matched to NDF, then VA Product will be "" ***
    141         . ;
    142         . N MEDIEN S MEDIEN=$$GET1^DIQ(52,RXIEN,6,"I") ; Drug IEN in 50
    143         . N VAPROD S VAPROD=$$GET1^DIQ(50,MEDIEN,22,"I") ; VA Product in file 50.68
    144         . I +VAPROD D
    145         . . S @MAP@("MEDSTRENGTHVALUE")=$$GET1^DIQ(50.68,VAPROD,2)
    146         . . S @MAP@("MEDSTRENGTHUNIT")=$$GET1^DIQ(50.68,VAPROD,3)
    147         . . S @MAP@("MEDFORMTEXT")=$$GET1^DIQ(50.68,VAPROD,1)
    148         . . S @MAP@("MEDCONCVALUE")=@MAP@("MEDSTRENGTHVALUE")
    149         . . S @MAP@("MEDCONCUNIT")=@MAP@("MEDSTRENGTHUNIT")
    150         . E  D
    151         . . S @MAP@("MEDSTRENGTHVALUE")=""
    152         . . S @MAP@("MEDSTRENGTHUNIT")=""
    153         . . S @MAP@("MEDFORMTEXT")=""
    154         . . S @MAP@("MEDCONCVALUE")=""
    155         . . S @MAP@("MEDCONCUNIT")=""
    156         . ; End Strengh/Conc stuff
    157         . ;
    158         . ; Quantity is in the prescription, field 7
    159         . S @MAP@("MEDQUANTITYVALUE")=$$GET1^DIQ(52,RXIEN,7)
    160         . ; Dispense unit is in the drug file, field 14.5
    161         . S @MAP@("MEDQUANTITYUNIT")=$$GET1^DIQ(50,MEDIEN,14.5)
    162         . ;
    163         . ; --- START OF DIRECTIONS ---
    164         . ; Sig data not in any API :-(  Oh yes, you can get the whole thing, but...
    165         . ; we want the components.
    166         . ; It's in multiple 113 in the Prescription File (52)
    167         . ; #.01 DOSAGE ORDERED [1F]                    "20"
    168         . ; #1 DISPENSE UNITS PER DOSE [2N]     "1"
    169         . ; #2 UNITS [3P:50.607]                                "MG"
    170         . ; #3 NOUN [4F]                                                "TABLET"
    171         . ; #4 DURATION [5F]                                    "10D"
    172         . ; #5 CONJUNCTION [6S]                                 "AND"
    173         . ; #6 ROUTE [7P:51.2]                          "ORAL"
    174         . ; #7 SCHEDULE [8F]                                    "BID"
    175         . ; #8 VERB [9F]                                                "TAKE"
    176         . ;
    177         . ; Will use GETS^DIQ to get fields.
    178         . ; Data comes out like this:
    179         . ; SAMINS(52.0113,"1,23,",.01)=20
    180         . ; SAMINS(52.0113,"1,23,",1)=1
    181         . ; SAMINS(52.0113,"1,23,",2)="MG"
    182         . ; SAMINS(52.0113,"1,23,",3)="TABLET"
    183         . ; SAMINS(52.0113,"1,23,",4)="5D"
    184         . ; SAMINS(52.0113,"1,23,",5)="THEN"
    185         . ;
    186         . N RAWDATA
    187         . D GETS^DIQ(52,RXIEN,"113*",,"RAWDATA","DIERR")
    188         . D:$D(DIERR) ^%ZTER  ; Log if there's an error in retrieving sig field
    189         . ; none the less, continue; some parts are retrievable.
    190         . N FMSIG M FMSIG=RAWDATA(52.0113) ; Merge into subfile...
    191         . K RAWDATA
    192         . N FMSIGNUM S FMSIGNUM="" ; Sigline number in fileman.
    193         . ; FMSIGNUM gets outputted as "IEN,RXIEN,".
    194         . ; DIRCNT is the proper Sigline numer.
    195         . ; SIGDATA is the simplfied array.
    196         . F  S FMSIGNUM=$O(FMSIG(FMSIGNUM)) Q:FMSIGNUM=""  D
    197         . . N DIRCNT S DIRCNT=$P(FMSIGNUM,",")
    198         . . N SIGDATA M SIGDATA=FMSIG(FMSIGNUM)
    199         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDIRECTIONDESCRIPTIONTEXT")=""  ; This is reserved for systems not able to generate the sig in components.
    200         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDOSEINDICATOR")="1"  ; means that we are specifying it. See E2369-05.
    201         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDELIVERYMETHOD")=$G(SIGDATA(8))
    202         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDOSEVALUE")=$G(SIGDATA(.01))
    203         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDOSEUNIT")=$G(SIGDATA(2))
    204         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDRATEVALUE")=""  ; For inpatient
    205         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDRATEUNIT")=""  ; For inpatient
    206         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDVEHICLETEXT")=""  ; For inpatient
    207         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDIRECTIONROUTETEXT")=$G(SIGDATA(6))
    208         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDFREQUENCYVALUE")=$G(SIGDATA(7))
    209         . . ; Invervals... again another call.
    210         . . ; In the wisdom of the original programmers, the schedule is a free text field
    211         . . ; However, it gets translated by a call to the administration schedule file
    212         . . ; to see if that schedule exists.
    213         . . ; That's the same thing I am going to do.
    214         . . ; Search B index of 51.1 (Admin Schedule) with schedule
    215         . . ; First, remove "PRN" if it exists (don't ask, that's how the file
    216         . . ; works; I wouldn't do it that way).
    217         . . N SCHNOPRN S SCHNOPRN=$G(SIGDATA(7))
    218         . . I SCHNOPRN["PRN" S SCHNOPRN=$E(SCHNOPRN,1,$F(SCHNOPRN,"PRN")-5)
    219         . . ; Super call below:
    220         . . ; 1=File 51.1 3=Field 2 (Frequency in Minutes)
    221         . . ; 4=Packed format, Exact Match 5=Lookup Value
    222         . . ; 6=# of entries to return 7=Index 10=Return Array
    223         . . ;
    224         . . ; I do not account for the fact that two schedules can be
    225         . . ; spelled identically (ie duplicate entry). In that case,
    226         . . ; I get the first. That's just a bad pharmacy pkg maintainer.
    227         . . N C0C515
    228         . . D FIND^DIC(51.1,,"@;2","PX",SCHNOPRN,1,"B",,,"C0C515")
    229         . . N INTERVAL S INTERVAL="" ; Default
    230         . . ; If there are entries found, get it
    231         . . I +$G(C0C515("DILIST",0)) S INTERVAL=$P(C0C515("DILIST",1,0),U,2)
    232         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDINTERVALVALUE")=INTERVAL
    233         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDINTERVALUNIT")="Minute"
    234         . . ; Duration is 10M minutes, 10H hours, 10D for Days
    235         . . ; 10W for weeks, 10L for months. I smell $Select
    236         . . ; But we don't need to do that if there isn't a duration
    237         . . I +$G(SIGDATA(4)) D
    238         . . . N DURUNIT S DURUNIT=$E(SIGDATA(4),$L(SIGDATA(4))) ; get last char
    239         . . . N DURTXT S DURTXT=$S(DURUNIT="M":"Minutes",DURUNIT="H":"Hours",DURUNIT="D":"Days",DURUNIT="W":"Weeks",DURUNIT="L":"Months",1:"Days")
    240         . . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDURATIONVALUE")=+SIGDATA(4)
    241         . . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDURATIONUNIT")=DURTXT
    242         . . E  D
    243         . . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDURATIONVALUE")=""
    244         . . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDURATIONUNIT")=""
    245         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPRNFLAG")=$G(SIGDATA(4))["PRN"
    246         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMOBJECTID")="" ; when avail
    247         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMTYPETXT")=""
    248         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMDESCRIPTION")=""
    249         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMCODEVALUE")=""
    250         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMCODINGSYSTEM")=""
    251         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMCODINGVERSION")=""
    252         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMSOURCEACTORID")=""
    253         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDSTOPINDICATOR")="" ; not stored
    254         . . ; Another confusing line; I am pretty bad:
    255         . . ; If there is another entry in the FMSIG array (i.e. another line
    256         . . ; in the sig), set the direction count indicator.
    257         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDIRSEQ")=""  ; Default
    258         . . S:+$O(FMSIG(FMSIGNUM)) @MAP@("M","DIRECTIONS",DIRCNT,"MEDDIRSEQ")=DIRCNT
    259         . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDMULDIRMOD")=$G(SIGDATA(5))
    260         . ;
    261         . ; --- END OF DIRECTIONS ---
    262         . ;
    263         . ; Med instructions is a WP field, thus the acrobatics
    264         . ; Notice buffer overflow protection set at 10,000 chars
    265         . ; -- 1. Med Patient Instructions
    266         . N MEDPTIN1 S MEDPTIN1=$$GET1^DIQ(52,RXIEN,115,,"MEDPTIN1")
    267         . N MEDPTIN2,J  S (MEDPTIN2,J)=""
    268         . I $L(MEDPTIN1) F  S J=$O(@MEDPTIN1@(J)) Q:J=""  Q:$L(MEDPTIN2)>10000  S MEDPTIN2=MEDPTIN2_@MEDPTIN1@(J)_" "
    269         . S @MAP@("MEDPTINSTRUCTIONS")=MEDPTIN2
    270         . K J
    271         . ; -- 2. Med Provider Instructions
    272         . N MEDPVIN1 S MEDPVIN1=$$GET1^DIQ(52,RXIEN,39,,"MEDPVIN1")
    273         . N MEDPVIN2,J S (MEDPVIN2,J)=""
    274         . I $L(MEDPVIN1) F  S J=$O(@MEDPVIN1@(J)) Q:J=""  Q:$L(MEDPVIN2)>10000  S MEDPVIN2=MEDPVIN2_@MEDPVIN1@(J)_" "
    275         . S @MAP@("MEDFULLFILLMENTINSTRUCTIONS")=MEDPVIN2
    276         . ;
    277         . ; Remaining refills
    278         . S @MAP@("MEDRFNO")=$P(MEDS(MEDCNT),U,6)
    279         . ; ------ END OF MAPPING
    280         . ;
    281         . ; ------ BEGIN XML INSERTION
    282         . N RESULT S RESULT=$NA(^TMP("C0CCCR",$J,"MAPPED"))
    283         . K @RESULT
    284         . D MAP^C0CXPATH(MINXML,MAP,RESULT)
    285         . ; D PARY^C0CXPATH(RESULT)
    286         . ; MAPPING DIRECTIONS
    287         . N MEDDIR1,DIRXML1 S DIRXML1="MEDDIR1" ; VARIABLE AND NAME VARIABLE TEMPLATE
    288         . N MEDDIR2,DIRXML2 S DIRXML2="MEDDIR2" ; VARIABLE AND NAME VARIABLE RESULT
    289         . D QUERY^C0CXPATH(MINXML,"//Medications/Medication/Directions",DIRXML1)
    290         . D REPLACE^C0CXPATH(RESULT,"","//Medications/Medication/Directions")
    291         . ; N MDZ1,MDZNA
    292         . N DIRCNT S DIRCNT=""
    293         . I +$O(@MAP@("M","DIRECTIONS",DIRCNT)) D  ; IF THERE ARE DIRCTIONS
    294         . . F DIRCNT=$O(@MAP@("M","DIRECTIONS",DIRCNT)) D  ; FOR EACH DIRECTION
    295         . . . S MDZNA=$NA(@MAP@("M","DIRECTIONS",DIRCNT))
    296         . . . D MAP^C0CXPATH(DIRXML1,MDZNA,DIRXML2)
    297         . . . D INSERT^C0CXPATH(RESULT,DIRXML2,"//Medications/Medication")
    298         . D:MEDCNT=1 CP^C0CXPATH(RESULT,OUTXML) ; First one is a copy
    299         . D:MEDCNT>1 INSINNER^C0CXPATH(OUTXML,RESULT) ; AFTER THE FIRST, INSERT INNER XML
    300         . S MEDCOUNT=MEDCNT
    301         N MEDTMP,MEDI
    302         D MISSING^C0CXPATH(OUTXML,"MEDTMP") ; SEARCH XML FOR MISSING VARS
    303         I MEDTMP(0)>0 D  ; IF THERE ARE MISSING VARS - MARKED AS @@X@@
    304         . W "MEDICATION MISSING ",!
    305         . F MEDI=1:1:MEDTMP(0) W MEDTMP(MEDI),!
    306         Q
    307         ;
     1C0CMED6 ; WV/CCDCCR/SMH - Meds from RPMS: Outpatient Meds;01/10/09
     2 ;;1.0;C0C;;May 19, 2009;
     3 ; Copyright 2008 WorldVistA.  Licensed under the terms of the GNU
     4 ; General Public License See attached copy of the License.
     5 ;
     6 ; This program is free software; you can redistribute it and/or modify
     7 ; it under the terms of the GNU General Public License as published by
     8 ; the Free Software Foundation; either version 2 of the License, or
     9 ; (at your option) any later version.
     10 ;
     11 ; This program is distributed in the hope that it will be useful,
     12 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 ; GNU General Public License for more details.
     15 ;
     16 ; You should have received a copy of the GNU General Public License along
     17 ; with this program; if not, write to the Free Software Foundation, Inc.,
     18 ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     19 ;
     20 W "NO ENTRY FROM TOP",!
     21 Q
     22 ;
     23EXTRACT(MINXML,DFN,OUTXML,MEDCOUNT,FLAGS)  ; EXTRACT MEDICATIONS INTO PROVIDED XML TEMPLATE
     24 ;
     25 ; MINXML and OUTXML are passed by name so globals can be used
     26 ; MINXML will contain only the medications skeleton of the overall template
     27 ; MEDCOUNT is a counter passed by Reference.
     28 ; FLAGS are: MEDALL(bool)^MEDLIMIT(int)^MEDACTIVE(bool)^MEDPENDING(bool)
     29 ; FLAGS are set-up in C0CMED.
     30 ;
     31 ; MEDS is return array from RPC.
     32 ; MAP is a mapping variable map (store result) for each med
     33 ; MED is holds each array element from MEDS(J), one medicine
     34 ; J is a counter.
     35 ;
     36 ; GETRXS^BEHORXFN(ARRAYNAME,DFN,DAYS) will be the the API used.
     37 ; This API has been developed by Medsphere for IHS for getting
     38 ; Medications from RPMS. It has most of what we need.
     39 ; API written by Doug Martin when he worked for Medsphere (thanks Doug!)
     40 ; -- ARRAYNAME is passed by name (required)
     41 ; -- DFN is passed by value (required)
     42 ; -- DAYS is passed by value (optional; if not passed defaults to 365)
     43 ;
     44 ; Return:
     45 ; ~Type^PharmID^Drug^InfRate^StopDt^RefRem^TotDose^UnitDose^OrderID
     46 ; ^Status^LastFill^Chronic^Issued^Rx #^Provider^
     47 ; Status Reason^DEA Handling
     48 ;
     49 N MEDS,MEDS1,MAP
     50 D GETRXS^BEHORXFN("MEDS1",DFN,$P($P(FLAGS,U,2),"-",2)) ; 2nd piece of FLAGS is # of days to retrieve, which comes in the form "T-360"
     51 N ALL S ALL=+FLAGS
     52 N ACTIVE S ACTIVE=$P(FLAGS,U,3)
     53 N PENDING S PENDING=$P(FLAGS,U,4)
     54 S @OUTXML@(0)=0  ;By default, no meds
     55 ; If MEDS1 is not defined, then no meds
     56 I '$D(MEDS1) QUIT
     57 I DEBUG ZWR MEDS1,MINXML
     58 N MEDCNT S MEDCNT=0 ; Med Count
     59 ; The next line is a super line. It goes through the array return
     60 ; and if the first characters are ~OP, it grabs the line.
     61 ; This means that line is for a dispensed Outpatient Med.
     62 ; That line has the metadata about the med that I need.
     63 ; The next lines, however many, are the med and the sig.
     64 ; I won't be using those because I have to get the sig parsed exactly.
     65 N J S J="" F  S J=$O(MEDS1(J)) Q:J=""  I $E(MEDS1(J),1,3)="~OP" S MEDCNT=MEDCNT+1 S MEDS(MEDCNT)=MEDS1(J)
     66 K MEDS1
     67 S MEDCNT="" ; Initialize for $Order
     68 F  S MEDCNT=$O(MEDS(MEDCNT)) Q:MEDCNT=""  D  ; for each medication in the list
     69 . I 'ALL,ACTIVE,$P(MEDS(MEDCNT),U,10)'="ACTIVE" QUIT
     70 . I 'ALL,PENDING,$P(MEDS(MEDCNT),U,10)'="PENDING" QUIT
     71 . I DEBUG W "MEDCNT IS ",MEDCNT,!
     72 . S MAP=$NA(^TMP("C0CCCR",$J,"MEDMAP",MEDCNT))
     73 . ; K @MAP DO NOT KILL HERE, WAS CLEARED IN C0CMED
     74 . I DEBUG W "MAP= ",MAP,!
     75 . S @MAP@("MEDOBJECTID")="MED"_MEDCNT ; MEDCNT FOR ID
     76 . S @MAP@("MEDISSUEDATETXT")="Issue Date"
     77 . S @MAP@("MEDISSUEDATE")=$$FMDTOUTC^C0CUTIL($P(MEDS(MEDCNT),U,15),"DT")
     78 . S @MAP@("MEDLASTFILLDATETXT")="Last Fill Date"
     79 . S @MAP@("MEDLASTFILLDATE")=$$FMDTOUTC^C0CUTIL($P(MEDS(MEDCNT),U,11),"DT")
     80 . S @MAP@("MEDRXNOTXT")="Prescription Number"
     81 . S @MAP@("MEDRXNO")=$P(MEDS(MEDCNT),U,14)
     82 . S @MAP@("MEDTYPETEXT")="Medication"
     83 . S @MAP@("MEDDETAILUNADORNED")=""  ; Leave blank, field has its uses
     84 . S @MAP@("MEDSTATUSTEXT")=$P(MEDS(MEDCNT),U,10)
     85 . ; Provider only provided in API as text, not DUZ.
     86 . ; We need to get DUZ from filman file 52 (Prescription)
     87 . ; Field 4; IEN is Piece 2 of Meds stripped of trailing characters.
     88 . ; Note that I will use RXIEN several times later
     89 . N RXIEN S RXIEN=+$P(MEDS(MEDCNT),U,2)
     90 . S @MAP@("MEDSOURCEACTORID")="ACTORPROVIDER_"_$$GET1^DIQ(52,RXIEN,4,"I")
     91 . S @MAP@("MEDPRODUCTNAMETEXT")=$P(MEDS(MEDCNT),U,3)
     92 . ; --- RxNorm Stuff
     93 . ; 176.001 is the file for Concepts; 176.003 is the file for
     94 . ; sources (i.e. for RxNorm Version)
     95 . ;
     96 . ; I use 176.001 for the Vista version of this routine (files 1-3)
     97 . ; Since IHS does not have VUID's, I will be getting RxNorm codes
     98 . ; using NDCs. My specially crafted index (sounds evil) named "NDC"
     99 . ; is in file 176.002. The file is called RxNorm NDC to VUID.
     100 . ; Except that I don't need the VUID, but it's there if I need it.
     101 . ;
     102 . ; We obviously need the NDC. That is easily obtained from the prescription.
     103 . ; Field 27 in file 52
     104 . N NDC S NDC=$$GET1^DIQ(52,RXIEN,27,"I")
     105 . ; I discovered that file 176.002 might give you two codes for the NDC
     106 . ; One for the Clinical Drug, and one for the ingredient.
     107 . ; So the plan is to get the two RxNorm codes, and then find from
     108 . ; file 176.001 which one is the Clinical Drug.
     109 . ; ... I refactored this into GETRXN
     110 . N RXNORM,SRCIEN,RXNNAME,RXNVER
     111 . I +NDC,$D(^C0CRXN) D  ; $Data is for Systems that don't have our RxNorm file yet.
     112 . . S RXNORM=$$GETRXN(NDC)
     113 . . S SRCIEN=$$FIND1^DIC(176.003,,,"RXNORM","B")
     114 . . S RXNNAME=$$GET1^DIQ(176.003,SRCIEN,6)
     115 . . S RXNVER=$$GET1^DIQ(176.003,SRCIEN,7)
     116 . ;
     117 . E  S (RXNORM,RXNNAME,RXNVER)=""
     118 . ; End if/else block
     119 . S @MAP@("MEDPRODUCTNAMECODEVALUE")=RXNORM
     120 . S @MAP@("MEDPRODUCTNAMECODINGINGSYSTEM")=RXNNAME
     121 . S @MAP@("MEDPRODUCTNAMECODEVERSION")=RXNVER
     122 . ; --- End RxNorm section
     123 . ;
     124 . ; Brand name is 52 field 6.5
     125 . S @MAP@("MEDBRANDNAMETEXT")=$$GET1^DIQ(52,RXIEN,6.5)
     126 . ;
     127 . ; Next I need Med Form (tab, cap etc), strength (250mg)
     128 . ; concentration for liquids (250mg/mL)
     129 . ; Since IHS does not have any of the new calls that
     130 . ; Vista has, I will be doing a crosswalk:
     131 . ; File 52, field 6 is Drug IEN in file 50
     132 . ; File 50, field 22 is VA Product IEN in file 50.68
     133 . ; In file 50.68, I will get the following:
     134 . ; -- 1: Dosage Form
     135 . ; -- 2: Strength
     136 . ; -- 3: Units
     137 . ; -- 8: Dispense Units
     138 . ; -- Conc is 2 concatenated with 3
     139 . ;
     140 . ; *** If Drug is not matched to NDF, then VA Product will be "" ***
     141 . ;
     142 . N MEDIEN S MEDIEN=$$GET1^DIQ(52,RXIEN,6,"I") ; Drug IEN in 50
     143 . N VAPROD S VAPROD=$$GET1^DIQ(50,MEDIEN,22,"I") ; VA Product in file 50.68
     144 . I +VAPROD D
     145 . . S @MAP@("MEDSTRENGTHVALUE")=$$GET1^DIQ(50.68,VAPROD,2)
     146 . . S @MAP@("MEDSTRENGTHUNIT")=$$GET1^DIQ(50.68,VAPROD,3)
     147 . . S @MAP@("MEDFORMTEXT")=$$GET1^DIQ(50.68,VAPROD,1)
     148 . . S @MAP@("MEDCONCVALUE")=@MAP@("MEDSTRENGTHVALUE")
     149 . . S @MAP@("MEDCONCUNIT")=@MAP@("MEDSTRENGTHUNIT")
     150 . E  D
     151 . . S @MAP@("MEDSTRENGTHVALUE")=""
     152 . . S @MAP@("MEDSTRENGTHUNIT")=""
     153 . . S @MAP@("MEDFORMTEXT")=""
     154 . . S @MAP@("MEDCONCVALUE")=""
     155 . . S @MAP@("MEDCONCUNIT")=""
     156 . ; End Strengh/Conc stuff
     157 . ;
     158 . ; Quantity is in the prescription, field 7
     159 . S @MAP@("MEDQUANTITYVALUE")=$$GET1^DIQ(52,RXIEN,7)
     160 . ; Dispense unit is in the drug file, field 14.5
     161 . S @MAP@("MEDQUANTITYUNIT")=$$GET1^DIQ(50,MEDIEN,14.5)
     162 . ;
     163 . ; --- START OF DIRECTIONS ---
     164 . ; Sig data not in any API :-(  Oh yes, you can get the whole thing, but...
     165 . ; we want the components.
     166 . ; It's in multiple 113 in the Prescription File (52)
     167 . ; #.01 DOSAGE ORDERED [1F]                   "20"
     168 . ; #1 DISPENSE UNITS PER DOSE [2N]    "1"
     169 . ; #2 UNITS [3P:50.607]                               "MG"
     170 . ; #3 NOUN [4F]                                               "TABLET"
     171 . ; #4 DURATION [5F]                                   "10D"
     172 . ; #5 CONJUNCTION [6S]                                "AND"
     173 . ; #6 ROUTE [7P:51.2]                                 "ORAL"
     174 . ; #7 SCHEDULE [8F]                                   "BID"
     175 . ; #8 VERB [9F]                                               "TAKE"
     176 . ;
     177 . ; Will use GETS^DIQ to get fields.
     178 . ; Data comes out like this:
     179 . ; SAMINS(52.0113,"1,23,",.01)=20
     180 . ; SAMINS(52.0113,"1,23,",1)=1
     181 . ; SAMINS(52.0113,"1,23,",2)="MG"
     182 . ; SAMINS(52.0113,"1,23,",3)="TABLET"
     183 . ; SAMINS(52.0113,"1,23,",4)="5D"
     184 . ; SAMINS(52.0113,"1,23,",5)="THEN"
     185 . ;
     186 . N RAWDATA
     187 . D GETS^DIQ(52,RXIEN,"113*",,"RAWDATA","DIERR")
     188 . D:$D(DIERR) ^%ZTER  ; Log if there's an error in retrieving sig field
     189 . ; none the less, continue; some parts are retrievable.
     190 . N FMSIG M FMSIG=RAWDATA(52.0113) ; Merge into subfile...
     191 . K RAWDATA
     192 . N FMSIGNUM S FMSIGNUM="" ; Sigline number in fileman.
     193 . ; FMSIGNUM gets outputted as "IEN,RXIEN,".
     194 . ; DIRCNT is the proper Sigline numer.
     195 . ; SIGDATA is the simplfied array.
     196 . F  S FMSIGNUM=$O(FMSIG(FMSIGNUM)) Q:FMSIGNUM=""  D
     197 . . N DIRCNT S DIRCNT=$P(FMSIGNUM,",")
     198 . . N SIGDATA M SIGDATA=FMSIG(FMSIGNUM)
     199 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDIRECTIONDESCRIPTIONTEXT")=""  ; This is reserved for systems not able to generate the sig in components.
     200 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDOSEINDICATOR")="1"  ; means that we are specifying it. See E2369-05.
     201 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDELIVERYMETHOD")=$G(SIGDATA(8))
     202 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDOSEVALUE")=$G(SIGDATA(.01))
     203 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDOSEUNIT")=$G(SIGDATA(2))
     204 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDRATEVALUE")=""  ; For inpatient
     205 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDRATEUNIT")=""  ; For inpatient
     206 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDVEHICLETEXT")=""  ; For inpatient
     207 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDIRECTIONROUTETEXT")=$G(SIGDATA(6))
     208 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDFREQUENCYVALUE")=$G(SIGDATA(7))
     209 . . ; Invervals... again another call.
     210 . . ; In the wisdom of the original programmers, the schedule is a free text field
     211 . . ; However, it gets translated by a call to the administration schedule file
     212 . . ; to see if that schedule exists.
     213 . . ; That's the same thing I am going to do.
     214 . . ; Search B index of 51.1 (Admin Schedule) with schedule
     215 . . ; First, remove "PRN" if it exists (don't ask, that's how the file
     216 . . ; works; I wouldn't do it that way).
     217 . . N SCHNOPRN S SCHNOPRN=$G(SIGDATA(7))
     218 . . I SCHNOPRN["PRN" S SCHNOPRN=$E(SCHNOPRN,1,$F(SCHNOPRN,"PRN")-5)
     219 . . ; Super call below:
     220 . . ; 1=File 51.1 3=Field 2 (Frequency in Minutes)
     221 . . ; 4=Packed format, Exact Match 5=Lookup Value
     222 . . ; 6=# of entries to return 7=Index 10=Return Array
     223 . . ;
     224 . . ; I do not account for the fact that two schedules can be
     225 . . ; spelled identically (ie duplicate entry). In that case,
     226 . . ; I get the first. That's just a bad pharmacy pkg maintainer.
     227 . . N C0C515
     228 . . D FIND^DIC(51.1,,"@;2","PX",SCHNOPRN,1,"B",,,"C0C515")
     229 . . N INTERVAL S INTERVAL="" ; Default
     230 . . ; If there are entries found, get it
     231 . . I +$G(C0C515("DILIST",0)) S INTERVAL=$P(C0C515("DILIST",1,0),U,2)
     232 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDINTERVALVALUE")=INTERVAL
     233 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDINTERVALUNIT")="Minute"
     234 . . ; Duration is 10M minutes, 10H hours, 10D for Days
     235 . . ; 10W for weeks, 10L for months. I smell $Select
     236 . . ; But we don't need to do that if there isn't a duration
     237 . . I +$G(SIGDATA(4)) D
     238 . . . N DURUNIT S DURUNIT=$E(SIGDATA(4),$L(SIGDATA(4))) ; get last char
     239 . . . N DURTXT S DURTXT=$S(DURUNIT="M":"Minutes",DURUNIT="H":"Hours",DURUNIT="D":"Days",DURUNIT="W":"Weeks",DURUNIT="L":"Months",1:"Days")
     240 . . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDURATIONVALUE")=+SIGDATA(4)
     241 . . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDURATIONUNIT")=DURTXT
     242 . . E  D
     243 . . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDURATIONVALUE")=""
     244 . . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDURATIONUNIT")=""
     245 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPRNFLAG")=$G(SIGDATA(4))["PRN"
     246 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMOBJECTID")="" ; when avail
     247 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMTYPETXT")=""
     248 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMDESCRIPTION")=""
     249 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMCODEVALUE")=""
     250 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMCODINGSYSTEM")=""
     251 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMCODINGVERSION")=""
     252 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDPROBLEMSOURCEACTORID")=""
     253 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDSTOPINDICATOR")="" ; not stored
     254 . . ; Another confusing line; I am pretty bad:
     255 . . ; If there is another entry in the FMSIG array (i.e. another line
     256 . . ; in the sig), set the direction count indicator.
     257 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDDIRSEQ")=""  ; Default
     258 . . S:+$O(FMSIG(FMSIGNUM)) @MAP@("M","DIRECTIONS",DIRCNT,"MEDDIRSEQ")=DIRCNT
     259 . . S @MAP@("M","DIRECTIONS",DIRCNT,"MEDMULDIRMOD")=$G(SIGDATA(5))
     260 . ;
     261 . ; --- END OF DIRECTIONS ---
     262 . ;
     263 . ; Med instructions is a WP field, thus the acrobatics
     264 . ; Notice buffer overflow protection set at 10,000 chars
     265 . ; -- 1. Med Patient Instructions
     266 . N MEDPTIN1 S MEDPTIN1=$$GET1^DIQ(52,RXIEN,115,,"MEDPTIN1")
     267 . N MEDPTIN2,J  S (MEDPTIN2,J)=""
     268 . I $L(MEDPTIN1) F  S J=$O(@MEDPTIN1@(J)) Q:J=""  Q:$L(MEDPTIN2)>10000  S MEDPTIN2=MEDPTIN2_@MEDPTIN1@(J)_" "
     269 . S @MAP@("MEDPTINSTRUCTIONS")=MEDPTIN2
     270 . K J
     271 . ; -- 2. Med Provider Instructions
     272 . N MEDPVIN1 S MEDPVIN1=$$GET1^DIQ(52,RXIEN,39,,"MEDPVIN1")
     273 . N MEDPVIN2,J S (MEDPVIN2,J)=""
     274 . I $L(MEDPVIN1) F  S J=$O(@MEDPVIN1@(J)) Q:J=""  Q:$L(MEDPVIN2)>10000  S MEDPVIN2=MEDPVIN2_@MEDPVIN1@(J)_" "
     275 . S @MAP@("MEDFULLFILLMENTINSTRUCTIONS")=MEDPVIN2
     276 . ;
     277 . ; Remaining refills
     278 . S @MAP@("MEDRFNO")=$P(MEDS(MEDCNT),U,6)
     279 . ; ------ END OF MAPPING
     280 . ;
     281 . ; ------ BEGIN XML INSERTION
     282 . N RESULT S RESULT=$NA(^TMP("C0CCCR",$J,"MAPPED"))
     283 . K @RESULT
     284 . D MAP^C0CXPATH(MINXML,MAP,RESULT)
     285 . ; D PARY^C0CXPATH(RESULT)
     286 . ; MAPPING DIRECTIONS
     287 . N MEDDIR1,DIRXML1 S DIRXML1="MEDDIR1" ; VARIABLE AND NAME VARIABLE TEMPLATE
     288 . N MEDDIR2,DIRXML2 S DIRXML2="MEDDIR2" ; VARIABLE AND NAME VARIABLE RESULT
     289 . D QUERY^C0CXPATH(MINXML,"//Medications/Medication/Directions",DIRXML1)
     290 . D REPLACE^C0CXPATH(RESULT,"","//Medications/Medication/Directions")
     291 . ; N MDZ1,MDZNA
     292 . N DIRCNT S DIRCNT=""
     293 . I +$O(@MAP@("M","DIRECTIONS",DIRCNT)) D  ; IF THERE ARE DIRCTIONS
     294 . . F DIRCNT=$O(@MAP@("M","DIRECTIONS",DIRCNT)) D  ; FOR EACH DIRECTION
     295 . . . S MDZNA=$NA(@MAP@("M","DIRECTIONS",DIRCNT))
     296 . . . D MAP^C0CXPATH(DIRXML1,MDZNA,DIRXML2)
     297 . . . D INSERT^C0CXPATH(RESULT,DIRXML2,"//Medications/Medication")
     298 . D:MEDCNT=1 CP^C0CXPATH(RESULT,OUTXML) ; First one is a copy
     299 . D:MEDCNT>1 INSINNER^C0CXPATH(OUTXML,RESULT) ; AFTER THE FIRST, INSERT INNER XML
     300 . S MEDCOUNT=MEDCNT
     301 N MEDTMP,MEDI
     302 D MISSING^C0CXPATH(OUTXML,"MEDTMP") ; SEARCH XML FOR MISSING VARS
     303 I MEDTMP(0)>0 D  ; IF THERE ARE MISSING VARS - MARKED AS @@X@@
     304 . W "MEDICATION MISSING ",!
     305 . F MEDI=1:1:MEDTMP(0) W MEDTMP(MEDI),!
     306 Q
     307 ;
    308308GETRXN(NDC)     ; Extrinsic Function; PUBLIC; NDC to RxNorm
    309         ;; Get RxNorm Concept Number for a Given NDC
    310         ;
    311         S NDC=$TR(NDC,"-")  ; Remove dashes
    312         N RXNORM,C0CZRXN,DIERR
    313         D FIND^DIC(176.002,,"@;.01","PX",NDC,"*","NDC",,,"C0CZRXN","DIERR")
    314         I $D(DIERR) D ^%ZTER BREAK
    315         S RXNORM(0)=+C0CZRXN("DILIST",0) ; RxNorm(0) will be # of entries
    316         N I S I=0
    317         F  S I=$O(C0CZRXN("DILIST",I)) Q:I=""  S RXNORM(I)=$P(C0CZRXN("DILIST",I,0),U,2)
    318         ; At this point, RxNorm(0) is # of entries; RxNorm(1...) are the entries
    319         ; If RxNorm(0) is 1, then we only have one entry, and that's it.
    320         I RXNORM(0)=1 QUIT RXNORM(1)  ; RETURN RXNORM(1)
    321         ; Otherwise, we need to find out which one is the semantic
    322         ; clinical drug. I built an index on 176.001 (RxNorm Concepts)
    323         ; for that purpose.
    324         I RXNORM(0)>1 D
    325         . S I=0
    326         . F  S I=$O(RXNORM(I)) Q:I=""  D  Q:$G(RXNORM)
    327         . . N RXNIEN S RXNIEN=$$FIND1^DIC(176.001,,,RXNORM(I),"SCD")
    328         . . I +$G(RXNIEN)=0 QUIT  ; try the next entry...
    329         . . E  S RXNORM=RXNORM(I) QUIT  ; We found the right code
    330         QUIT +$G(RXNORM)  ; RETURN RXNORM; if we couldn't find a clnical drug, return with 0
    331        
     309 ;; Get RxNorm Concept Number for a Given NDC
     310 ;
     311 S NDC=$TR(NDC,"-")  ; Remove dashes
     312 N RXNORM,C0CZRXN,DIERR
     313 D FIND^DIC(176.002,,"@;.01","PX",NDC,"*","NDC",,,"C0CZRXN","DIERR")
     314 I $D(DIERR) D ^%ZTER BREAK
     315 S RXNORM(0)=+C0CZRXN("DILIST",0) ; RxNorm(0) will be # of entries
     316 N I S I=0
     317 F  S I=$O(C0CZRXN("DILIST",I)) Q:I=""  S RXNORM(I)=$P(C0CZRXN("DILIST",I,0),U,2)
     318 ; At this point, RxNorm(0) is # of entries; RxNorm(1...) are the entries
     319 ; If RxNorm(0) is 1, then we only have one entry, and that's it.
     320 I RXNORM(0)=1 QUIT RXNORM(1)  ; RETURN RXNORM(1)
     321 ; Otherwise, we need to find out which one is the semantic
     322 ; clinical drug. I built an index on 176.001 (RxNorm Concepts)
     323 ; for that purpose.
     324 I RXNORM(0)>1 D
     325 . S I=0
     326 . F  S I=$O(RXNORM(I)) Q:I=""  D  Q:$G(RXNORM)
     327 . . N RXNIEN S RXNIEN=$$FIND1^DIC(176.001,,,RXNORM(I),"SCD")
     328 . . I +$G(RXNIEN)=0 QUIT  ; try the next entry...
     329 . . E  S RXNORM=RXNORM(I) QUIT  ; We found the right code
     330 QUIT +$G(RXNORM)  ; RETURN RXNORM; if we couldn't find a clnical drug, return with 0
     331 
Note: See TracChangeset for help on using the changeset viewer.