How to set my custom class in a business process written manually, not BPL (contextsuperclass)

Primary tabs

I need to set and use some context variables in a transformation (written in DTL), but the code is manually written.

When writing the same as BPL I define context variables and they are visible in transformations called by that process.

In something like this my.DTLtransform sets HL7 message fields to values in context variables:

Set dtl = ##class(my.DTLtransform).%New()
Set qStatus = dtl.Transform(pRequest, .msg)
 

However, when I create a business process using custom code option, I don't see an obvious option, as well as documentation covering that area.

Replies

Hi Goran,

The context is created automatically by the BPL editor. The context is a subclass of Ens.BP.Context, in a very simplistic way, the context is a persistent class that is used as a VO, to move data between the different stages of BPL execution.

More about context:

https://cedocs.intersystems.com/latest/csp/docbook/Doc.View.cls?KEY=EBPL_use#EBPL_exec_context

https://cedocs.intersystems.com/latest/csp/docbook/Doc.View.cls?KEY=EBPL_editor#EBPL_editor_proptab_context

https://cedocs.intersystems.com/latest/csp/documatic/%25CSP.Documatic.cls?PAGE=CLASS&LIBRARY=ENSLIB&CLASSNAME=Ens.BP.Context

Thanks Cristiano,

I know that, but I need that not from BPL but from some custom code as mentioned.

BP class object is your context.

Just add a property to hold your data.

#1)
- create a simple Business Process using the wizard
- compile it and see the resulting class and at least 4 related .int routines.
- then decide if you really want to do this all manually
the challenge is to properly use and service the methods you see in Ens.BusinessProcess

To make it easier you may install (or activate) the ENSDEMO namespace as an example (before IRIS. have no idea where it is gone)

#2)

you write.    ---transformation (written in DTL), but the code is manually written. ---

It might sufficient to put your code just into a CODE Block of a BP generated with the wizard.

Just found an example:

