Duplication of Incremental ID with prefix issue

Hello. I am having trouble with my project about the id with prefix and incremental logic. The scenario was a simultaneously created a record of two different user of this module. Thus, the said two created record has now with the same id.


The image above is the example of my customer’s issue having the same id.


The image above is my code to generate the incremental id number.

I would like to ask a help any idea from the readers. Thank You

In which module are you getting this kind of problem? Also, have you used any Logic Hook for executing your code?

Hello. I had created an Order Module for this. And yes, I have used logic hook to execute my code.

@rommeltraya25

You have quite a lot of orders if looking at the quantity. Scripts of two users worked at time. It could be a coincidence.
You can use special file or record in DB for create lock key for control saving process. If the key ‘switch on’ you script waiting. The key can be switch on in logichook - before_save and switch off in logichook - after_save.

Hello @p.konetskiy Thank you for this idea.

Unfortunately, I am not quite familiar with creating lock key for control saving process. Can you give me an example/s of implementing this code in logichook? Your help would be highly appreciated. Thank you

@rommeltraya25

I made the code and tested it. It’s universal. You can use it for any module.

  1. custom/modules/<module name>/logic_hooks.php
$hook_array['before_save'][] = Array(
    1, 
    'create record with new number', 
    'custom/modules/<module name>/Records_control.php',
    'controlRecords', 
    'createNewRecord'
); 
$hook_array['after_save'][] = Array(
    1, 
    'unlook new record', 
    'custom/modules/<module name>/Records_control.php',
    'controlRecords', 
    'unlookNewRecord'
); 
  1. custom/modules/<module name>/Records_control.php
class controlRecords{
    function __construct (){
        /* Set max timeout for waiting for hook execution*/
        $this->timeOut=round(ini_get('max_execution_time')/2,0);
        /* Temporary directory for saving file */
        $this->look_dir=$GLOBALS['sugar_config']['cache_dir']."custom/look_keys/";
        /* Time in seconds to stop script */
        $this->stopTime = 2;
    }
    /* Hook before_save */
    function createNewRecord (&$bean, $event, $arguments){
        $lookResult = $this->switchLookNewRecords($bean, $event);
        // 
        // Write custom code here or create other "before_save" logic hook with higher number.
        // 
    }
    /* Hook after_save */
    function unlookNewRecord (&$bean, $event, $arguments){
        $lookResult = $this->switchLookNewRecords($bean, $event, $this->timeOut);
    }
    /** 
     * Code execution blocking control 
     * @param object bean
     * @param string $event
     * @param int $timeOut
     * @return bool
     */
    function switchLookNewRecords ($bean, $event='before_save',$timeOut=15){
        if($timeOut>0){
            if ($event==='before_save'){
                if(sugar_file_get_contents($this->look_dir.$bean->module_name."_record_look.txt")=='1'){
                    sleep($this->stopTime);
                    $this->switchLookNewRecords($bean, 'before_save',$timeOut-$this->stopTime);
                }else{
                    if (!isset($_SESSION['custom_look_keys'])){
                        $_SESSION['custom_look_keys']=array();
                    }
                    $_SESSION['custom_look_keys'][$bean->module_name] = true;
                    sugar_mkdir($this->look_dir,775,true);
                    sugar_file_put_contents($this->look_dir.$bean->module_name."_record_look.txt","1",LOCK_EX);
                }
                return true;
            }elseif ($event==='after_save' && $_SESSION['custom_look_keys'][$bean->module_name]){
                if(sugar_file_get_contents($this->look_dir.$bean->module_name."_record_look.txt")=='1'){
                    sugar_mkdir($this->look_dir,775,true);
                    sugar_file_put_contents($this->look_dir.$bean->module_name."_record_look.txt","0",LOCK_EX);
                };
                $_SESSION['custom_look_keys'][$bean->module_name] = false;
                return true;
            }
        }else{
            $GLOBALS['log']->fatal("Object: '".get_class()."' method: '". __FUNCTION__."' - timeout to save record of module: '$bean->module_name' with ID: '$bean->id'\n ");
            return false;
        }
    }
}
2 Likes

@p.konetskiy Thank you so much for this codes of yours, I appreciate it. However, can I ask another question? What is the advantage and disadvantage of this control records logic? Thank you so much.

@rommeltraya25

The code will work for any module! :joy: