PXVWICE ;ISP/LMT - ICE interface main routine ;Jun 06, 2019@07:59:57
 ;;1.0;PCE PATIENT CARE ENCOUNTER;**217**;Aug 12, 1996;Build 134
 ;
 ; Thanks to George Lilly for developing (and sharing) his prototype of the interface of VistA and ICE;
 ; it was instrumental in the development of this production version.
 ;
 ; TODO:
 ;   - Create national Clinical Reminders and update Build Logic
 ;     in PX ICE MESSAGE entries that call into GETREM^PXVWVMR
 ;     to use national reminders.
 ;   - Add code to SELECT^ORWPC to check if ICE cache has been validated today;
 ;     and if not, task job to validate cache, and if necessary update cache
 ;
 ;
RPC(PXRETURN,DFN,PXCHKCACHE,PXASYNC) ; Entry point for RPC
 ;
 ; Returns ICE recommendations
 ;
 ;Input:
 ;         DFN - Patient (#2) IEN
 ;  PXCHKCACHE - Use cached results, if available? 1=Yes; 0=No (default: 1)
 ;     PXASYNC - Call ICE asynchronously? 1=Yes; 0=No; Handle; (default: 0)
 ;               (See EN tag below for more info on asynchronous functionality).
 ;
 ;Returns:
 ; If Unsuccessful:
 ;   0) = X^Error Message
 ;          Note: X can be one of the following values:
 ;                 0: Cache is in middle of being built; check back later
 ;                -1: Invalid input
 ;                -2: Could not make SOAP call (e.g., URL not populated in 920.75, etc.)
 ;                -3: HTTP call returned unsuccessful status code (i.e., Server returned status code other than 200)
 ;                -4: Unable to process incoming message from ICE
 ;                -5: Error during asynchronous process.
 ;                -6: Interface is down/disabled
 ;   n) = If SOAP call was unsuccessful, this will be the message returned by the ICE server.
 ;
 ; If Successful:
 ;   0) = 1 ^ Number of Lines
 ;   n) = GRP ^ Vaccine Group Name ^ Group/CVX Code Recommended ^ Group/CVX Display Name ^ Earliest Recommended Date ^
 ;        Overdue Date ^ Recommend Code ^ Recommend Display Name ^ Doses Remaining
 ;          1: GRP
 ;          2: Vaccine Group Name - This is the vaccine group for this recommendation
 ;          3: Group/CVX Code Recommended - Vaccine or vaccine group recommended.
 ;             If a specific vaccine is recommended, this will be the CVX code, in the format C:CVX_Code.
 ;             More commonly, this will be populated with the vaccine group, in the format G:Group_Name
 ;          4: Group/CVX Display Name - Display Name for CVX/Group in piece #3.
 ;          5: Recommended Date
 ;          6: Overdue Date
 ;          7: Earliest Date
 ;          8: Recommend Code (currently either RECOMMENDED, FUTURE_RECOMMENDED, CONDITIONALLY_RECOMMENDED, or NOT_RECOMMENDED)
 ;          9: Recommend Display Name
 ;          10: Doses Remaining
 ;   n) = RSN ^ Reason Code ^ Reason Display Name
 ;          Note: This is the reason(s) for the recommendation above.
 ;          1: RSN
 ;          2: Reason Code
 ;          3: Reason Display Name
 ;   n) = HIST ^ V Immunization IEN ^ Immunization Name ^ Administered CVX Code ^ Admin date/time ^ Dose Number ^
 ;        Component CVX Code ^ CVX Display Name ^ Validity Code ^ Validity Display Name
 ;          1: HIST
 ;          2: V Immunization IEN (#9000010.11 IEN)
 ;          3: Immunization Name (#9999999.14, #.01)
 ;          4: Administered CVX Code (#9999999.14, #.03)
 ;          5: Admin date/time
 ;          6: Dose Number
 ;          7: Component CVX Code (for combination vaccines, this can defer from the CVX administered)
 ;          8: CVX Display Name
 ;          9: Validity Code
 ;          10: Validity Display Name
 ;   n) = HISTRSN ^ Reason Code ^ Reason Display Name
 ;          Note: This is the reason(s) why the vaccine is valid, invalid or accepted.
 ;          1: HISTRSN
 ;          2: Reason Code
 ;          3: Reason Display Name
 ;
 N PXCNT,PXI,PXICEWEB,PXJ,PXK
 ;
 S PXRETURN=$NA(^TMP("PXICERPC",$J))
 K ^TMP("PXICERPC",$J)
 ;
 D EN(.PXICEWEB,$G(DFN),$G(PXCHKCACHE),$G(PXASYNC))
 ;
 S PXCNT=0
 ;
 S ^TMP("PXICERPC",$J,0)=$G(^TMP("PXICEWEB",$J,0))
 ;
 ; If Unsuccessful
 I $P(^TMP("PXICERPC",$J,0),U,1)<1 D  Q
 . M ^TMP("PXICERPC",$J)=^TMP("PXICEWEB",$J)
 ;
 ; If Successful, flatten output
 S PXI=0
 F  S PXI=$O(^TMP("PXICEWEB",$J,PXI)) Q:PXI=""  D
 . S PXCNT=PXCNT+1
 . S ^TMP("PXICERPC",$J,PXCNT)="GRP^"_PXI_U_$G(^TMP("PXICEWEB",$J,PXI))
 . ;
 . S PXJ=""
 . F  S PXJ=$O(^TMP("PXICEWEB",$J,PXI,"REASON",PXJ)) Q:PXJ=""  D
 . . S PXCNT=PXCNT+1
 . . S ^TMP("PXICERPC",$J,PXCNT)="RSN^"_$G(^TMP("PXICEWEB",$J,PXI,"REASON",PXJ))
 . ;
 . S PXJ=""
 . F  S PXJ=$O(^TMP("PXICEWEB",$J,PXI,"HISTORY",PXJ)) Q:PXJ=""  D
 . . S PXCNT=PXCNT+1
 . . S ^TMP("PXICERPC",$J,PXCNT)="HIST^"_PXJ_U_$G(^TMP("PXICEWEB",$J,PXI,"HISTORY",PXJ))
 . . ;
 . . S PXK=""
 . . F  S PXK=$O(^TMP("PXICEWEB",$J,PXI,"HISTORY",PXJ,"REASON",PXK)) Q:PXK=""  D
 . . . S PXCNT=PXCNT+1
 . . . S ^TMP("PXICERPC",$J,PXCNT)="HISTRSN^"_$G(^TMP("PXICEWEB",$J,PXI,"HISTORY",PXJ,"REASON",PXK))
 ;
 S $P(^TMP("PXICERPC",$J,0),U,2)=PXCNT
 ;
 K ^TMP("PXICEWEB",$J)
 ;
 Q
 ;
 ;
EN(PXRETURN,DFN,PXCHKCACHE,PXASYNC) ; Entry point for API
 ;
 ; Returns ICE recommendations
 ;
 ;Input:
 ;         DFN - Patient (#2) IEN
 ;  PXCHKCACHE - Use cached results, if available? 1=Yes; 0=No; (default: 1)
 ;     PXASYNC - Call ICE asynchronously? 1=Yes; 0=No; Handle; (default: 0)
 ;               When calling ICE asynchronously, first pass "1" as the PXASYNC argument.
 ;               If cached results are available (AND PXCHKCACHE is set to 1),
 ;               we will return them immediately.
 ;               If cached results are not available (OR PXCHKCACHE is set to 0),
 ;               we will task a job to call ICE, and return a handle to the calling
 ;               process. This handle should be passed in as the PXASYNC paramater
 ;               on future calls. The calling process should keep checking back to see
 ;               if the ICE task completed. On these subsequent calls, the same arguments
 ;               should be passed in as the original call, except that in the subsequent
 ;               calls, the PXASYNC argument should be the "handle" returned in the original
 ;               call.
 ;
 ;
 ;Returns:
 ;
 ; If called asynchronously (i.e., PXASYNC>0) AND a background task was queued (or is still running):
 ;   @PXRETURN@(0)=0^Handle
 ;   This "Handle" is a number >1 and should be passed in on future calls.
 ;
 ; If Unsuccessful:
 ;  @PXRETURN@(0)=X^Error Message
 ;                  Note: X can be one of the following values:
 ;                      -1: Invalid input
 ;                      -2: Could not make SOAP call (e.g., URL not populated in 920.75, etc.)
 ;                      -3: HTTP call returned unsuccessful status code (i.e., Server returned status code other than 200)
 ;                      -4: Unable to process incoming message from ICE
 ;                      -5: Error during asynchronous process.
 ;                      -6: Interface is down/disabled
 ;  @PXRETURN@(n)=If SOAP call was unsuccessful, this will be the message returned by the ICE server.
 ;
 ; If Successful:
 ;  @PXRETURN@(0)=1
 ;  @PXRETURN@(VaccineGroup)=Group/CVX Code Recommended ^ Group/CVX Display Name ^ Recommended Date ^ Overdue Date ^
 ;                           Earliest Date ^ Recommend Code ^ Recommend Display Name ^ Doses Remaining
 ;  @PXRETURN@(VaccineGroup,"REASON",n)=Reason Code ^ Reason Display Name
 ;  @PXRETURN@(VaccineGroup,"HISTORY",V_Imm_IEN)=Immunization Name ^ Administered CVX Code ^ Admin date/time ^
 ;                                               Dose Number ^ Component CVX Code ^ CVX Display Name ^
 ;                                               Validity Code ^ Validity Display Name
 ;  @PXRETURN@(VaccineGroup,"HISTORY",V_Imm_IEN,"REASON",n)=Reason Code ^ Reason Display Name
 ;
 N PXCACHESTAT,PXCNT,PXDESC,PXHANDLE,PXRTN,PXSTALL,PXTASK,PXURL,PXVARS,PXVOTH
 ;
 S PXRETURN=$NA(^TMP("PXICEWEB",$J))
 K ^TMP("PXICEWEB",$J)
 K ^TMP("PXVWMSG",$J)
 S PXCNT=0
 ;
 ; TODO - if ICE is down, should we allow to return from cache if available?
 ;        currently, if disabled, we dont check cache; but if unavailable, we check
 I $$CHKSTAT^PXVWSTAT()=0 D  Q
 . S ^TMP("PXICEWEB",$J,PXCNT)="-6^ICE interface is disabled"
 ;
 I $G(PXCHKCACHE)'?1(1"0",1"1") S PXCHKCACHE=1
 I $G(PXASYNC)="" S PXASYNC=0
 I PXASYNC>1 S PXHANDLE="PXVWICETMP-"_PXASYNC
 ;
 I '$G(DFN) D  Q
 . S ^TMP("PXICEWEB",$J,PXCNT)="-1^Missing DFN parameter"
 S PXURL=$$GETURL()
 I PXURL="" D  Q
 . S ^TMP("PXICEWEB",$J,PXCNT)="-2^Unable to determine default ICE server"
 ;
 ; Check asynchronous background task and quit
 I PXASYNC>1 D  Q
 . D ASYNC(PXHANDLE,DFN,PXASYNC,PXCNT)
 . D LOGSTAT^PXVWSTAT(DFN)
 ;
 ; if synchronous, call ICE in this process
 I 'PXASYNC D CALLICE
 ;
 ; if asynchronous, call ICE in tasked process. Return handle to caller.
 I PXASYNC D
 . ;
 . ; Before tasking background process, check cache. If cache is
 . ; valid, return from cache and no need to task background job.
 . I PXCHKCACHE,$$EXIST^PXVWCCH(DFN) D  Q:$G(PXCACHESTAT)=1
 . . D BLDVMR^PXVWVMR(DFN)
 . . I '$D(^TMP("PXVWMSG",$J)) D  Q
 . . . S ^TMP("PXICEWEB",$J,PXCNT)="-2^Unable to generate outbound VMR message"
 . . . S PXCACHESTAT=1
 . . S PXCACHESTAT=$$CHKCACHE(DFN,0)
 . . K ^TMP("PXVWMSG",$J)
 . ;
 . I '$$CHKSTAT^PXVWSTAT() D  Q
 . . S ^TMP("PXICEWEB",$J,PXCNT)="-6^ICE interface is down"
 . ;
 . ; Task process to call ICE
 . S PXHANDLE=$$HANDLE(DFN)
 . S PXRTN="CALLICE^PXVWICE"
 . S PXDESC="PCE Call ICE Engine (Immunizations)"
 . S PXVARS="PXCHKCACHE;PXURL;DFN;PXHANDLE"
 . S PXVOTH("ZTDTH")=$H
 . S PXTASK=$$NODEV^XUTMDEVQ(PXRTN,PXDESC,PXVARS,.PXVOTH)
 . ;
 . I $G(PXTASK)>0 D
 . . S ^XTMP(PXHANDLE,"STATUS")=0_U_PXTASK
 . . S ^TMP("PXICEWEB",$J,PXCNT)="0^"_$P(PXHANDLE,"-",2)
 . ;
 . I $G(PXTASK)=-1 D
 . . S ^TMP("PXICEWEB",$J,PXCNT)="-5^Error tasking asynchronous process."
 . . K ^XTMP(PXHANDLE)
 ;
 D LOGSTAT^PXVWSTAT(DFN)
 ;
 K ^TMP("PXVWMSG",$J)
 ;
 Q
 ;
 ;
CHKCACHE(DFN,PXSTALL) ;Check Cache for DFN
 ;
 ; Requires vMR to already be created in ^TMP("PXVWMSG",$J)
 ;
 N PXCACHESTAT,PXI
 ;
 S PXCACHESTAT=$$STAT^PXVWCCH(DFN)
 ;
 I $G(PXSTALL),PXCACHESTAT=2 D
 . F PXI=1:1:40 D  Q:PXCACHESTAT'=2
 . . H .5
 . . S PXCACHESTAT=$$STAT^PXVWCCH(DFN)
 ;
 I PXCACHESTAT'=1 Q PXCACHESTAT
 ;
 D LOAD^PXVWCCH(DFN)
 ;
 Q PXCACHESTAT
 ;
 ;
ASYNC(PXHANDLE,DFN,PXASYNC,PXCNT) ;Check asynchronous background task
 ;
 N PXDT
 ;
 I '$D(^XTMP(PXHANDLE)) D  Q
 . S ^TMP("PXICEWEB",$J,PXCNT)="-5^Error during asynchronous process."
 ;
 I $P($G(^XTMP(PXHANDLE,1)),U,1)'=DFN D  Q
 . S ^TMP("PXICEWEB",$J,PXCNT)="-5^Error during asynchronous process. DFN does not match."
 ;
 S PXDT=$P($G(^XTMP(PXHANDLE,"DT")),U,1)
 I 'PXDT D  Q
 . S ^TMP("PXICEWEB",$J,PXCNT)="-5^Error during asynchronous process."
 ; if background task is running for more than 2 min, return error
 I $$HDIFF^XLFDT($H,PXDT,2)>120 D  Q
 . S ^TMP("PXICEWEB",$J,PXCNT)="-5^Error during asynchronous process. Process timed out."
 ;
 ; background task completed.
 I $P($G(^XTMP(PXHANDLE,"STATUS")),U,1)=1 D  Q
 . M ^TMP("PXICEWEB",$J)=^XTMP(PXHANDLE,"ICE")
 . K ^XTMP(PXHANDLE)
 ;
 ; background task is still running
 I $P($G(^XTMP(PXHANDLE,"STATUS")),U,1)=0 D  Q
 . S ^TMP("PXICEWEB",$J,PXCNT)="0^"_PXASYNC
 ;
 Q
 ;
 ;
CALLICE ;
 ;
 ; ZEXCEPT: PXCHKCACHE,PXURL,DFN,PXHANDLE,ZTQUEUED,ZTREQ
 ;
 N PXCACHESTAT,PXCNT,PXNOW
 ;
 S ZTREQ="@"
 K ^TMP("PXICEWEB",$J)
 K ^TMP("PXVWMSG",$J)
 S PXNOW=$$NOW^XLFDT
 S PXCNT=0
 ;
 D BLDVMR^PXVWVMR(DFN)
 ;
 I '$D(^TMP("PXVWMSG",$J)) D  Q
 . S ^TMP("PXICEWEB",$J,PXCNT)="-2^Unable to generate outbound VMR message"
 . I $G(PXHANDLE)'="" D MOVERES(PXHANDLE)
 ;
 ; check cache
 I PXCHKCACHE D  Q:$G(PXCACHESTAT)=1
 . S PXCACHESTAT=$$CHKCACHE(DFN,1) ;Check Cache for DFN
 . I PXCACHESTAT=1 D
 . . I $G(PXHANDLE)'="" D MOVERES(PXHANDLE)
 . . K ^TMP("PXVWMSG",$J)
 ;
 I '$$CHKSTAT^PXVWSTAT() D  Q
 . S ^TMP("PXICEWEB",$J,PXCNT)="-6^ICE interface is down"
 . I $G(PXHANDLE)'="" D MOVERES(PXHANDLE)
 ;
 ; Set flag that cache is in middle of building
 D BLDNG^PXVWCCH(DFN)
 ;
 D EN^PXVWSOAP(PXURL) ; Call ICE
 ;
 ; if ICE call successfull, save output to cache
 I $P($G(^TMP("PXICEWEB",$J,0)),U,1)=1 D SAVE^PXVWCCH(DFN,PXNOW)
 ;
 ; Clear flag that cache is in middle of building
 D CLRBLDNG^PXVWCCH(DFN)
 ;
 ; if this is a background task, save output to XTMP
 I $G(PXHANDLE)'="" D MOVERES(PXHANDLE)
 ;
 K ^TMP("PXVWMSG",$J)
 ;
 Q
 ;
 ;
MOVERES(PXHANDLE) ;
 M ^XTMP(PXHANDLE,"ICE")=^TMP("PXICEWEB",$J)
 S ^XTMP(PXHANDLE,"STATUS")=1
 K ^TMP("PXICEWEB",$J)
 Q
 ;
 ;
HANDLE(DFN) ;Return a unique handle into ^XTMP
 ;
 N PXHANDLE,PXI,PXSUCCESS
 ;
 S PXI=$R(9999)+2
 S PXHANDLE="PXVWICETMP-"_PXI
 F  D  Q:$G(PXSUCCESS)
 . S PXSUCCESS=$$HANDLE2(PXHANDLE,DFN)
 . I $G(PXSUCCESS) Q
 . S PXI=PXI+1
 . S PXHANDLE="PXVWICETMP-"_PXI
 ;
 Q PXHANDLE
 ;
HANDLE2(PXHANDLE,DFN) ;
 ;
 I $D(^XTMP(PXHANDLE)) Q 0
 ;
 L +^XTMP(PXHANDLE):DILOCKTM
 I '$T Q 0
 ;
 I $D(^XTMP(PXHANDLE)) L -^XTMP(PXHANDLE) Q 0
 ;
 S ^XTMP(PXHANDLE,0)=DT_".24^"_DT
 S ^XTMP(PXHANDLE,1)=DFN
 S ^XTMP(PXHANDLE,"STATUS")=0
 S ^XTMP(PXHANDLE,"DT")=$H
 ;
 L -^XTMP(PXHANDLE)
 ;
 Q 1
 ;
 ;
GETURL() ; Get ICE Server URL
 ;
 N PXIEN,PXTMP
 ;
 S PXIEN=$$GET^XPAR("ALL","PX ICE WEB DEFAULT SERVER")
 ; If the value has not been set, then see if there is only one
 I 'PXIEN D
 . S PXTMP=$O(^PXV(920.75,0))
 . I $O(^PXV(920.75,PXTMP))'>0 S PXIEN=PXTMP
 I 'PXIEN Q ""
 Q $$GET1^DIQ(920.75,PXIEN,8)
 ;
 ;
TESTICE() ; Test ICE Interface
 ; Returns:
 ;    1 - Success
 ;    0 - Fail
 ;
 N PXSUCCESS,PXURL
 ;
 S PXURL=$$GETURL()
 I PXURL="" Q 0
 ;
 K ^TMP("PXICEWEB",$J)
 K ^TMP("PXVWMSG",$J)
 ;
 D TESTVMR^PXVWVMR
 ;
 I '$D(^TMP("PXVWMSG",$J)) Q 0
 ;
 D EN^PXVWSOAP(PXURL) ; Call ICE
 ;
 S PXSUCCESS=0
 I $P($G(^TMP("PXICEWEB",$J,0)),U,1)=1 S PXSUCCESS=1
 ;
 K ^TMP("PXICEWEB",$J)
 K ^TMP("PXVWMSG",$J)
 ;
 Q PXSUCCESS
 
--- Routine Detail   --- with STRUCTURED ROUTINE LISTING ---[H[J[2J[HPXVWICE   14197     printed  Sep 23, 2025@20:08:15                                                                                                                                                                                                    Page 2
PXVWICE   ;ISP/LMT - ICE interface main routine ;Jun 06, 2019@07:59:57
 +1       ;;1.0;PCE PATIENT CARE ENCOUNTER;**217**;Aug 12, 1996;Build 134
 +2       ;
 +3       ; Thanks to George Lilly for developing (and sharing) his prototype of the interface of VistA and ICE;
 +4       ; it was instrumental in the development of this production version.
 +5       ;
 +6       ; TODO:
 +7       ;   - Create national Clinical Reminders and update Build Logic
 +8       ;     in PX ICE MESSAGE entries that call into GETREM^PXVWVMR
 +9       ;     to use national reminders.
 +10      ;   - Add code to SELECT^ORWPC to check if ICE cache has been validated today;
 +11      ;     and if not, task job to validate cache, and if necessary update cache
 +12      ;
 +13      ;
RPC(PXRETURN,DFN,PXCHKCACHE,PXASYNC) ; Entry point for RPC
 +1       ;
 +2       ; Returns ICE recommendations
 +3       ;
 +4       ;Input:
 +5       ;         DFN - Patient (#2) IEN
 +6       ;  PXCHKCACHE - Use cached results, if available? 1=Yes; 0=No (default: 1)
 +7       ;     PXASYNC - Call ICE asynchronously? 1=Yes; 0=No; Handle; (default: 0)
 +8       ;               (See EN tag below for more info on asynchronous functionality).
 +9       ;
 +10      ;Returns:
 +11      ; If Unsuccessful:
 +12      ;   0) = X^Error Message
 +13      ;          Note: X can be one of the following values:
 +14      ;                 0: Cache is in middle of being built; check back later
 +15      ;                -1: Invalid input
 +16      ;                -2: Could not make SOAP call (e.g., URL not populated in 920.75, etc.)
 +17      ;                -3: HTTP call returned unsuccessful status code (i.e., Server returned status code other than 200)
 +18      ;                -4: Unable to process incoming message from ICE
 +19      ;                -5: Error during asynchronous process.
 +20      ;                -6: Interface is down/disabled
 +21      ;   n) = If SOAP call was unsuccessful, this will be the message returned by the ICE server.
 +22      ;
 +23      ; If Successful:
 +24      ;   0) = 1 ^ Number of Lines
 +25      ;   n) = GRP ^ Vaccine Group Name ^ Group/CVX Code Recommended ^ Group/CVX Display Name ^ Earliest Recommended Date ^
 +26      ;        Overdue Date ^ Recommend Code ^ Recommend Display Name ^ Doses Remaining
 +27      ;          1: GRP
 +28      ;          2: Vaccine Group Name - This is the vaccine group for this recommendation
 +29      ;          3: Group/CVX Code Recommended - Vaccine or vaccine group recommended.
 +30      ;             If a specific vaccine is recommended, this will be the CVX code, in the format C:CVX_Code.
 +31      ;             More commonly, this will be populated with the vaccine group, in the format G:Group_Name
 +32      ;          4: Group/CVX Display Name - Display Name for CVX/Group in piece #3.
 +33      ;          5: Recommended Date
 +34      ;          6: Overdue Date
 +35      ;          7: Earliest Date
 +36      ;          8: Recommend Code (currently either RECOMMENDED, FUTURE_RECOMMENDED, CONDITIONALLY_RECOMMENDED, or NOT_RECOMMENDED)
 +37      ;          9: Recommend Display Name
 +38      ;          10: Doses Remaining
 +39      ;   n) = RSN ^ Reason Code ^ Reason Display Name
 +40      ;          Note: This is the reason(s) for the recommendation above.
 +41      ;          1: RSN
 +42      ;          2: Reason Code
 +43      ;          3: Reason Display Name
 +44      ;   n) = HIST ^ V Immunization IEN ^ Immunization Name ^ Administered CVX Code ^ Admin date/time ^ Dose Number ^
 +45      ;        Component CVX Code ^ CVX Display Name ^ Validity Code ^ Validity Display Name
 +46      ;          1: HIST
 +47      ;          2: V Immunization IEN (#9000010.11 IEN)
 +48      ;          3: Immunization Name (#9999999.14, #.01)
 +49      ;          4: Administered CVX Code (#9999999.14, #.03)
 +50      ;          5: Admin date/time
 +51      ;          6: Dose Number
 +52      ;          7: Component CVX Code (for combination vaccines, this can defer from the CVX administered)
 +53      ;          8: CVX Display Name
 +54      ;          9: Validity Code
 +55      ;          10: Validity Display Name
 +56      ;   n) = HISTRSN ^ Reason Code ^ Reason Display Name
 +57      ;          Note: This is the reason(s) why the vaccine is valid, invalid or accepted.
 +58      ;          1: HISTRSN
 +59      ;          2: Reason Code
 +60      ;          3: Reason Display Name
 +61      ;
 +62       NEW PXCNT,PXI,PXICEWEB,PXJ,PXK
 +63      ;
 +64       SET PXRETURN=$NAME(^TMP("PXICERPC",$JOB))
 +65       KILL ^TMP("PXICERPC",$JOB)
 +66      ;
 +67       DO EN(.PXICEWEB,$GET(DFN),$GET(PXCHKCACHE),$GET(PXASYNC))
 +68      ;
 +69       SET PXCNT=0
 +70      ;
 +71       SET ^TMP("PXICERPC",$JOB,0)=$GET(^TMP("PXICEWEB",$JOB,0))
 +72      ;
 +73      ; If Unsuccessful
 +74       IF $PIECE(^TMP("PXICERPC",$JOB,0),U,1)<1
               Begin DoDot:1
 +75               MERGE ^TMP("PXICERPC",$JOB)=^TMP("PXICEWEB",$JOB)
               End DoDot:1
               QUIT 
 +76      ;
 +77      ; If Successful, flatten output
 +78       SET PXI=0
 +79       FOR 
               SET PXI=$ORDER(^TMP("PXICEWEB",$JOB,PXI))
               if PXI=""
                   QUIT 
               Begin DoDot:1
 +80               SET PXCNT=PXCNT+1
 +81               SET ^TMP("PXICERPC",$JOB,PXCNT)="GRP^"_PXI_U_$GET(^TMP("PXICEWEB",$JOB,PXI))
 +82      ;
 +83               SET PXJ=""
 +84               FOR 
                       SET PXJ=$ORDER(^TMP("PXICEWEB",$JOB,PXI,"REASON",PXJ))
                       if PXJ=""
                           QUIT 
                       Begin DoDot:2
 +85                       SET PXCNT=PXCNT+1
 +86                       SET ^TMP("PXICERPC",$JOB,PXCNT)="RSN^"_$GET(^TMP("PXICEWEB",$JOB,PXI,"REASON",PXJ))
                       End DoDot:2
 +87      ;
 +88               SET PXJ=""
 +89               FOR 
                       SET PXJ=$ORDER(^TMP("PXICEWEB",$JOB,PXI,"HISTORY",PXJ))
                       if PXJ=""
                           QUIT 
                       Begin DoDot:2
 +90                       SET PXCNT=PXCNT+1
 +91                       SET ^TMP("PXICERPC",$JOB,PXCNT)="HIST^"_PXJ_U_$GET(^TMP("PXICEWEB",$JOB,PXI,"HISTORY",PXJ))
 +92      ;
 +93                       SET PXK=""
 +94                       FOR 
                               SET PXK=$ORDER(^TMP("PXICEWEB",$JOB,PXI,"HISTORY",PXJ,"REASON",PXK))
                               if PXK=""
                                   QUIT 
                               Begin DoDot:3
 +95                               SET PXCNT=PXCNT+1
 +96                               SET ^TMP("PXICERPC",$JOB,PXCNT)="HISTRSN^"_$GET(^TMP("PXICEWEB",$JOB,PXI,"HISTORY",PXJ,"REASON",PXK))
                               End DoDot:3
                       End DoDot:2
               End DoDot:1
 +97      ;
 +98       SET $PIECE(^TMP("PXICERPC",$JOB,0),U,2)=PXCNT
 +99      ;
 +100      KILL ^TMP("PXICEWEB",$JOB)
 +101     ;
 +102      QUIT 
 +103     ;
 +104     ;
EN(PXRETURN,DFN,PXCHKCACHE,PXASYNC) ; Entry point for API
 +1       ;
 +2       ; Returns ICE recommendations
 +3       ;
 +4       ;Input:
 +5       ;         DFN - Patient (#2) IEN
 +6       ;  PXCHKCACHE - Use cached results, if available? 1=Yes; 0=No; (default: 1)
 +7       ;     PXASYNC - Call ICE asynchronously? 1=Yes; 0=No; Handle; (default: 0)
 +8       ;               When calling ICE asynchronously, first pass "1" as the PXASYNC argument.
 +9       ;               If cached results are available (AND PXCHKCACHE is set to 1),
 +10      ;               we will return them immediately.
 +11      ;               If cached results are not available (OR PXCHKCACHE is set to 0),
 +12      ;               we will task a job to call ICE, and return a handle to the calling
 +13      ;               process. This handle should be passed in as the PXASYNC paramater
 +14      ;               on future calls. The calling process should keep checking back to see
 +15      ;               if the ICE task completed. On these subsequent calls, the same arguments
 +16      ;               should be passed in as the original call, except that in the subsequent
 +17      ;               calls, the PXASYNC argument should be the "handle" returned in the original
 +18      ;               call.
 +19      ;
 +20      ;
 +21      ;Returns:
 +22      ;
 +23      ; If called asynchronously (i.e., PXASYNC>0) AND a background task was queued (or is still running):
 +24      ;   @PXRETURN@(0)=0^Handle
 +25      ;   This "Handle" is a number >1 and should be passed in on future calls.
 +26      ;
 +27      ; If Unsuccessful:
 +28      ;  @PXRETURN@(0)=X^Error Message
 +29      ;                  Note: X can be one of the following values:
 +30      ;                      -1: Invalid input
 +31      ;                      -2: Could not make SOAP call (e.g., URL not populated in 920.75, etc.)
 +32      ;                      -3: HTTP call returned unsuccessful status code (i.e., Server returned status code other than 200)
 +33      ;                      -4: Unable to process incoming message from ICE
 +34      ;                      -5: Error during asynchronous process.
 +35      ;                      -6: Interface is down/disabled
 +36      ;  @PXRETURN@(n)=If SOAP call was unsuccessful, this will be the message returned by the ICE server.
 +37      ;
 +38      ; If Successful:
 +39      ;  @PXRETURN@(0)=1
 +40      ;  @PXRETURN@(VaccineGroup)=Group/CVX Code Recommended ^ Group/CVX Display Name ^ Recommended Date ^ Overdue Date ^
 +41      ;                           Earliest Date ^ Recommend Code ^ Recommend Display Name ^ Doses Remaining
 +42      ;  @PXRETURN@(VaccineGroup,"REASON",n)=Reason Code ^ Reason Display Name
 +43      ;  @PXRETURN@(VaccineGroup,"HISTORY",V_Imm_IEN)=Immunization Name ^ Administered CVX Code ^ Admin date/time ^
 +44      ;                                               Dose Number ^ Component CVX Code ^ CVX Display Name ^
 +45      ;                                               Validity Code ^ Validity Display Name
 +46      ;  @PXRETURN@(VaccineGroup,"HISTORY",V_Imm_IEN,"REASON",n)=Reason Code ^ Reason Display Name
 +47      ;
 +48       NEW PXCACHESTAT,PXCNT,PXDESC,PXHANDLE,PXRTN,PXSTALL,PXTASK,PXURL,PXVARS,PXVOTH
 +49      ;
 +50       SET PXRETURN=$NAME(^TMP("PXICEWEB",$JOB))
 +51       KILL ^TMP("PXICEWEB",$JOB)
 +52       KILL ^TMP("PXVWMSG",$JOB)
 +53       SET PXCNT=0
 +54      ;
 +55      ; TODO - if ICE is down, should we allow to return from cache if available?
 +56      ;        currently, if disabled, we dont check cache; but if unavailable, we check
 +57       IF $$CHKSTAT^PXVWSTAT()=0
               Begin DoDot:1
 +58               SET ^TMP("PXICEWEB",$JOB,PXCNT)="-6^ICE interface is disabled"
               End DoDot:1
               QUIT 
 +59      ;
 +60       IF $GET(PXCHKCACHE)'?1(1"0",1"1")
               SET PXCHKCACHE=1
 +61       IF $GET(PXASYNC)=""
               SET PXASYNC=0
 +62       IF PXASYNC>1
               SET PXHANDLE="PXVWICETMP-"_PXASYNC
 +63      ;
 +64       IF '$GET(DFN)
               Begin DoDot:1
 +65               SET ^TMP("PXICEWEB",$JOB,PXCNT)="-1^Missing DFN parameter"
               End DoDot:1
               QUIT 
 +66       SET PXURL=$$GETURL()
 +67       IF PXURL=""
               Begin DoDot:1
 +68               SET ^TMP("PXICEWEB",$JOB,PXCNT)="-2^Unable to determine default ICE server"
               End DoDot:1
               QUIT 
 +69      ;
 +70      ; Check asynchronous background task and quit
 +71       IF PXASYNC>1
               Begin DoDot:1
 +72               DO ASYNC(PXHANDLE,DFN,PXASYNC,PXCNT)
 +73               DO LOGSTAT^PXVWSTAT(DFN)
               End DoDot:1
               QUIT 
 +74      ;
 +75      ; if synchronous, call ICE in this process
 +76       IF 'PXASYNC
               DO CALLICE
 +77      ;
 +78      ; if asynchronous, call ICE in tasked process. Return handle to caller.
 +79       IF PXASYNC
               Begin DoDot:1
 +80      ;
 +81      ; Before tasking background process, check cache. If cache is
 +82      ; valid, return from cache and no need to task background job.
 +83               IF PXCHKCACHE
                       IF $$EXIST^PXVWCCH(DFN)
                           Begin DoDot:2
 +84                           DO BLDVMR^PXVWVMR(DFN)
 +85                           IF '$DATA(^TMP("PXVWMSG",$JOB))
                                   Begin DoDot:3
 +86                                   SET ^TMP("PXICEWEB",$JOB,PXCNT)="-2^Unable to generate outbound VMR message"
 +87                                   SET PXCACHESTAT=1
                                   End DoDot:3
                                   QUIT 
 +88                           SET PXCACHESTAT=$$CHKCACHE(DFN,0)
 +89                           KILL ^TMP("PXVWMSG",$JOB)
                           End DoDot:2
                           if $GET(PXCACHESTAT)=1
                               QUIT 
 +90      ;
 +91               IF '$$CHKSTAT^PXVWSTAT()
                       Begin DoDot:2
 +92                       SET ^TMP("PXICEWEB",$JOB,PXCNT)="-6^ICE interface is down"
                       End DoDot:2
                       QUIT 
 +93      ;
 +94      ; Task process to call ICE
 +95               SET PXHANDLE=$$HANDLE(DFN)
 +96               SET PXRTN="CALLICE^PXVWICE"
 +97               SET PXDESC="PCE Call ICE Engine (Immunizations)"
 +98               SET PXVARS="PXCHKCACHE;PXURL;DFN;PXHANDLE"
 +99               SET PXVOTH("ZTDTH")=$HOROLOG
 +100              SET PXTASK=$$NODEV^XUTMDEVQ(PXRTN,PXDESC,PXVARS,.PXVOTH)
 +101     ;
 +102              IF $GET(PXTASK)>0
                       Begin DoDot:2
 +103                      SET ^XTMP(PXHANDLE,"STATUS")=0_U_PXTASK
 +104                      SET ^TMP("PXICEWEB",$JOB,PXCNT)="0^"_$PIECE(PXHANDLE,"-",2)
                       End DoDot:2
 +105     ;
 +106              IF $GET(PXTASK)=-1
                       Begin DoDot:2
 +107                      SET ^TMP("PXICEWEB",$JOB,PXCNT)="-5^Error tasking asynchronous process."
 +108                      KILL ^XTMP(PXHANDLE)
                       End DoDot:2
               End DoDot:1
 +109     ;
 +110      DO LOGSTAT^PXVWSTAT(DFN)
 +111     ;
 +112      KILL ^TMP("PXVWMSG",$JOB)
 +113     ;
 +114      QUIT 
 +115     ;
 +116     ;
CHKCACHE(DFN,PXSTALL) ;Check Cache for DFN
 +1       ;
 +2       ; Requires vMR to already be created in ^TMP("PXVWMSG",$J)
 +3       ;
 +4        NEW PXCACHESTAT,PXI
 +5       ;
 +6        SET PXCACHESTAT=$$STAT^PXVWCCH(DFN)
 +7       ;
 +8        IF $GET(PXSTALL)
               IF PXCACHESTAT=2
                   Begin DoDot:1
 +9                    FOR PXI=1:1:40
                           Begin DoDot:2
 +10                           HANG .5
 +11                           SET PXCACHESTAT=$$STAT^PXVWCCH(DFN)
                           End DoDot:2
                           if PXCACHESTAT'=2
                               QUIT 
                   End DoDot:1
 +12      ;
 +13       IF PXCACHESTAT'=1
               QUIT PXCACHESTAT
 +14      ;
 +15       DO LOAD^PXVWCCH(DFN)
 +16      ;
 +17       QUIT PXCACHESTAT
 +18      ;
 +19      ;
ASYNC(PXHANDLE,DFN,PXASYNC,PXCNT) ;Check asynchronous background task
 +1       ;
 +2        NEW PXDT
 +3       ;
 +4        IF '$DATA(^XTMP(PXHANDLE))
               Begin DoDot:1
 +5                SET ^TMP("PXICEWEB",$JOB,PXCNT)="-5^Error during asynchronous process."
               End DoDot:1
               QUIT 
 +6       ;
 +7        IF $PIECE($GET(^XTMP(PXHANDLE,1)),U,1)'=DFN
               Begin DoDot:1
 +8                SET ^TMP("PXICEWEB",$JOB,PXCNT)="-5^Error during asynchronous process. DFN does not match."
               End DoDot:1
               QUIT 
 +9       ;
 +10       SET PXDT=$PIECE($GET(^XTMP(PXHANDLE,"DT")),U,1)
 +11       IF 'PXDT
               Begin DoDot:1
 +12               SET ^TMP("PXICEWEB",$JOB,PXCNT)="-5^Error during asynchronous process."
               End DoDot:1
               QUIT 
 +13      ; if background task is running for more than 2 min, return error
 +14       IF $$HDIFF^XLFDT($HOROLOG,PXDT,2)>120
               Begin DoDot:1
 +15               SET ^TMP("PXICEWEB",$JOB,PXCNT)="-5^Error during asynchronous process. Process timed out."
               End DoDot:1
               QUIT 
 +16      ;
 +17      ; background task completed.
 +18       IF $PIECE($GET(^XTMP(PXHANDLE,"STATUS")),U,1)=1
               Begin DoDot:1
 +19               MERGE ^TMP("PXICEWEB",$JOB)=^XTMP(PXHANDLE,"ICE")
 +20               KILL ^XTMP(PXHANDLE)
               End DoDot:1
               QUIT 
 +21      ;
 +22      ; background task is still running
 +23       IF $PIECE($GET(^XTMP(PXHANDLE,"STATUS")),U,1)=0
               Begin DoDot:1
 +24               SET ^TMP("PXICEWEB",$JOB,PXCNT)="0^"_PXASYNC
               End DoDot:1
               QUIT 
 +25      ;
 +26       QUIT 
 +27      ;
 +28      ;
CALLICE   ;
 +1       ;
 +2       ; ZEXCEPT: PXCHKCACHE,PXURL,DFN,PXHANDLE,ZTQUEUED,ZTREQ
 +3       ;
 +4        NEW PXCACHESTAT,PXCNT,PXNOW
 +5       ;
 +6        SET ZTREQ="@"
 +7        KILL ^TMP("PXICEWEB",$JOB)
 +8        KILL ^TMP("PXVWMSG",$JOB)
 +9        SET PXNOW=$$NOW^XLFDT
 +10       SET PXCNT=0
 +11      ;
 +12       DO BLDVMR^PXVWVMR(DFN)
 +13      ;
 +14       IF '$DATA(^TMP("PXVWMSG",$JOB))
               Begin DoDot:1
 +15               SET ^TMP("PXICEWEB",$JOB,PXCNT)="-2^Unable to generate outbound VMR message"
 +16               IF $GET(PXHANDLE)'=""
                       DO MOVERES(PXHANDLE)
               End DoDot:1
               QUIT 
 +17      ;
 +18      ; check cache
 +19       IF PXCHKCACHE
               Begin DoDot:1
 +20      ;Check Cache for DFN
                   SET PXCACHESTAT=$$CHKCACHE(DFN,1)
 +21               IF PXCACHESTAT=1
                       Begin DoDot:2
 +22                       IF $GET(PXHANDLE)'=""
                               DO MOVERES(PXHANDLE)
 +23                       KILL ^TMP("PXVWMSG",$JOB)
                       End DoDot:2
               End DoDot:1
               if $GET(PXCACHESTAT)=1
                   QUIT 
 +24      ;
 +25       IF '$$CHKSTAT^PXVWSTAT()
               Begin DoDot:1
 +26               SET ^TMP("PXICEWEB",$JOB,PXCNT)="-6^ICE interface is down"
 +27               IF $GET(PXHANDLE)'=""
                       DO MOVERES(PXHANDLE)
               End DoDot:1
               QUIT 
 +28      ;
 +29      ; Set flag that cache is in middle of building
 +30       DO BLDNG^PXVWCCH(DFN)
 +31      ;
 +32      ; Call ICE
           DO EN^PXVWSOAP(PXURL)
 +33      ;
 +34      ; if ICE call successfull, save output to cache
 +35       IF $PIECE($GET(^TMP("PXICEWEB",$JOB,0)),U,1)=1
               DO SAVE^PXVWCCH(DFN,PXNOW)
 +36      ;
 +37      ; Clear flag that cache is in middle of building
 +38       DO CLRBLDNG^PXVWCCH(DFN)
 +39      ;
 +40      ; if this is a background task, save output to XTMP
 +41       IF $GET(PXHANDLE)'=""
               DO MOVERES(PXHANDLE)
 +42      ;
 +43       KILL ^TMP("PXVWMSG",$JOB)
 +44      ;
 +45       QUIT 
 +46      ;
 +47      ;
MOVERES(PXHANDLE) ;
 +1        MERGE ^XTMP(PXHANDLE,"ICE")=^TMP("PXICEWEB",$JOB)
 +2        SET ^XTMP(PXHANDLE,"STATUS")=1
 +3        KILL ^TMP("PXICEWEB",$JOB)
 +4        QUIT 
 +5       ;
 +6       ;
HANDLE(DFN) ;Return a unique handle into ^XTMP
 +1       ;
 +2        NEW PXHANDLE,PXI,PXSUCCESS
 +3       ;
 +4        SET PXI=$RANDOM(9999)+2
 +5        SET PXHANDLE="PXVWICETMP-"_PXI
 +6        FOR 
               Begin DoDot:1
 +7                SET PXSUCCESS=$$HANDLE2(PXHANDLE,DFN)
 +8                IF $GET(PXSUCCESS)
                       QUIT 
 +9                SET PXI=PXI+1
 +10               SET PXHANDLE="PXVWICETMP-"_PXI
               End DoDot:1
               if $GET(PXSUCCESS)
                   QUIT 
 +11      ;
 +12       QUIT PXHANDLE
 +13      ;
HANDLE2(PXHANDLE,DFN) ;
 +1       ;
 +2        IF $DATA(^XTMP(PXHANDLE))
               QUIT 0
 +3       ;
 +4        LOCK +^XTMP(PXHANDLE):DILOCKTM
 +5        IF '$TEST
               QUIT 0
 +6       ;
 +7        IF $DATA(^XTMP(PXHANDLE))
               LOCK -^XTMP(PXHANDLE)
               QUIT 0
 +8       ;
 +9        SET ^XTMP(PXHANDLE,0)=DT_".24^"_DT
 +10       SET ^XTMP(PXHANDLE,1)=DFN
 +11       SET ^XTMP(PXHANDLE,"STATUS")=0
 +12       SET ^XTMP(PXHANDLE,"DT")=$HOROLOG
 +13      ;
 +14       LOCK -^XTMP(PXHANDLE)
 +15      ;
 +16       QUIT 1
 +17      ;
 +18      ;
GETURL()  ; Get ICE Server URL
 +1       ;
 +2        NEW PXIEN,PXTMP
 +3       ;
 +4        SET PXIEN=$$GET^XPAR("ALL","PX ICE WEB DEFAULT SERVER")
 +5       ; If the value has not been set, then see if there is only one
 +6        IF 'PXIEN
               Begin DoDot:1
 +7                SET PXTMP=$ORDER(^PXV(920.75,0))
 +8                IF $ORDER(^PXV(920.75,PXTMP))'>0
                       SET PXIEN=PXTMP
               End DoDot:1
 +9        IF 'PXIEN
               QUIT ""
 +10       QUIT $$GET1^DIQ(920.75,PXIEN,8)
 +11      ;
 +12      ;
TESTICE() ; Test ICE Interface
 +1       ; Returns:
 +2       ;    1 - Success
 +3       ;    0 - Fail
 +4       ;
 +5        NEW PXSUCCESS,PXURL
 +6       ;
 +7        SET PXURL=$$GETURL()
 +8        IF PXURL=""
               QUIT 0
 +9       ;
 +10       KILL ^TMP("PXICEWEB",$JOB)
 +11       KILL ^TMP("PXVWMSG",$JOB)
 +12      ;
 +13       DO TESTVMR^PXVWVMR
 +14      ;
 +15       IF '$DATA(^TMP("PXVWMSG",$JOB))
               QUIT 0
 +16      ;
 +17      ; Call ICE
           DO EN^PXVWSOAP(PXURL)
 +18      ;
 +19       SET PXSUCCESS=0
 +20       IF $PIECE($GET(^TMP("PXICEWEB",$JOB,0)),U,1)=1
               SET PXSUCCESS=1
 +21      ;
 +22       KILL ^TMP("PXICEWEB",$JOB)
 +23       KILL ^TMP("PXVWMSG",$JOB)
 +24      ;
 +25       QUIT PXSUCCESS