How can I set the "Created By" field when importing data through the API?

I'm importing some data through the API, and I found I was not able to set the 'created_by' field when creating records.  I thought I used to be able to do this, but maybe I am mistaken.

POST: <sugar_url>/rest/v11_16/Accounts

{
    "name" : "test5",
    "date_entered":"2024-10-17T12:34:12-04:00",
    "created_by":"seed_will_id"
}

I did notice that in SugarBean, there is a flag you can set (set_created_by), and so I tried that as well, but with the same result

{
    "name" : "test5",
    "date_entered":"2024-10-17T12:34:12-04:00",
    "created_by":"seed_will_id",
    "set_created_by":false
}

I see there is documentation to allow this to be done through the import wizard, but I haven't tested to see if it works. I've too many records to be importing data that way.

https://support.sugarcrm.com/documentation/sugar_versions/14.0/serve/application_guide/import/#Updating_the_Date_Created_and_Created_By_ID_Fields

In the file:

SugarBeanAPiHelper.php:

There is a section that loops through all of the fielddefs and then if there are any matches in the submitted data, it'll add it to the save event.  however, it looks like 'set_created_by' isn't in the field defs, so it never gets passed to the SugarBean save() process.

I can get it to work if I modify the core file like this so sugar thinks that set_created_by is a field.

Is this a bug, or intentional?

Thanks!

Parents
  • As far as I know from old projects the creator can only be set with an additional PUT call having set_created_by set to true.

    The idea behind is that the POST call always sets the created_by to the user running the REST code ( who really created this record ) and if you want to change this user to another id you must run an update on the created_by field with set_created_by explicitely set to true.

    If I‘m wrong correct my guys but don‘t change the code because you need this feature sometimes.

  • I did find why updating the records to set the created_by doesn't work anymore.

    Starting in version 11, there was a change made to clients/base/api/ModuleApi.php

        protected $disabledUpdateFields = array(
            'deleted',
        );

    changed to:

        protected $disabledUpdateFields = array(
            'deleted',
            'created_by',
        );

    So the 'created_by' field gets removed by "ModuleApi".

Reply Children
  • Hi  ,

    nethertheless you can use a logic hook after_save to update the created_by field just after it had been written by the bean. I did this with an additional user related field creation_user_c which I created in studio in module Accounts. When I write a record by REST I add a valid user_id to the new field and it will be copied to the created_by field.

    When I did this Sugar created a custom database field user_id_c in the database resp. bean. If you have some other user related fields already it may have a different name with some numbering in it.

    Then I created a logic_hook anchor in custom/Extension/modules/Accouts/LogicHook/set_account_data_hook.php:

    <?php
    $hook_array['after_save'][] = [
        100,
        'Accounts after_save',
        'custom/modules/accounts/setAccountData.php',
        'setAccountData', 
        'setCreator'
    ];

    and a logic hook class module custom/modules/accounts/setAccountData.php:

    <?php
    if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    
    class setAccountData {
    
    	function setCreator(&$bean, $event, $arguments){
    		
    	$GLOBALS['log']->fatal("setCreator1".print_r($arguments,true));
    
    	    // use event = after_save 
    		if(($event=="after_save")){
    
    	$GLOBALS['log']->fatal("setCreator2:".print_r($bean->dataChanges['status'],true));
    	$GLOBALS['log']->fatal("setCreator2a:".$bean->created_by);
    	$GLOBALS['log']->fatal("setCreator2b:".$bean->creation_user_c);
    	$GLOBALS['log']->fatal("setCreator2c:".$bean->user_id_c);
    	
    			if (($bean->created_by != $bean->user_id_c) &&
    			    ($bean->user_id_c != ""))
    			{
    				
    /*  UPDATE with SuagrBean */
    				$account = BeanFactory::retrieveBean('Accounts', $bean->id);
    				$account->created_by = $bean->user_id_c;
    				$account->save();
    
    
    /* UPDATE with DBMANAGER */
    /*				
    				$query = 'UPDATE accounts SET created_by = ? WHERE id = ? ';
    	$GLOBALS['log']->fatal("setCreator3".$query);
    				$conn = $GLOBALS['db']->getConnection();
    				$rowCount = $conn->executeStatement($query, [$bean->user_id_c, $bean->id]);
    */		
    			}
    		}	
    	}
    
    } //end class setAccountData

    The log calls with level fatal are only for testing, you can remove them.

    I tried two different (still allowed) methods to update the created_by field.

    1. the Bean method, retrieving the bean and updating the field and save the bean. This method is a little bit dangerous because you risk an endles loop if you decide to add some bugs in the code (actually active).

    2. the DBMANAGER method which just calls an SQL update on the just written record in the database (commented out).

    With this logic_hook in place I just write data to Accounts by some REST calls like this:

    /////////////////////////////
    //Login - POST /oauth2/token
    /////////////////////////////
    $url = $base_url . "/oauth2/token";
    $oauth2_token_arguments = array(
        "grant_type" => "password",
        "client_id" => "sugar",
        "client_secret" => "",
        "username" => $username,
        "password" => $password,
        "platform" => "mobile"  //must be defined in admin - configure API platforms
    );
    $oauth2_token_response = call($url, '', 'POST', $oauth2_token_arguments);
    echo "<hr>".print_r($oauth2_token_response,true)."<hr>";
    
    if ($oauth2_token_response->access_token == "") die("No Login");
    
    ///////////////////////////////
    //Create Account
    ///////////////////////////////
    
    $url = $base_url . "/Accounts";
    $account_arguments = array(
    	"name" => "Account1",
    //	"created_by" => "seed_will_id",
    //	"creation_user_c" => "Will Westin",
    	"user_id_c" => "seed_will_id",
    );
    $account_response = call($url, $oauth2_token_response->access_token, 'POST', $account_arguments);
    echo "<hr>".print_r($account_response,true)."<hr>";
    
    if ($account_response->id == "") die("No Account");
    die();
    

  • Ok, sometimes I do not see the forest because there are too many trees.

    You can write a simple before_save logic hook which sets the created_by field to the creation user value like this:

    <?php
    if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
    
    class setAccountData {
    
    	function setCreator(&$bean, $event, $arguments){
    		
    		if(($event=="before_save")){
    			if (($bean->created_by != $bean->user_id_c) &&
    			    ($bean->user_id_c != ""))
    			{
    				$bean->created_by = $bean->user_id_c;
    			}
    		}		
    	}
    
    } //end class setAccountData