Class Demo.Loan.BankUS Extends Ens.BusinessProcess [ ClassType = persistent, ProcedureBlock ]
{ /// 2 modes: Queue, InProc
Parameter INVOCATION = "Queue"; Property CreditRating As %Integer; Property PrimeRate As %Numeric; Method OnRequest(
    request As Demo.Loan.Msg.Application,
    Output response As Demo.Loan.Msg.Approval) As %Status
{
    Set $ZT="Trap",tSC=$$$OK
    Do {
        $$$TRACE("received application for "_request.Name)
        #;
        If $zcrc(request.Name,2)#5=0 {
            Set response = ##class(Demo.Loan.Msg.Approval).%New()
            Set response.BankName = "BankUS"
            Set response.IsApproved = 0
            $$$TRACE("application is denied because of bank holiday")
            Quit
        }
        #;
        Set tRequest = ##class(Demo.Loan.Msg.PrimeRateRequest).%New()
        Set tSC = ..SendRequestAsync("Demo.Loan.WebOperations",tRequest,1,"PrimeRate")
        #;
        Set tRequest = ##class(Demo.Loan.Msg.CreditRatingRequest).%New()
        Set tRequest.TaxID = request.TaxID
        Set tSC = ..SendRequestAsync("Demo.Loan.WebOperations",tRequest,1,"CreditRating")
        #;
        Set tSC = ..SetTimer("PT15S")
        #;
        Quit
    While (0)
Exit
    Quit tSC
Trap
    Set $ZT="",tSC=$$$EnsSystemError Goto Exit
} /// Handle a 'Response'
Method OnResponse(
    request As Ens.Request,
    ByRef response As Ens.Response,
    callrequest As Ens.Request,
    callresponse As Ens.Response,
    pCompletionKey As %String) As %Status
{
    Set $ZT="Trap",tSC=$$$OK
    Do {
        If pCompletionKey="PrimeRate" {
            Set ..PrimeRate = callresponse.PrimeRate
        Elseif pCompletionKey="CreditRating" {
            Set ..CreditRating = callresponse.CreditRating
        }
        Quit
    While (0)
Exit
    Quit tSC
Trap
    Set $ZT="",tSC=$$$EnsSystemError Goto Exit
} Method OnComplete(
    request As Ens.Request,
    ByRef response As Ens.Response) As %Status
{
    Set $ZT="Trap",tSC=$$$OK
    Do {
        Set response = ##class(Demo.Loan.Msg.Approval).%New()
        Set response.BankName = "BankUS"
        Set tIsUsCitizen=($zcvt($tr(request.Nationality,"."),"u")="USA")||($zcvt($tr(request.Nationality,"."),"u")="US")
        If ('tIsUsCitizen)||(..CreditRating<50) {
            Set response.IsApproved = 0
            $$$TRACE("application is denied")
        Else {
            Set response.IsApproved = 1
            Set response.InterestRate = ..PrimeRate+2+(5*(1-(..CreditRating/100)))
            $$$TRACE("application is approved for "_response.InterestRate_"%")
        }
        Quit
    While (0)
Exit
    Quit tSC
Trap
    Set $ZT="",tSC=$$$EnsSystemError Goto Exit
}
Storage Default
{
 <Data name="BankUSDefaultData">
   <Subscript>"BankUS"</Subscript>
   <Value name="1">
      <Value>CreditRating</Value>
   </Value>
   <Value name="2">
      <Value>PrimeRate</Value>
   </Value>
 </Data>
 <DefaultData>BankUSDefaultData</DefaultData>
 <Type>%Library.CacheStorage</Type>
} }

 

It might sufficient to put your code just into a CODE Block of a BP generated with the wizard.

If you need to execute raw ObjectScript from BPL add assign activity and set status variable to the value of your classmethod. No need to add a code block.

Still, BP without BPL are quite easy to implement, here's the guide.

Hi

Bear in mind that when you are working with DTL's when you invoke the Transform() method there is a third parameter called aux. The aux object can be an instance of any class you design and can contain any properties you desire. These are typically values that you want to use in the DTL that are not part of your request object.

When you call the DTL you create a new instance of your aux class and then when you invoke the DTL Transform you can write the following code:

set tSC=##class({Your DTL}).Transform(request,.response, .aux) where aux is an instance of your custom aux class.

This is true also of DTL's called from a BPL with one exception. If the DTL is invoked from a Business Rule then the Business rule creates an instance of a system defined aux object that contains information about which rule invoked the DTL and so on. 

I am busy trying to convert a Custom Code Business Process that will invoke a DTL and am still trying to get my head around what variables/objects are available in the BPL (Context) and the DTL.

If you resolve how to create a BPL using the context object and then invoke a DTL into which you can pass data other than the request and response message I would be interested to know how if you have success and how you managed to get it to work.

Yours

Nigel

Thank you very much, Nigel.

I know for aux... but it turned out that I was making mistake when trying to implement this, however simple that is.

Hi Goran

I am going to attach a set of classes from a real life application. I am going to put the class definitions into a word document. I would send you the XML but if you import the XML the classes won'r compile as there are too many claseses referenced in my code that I can't include.

The Basic overview of this production is that I have a Business Service that is processing a queue of messages that are created when data is trickle fed into a Data Warehouse. In my Business Process my request object contains a single property that is the MessageID of the message processed by the Business Service. 

In the Business service I open up the Message and from that I extract properties such as the Patient ID, three key fields LogType (where the data came from: PMI, In-Patient, Out-Patient...), a TransactionType that tells me more about what table in the Data Store is being Updated and an Action which is Add/Revise/Delete.

The Business Process  opens a configuration record from which it gets certain fields that give this Production Context.  I then find the correct Patient Object and I use a DTL to assign fileds in my Patient Class and other linked classes and populate a Standard HL7 ADT Message. The configuration settings include fields like Sending Facility, Sending Application, Receiving Application, Receiving Facility. These need to be sent into the DTL to populate these fields in the HL7 MSH header record. So I have created a custom AUX class which I can populate these fields within the DTL.

I then do another check to see if the data I am processing belongs to In-Patients or Out-Patients in which case I want to populate the Facility Code in the Visit Segment with the Facility code which I have transformed from an Application specific value into a National Facility Code.

Finally, if the data being processed is a Patient Merge then the ADT message structure has a different structure so I invoke another DTL to convert the ADT_A01 message into an ADT_A39 structure.

Finally I send the resultant message to an HTTP Operation and optionally to a File Operation.

I also have a build in Debugging class where I can write selected Debug information. In Development and UAT I want debugging turned on but in Production I don't so I have a property in the configuration that is a boolean flag that determines whether the debug message should be created or not.

Finally the configuration record also tells me how long I want to retain Debug Messages, Message Queue Messages, Ensemble Messages and Ensemble  Trace Logs and I have a business service that runs once a day and clears down any data that is older than the number of days I want to retain this data.

I have included the class definitions for all of the major classes I have described above.

Yours

Nigel 

Here is the attachment . I can't see if the attatchement has been uploaded. If not please send me an email address I can send the file to you.

Nigel