Home   Package List   Routine Alphabetical List   Global Alphabetical List   FileMan Files List   FileMan Sub-Files List   Package Component Lists   Package-Namespace Mapping  
Routine: ABSPOSQ4

ABSPOSQ4.m

Go to the documentation of this file.
  1. ABSPOSQ4 ; IHS/FCS/DRS - Process responses ; [ 10/07/2002 10:36 AM ]
  1. ;;1.0;PHARMACY POINT OF SALE;**3,6,31**;JUN 21, 2001;Build 38
  1. ; Called from ABSPOSQ3 at RESPONSE()
  1. ;
  1. ; What's here: the main LOOP and several miscellaneous subroutines,
  1. ; many of which are called from outside.
  1. ;
  1. ; The meat of the response packet processing is in RESPONSE^ABSPOSQL
  1. ; and its subroutines, ONE, ONE1, RESP1
  1. ;
  1. ;---------------------------------------------------------
  1. ;IHS/SD/lwj 10/07/02 NCPDP 5.1 changes
  1. ; The responses are exactly the same between 5.1 and 3.2 - we needed
  1. ; to add new logic to RESP1000 and RESPMSG to capture the newer
  1. ; information
  1. ;
  1. ;----------------------------------------------------------
  1. ;IHS/SD/lwj 6/10/03 Patch 6 - insurer sleep override
  1. ; Usually a rejection code of 99 on a claim indicates that
  1. ; the insurer/processor is not able to accept or process
  1. ; claims at this time. POS puts the insurer in a sleep state
  1. ; and probes the insurer for response. This was done to cut
  1. ; cost and traffic from sending claims when the insurer is down.
  1. ; Unfortunately, some insurers send the 99 to reflect that the
  1. ; patient simply isn't on their plan - this was causing the insurer
  1. ; to stay in a permanent sleep state. Changes were made to REJSLEEP
  1. ; to check a new flag in the insurer file (101.07 99 REJECT SLEEP
  1. ; OVERRIDE) - when set, we will not put the insurer to sleep,
  1. ; even when we get a rejection of 99.
  1. ;---------------------------------------------------------
  1. Q
  1. EN ; the task from ABSPOSQ3 starts here
  1. ; for a specific DIALOUT
  1. ; Q4WAIT might be defined, too
  1. I '$G(Q4WAIT),'$O(^ABSPECX("POS",DIALOUT,"R",0)) Q ; not waiting; nothing ready
  1. N A,B,BLIMIT,ODIALOUT,GOTLOCK ; "O" as in "Original"
  1. S ODIALOUT=DIALOUT,BLIMIT=$G(Q4WAIT,10)
  1. D INIT^ABSPOSL(.11)
  1. D LOG($T(+0)_" - Job "_$J_" processing POS responses.")
  1. LOOP ;
  1. ; The task may have been started before the responses were ready yet.
  1. ; For example, it may have been started before dialing - figure up
  1. ; to a minute before something might be available.
  1. S B=0 F A=5:5:BLIMIT D Q:B
  1. . S B=$O(^ABSPECX("POS",DIALOUT,"R","")) Q:B
  1. . HANG 2+$R(6) ; averages out to 5 seconds between checking
  1. I 'B G LOOP7 ; no responses ready for this DIALOUT
  1. LOOP1 ;
  1. D LOG($T(+0)_" - Processing responses for DIALOUT="_DIALOUT)
  1. L +^TMP("ABSPOSQ4",DIALOUT):5 ; only one job per DIALOUT (overcautious)
  1. S GOTLOCK=$T
  1. I GOTLOCK D
  1. . D RESPONSE^ABSPOSQL(DIALOUT) ; process all responses for this DIALOUT
  1. . L -^TMP("ABSPOSQ4",DIALOUT)
  1. . D LOG($T(+0)_" - Done for DIALOUT="_DIALOUT)
  1. E D G LOOP9
  1. . D LOG($T(+0)_" - couldn't get LOCK? Another one already running?")
  1. . D TASKAT^ABSPOSQ3($$TADDNOW^ABSPOSUD(.0002)) ; try again in 2 mins.
  1. LOOP7 S DIALOUT=$$ANYRESPS(0) ; any others for anybody else we can do now?
  1. I DIALOUT G LOOP1
  1. I B S DIALOUT=ODIALOUT,BLIMIT=10 G LOOP ; worth looping back to check original
  1. LOOP9 D LOG($T(+0)_" - Job "_$J_" completed.")
  1. D RELSLOT^ABSPOSL
  1. ; If there are any Status 19's, rev up a processor to rescue them
  1. I $D(^ABSPT("AD",19)) D TASK^ABSPOSIZ ; ABSPOSQ1
  1. Q
  1. LOG(X) D LOG^ABSPOSL(X) Q
  1. ANYRESPS(DIALOUT) ;EP - ABSPOS2D ;
  1. ; are there any responses waiting to be processed?
  1. ; Also called from POKE^ABSPOSUD
  1. I $G(DIALOUT) Q $S($O(^ABSPECX("POS",DIALOUT,"R","")):DIALOUT,1:0)
  1. ; DIALOUT not given, so look for any DIALOUTs that need work
  1. ; If any waiting, return DIALOUT where there are
  1. ; Else return ""
  1. N SET,RET S (SET,RET)=0
  1. F S SET=$O(^ABSP(9002313.55,SET)) Q:'SET I $$ANYRESPS(SET) S RET=SET Q
  1. Q RET
  1. ;
  1. ; The following are separate little utilities called from elsewhere.
  1. ;
  1. N TMP D RESPINFO(IEN59,.TMP) Q:'$D(TMP("RSP")) 0
  1. N X S X=TMP("RSP")
  1. I X="Payable" Q 1
  1. ;I X="Captured" Q .5 ; should we?
  1. Q 0
  1. RESPINFO(RXI,DST) ;EP - ABSPOS6B,ABSPOSNC,ABSPOSUA
  1. ; quick way to get all the response info for a given RXI
  1. ; IMPORTANT!! D not change spelling, case, wording, or spacing!!!
  1. ; Callers such as ABSPOSNC are depending on the exact DST("RSP")
  1. ; If a reversal was attempted, it complicates things.
  1. ; fills DST array as follows:
  1. ; DST("HDR")=Response Status (header)
  1. ; DST("RSP")=Response Status (prescription)
  1. ; This could be: "Payable" "Rejected" "Captured" "Duplicate"
  1. ; or "Accepted reversal" or "Rejected reversal"
  1. ; or "null" or "null reversal" (no response or corrupt response
  1. ; or maybe someone without insurance, so no request was sent)
  1. ; DST("REJ",0)=count of reject codes
  1. ; DST("REJ",n)=each reject code
  1. ; DST("MSG")=message with the response
  1. ; All of these are defined, even if originals were '$D.
  1. ; The external forms are returned.
  1. N REVERSAL S REVERSAL=$G(^ABSPT(RXI,4))>0
  1. N RESP
  1. I 'REVERSAL S RESP=$P(^ABSPT(RXI,0),U,5)
  1. E S RESP=$P(^ABSPT(RXI,4),U,2)
  1. Q:'RESP
  1. N POS S POS=$P(^ABSPT(RXI,0),U,9) Q:'POS
  1. N FMT S FMT="E"
  1. S DST("HDR")=$$RESP500(RESP,FMT)
  1. S DST("RSP")=$$RESP1000(RESP,POS,FMT)
  1. S DST("REJ",0)=$$REJCOUNT(RESP,POS,FMT)
  1. I DST("REJ",0) D
  1. .N I F I=1:1:DST("REJ",0) S DST("REJ",I)=$$REJCODE(RESP,POS,I,FMT)
  1. S DST("MSG")=$$RESPMSG(RESP,POS,FMT)
  1. ; Dealing with oddities of PCS (and others'?) response to reversals
  1. I REVERSAL,DST("RSP")["null" D
  1. .I DST("RSP")["null" S DST("RSP")=DST("HDR")_" reversal"
  1. Q
  1. ; In the following quickies:
  1. ; RESP = RESPIEN, pointer to 9002313.03
  1. ; FMT = "I" for internal, "E" for external, defaults to internal
  1. RESP500(RESP,FMT) ;EP - ABSPOS57,ABSPOSP2,ABSPOSUC
  1. ; returns the response header status
  1. N X S X=$P($G(^ABSPR(RESP,500)),U)
  1. I $G(FMT)'="E" Q X
  1. I X="" S X="null"
  1. S X=$S(X="A":"Accepted",X="R":"Rejected",1:"?"_X)
  1. Q X
  1. RESP1000(RESP,POS,FMT) ;EP - ABSPOSP2,ABSPOSUC
  1. ; returns the prescription response status
  1. ; Note! Could be DP or DC for duplicates
  1. N X S X=$P($G(^ABSPR(RESP,1000,POS,500)),U)
  1. I $G(FMT)'="E" Q X
  1. I X="" S X="null"
  1. ;
  1. ;IHS/SD/lwj 10/07/02 NCPDP 5.1 changes - they will send an "A" back
  1. ; now on the transaction level to indicate that it has been accepted
  1. ; Next code line remarked out - following added
  1. ;
  1. ;S X=$S(X="P":"Payable",X="R":"Rejected",X="C":"Captured",X="D"!(X="DP")!(X="DC"):"Duplicate",1:"?"_X)
  1. S X=$S(X="A":"Accepted",X="P":"Payable",X="R":"Rejected",X="C":"Captured",X="D"!(X="DP")!(X="DC"):"Duplicate",1:"?"_X)
  1. Q X
  1. REJCOUNT(RESP,POS,FMT) ; returns rejection count
  1. Q +$P($G(^ABSPR(RESP,1000,POS,511,0)),U,3)
  1. REJCODE(RESP,POS,N,FMT) ; returns Nth rejection code
  1. ; if FMT="E", returns code:text
  1. N CODE S CODE=$P($G(^ABSPR(RESP,1000,POS,511,N,0)),U)
  1. I CODE="" S CODE="null"
  1. I FMT'="E" Q CODE
  1. N X S X=$O(^ABSPF(9002313.93,"B",CODE,0))
  1. I X]"" S CODE=CODE_":"_$P($G(^ABSPF(9002313.93,X,0)),U,2)
  1. E S CODE="?"_CODE
  1. Q CODE
  1. ;
  1. ;IHS/SD/lwj 10/07/02 NCPDP 5.1 changes - message may not come
  1. ; back in 504 - may come back in 526 instead
  1. ;
  1. RESPMSG(RESP,POS,FMT) ; response message - additional text from insurer
  1. ;
  1. N MSG
  1. S MSG=""
  1. S MSG=$G(^ABSPR(RESP,1000,POS,504))
  1. S:MSG="" MSG=$G(^ABSPR(RESP,1000,POS,526))
  1. ;Q $G(^ABSPR(RESP,1000,POS,504))
  1. Q MSG
  1. ;
  1. ;IHS/SD/lwj 10/07/02 end of NCPDP 5.1 changes to RESPMSG
  1. ;
  1. NOW() N %,%H,%I,X D NOW^%DTC Q %
  1. ;
  1. ; The xxxSLEEP functions are called from ABSPOSQL
  1. ;
  1. CLRSLEEP(INS,WHY) ;EP - ABSPOSQL
  1. ; clear insurer sleeping condition
  1. ; also called from CANCEL^ABSPOSUD
  1. ; WHY = 1 - we know for sure they're awake now
  1. Q:$G(INS)="" ;IHS/OIT/SCR 05/07/09 avoid undefined patch 31
  1. N X S X=$G(^ABSPEI(INS,101)) Q:'X ; not asleep
  1. S $P(X,U)="",$P(X,U,5)="",$P(X,U,6)="",^ABSPEI(INS,101)=X
  1. I $D(^ABSPT("AD",31)) D
  1. . D TASK^ABSPOSQ1 ; awaken any other 31s waiting for this insurer
  1. Q
  1. REJSLEEP(RESP,POS) ;EP - ABSPOSQL
  1. ; return TRUE if this claim was rejected because the
  1. ; insurer is sleeping
  1. ; Reject codes we look for depend on which switch.
  1. ; Envoy's:
  1. I $G(^ABSPR(RESP,1000,POS,504))?1"EV16-".E Q 1
  1. I $G(^ABSPR(RESP,1000,POS,504))?1"EV38-".E Q 1
  1. I $G(^ABSPR(RESP,1000,POS,504))?1"EV32-".E Q 1
  1. I $G(^ABSPR(RESP,1000,POS,504))?1"EV25-".E Q 1 ; ABSP*1.0T7*4
  1. ; NDC's, and theoretically, Envoy too, though they seem to do EV- msgs
  1. I $O(^ABSPR(RESP,1000,POS,511,"B",90))="" Q 0 ; cheap check
  1. ; But for a PCS case we see, Code 99 + some code < 90 ; ABSP*1.0T7*2
  1. ; isn't "asleep" - 99 is something PCS threw in ; ABSP*1.0T7*2
  1. ; so require 99 to be accompanied by something <99 too ; ABSP*1.0T7*2
  1. N RET S RET=0 N I F I=92,93,99 D Q:RET
  1. . I $D(^ABSPR(RESP,1000,POS,511,"B",I)) S RET=1
  1. . Q:I'=99 Q:'RET ; ABSP*1.0T7*2
  1. . I I=99,$O(^ABSPR(RESP,1000,POS,511,"B",0))<90 S RET=0 ; ABSP*1.0T7*2
  1. ;
  1. ;IHS/SD/lwj 06/10/03 Patch 6 Version 1.0
  1. ;Check for sleep override - some insurers naturally return a
  1. ;rejection of 99 - it doesn't mean they're asleep, and we need
  1. ;to bypass putting them in a sleep state
  1. ;
  1. I RET=1 D
  1. . N ABSPCID,ABSPIID,ABSPSLP
  1. . S (ABSPCID,ABSPIID,ABSPSLP)=""
  1. . S ABSPCID=$P($G(^ABSPR(RESP,0)),U) ;pointer to claim file
  1. . Q:ABSPCID=""
  1. . S ABSPIID=$P($G(^ABSPC(ABSPCID,0)),U,2) ;pntr to insurer file
  1. . Q:ABSPIID=""
  1. . S ABSPSLP=$P($G(^ABSPEI(ABSPIID,101)),U,7) ;99 rej slp ovr
  1. . S:ABSPSLP RET=0 ;don't go to sleep
  1. ;
  1. ;IHS/SD/lwj 6/10/03 end of changes
  1. ;
  1. Q RET
  1. INCSLEEP(INS) ;EP - ABSPOSQL
  1. ; Increment sleep time for this insurer, if necessary.
  1. ; Return the scheduled retry time
  1. N X S X=$G(^ABSPEI(INSURER,101))
  1. I $P(X,U)<$$NOW D ; previous retry expired, let's retry:
  1. . I '$P(X,U,2) S $P(X,U,2)=600 ; base time = 10 minutes
  1. . I '$P(X,U,3) S $P(X,U,3)=3 ; multiplier
  1. . I '$P(X,U,4) S $P(X,U,4)=2.5*60*60 ; max wait time ; 2.5 hrs
  1. . I '$P(X,U,5) S $P(X,U,5)=$P(X,U,2) ; current wait time (either init
  1. . E S $P(X,U,5)=$P(X,U,5)*$P(X,U,3) ; or multiply)
  1. . S $P(X,U,5)=$P(X,U,5)\1
  1. . S:$P(X,U,5)>$P(X,U,4) $P(X,U,5)=$P(X,U,4) ; apply max if needed
  1. . S $P(X,U)=$$TADDNOWS^ABSPOSUD($P(X,U,5)) ; set retry time
  1. . S ^ABSPEI(INSURER,101)=X
  1. . D TASKAT^ABSPOSQ1($P(X,U)) ; ABSPOSQ2 will run again upon expiry
  1. . D TASK^ABSPOSQ1 ; and run it again right away, too, to stamp new times on the others in status 31
  1. Q $P(X,U)