I think it really depends on your coding preferences. There are benefits to writing using Objects (CLS) and benefits to writing in (MAC) and which you use may simply depend on what your coding preferences are.

Do you like to code using objects, then CLS is the way to go. Are you a procedural programmer, then (MAC) is the way to go.

Using CLS, you program using objects with properties and methods. You gain the benefit of being able to access your object data via three different mechanisms, direct global access, object access, or sql. You implement methods and typically your methods are logically organized into the classes that they pertain to. You gain inheritance, XML support, JSON support, and so much more.

All that said, if you come from a background of procedural programming and don't have a need or desire to work in objects, there's nothing wrong with using MAC routines.


First, admittedly I'm not sure the cause to your error as I do not have access to your generated SOAP client classes, your SSL Configuration, etc.

That said, I was able to implement the UPS API for the Tracking API and was able to execute without issue.  To get it to work you will need to do the following.

1.   Create a SSL client configuration (test it against the UPS server) to be used for SSL encryption.  it does not appear that UPS provides a non encrypted connection for testing.

2.   Obtain all of the wsdl files (including the additional xsd documentts that define the different types that UPS API supports. 

3.  Use the SOAP wizard to create a client.  I used the package UPS.   In the wizard, on the Step 3 page, select the option "Use unwrapped message format for document style web methods "  This is critical because the SOAP wizard will not create the correct client without it checked.

Once created, the following class method can be used to test your service.  I just added this to my SOAP client class UPS.TrackPort

ClassMethod Test(InquiryNumber As %String) As UPS.common.ResponseType
    ; Setup Web Service Client and Security
    s ws=##class(UPS.TrackPort).%New()
     s ws.SSLConfiguration="SSLClient"
     s sechdr=##class(UPS.upss.UPSSecurity).%New()
     s usertoken=##class(UPS.upss.UsernameToken).%New()
     s usertoken.Username="myusername"
     s usertoken.Password="mypassword"
     s sechdr.UsernameToken=usertoken
     s acctoken=##class(UPS.upss.ServiceAccessToken).%New()
     s acctoken.AccessLicenseNumber="myaccessLicenseNumber"
     s sechdr.ServiceAccessToken=acctoken
     do ws.HeadersOut.SetAt(sechdr,"UPSSecurity")
    ; Setup Request
    set trakRequest=##class(UPS.trk.TrackRequest).%New()
    set trakRequest.Request=##class(UPS.common.RequestType).%New()
    do trakRequest.Request.RequestOption.Insert(1)
    set transactionReference=##class(UPS.common.TransactionReferenceType).%New()
    set transactionReference.CustomerContext="My Ensemble Process "_$j
    set trakRequest.Request.TransactionReference=transactionReference
    set trakRequest.InquiryNumber=InquiryNumber
    quit ws.ProcessTrack(trakRequest)

Once this is done, you can test as follows

USER>s resp=##class(UPS.TrackPort).Test("1Z12345E0205271688")
USER>w resp
USER>zw resp
resp=<OBJECT REFERENCE>[20@UPS.trk.TrackResponse]
+----------------- general information ---------------
|      oref value: 20
|      class name: UPS.trk.TrackResponse
| reference count: 2
+----------------- attribute values ------------------
|           (none)
+----------------- swizzled references ---------------
|       i%Disclaimer = ""
|    i%Disclaimer(1) = "You are using UPS tracking service on customer integration test environment, please switch to UPS production environment once you finish the test. The URL is https://onlinetools.ups.com/webservices/Track"
|       r%Disclaimer = "49@%Collection.ListOfDT"  <Set>
|         i%Response = ""
|         r%Response = "21@UPS.common.ResponseType"
|         i%Shipment = ""
|      i%Shipment(1) = ""
|         r%Shipment = "48@%Collection.ListOfObj"
|      r%Shipment(1) = "24@UPS.trk.ShipmentType"

Hope this helps

Curious as to whether you are trying to implement their REST api or their XML (SOAP) api?

The mechanisms to interface with each are quite different.


Thanks Robert-

I dont think I have a choice here.  the All method of the %SYSTEM.OBJ.FM2Class expects the array to be passed by reference.  I did come up with a solution though....

/// Run FM2Class in background fo rnewly created namespace

ClassMethod ConfigFM2Class(Namespace As %String, LocalPath As %String) As %String
new $namespace set curnsp=$namespace,$namespace=Namespace
write !,"Starting FM2Class for Namespace ",Namespace," in background"
; Build Up Parameters
set params("childTableNameFormat")="SUB_<FILENAME>,<FILENUMBER>"
    set params("compile")=1
    set params("compileQSpec")="/display=all/lock=0"
    set params("dateType")="%Library.FilemanDate"
    set params("datetimeType")="%Library.FilemanTimeStamp"
    set params("deleteQSpec")="/display=all"
    set params("display")=0
    set params("expandPointers")=0
    set params("expandSetOfCodes")=0
    set params("extendedMapping")=""
    set params("fieldNameFormat")="Exact"
    set params("ienFieldName")="IEN"
    set params("logFile")=LocalPath_"fm2class_"_Namespace_".log"
    set params("nameLength")=180
    set params("owner")="_SYSTEM"
    set params("package")="VISTA"
    set params("readonly")=0
    set params("recursion")=2
    set params("requiredType")=0
    set params("retainClass")=1
    set params("setOfCodesEnum")=1
    set params("strictData")=0
    set params("superClasses")=""
    set params("tableNameFormat")="<FILENAME>,<FILENUMBER>"
    set params("variablePointerValueField")=0
    set params("wpIsList")=0
    kill ^UTILITY(Namespace,$j,"ISC.HealthConnect.Installer") merge ^UTILITY($j,"ISC.HealthConnect.Installer")=params
    set $namespace=curnsp
    job ##class(ISC.HealthConnect.Installer).jobfm(Namespace,$j)::5
set zSC=1
if '$t set zSC=0
quit zSC
ClassMethod jobfm(Namespace,job)
;Startup FM2Class
new $namespace set $namespace=Namespace
merge params=^UTILITY(job,"ISC.HealthConnect.Installer")
kill ^UTILITY(job,"ISC.HealthConnect.Installer")
do ##class(%SYSTEM.OBJ.FM2Class).All(.params)


Eduard, there are dozens.  params contains any number of values, not all required.

Thinking the easiest way may be to just save params to a subscripted global, job off a wrapper, passing the subscript.  Grab the array out of the global and then start the class method, killing the global.


Looking further, it would seem that we can not pass an array as an argument to a JOB command so I need to come up with a new way to get this array of parameters to the JOBed process.