Skip to main content


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:


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

how to map an attachment file in the inbound transform map

onAfter script:

//--Attachments handling:
(function runTransformScript(source, map, log, target /*undefined onStart*/ ) {
    //gs.log('--test attach');
    if (source.u_attachments.nil()){
        return; // noop
        //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);


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:

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)){
    if (source.sys_import_state == 'ignored'){
        //--allow the vendor ref number to update, if missing before
        gs.log(logPrefix, '--onafter skipped', logPrefix);
        //--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:-

                                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

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


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';
        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



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 ); }