go to post Jeffrey Drumm · 17 hr ago Is the routing rule attempting to filter/route based on content embedded in the RTF? And how large is the message?
go to post Jeffrey Drumm · 23 hr ago Do you see any difference when removing action #1 and setting this property for the DTL instead?
go to post Jeffrey Drumm · Mar 27 Glad you got it working. I feel I should mention that I specifically told you to just that 2 days ago ... quoted here: There are a few issues with this code, but the biggest one is that you've created a clone and should be modifying the clone (pOutput) exclusively. However, you're still calling SetValueAt() against a segment pulled from pRequest. The above notwithstanding, you're still sending the original unchanged message object (pRequest) to the target operation with the SendRequestAsync() call. Fundamentally, you should: Create a clone of the request object pRequest (i.e. pOutput) Modify the clone, which is a mutable copy of the original message Send the modified clone (pOutput) to the target operation
go to post Jeffrey Drumm · Mar 26 You're cloning the source message inside the While loop that is iterating over segments within the message. That's not doing anything useful. Clone the message, then iterate over its OBX segments, making whatever changes are necessary. Before sending it with SendRequestAsync(), do a pOutput.%Save().This snippet below is completely untested and there are other enhancements I would make to it, but I'm not going to be available for a while, so here's something to play with. It's a cleaned up version of the code snippet you provided above. Note that there is not a single call to GetSegmentAt() ... it's an unnecessary extra step. // Message Subtype Set tMessageSubType = pRequest.GetValueAt("ORCgrp(1).ORC:1") // // Check if OBR:19 contains "Implant Usage (PSAS)" OR "Issued in Clinic (PSAS)" Set tOrderType = pRequest.GetValueAt("ORCgrp(1).OBRuniongrp.OBRunion.OBR:19(1).1") If ((tOrderType["Implant Usage (PSAS)") || (tOrderType["Issued in Clinic (PSAS)")) { // First loop: Count occurrences of "Item Number:" Set i = 1 Set tItemNumberCount = 0 While (pRequest.GetValueAt("ORCgrp(1).OBRuniongrp.OBXgrp("_i_").OBX")'="") { Set tOBXText = pRequest.GetValueAt("ORCgrp(1).OBRuniongrp.OBXgrp("_i_").OBX.5", .tStatus) // If (tOBXText [ "Item Number:") { Set tItemNumberCount = tItemNumberCount + 1 } // If (tOBXText[ "Total Cost:") { Set tTotalCostSegment = i //$$$LOGINFO(tTotalCostSegment_" ------ "tTotalCostSegment check Total Cost") } Set i = i + 1 } // Second loop: Modify OBX segments if necessary Set i = 1 Set tItemNumberProcessed = 0 Set pOutput = pRequest.%ConstructClone(1) // moved here because %ConstructClone() need only be done at the message object level. While (pOutput.GetValueAt("ORCgrp(1).OBRuniongrp.OBXgrp("_i_").OBX")'="") { Set tOBXText = pOutput.GetValueAt("ORCgrp(1).OBRuniongrp.OBXgrp("_i_").OBX.5", .tStatus) // using pOutput instead of pRequest If (tOBXText [ "Item Number:") { Set tItemNumberProcessed = tItemNumberProcessed + 1 } If (tItemNumberCount > 1) && (tOBXText [ "REASON FOR REQUEST:") { set tOBXKey = i Set tOBXText=$p(tOBXText,":",2,5) /// OBX 5 text parsed to replace in OBX 5 later // Start replacement process Do pOutput.SetValueAt(tOBXText,"ORCgrp(1).OBRuniongrp.OBXgrp("_i_").OBX.5") $$$LOGINFO(tOBXText_" ---- OBX 5 parsed to be saved in new OBX 5") /// works Set tOBXTextChanged = pOutput.GetValueAt("ORCgrp(1).OBRuniongrp.OBXgrp("_i_").OBX.5") $$$LOGINFO(i_tOBXTextChanged_" --- i --- tOBXTextChanged, Is OBX 5 changed???") } Set i = i + 1 } } Do pOutput.%Save()
go to post Jeffrey Drumm · Mar 26 %ConstructClone() need only be done at the message object level. And I'm not sure why you're extracting segments to update them; you can use SetValueAt() against the message object instead a segment object ... For example this code: Set tOBXSegmentpOutput = pOutput.GetSegmentAt("ORCgrp(1).OBRuniongrp.OBXgrp("_i_").OBX", .tStatus) Do tOBXSegmentpOutput.SetValueAt(tOBXText, 5) Is functionally identical to: Do pOutput.SetValueAt(tOBXText,"ORCgrp(1).OBRuniongrp.OBXgrp("_i_").OBX.5") That should help simplify the code. You shouldn't need to do a "deep clone" for this, so the "1" argument to %ConstructClone() is optional.
go to post Jeffrey Drumm · Mar 25 Somewhere between the %ContstructClone() call and the SetValueAt() call, you'll be using the GetSegmentAt() method of the clone to get the segment object into tOBXSegmentpOutput. The syntax of the SetValueAt() call should have the string to store as the first argument rather than the pOutput message object. tOBXSegmentpOutput is a reference to the segment in the clone message. It should not need to be explicitly saved, and I'm pretty sure SaveData() doesn't do what you think it does anyway.
go to post Jeffrey Drumm · Mar 25 There are a few issues with this code, but the biggest one is that you've created a clone and should be modifying the clone (pOutput) exclusively. However, you're still calling SetValueAt() against a segment pulled from pRequest. The above notwithstanding, you're still sending the original unchanged message object (pRequest) to the target operation with the SendRequestAsync() call. Fundamentally, you should: Create a clone of the request object pRequest (i.e. pOutput) Modify the clone, which is a mutable copy of the original message Send the modified clone (pOutput) to the target operation
go to post Jeffrey Drumm · Mar 25 The code sample you've provided above is pulling the OBX segment from pRequest, not the clone. pRequest is immutable so you can't make changes to it. You should be using the pOutput object for your SetValueAt() calls, and since it's a clone you can use it for the GetValueAt() calls as well. I provided pretty much everything you need to do this via a DTL in your other post on this subject. If you're worried about keeping things simple for ongoing support, the DTL solution is likely the better option.
go to post Jeffrey Drumm · Mar 21 A couple of thoughts ... In my experience, the pool of resources that can build complex integrations using the Health Connect GUI is an order of magnitude larger than those that can do the same in pure ObjectScript. The rarer the resource, the more it costs. I've also found that some of those that have used ObjectScript as a method to enhance/alter the behavior of production components have implemented "private" methods or relied on undocumented behavior that has the potential to change or become deprecated, requiring extensive testing and possibly re-coding when upgrading.
go to post Jeffrey Drumm · Mar 20 You can do this by creating a collection object in a code block, and iterate over the comma-separated string to populate it: Set tArray = ##class(%ArrayOfDataTypes).%New() For i = 1:1:$LENGTH(LookupVal,",") { Do tArray.SetAt($PIECE(LookupVal,",",i),i) } You can now iterate over the collection variable in the for each action:
go to post Jeffrey Drumm · Mar 17 Seems like the operation isn't working as it should; you may want to take this up with the WRC.
go to post Jeffrey Drumm · Mar 17 Looks like HealthConnect/IRIS for Health doesn't supply ISO-8859-4 ("Northern European"), or its successor ISO-8859-10. You can try forcing other character sets by preceding them with an exclamation point in the operation's Default Char Encoding property, but there may be characters that translate incorrectly:
go to post Jeffrey Drumm · Mar 15 Here's how I would approach this using a DTL ... Create a counter variable to hold the number of occurrences of "Item Number:" Use a for each action to iterate over the OBX segments In the for each, create an if action that checks for the presence of "Item Number:" in OBX:5 (using ..Contains()) If the action is true, increment the counter variable Example: On completion of the for each, you should have a value that indicates the presence of more than one "Item Number." Next, update the OBXs: Create another counter variable to track occurrences of "Item Number" to be used for comparison Add another for each action to perform the modifications to the OBX segments Use the $REPLACE() or ..Replace() functions to replace "REASON FOR REQUEST:" in each OBX:5 with an empty string Add an if action to check the OBX:5 field for "Item Number:"; increment the new counter variable if found Add an if action to evaluate the new counter variable against the original; if it's less than the original, add a line break (not actual $C(13)/$C(10) characters, but escaped representation such as \.br\ or \X0D\\X0A\; likely vendor-dependent) Example:
go to post Jeffrey Drumm · Mar 13 While you can create multiple productions in a single namespace, you can only run one at a time. There's really no good reason to have more than one production in a namespace ... and with each production in its own namespace, they can be running concurrently.
go to post Jeffrey Drumm · Mar 11 Do you get a different result with this? SELECT COUNT(*) FROM Ens.MessageHeader WHERE ID >= (SELECT TOP 1 ID FROM Ens.MessageHeader WHERE TimeCreated >='2025-02-01 00:00:00.000' ORDER BY TimeCreated ASC) AND ID <= (SELECT TOP 1 ID FROM Ens.MessageHeader WHERE TimeCreated <='2025-02-28 23:59:59.999' ORDER BY TimeCreated DESC) AND ID = SessionId
go to post Jeffrey Drumm · Mar 11 That's odd. I obtained the same results from both queries on my system; the only difference was the speed of execution. The subquery model from my example is the same one used behind the scenes by InterSystems to select messages by date range in the message viewer. I can't imagine why you'd be getting different results.
go to post Jeffrey Drumm · Mar 8 I'm not seeing an example of your desired result(s) ... can you share that as well?
go to post Jeffrey Drumm · Mar 7 Likely significantly faster: SELECT COUNT(DISTINCT SessionId) FROM Ens.MessageHeader WHERE ID >= (SELECT TOP 1 ID FROM Ens.MessageHeader WHERE TimeCreated >='2025-02-01 00:00:00.000' ORDER BY TimeCreated ASC) AND ID <= (SELECT TOP 1 ID FROM Ens.MessageHeader WHERE TimeCreated <='2025-02-28 23:59:59.999' ORDER BY TimeCreated DESC) In my crude and hasty benchmarking, twice as fast on a sampling of 2.7M message headers.
go to post Jeffrey Drumm · Mar 7 Inserting characters that are defined as HL7 delimiters to fields is likely to be problematic. It would be very helpful if you would provide an example of the source message and the desired result.
go to post Jeffrey Drumm · Mar 4 You can suspend the task via either ObjectScript or SQL. Assuming you know the Task ID, and using 1001 as an example: Set tsk = ##class(%SYS.Task).%OpenId(1001) Set tsk.Suspended = 1 Do tsk.%Save() or Do ##class(%SYS.Task).Suspend(1001,1) Resume the task with Do ##class(%SYS.Task).Resume(1001) Via SQL: UPDATE %SYS.Task SET Suspended = 1 WHERE ID = 1001 or UPDATE %SYS.Task SET Suspended = 1 WHERE TaskClass = 'Sample.Util.CreateTask' Set Suspended to 0 to re-enable the task.