Error message

Deprecated function: The each() function is deprecated. This message will be suppressed on further calls in menu_set_active_trail() (line 2396 of /home/cxdevelo/public_html/includes/menu.inc).

CPMs 101: Introduction to Custom Process Models

CPMs provide the ability to trigger custom code whenever select objects in the system are either created, updated, or destroyed. This is extremely useful for myriad types of functionality such as external integrations and advanced business logic. This tutorial is a primer for those just getting started and will walk through how to build a simple CPM from the ground up. More advanced CPM articles are also available. Enjoy!

Source for this tutorial is available on Bitbucket under / CPMs / Intro to CPMs / and for download.

Step 1: Write Your CPM Logic

Using your favorite IDE, create a new PHP file called MinimalContactHandler.php. In this tutorial, we will be building a very simple CPM that sets a contact's first name to a static string, whenever one is updated or created. A very specific format must be adhered to, in order for the CPM framework to run the code successfully. We'll walk through it section by section:

CPM Header

The CPM header tells the framework how to use the code therein, is a required comment block: <?php /** * CPMObjectEventHandler: MinimalContactHandler * Package: RN * Objects: Contact * Actions: Create, Update * Version: 1.2 * Purpose: Minimal CPM handler for contact create and update. */ The first line must specify the name of the file without the extension. The next two lines list the package and objects for which this CPM will be available (a single CPM can be used for multiple objects, if needed). The Actions line is a list of possible actions and must be a comma-separated list of a combination of "Create", "Update", or "Destroy" options. The Version line is not the version of your code, but specifies the Connect for PHP version. Finally the last line is a simple textual description of what your CPM will accomplish.

Use Statements

use \RightNow\Connect\v1_2 as RNCPHP; use \RightNow\CPM\v1 as RNCPM; These define the rather standard namespace for the Connect for PHP version as well as the required CPM namespace. Something to note here, even though we have not explicitly specified a namespace, the CPM framework automatically wraps our code in one, in this case RightNow\CPMObjectEventHandlers\MinimalContactHandler.

Handler Class and Apply Method

The handler class should be named the same as your file. The apply method does all the real CPM work: /** * Handler class for CPM */ class MinimalContactHandler implements RNCPM\ObjectEventHandler { /** * Apply CPM logic to object. * @param int $runMode * @param int $action * @param object $contact * @param int $cycle */ public static function apply($runMode, $action, $contact, $cycle) { if ($cycle !== 0) return; if (RNCPM\ActionUpdate == $action) { $contact->Name->First = "CPM Update Test"; $contact->save(); } elseif (RNCPM\ActionCreate == $action) { $contact->Name->First = "CPM Create Test"; $contact->save(); } } }

Let's first take a look at the apply method's parameters in detail:

ParameterDescriptionPossible Values
$runMode Whether the code is being run in test or production mode. I rarely use this parameter, even during debugging.
  • RNCPM\RunModeLive
  • RNCPM\RunModeTestObject
  • RNCPM\RunModeTestHarness
$action The action that is being performed on the object. This allows different logic to be accomplished depending on whether the object is being created, updated, or destroyed.
  • RNCPM\ActionCreate
  • RNCPM\ActionUpdate
  • RNCPM\ActionDestroy
$contact The instance of the object being processed. In this case, we are performing logic on a contact object. I typically modify the name of this parameter to fit the object type, unless the CPM will be operating on multiple object types, in which case I simply use $object. Any Connect for PHP object that is available to CPMs
$cycle The recursive depth of this event. When an object is modified within a CPM and saved, it may then trigger the same or another CPM to run recursively. This counter can be used to halt or run logic based on the cycle number. I typically restrict my CPMs to a depth of zero, unless I have reason to do otherwise. Integer >= 0

The content of the apply method first restricts the CPM to run only on the first recursive cycle. If the contact has been updated, its first name is set to "CPM Update Test"; if the contact was newly created, its first name is set to "CPM Create Test".

Great! Now you're done and ready to test, right? Wait, sorry! Just a little more patience is required. The CPM framework requires a minimal unit testing framework be implemented, or your logic will not run.

Step 2: Implement Your Test Harness

