Skip to main content

Perspectium

Pulling together the Perspectium posts in a single place...




how to access the current operation in a table map> field map script


gs.log(current.number + ': OP=' + current.operation(),'getWNList');


how to map either the last worknotes or the full history, depending on whether insert or update

/in the outbound table map, field mapping:



answer=getWNList();

function getWNList(){
    var sReturn=current.work_notes.getJournalEntry(1);
    gs.log(current.number + ': OP=' + ,'getWNList');
    if (current.operation()=='insert'){
        sReturn=current.work_notes.getJournalEntry(-1);
    }
    return sReturn;
}


how to map an attachment file in the inbound transform map


onAfter script:

INCIDENT EXAMPLE:
//--Attachments handling:
(function runTransformScript(source, map, log, target /*undefined onStart*/ ) {
    //gs.log('--test attach');
   
    if (source.u_attachments.nil()){
        return; // noop
    }else{
        //gs.log('--test attach 2');
        var pspAtt = new PerspectiumAttachment();
       
        var xmldoc = new XMLDocument(source.u_attachments);
        var nodelist = xmldoc.getNodes("//attachment");
        if (nodelist == null){
            return; // noop
        }
        for (var ii=0; ii < nodelist.getLength(); ii++) {
            var nodeItem = nodelist.item(ii);
            pspAtt.addAttachment(nodeItem, "incident", target.sys_id, "msp_client_incident_sent");
        }
    }
})(source, map, log, target);
-------------------------------------------

PROBLEM EXAMPLE:

pspAtt.addAttachment(nodeItem, "problem", target.sys_id, "msp_client_problem_sent");

how to map attachments in an outbound table map field mapping




//--this goes in source field:
//--${TM:psp_attachment;table_sys_id=$[GR:sys_id];msp_client_incident_sent;skip_insert}

how to return the target ticket number when the source system inserts a ticket


transform map: onAfter script


//--return the MAB number to TSFNow
(function runTransformScript(source, map, log, target /*undefined onStart*/ ) {
   
    var logSource=':TMAP:AFTER-SRIPT:INC';
    var logPrefix=' [ number: ' + source.u_number + ';  number' + source.u_correlation_display + '] ';
   
    if (action=='update' && target.u_vendor=='91c6f451371e420041c5616043990eee'){
        if (target.state==6 && target.u_vendor_reference_number==''){ //--Fujitsu
            //--update the vendor ref number
            //-- ......
            var grInc=new GlideRecord('incident');
            if (grInc.get('number', source.u_number)){
                grInc.u_vendor_reference_number=source.u_correlation_display;
                grInc.update();
            }
        }
    }
   
    if (source.sys_import_state == 'ignored'){
        //--allow the vendor ref number to update, if missing before
       
        gs.log(logPrefix, '--onafter skipped', logPrefix);
        return;
       
    }else{
        //--carry on:
        if (action=='insert' || gs.nil(source.u_correlation_display)){
            var pspR = new PerspectiumReplicator();pspR.shareRecord(current, 'incident', '', '36709489372a93008ca1138943990efb');
        }
    }
})(source, map, log, target);


outbound table maps> field maps> field types

When the outbound table map will result in an XML, may as well define all field types (even if the source/target field is Boolean for example) as String

prevent circular updates



 “interactive=true” is an option, but bear in mind this will prevent any non interactive updates from sending across the system (also any update from other integrations).

Instead,  use below piece of code in your onbefore transform script to prevent bounce back issues:-

if(action=='update'){                     
                                target.psp_subscribed_record = true;
}

workflows not triggering dynamic shares


Managed to get round this by introducing a timer + worknotes update in the workflow
in this example in the RITM workflow, the sc_task is supposed to trigger the dynamic share


work notes duplicates niggle


Scenario:
a duplicate worknote ends up getting written whereby an extra update transaction from Perspectium containing the following in the xml is sent


    <work_notes>_123STREAMENTRY321_original worknotes entered</work_notes>


Not too sure how this has come about but the steps to create it were reproducible


  1. Create problem ticket in ServiceNow instance 1 and send to ServiceNow instance 2
  2. Wait until number returned to ServiceNow instance 1 from ServiceNow instance 2
  3. Go into ServiceNow instance 2
  4. Enter a comment, cick ‘post’, then immediately change the state to <some value>, click save

fix:

include some error trapping in a try>catch within the inbound transform map to ultimately set the row to ignore=true


var iWN_err=source.u_work_notes.toUpperCase().indexOf('STREAMENTRY');
if (iWN_err>-1){
                        //--known error whereby the worknote has arrived as a duplicate jumbled string from TSFN
        sErrMsg='STREAMENTRY located in worknote string from TFSNow';
        sSessionErr=sErrMsg;
        throw (sErrMsg);
}

script an ignore condition in a dynamic shareenter the additional filter in the 'before share script' section of the outbound dynamic share:




determine if create or update in before share script


use
 current.operation()


Comments

Popular posts from this blog

ServiceNow check for null or nil or empty (or not)

Haven't tested these all recently within global/local scopes, so feel free to have a play! option 1 use an encoded query embedded in the GlideRecord , e.g.  var grProf = new GlideRecord ( 'x_cls_clear_skye_i_profile' ); grProf . addQuery ( 'status=1^ owner=NULL ' ); grProf . query (); even better use the glideRecord  addNotNullQuery or addNullQuery option 2 JSUtil.nil / notNil (this might be the most powerful. See this link ) example: if ( current . operation () == 'insert' && JSUtil . notNil ( current . parent ) && ! current . work_effort . nil ())  option 3 there might be times when you need to get inside the GlideRecord and perform the check there, for example if the code goes down 2 optional routes depending on null / not null can use gs.nil : var grAppr = new GlideRecord ( 'sysapproval_approver' ); var grUser = new GlideRecord ( 'sys_user' ); if ( grUser . get ( 'sys_id' , current . approver )){...

Get URL Parameter - server side script (portal or classic UI)

Classic UI : var sURL_editparam = gs . action . getGlideURI (). getMap (). get ( ' sysparm_aparameter ' ); if ( sURL_editparam == 'true' ) { gs . addInfoMessage ( 'parameter passed ); } Portal : var sURL_editparam = $sp . getParameter ( " sysparm_aparameter " ); if ( sURL_editparam == 'true' ) { gs . addInfoMessage ( 'parameter passed ); }

Code a pause/wait - gs.sleep or gs.wait alternative, pause script for specified seconds (timer)

Code a pause/wait - gs.sleep / gs.wait alternative, pause script for specified seconds (timer)  e.g. 10 seconds: do_sleep ( 10000 ); function do_sleep ( milliseconds ) { var start = new Date (). getTime (); for ( var i = 0 ; i < 1e7 ; i ++) { if (( new Date (). getTime () - start ) > milliseconds ){ gs . print ( 'waking up!' ); break ; } } }