Well, that's no ordinary rabbit!
The MIS.OA.MSG.auto program can be used to email one, several or even all users. It can be used 2 ways - send a preformatted OA message to the group attached to it in the OA message dictionary or send a custom message to 1 or more users. The users can be hard coded into the program call, loaded from a distribution list, loaded from the group response dictionary, or even determined based on a query response. The program can be called from an attribute on a CDS or from within an NPR report.
This is done using the OA message mnemonic as argument A. The message is sent to the users/devices attached to the OA message in the OA message dictionary. To send the OA message HOT_PIZZA you would use this:
%MIS.OA.MSG.auto("HOT_PIZZA")X
This is done using argument B. If B exists argument A is
ignored. This argument contains at least 2 pieces of information in a
packed Q. The first is the structure that holds the text message you
want to send. I prefer to store my message in /MSG but any / structure
is valid. You load the information you want into /MSG before making the
program call.
"This is the
first line of info"^/MSG[XX+1^XX],
"This is the second line
of info"^/MSG[XX+1^XX],
"This is the third line
of info"^/MSG[XX+1^XX]
The other pieces of information are the email recipients. These are simply added to the Q separated by commas. You could send the /MSG message to users "XYZ", "YYZ" and "ZYZ" like this.
%MIS.OA.MSG.auto("",Q(^/MSG,"XYZ","YYZ","ZYZ"))X
In the example "XYZ" is the MIS user id. You can also send messages to printers and even smtp email addresses (as long as you have an external mail server configured). Prefix printers with ! and smtp addresses with !!. You would send to user XYZ and printer PTR75 and smtp address tt@xyz.com like this.
%MIS.OA.MSG.auto("",Q(^/MSG,"XYZ","!PTR75","!!tt@xyz.com"))X
Send an email to user "XXX" from
an OE procedure query if response is "Y"
Note: message is stored in /MSG
Message consists of patient name,
location, and OE procedure name
Note: email is sent when FCL is evaluated, not when order is filed.
Send an email to users "XXX", "XXY" and "XXZ" from an OE
procedure query if response is "Y"
Same other conditions as above.
FCL1=IF{@.response="Y" @ADM.PAT.name^/MSG[1],
FCL1=@ADM.PAT.location^/MSG[2],
FCL1=@procedure.name^/MSG[3],
FCL1=%MIS.OA.MSG.auto("",Q(^/MSG,"XXX","XXY","XXZ"))X}
This will send the same info as above but to all users in a
distribution group. Again the query response must be "Y"
The first method loops thru the distribution list and emails each one
individually. The second method loops thru the distribution group and
stores all the recipients in RES and then emails the whole group. Do
not use the second method except for short lists.
FCL1=IF{@.response="Y"
@ADM.PAT.name^/MSG[1],
FCL1=@ADM.PAT.location^/MSG[2],
FCL1=@procedure.name^/MSG[3],
FCL1=DO{+\GUG["EMAIL","U",XX]^XX
FCL1= %MIS.OA.MSG.auto("",Q(^/MSG,XX))X}}
or
FCL1=IF{@.response="Y"
@ADM.PAT.name^/MSG[1],
FCL1=@ADM.PAT.location^/MSG[2],
FCL1=@procedure.name^/MSG[3],
FCL1=^/MSG^RES|0,DO{+\GUG["EMAIL","U,XX]^XX
FCL1= QQ+1^QQ,XX^RES|QQ},%MIS.OA.MSG.auto("",RES)X}
Same conditions as above but this time using a list of users
stored in the group response dictionary in a group called "EMAIL".
The first sends each individual a message. The second emails the group.
Again, do not use the second method except for short lists.
FCL1=IF{@.response="Y"
@ADM.PAT.name^/MSG[1],
FCL1=@ADM.PAT.location^/MSG[2],
FCL1=@procedure.name^/MSG[3],
FCL1=DO{+\GGL["EMAIL","E",XX]^XX
FCL1=
%MIS.OA.MSG.auto("",Q(^/MSG,XX))X}}
or
FCL1=IF{@.response="Y"
@ADM.PAT.name^/MSG[1],
FCL1=@ADM.PAT.location^/MSG[2],
FCL1=@procedure.name^/MSG[3],
FCL1=^/MSG^RES|0,DO{+\GGL["EMAIL","E,XX]^XX
FCL1=
QQ+1^QQ,XX^RES|QQ},%MIS.OA.MSG.auto("",RES)X}
Sending email to all users from an attribute is not something I would recommend since it could take quite a while to loop thru all the users and email them. Meanwhile someone is waiting for the cursor to go on the next query and is probably getting frustrated.
FCL1=IF{@.response="Y" @ADM.PAT.name^/MSG[1],
FCL1=@ADM.PAT.location^/MSG[2],
FCL1=@procedure.name^/MSG[3],
FCL1=DO{+\GU[XX]^XX IF{"Y"=\GU[XX]|0
FCL1= %MIS.OA.MSG.auto("",Q(^/MSG,XX))X}}}
I use this quite often so users do not have to look for spool files or to immediately notify someone of a problem. I have reports that check printer status, scheduled reports status, fax port status, etc. The reports email me any problems found. This example checks the MIS report scheduler and notifies me of any that have been running for an excessive amount of time or that are missing from the schedule. The report itself doesn't print anything - the detail macro loads data into /MSG and the email macro emails it when the report is finished.
Detail DPM: MIS.JOB
Detail Segment: mis.print.jobs
Selection 1: mnemonic NE "SCHEDULES"
Note: SCHEDULES is the mnemonic of the schedule that runs the report.
We skip it because it would always be running.
Selection 2: end.date EQ ""
Selection 3: end.date GE (@.today)
Selection 4: active EQ "Y"
Select Relationship: C2!C3
Footnotes: AL START start
AL D detail
AL CLOSE.UP email
;--- start macro
;--- this loops thru the scheduled jobs and stores
;--- the next run information in /INFO
""^DT,
DO{+:GZJI[DT]^DT ""^TM,
DO{+:GZJI[DT,TM]^TM ""^MNE,
DO{+:GZJI[DT,TM,MNE]^MNE @JOB.INFO}}}
JOB.INFO
;--- store next run date, time, current status in /INFO
IF{/INFO[MNE];
DT^/INFO[MNE]|0,
TM^/INFO[MNE]|1,
:GZJI[DT,TM,MNE,DT,TM]|0^/INFO[MNE]|2}
;--- detail macro
mnemonic^MN,
IF{/INFO[MN]|2="R" @RUNNING;
/INFO[MN]|0_.=. @MISSING}
RUNNING
;--- sometimes a report will crash but its status is improperly
reported as running
;--- if report is currently running give time and date it started to run
;--- if the start run time is over 1 hr from current time send messge
%Z.elapsed.time(/.DAT,@.now,/INFO[MN]|0,/INFO[MN]|1,"hh.hh")^LAPSE,
IF{LAPSE+0<1;
MN_" has been running since
"_%Z.date.out(/INFO[MN]|0)_" "_/INFO[MN]|1^/MSG[XX+1^XX],
"Please investigate."^/MSG[XX+1^XX]}
MISSING
mnemonic_" is missing from schedule."^/MSG[XX+1^XX],
"Please investigate and reschedule if necessary."^/MSG[XX+1^XX]
;--- email macro
;--- if message queue is empty send OK message
IF{/MSG[1]_.=. "All scheduled RPTs OK "_%Z.date.out(@.today)_"
"_@.now^/MSG[1]},
;--- replace "ISTJT" with user initials who should receive the email
Q(^/MSG,"ISTJT")^ARG,
%MIS.OA.MSG.auto("",ARG)X
This is basically the same as the previous example, but this time we'll make it a little more complicated. We'll use one report to email each department head a list of the dept's employees with birthdays in a selected month/day range. To make it easy let's assume the department head ids are stored in a group response dictionary called DEPTHEADS with the department as the element and the department head as the element name.We need to put all the intended output including headers and/or footers into /MSG. We need to do these things:
1. store a header in the first line of the message
2. load the employee info for each detail record in suceeding message lines
3. email the message to the dept head in the dept trailer region and store errors
4. delete the previous message lines to prepare for the next dept
5. repeat from step 2 until all depts are processed and emailed
6. email an error report for missing dept head information
Detail DPM: PP.PER
Detail Segment: pp.employee.file
Index DPM: PP.PER
Index File: pp.employee.dept.name.index
Sorts - leave as they appear - dept/sort.name/employee
Select 1: month.and.day.of.birth GE From Birthday
(MM/DD)
Select 2: month.and.day.of.birth LE Thru Birthday
(MM/DD)
Select 3: being.paid EG "Y"
Footnotes:
AL START "Missing Dept Heads Error Message"^/ERR[YY+1^YY]
AL HK1 load.header
AL D
@name:30TL_(@number:10TL)_(%Z.date.out(@date.of.birth))^/MSG[XX+1^XX]
AL TK1 email.and.cleanup
AL CLOSE.UP email.errors
;--- load.header macro
;--- Load header line into /MSG
"Employee Name":30TL_("Number":10TL)_"Birthdate"^/MSG[1^XX],
;--- Load a line of dashes to separate the header from the data
"-":49^/MSG[XX+1^XX],
;--- store the dept for use in the email macro
@dept^DPT
;--- email.and.cleanup macro
;--- get the recipient from the group response dictionary
\GGL["DEPTHEADS","E",DPT]|0^RCP,
;--- if no value exists store the dept in /ERR for error email
;--- otherwise send the email
IF{'RCP DPT^/ERR[YY+1^YY];
%MIS.OA.MSG.auto("",Q(^/MSG,RCP))X},
;--- clear out /MSG so the same structure can be used for the next dept
""^XX,
DO{+/MSG[XX]^XX ""^/MSG[XX]}
;--- email.errors macro
;--- the departments that did not have dept heads defined in the group
response
;--- dictionary have been stored in /ERR.
;--- We will email these to user ABCDEF who is responsible for the
dictionary upkeep
;--- First check to see if there were any errors and if so email them
;--- We put header information into the first line
;--- so the first error will be in line 2 so see if it exists
;--- this should fit as a footnote but where would I have put the
comments?
IF{/ERR[2]_.'=. %MIS.OA.MSG.auto("",Q(^/ERR,"ABCDEF"))X}
Don't see what you
need? Visit one of these other sites
or email me your request (tomt at thomast357.com).