The framework requires this test harness be implemented. I do find it useful for some simple sanity checks, although you absolutely should still do your due diligence with smoke and integration testing in a live environment, of course!

Test Harness Class and Methods

/** * CPM test harness */ class MinimalContactHandler_TestHarness implements RNCPM\ObjectEventHandler_TestHarness { static $contactOneId = null, $contactTwoId = null; } The name of the class must exactly match your handler class and file name, but have "_TestHarness" appended to the end for the framework to accept it. We are going to be running tests on contact objects that have been processed by our handler logic, so I've added two static properties to store the ID of these objects for the test harness to access.

Setup Method

/** * Set up test cases. */ public static function setup() { // First test $contactOne = new RNCPHP\Contact; $contactOne->Name->First = "First"; $contactOne->save(); self::$contactOneId = $contactOne->ID; // Second test $contactTwo = new RNCPHP\Contact; $contactTwo->Name->First = "Second"; $contactTwo->save(); self::$contactTwoId = $contactTwo->ID; } The setup method runs once, creates all test objects, and configures objects prior to the CPM logic being applied. Here we're creating two contacts with differing first names, and storing their IDs in the static fields we've created for this purpose.

Fetch Object Method

/** * Return the object that we want to test with. You could also return * an array of objects to test more than one variation of an object. * @param int $action * @param class $object_type * @return object | array */ public static function fetchObject($action, $object_type) { $contactOne = $object_type::fetch(self::$contactOneId); $contactTwo = $object_type::fetch(self::$contactTwoId); return array($contactOne, $contactTwo); } This method runs once for every possible combination of object action and object type, which is valid for this CPM. It may return a single object, or an array of objects which will first have the CPM logic applied, and then validated. In this case we're simply fetching the contacts we created in the setup method.

Validate Method

/** * Validate test cases * @param int $action * @param object $contact * @return bool */ public static function validate($action, $contact) { if (RNCPM\ActionUpdate == $action) { if (assert($contact->Name->First == "CPM Update Test")) { echo "Update test passed\n"; return true; } else { echo "Update test FAILED\n"; } } elseif (RNCPM\ActionCreate == $action) { if (assert($contact->Name->First == "CPM Create Test")) { echo "Create test passed\n"; return true; } else { echo "Create test FAILED\n"; } } else { echo "Invalid action"; } return false; } This method runs after the CPM logic has been applied to the object. This is where you will inspect the modified object and validate your testing assertions. A false return value will generate a framework error. Here we're just checking to see if our first name change was applied, depending on the action taken. The echo statements will be displayed in a dialog box in the Process Designer during testing.

Cleanup Method

/** * Destroy every object created by this test. Not necessary since in * test mode and nothing is committed, but good practice if only to * document the side effects of this test. */ public static function cleanup() { if (self::$contactOneId) { $contactOne = RNCPHP\Contact::fetch(self::$contactOneId); $contactOne->destroy(); self::$contactOneId = null; } if (self::$contactTwoId) { $contactTwo = RNCPHP\Contact::fetch(self::$contactTwoId); $contactTwo->destroy(); self::$contactTwoId = null; } } Logic in this method is not necessarily needed, as during testing no objects are committed (unless done so explicitly, which you should not be doing). Typically this is used to document which objects were under inspection during the tests.

Step 3: Upload and Test Your CPM

Now that you've written your code, it needs to be placed on the server through the Process Designer. Your profile must have permission to access this in the console. If your navigation set does not contain the component, it is located under Components -> Common -> Process Designer. I usually add it to the Site Configuration group: Process designer navigation component

Create a New CPM Handler

  1. Open the Process Designer.
  2. Click New in the ribbon bar at the top.
  3. Click the file icon next to the PHP Code File entry and upload your CPM file. For this tutorial, upload the MinimalContactHandler.php file you created.
New CPM

Save and Test

  1. Click Save in the ribbon bar.
  2. Click the large Test button in the main panel. If your tests executed successfully, you should see the output statements of your validation method displayed in a popup dialog:
    CPM testing
    If you see any errors, you will need to fix your code locally, re-upload it to your CPM, save, and re-test.
  3. Click OK
  4. Click Yes to manually confirm your tests executed correctly:
    CPM test confirmation
  5. Finally, hit Save again in the ribbon bar.

Step 4: Assign Your CPM to Object Actions

Now that you've uploaded and tested your CPM, the final step is to assign it to the contact object for update and create:

  1. Drill into the RN package under the Process Model by Object in the left pane and select Contact:
    Select object for CPM
  2. Because our CPM was built to trigger on contact create and update, select the MinimalContactHandler CPM from the dropdowns under both Create and Update headings.
  3. Click Save in the ribbon bar.

Step 5: Deploy and Enjoy!

Finally, you need to deploy your changes:

  1. Click Deploy in the ribbon bar.
  2. Enter your email, if needed, and click the Deploy button in the dialog:
    Deploy CPM
  3. Click Yes to confirm deployment and wait a few moments:
    Deploy CPM status
  4. Click OK to confirm a refresh of the Process Designer.
  5. Finally, test your logic in production mode!

What's Next?

To make subsequent changes or bugfixes to your logic, the CPM code will need to be re-uploaded, tested, and deployed. Once you have completed this process a few times, you will notice that it is clunky and time-consuming. If only there were a better way to deploy changes in a developer-friendly manner... Read on to my Custom Process Management post regarding best-practices when using a Customer Portal library to manage and deploy CPM logic!

Comments

First, thanks for a great tutorial. It gave me a much better understanding of the construction of the CPMs. That said, I'm having a very hard time getting my first cpm to run as I would wish. It seems to fire off randomly rather than with every update. Here is my sig line:


/**
* CPMObjectEventHandler: LeadCreate
* Package: RN
* Objects: Incident
* Actions: Update
* Version: 1.2
* Purpose: Allows for the creation of a lead based on field values in Incident Create/Update
*/

So as you can see, it SHOULD fire every time I update an incident, but the reality is that most of the time it doesn't fire at all.

In order to be sure that I am not failing out early, my first call in the apply function is to write a new subject line to the incident to sanity test that I'm even entering the function on update:


class LeadCreate implements RNCPM\ObjectEventHandler
{
/**
* Apply CPM logic to object.

public static function apply($runMode, $action, $incident, $cycle)
{
if ($cycle !== 0) return;
$incident->Subject = 'Action type is: '.$action;
$incident->save();

What I am experiencing is that this subject change rarely seems to happen. I can create an incident, save it, and then open it and change the status or add a note, and most times, the event doesn't fire. While it does sometimes fire, I can't seem to find any common theme of when it does. I guess my baseline question is if update means to RNT what it means to me (any change to an object followed by a save) or is update more specific?

I have deployed the CPM, and it is attached to the update behavior of Incidents. I'm running out of ideas for why this isn't firing, so any help would be very nice. In the meanwhile, I may explore your other post about firing them off of business rules to see if that helps.

A little more detail. It seems that what we are seeing is that updates via business rules don't actually get read as actual updates. If I update it manually now, it always fires the business process, but the rules updating the incident never do.

Thanks for posting, ShilohM. As far as I know, whenever any fields on the main incident object are changed, an update should be fired. Which version of RightNow are you using? I have had problems with intermittent firing on versions earlier than 13.2, before CPMs had been vetted. One thing you might try, just to ensure that something later in your CPM code isn't bombing out and not allowing a commit, is to remove everything else from your CPM logic, except for the setting the incident Subject and save(). Then see if you still have the intermittent issue.

You were on the right track with the code failing in the function itself. The reason why it seemed to only be working when the opposite of the if was true was that I had an action happen before my if statement, however some code within the if itself was causing the whole function to bomb...so badly that even the code prior to the if clause wouldn't execute. So, thats why it appeared that the code only worked if the opposite of the if logic was true. Upshot...everything seems to work now. Thanks for your help!

Great news. Just as an FYI, what usually happens is that the API calls and code is actually executed up until the error, but Connect for PHP makes an automatic commit to the database only on successful script completion. So if there is a fatal error, it only looks like your previous code was not executed because the results and changes made were not stored.

Thank you Ben. this was very informative to understand how the CPMs work.
As always, you are a star!!

--Nanda

Nanda K Karnam
Pella Corp

hello, thanks for the tutorial.

I have a question, how do I relate to a PHP with a custom object (CO)?

for example, this simple test shows me an error saving the PHP "MinimalContactHandler: Event Handler Content must support At least one class":

<? php

/ **
  * CPMObjectEventHandler: MinimalContactHandler
  * Package: CO
  * Objects: AgentAvailable
  * Actions: Create, Update
  * Version: 1.2
  * Purpose: Minimal contact CPM handler for create and update.
  * /
use \ RightNow \ Connect \ v1_2 as RNCPHP;
use \ RightNow \ CPM \ v1 as RNCPM;

/ **
  * Handler class for CPM
  * /
MinimalContactHandler class implements RNCPM \ ObjectEventHandler
{

     / **
      * Apply CPM logic to object.
      * @ Param int $ RunMode
      * @ Param int $ action
      * @ Param object $ contact
      * @ Param int $ cycles
      * /
     public static function apply ($ RunMode, $ action, $ contact, $ cycle)
     {
         if ($ cycle == 0!) return;

................................

Thanks in advance

Max.-

Hi Max,
I believe you need to specify the package in the 'Objects:' line as well, so using the standard convention: "CO$AgentAvailable" should work. Let me know if that still throws an error.

Hi Ben, Thanks for your reply. The PHP saved, but this show me another error.

"---------------------------
Test Error
---------------------------
Fatal PHP error on line 51 of AccountEvent\AccountEvent:
Class RightNow\CPMObjectEventHandlers\AccountEvent\AccountEvent_TestHarness contains 4 abstract methods and must therefore be declared abstract or implement the remaining methods (RightNow\CPM\v1\ObjectEventHandler_TestHarness::setup, RightNow\CPM\v1\ObjectEventHandler_TestHarness::fetchObject, RightNow\CPM\v1\ObjectEventHandler_TestHarness::validate, ...)
---------------------------"

Code:

<?php

/**
* CPMObjectEventHandler: AccountEvent
* Package: CO
* Objects: CO$AgentAvailable
* Actions: Update
* Version: 1.2
* Purpose: Minimal CPM handler for contact create and update.
*/
use \RightNow\Connect\v1_2 as RNCPHP;
use \RightNow\CPM\v1 as RNCPM;

/**
* Handler class for CPM
*/
class AccountEvent implements RNCPM\ObjectEventHandler
{

/**
* Apply CPM logic to object.
* @param int $runMode
* @param int $action
* @param object $account
* @param int $cycles
*/
public static function apply($runMode, $action, $account, $cycle)
{
if ($cycle !== 0) return;

if (RNCPM\ActionUpdate == $action)
{
$account = RNCPHP\Account::fetch(2);
$account->Attributes->StaffAssignmentDisabled=1;
$account->save();
}

}

}

/**
* CPM test harness
*/
class AccountEvent_TestHarness
implements RNCPM\ObjectEventHandler_TestHarness
{

}

?>

Do you know why it is error?
I dont know if exist documentation on this CPM or Object Event (ObjectEventHandler_TestHarness), the books is very poor with this topic.

Thanks again.
Max.-

It looks like you are missing method implementations in your test harness class. You should be able to use the code in this tutorial for reference. All methods described are required for proper functioning of the CPM.

Hi Ben
My code with your recommend is working, but now I have another trouble.

How I do not hardcode the id in the fetch statement and automatically take the id where I am running the process?

    $ obj = RNCPHP \ Organization :: Fetch (1);

Thanks for your help!
Regards,
Max.-

Hey Max, I assume that this is in your apply() method, right? So, the object that's passed to that method should be all you need to modify here, no need to fetch, in this case. This object also contains its ID, so if you need to use this for other lookups, etc, you can just pull it directly from the object:

public static function apply($runMode, $action, $account, $cycle)
{
if ($cycle !== 0) return;

if (RNCPM\ActionUpdate == $action)
{
// $account already contains a reference to the relevant
// Staff Account object, so just modify it directly
$account->Attributes->StaffAssignmentDisabled = 1;
$account->save();

// Or if you need the specific ID, you can just grab it
// from the object
$accountId = $account->ID;
if ($accountId > 0)
{
doSomething($accountId);
}
}

}

Let me know if I'm misunderstanding what you're trying to do, though.

my code is:

<?

/*

* CPMObjectEventHandler: organization_update

* Package: RN
* Objects: Organization

* Actions: Create, Update

* Version: 1.1

*/

use \RightNow\Connect\v1_1 as RNCPHP;

use \RightNow\CPM\v1 as RNCPM;

class organization_update implements RNCPM\ObjectEventHandler

{

public static function apply( $run_mode, $action, $obj, $n_cycles )

{
$obj=RNCPHP\Organization::Fetch(1);
print "Name ->\"".$obj->Name."\"\n";
print "NameC ->\"".$obj->CustomFields->tn_name."\"\n";
$obj->Name=$obj->CustomFields->tn_name;
print "Name ->\"".$obj->Name."\"\n";

$obj->save();

}

}

class organization_update_TestHarness implements RNCPM\ObjectEventHandler_TestHarness

{

public static function setup()
{
return;
}

public static function fetchObject( $action, $object_type )

{
$cont = new RNCPHP\Organization;

//$obj->Name=$obj->CustomFields->c->tn_name;
//$obj->Name='proceso';
print "Name ->\"".$obj->Name."\"\n";

return;

}

public static function validate( $action, $object )

{

return true;

}

public static function cleanup()
{
return;
}

}

Yes, so my previous post should help. (i.e. The object that is being passed to the apply() method is already an instantiated Connect for PHP object, so you don't need to use fetch.)

One thing I noticed, though, is that you'll want to ensure that you're accessing custom fields and attributes correctly (make sure you're referencing the package name), such as:

$obj->CustomFields->[package name]->[field name]
For custom fields, the package name is always 'c' (at least for the most recent RightNow versions):
$obj->CustomFields->c->[field name]
Let me know if this helps!

if I delete the sentence $ obj = RNCPHP \ Organization :: Fetch (1), showsthe following error.

Fatal PHP Error on line 38 of organization_update: Call to undefined method stdClass :: save ()

You'll need to inspect what is being sent to you in the $obj parameter to debug. Let me know what you find.

go again... jajaja... sorry

this code is working successfully for one organization (id organization =1)
How do you take to the id of the organization of context if I'm standing in another organization (ie organization id = 2) to take the Id dynamically?

<?

/*

* CPMObjectEventHandler: organization_update

* Package: RN
* Objects: Organization

* Actions: Create, Update

* Version: 1.1

*/

use \RightNow\Connect\v1_1 as RNCPHP;

use \RightNow\CPM\v1 as RNCPM;

class organization_update implements RNCPM\ObjectEventHandler

{

public static function apply( $run_mode, $action, $obj, $n_cycles )

{
$obj=RNCPHP\Organization::Fetch(1);
print "Name ->\"".$obj->Name."\"\n";
print "NameC ->\"".$obj->CustomFields->tn_name."\"\n";
$obj->Name=$obj->CustomFields->tn_name;
print "Name ->\"".$obj->Name."\"\n";

$obj->save();

}

}

class organization_update_TestHarness implements RNCPM\ObjectEventHandler_TestHarness

{

public static function setup()
{
return;
}

public static function fetchObject( $action, $object_type )

{
$cont = new RNCPHP\Organization;

//$obj->Name=$obj->CustomFields->c->tn_name;
//$obj->Name='proceso';
print "Name ->\"".$obj->Name."\"\n";

return;

}

public static function validate( $action, $object )

{

return true;

}

public static function cleanup()
{
return;
}

}

As per my comments and solution description on the other thread, I have a CPM triggered by the creation of a custom object, in turn created by RNCPHP from a scheduled report's Custom Script.

All works well, but...

This CPM uses FTP and SFTP (using a local PHPSECLIB class) to fetch .csv files, and then ROQL to query for matching contacts by email, and then create Contacts to hold Incidents as appropriate. It will only fetch 40-70 rows of a file at a time (depending on how much RNCPHP activity on object creation) before silently exiting / being killed - in 5 SECONDS. This is despite it being ticked as "able to run asynchronously". The very fact that load_curl() is available also indicated that the script is of the asynch type. But the 5s timeout on overall execution time seems way too low for an Asynch script. Any others have similar issues ? Workarounds ? Extra config steps ? Thoughts ?

Iain.

How can I show a message in the workspace as a print or echo?

The application show me the next error:

Create test passed
Create test passed
Nombre Actualizado
Update test FAILED

Fatal PHP error on line 8 of MinimalContactHandler\MinimalContactHandler:
Uncaught exception 'Exception' with message 'Validation failed on update of a Contact' in MinimalContactHandler\MinimalContactHandler:8
Stack trace:
#0 {main}
thrown

The code is:

if ($cycle !== 0) return;

if (RNCPM\ActionUpdate == $action)
{
$contact->Name->First = "Maxim";
echo "Nombre Actualizado\n";
$contact->save();
}
elseif (RNCPM\ActionCreate == $action)
{
$contact->Name->First = "CPM Create Test";
$contact->save();
}

Regards,
Max.-

Thanks Ben for this article. It helped me in better understanding and writing my first CPM.

I have written this CPM, which sends an SMS to the Incident's Primary contact, when an Incident is created. I am getting this error "Fatal PHP error on line 8 of incident_sms\incident_sms. Class name must be valid object or a string".

Lines of Code:

<?
/*
* CPMObjectEventHandler: incident_sms
* Package: RN
* Objects: Incident
* Actions: Create
* Version: 1.1
*/---> Line 8

Regards
Sorujit

I've got the same error message, "Class name must be valid object or string", the only difference being the line number. I think it is not referring to the CPM code, but rather an internal file which is being run.

My usual way of troubleshooting such things is to run the code on the portal, but I need to add a reference to the CPM library to do that, which I haven't had any luck finding.

The weird thing is, my code was running successfully in my tests under the August 2013 version, and this error has come up after upgrading to the August 2014 version.

@Sorujit, did you ever find out what was causing this error?

The issue got fixed, once I added the minimum necessary code in the CPM testharness. I just instantiated an incident object and passed it to the object event handler(where the main logic is written).


Hope that helps.

Hi Ben.

I used your example changing the object by incident, but it only work if the action is "Update". If I add action create and I try to test it, it will popup an error saying "Fatal PHP error on line 8, validation failed on create of an Incident". Do you know the reason why? It's driving me crazy.

Please find the code below:

Thanks for your help!

**********************************************

**
* CPMObjectEventHandler: EmailHandlerCreate
* Package: RN
* Objects: Incident
* Actions: Create, Update
* Version: 1.2
*/

// This object procedure binds to v1_1 of the Connect PHP API
use \RightNow\Connect\v1_2 as RNCPHP;
// This object procedure binds to the v1 interface of the process designer
use \RightNow\CPM\v1 as RNCPM;

/**
* Handler class for CPM
*/
class EmailHandlerCreate implements RNCPM\ObjectEventHandler
{
/**
* Apply CPM logic to object.
* @param int $runMode
* @param int $action
* @param object $incident
* @param int $cycle
*/
public static function apply($runMode, $action, $incident, $cycle)
{
if ($cycle !== 0) return;

$incident->Subject = $incident->Subject . ' (Sent to SCC) ';

$data = array(
'incidentID' => $incident->ID,
'lookupName' => $incident->LookupName,
'queueID' => $incident->Queue->ID,
'queueName' => $incident->Queue->Name,
'createdTime' => $incident->CreatedTime,
'product' => $incident->Product->Name,
'category' => $incident->Category->Name,
'threads' => (string)$incident->Threads->ThreadList

);

if (RNCPM\ActionUpdate == $action)
{
$data['action'] = 'update';
}
elseif (RNCPM\ActionCreate == $action)
{
$data['action'] = 'create';
}
[...]

Hi Ben,

I followed this tut. and the other one that utilizes WebDav.

So I have my CPM created and the Lib that it uses as well.

What I am curious to know is what is the best way to trigger the CPM to run?

I currently have REST Service that writes files to a dir and then my model picks up the files and processes them and updates all of the contacts in the system.

I have thought about creating a BO that I just update with each service update and have that trigger the event but I would like to know if there is one that is much more elegant. Is it possible to enable a business rule that acts like a CRON job.

Thank you in advance for the response,

Mark

Hi Mark, I've addressed this in response to one of your later posts here. Sounds like you are working on a good approach for this!

Thank you so much for information on CPM. I am running into a strange issue, when testing CPM everything works fine and able to access Incident primary contact information ( custom fields, phone number etc.) without any issue. But when it gets kicked off via incident update, it logs error. So I also tried to do another fetch but no luck. This only happens on PCI Pod. Any idea on why it might be acting different? any suggestion?

public static function apply($runMode, $action, $incident, $cycle)
{

if ($cycle !== 0) return;

if ((RNCPM\ActionCreate == $action) )

{
$contact = $incident->PrimaryContact;
$contact = RNCPHP\Contact::fetch($contact->ID);
....

Hi,
I am working on CPM. My requirement is whenever incident is updated i need to send the incident data to third party. I have succeeded in that but my CPM code is calling multiple times. I logged the Cycles value, in every log the value is "0" only. Could you please suggest me how to stop the multiple calls. Its urgent requirement.

I have tried in many ways, but i could not succeeded in that.
if any small help it would be helpful.

Thanks in Advance.

Thanks and Regards
Narendra Muttineni

Hello,
how can I use the destroy action?
I mean, the $obj object is empty: every field is empty and every prev field is empty: without even knowing the ID of the object I am destroying the destroy action is USELESS.
Does anybody know why?

thank you
fed

Ehm $obj->ID works, sorry.

Hi,Ben Johns.
thanks for your great tutorial.I have a much better understanding of the construction of the CPMs. Also,i have had my first cpm run successfully.But now i added some codes to that php file,it did not run as supposed.I added some codes to connect my mysql database.But it did not work.Would you help me find how could this cpm connect to mysql database.Thanks a lot!

public static function apply($runMode, $action, $Opportunity, $cycle)
{
if ($cycle !== 0) return;
if (RNCPM\ActionUpdate == $action)
{

$db_host='*****************';
$db_database='**********';
$db_username='***********';
$db_password='***********';
$connection=mysql_connect($db_host,$db_username,$db_password);//
mysql_query("set names 'utf8'");//
if(!$connection){
die("could not connect to the database:".mysql_error());//诊断连接错误

}
$db_selecct=mysql_select_db($db_database);//
if(!$db_selecct)
{
die("could not to the database".mysql_error());
}
$Opportunity->Name = "CPM UPDATE TEST";
echo $Opportunity->Name."\n";
$Opportunity->save();
}
elseif (RNCPM\ActionCreate == $action)
{
$Opportunity->Name = "CPM CREATE TEST";
echo $Opportunity->Name."\n";
$Opportunity->save();
}
}

}

/**
* CPM test harness
*/

Is there a way that the CPM can stop the save action of the record.
So my requirement is to put a validation on a field.
Can it be done through CPM

If you're referring specifically to saving in the agent console, I'd recommend an AddIn.

Can an addin restrict a record from getting saved?

Hi,

I am writing the custom process using process designer to integrate with the external system. The custom process will trigger after update the incident. I am able to send all the details except fileattachment to external system. Later i used getAdminUrl() for fetching the attachment.

$fileattachment1 = $incident->FileAttachments[0]->getAdminUrl();

I am trying to fetch the attachment in custom process using getAdminUrl(). While doing testing of the custom process i am getting the file Url, able to encode it into the base64 format and able to send the file to external system without any errors

but after deploy the custom process and create incident with attachment then its not communicate with the external system, i am not getting the response and incident was not saving with the updated field values. later i realised that the problem is with getAdminUrl() only.

Can anyone please suggest how to bypass this one.

Hi sgsgupta27,

Were you able to resolve your issue.We also have a similar kind of requirement.

I have a situation where I need currently logged in agent account id to process the CPM.
Ex: On incident update, I need to perform a function in CPM only if the incident is updated by an agent belonging to the particular profile.
I am not able to figure out how this can be done?

Any help much appreciated.!
Thanks,

Rahul

Hi,

I am writing custom process for importing the child record under the corresponding contact by using contact pin number.
By using ROQL, I have fetch the contact ID by using pin number. So the data import working fine.

how to restrict or destroy the duplicate child record under the contact.
Can anyone please suggest how to solve this one.

refer the below code
<?php
/**
* CPMObjectEventHandler: Child_data_import
* Package: RN
* Objects: CO\x_obligations
* Actions: Create, Update, Destroy
* Version: 1.3
*/
use \RightNow\Connect\v1_3 as RNCPHP;
use \RightNow\CPM\v1 as RNCPM;

class Child_data_import implements RNCPM\ObjectEventHandler
{
public static function apply($runMode, $action, $x_obligations, $cycles)
{
try{
if ($cycles !== 0) return;

$recrd_id=$x_obligations->ID;

if(isset($x_obligations->x_obligation_type))
{
$x_type=$x_obligations->x_obligation_type;
}else
{
$x_type="";
}
if(isset($x_obligations->x_childrecord_id))
{
$childid=$x_obligations->x_childrecord_id;
}else
{
$childid="";
}

if(isset($x_obligations->x_obligation_status))
{
$x_status=$x_obligations->x_obligation_status;
}
else{
$x_status="";
}
if(isset($x_obligations->PIN))
{
$pin=$x_obligations->PIN;
}else
{
$pin="";
}

if(RNCPM\ActionCreate == $action || RNCPM\ActionUpdate == $action)
{
if(($recrd_id!="" && $recrd_id!=null) && ($pin!=null && $pin!=""))
{
$ROQL_Query = "Select Contact.ID as cont_id from Contact where Contact.CustomFields.c.x_pin='$pin'";
$roql_result_set = RNCPHP\ROQL::query($ROQL_Query);
while($roql_result = $roql_result_set->next())
{
while ($row = $roql_result->next())
{
$cont_id= $row['cont_id'];
}
}
if($cont_id!=null && $cont_id!="")
{
// $x_cont_child= new RNCPHP\CO\x_obligations();
// $x_cont_child->x_obligation_type = $x_type;
$x_obligations->Contact=RNCPHP\Contact::fetch($cont_id);
// $x_cont_child->x_obligation_status = $x_status;
// $x_cont_child->PIN = $pin;
// $x_cont_child->save();
}
else
{
$x_errorhandling=new RNCPHP\CO\x_errorhandling();
// $x_errorhandling->cont_id=RNCPHP\Contact::fetch($cont_id);
$x_errorhandling->x_obligation_type = $x_type;
$x_errorhandling->x_obligation_status = $x_status;
$x_errorhandling->PIN = $pin;
$x_errorhandling->x_childid=$recrd_id;
$x_errorhandling->save();
}
$x_obligations->save();
}

$x_obligations->x_childrecord_id=$recrd_id;
$x_obligations->save();
}

return;
}
catch (Exception $err )
{
echo $err->getMessage();
}
}
}

Hello, I created a php file and upload qith File Manager in /scripts/custom/file.php , I want call the file.php into CPM like library ¿it is possible? and ¿How can I call custom libraries in CPM?
This is my file.php
<?php
class h
{
public function pruebaHola(){
echo "HELLO WORLD";
}
}
?>

Thanks so much for this article!!!

I've create a new script and have everything working except when using as part of a Business Rule on an incident.

How do i set the current incident->ID to a variable?
$currentincidentid = Incident-->ID fails, as well as a bunch of other guesses...

(Basically as incident flows through the business rules I want to capture the Incident ID, Org ID and Product, so that I can query other data to populate for reporting).

Any help would be great

Thanks

You often have to make a CPM call to get the full incident to work with. Typically you're going to have to lean on your test harness to know what you have here, if you're using the above code, you can get the test incident id you construct...does that part of your code work (ie. do you have the incident id when you run the apply function in the test harness?) if so, then you're likely not pulling back the incident object in your code to make the ID visible to your apply function.

Zircon - This is a contributing Drupal Theme
Design by WeebPal.