How to add unique name validation to accounts module

How do I add a custom validation to the Accounts module that prevents save if the name of the account is not unique?

I have been refereing to the Adding Field Validation to the Record View documentation from the Sugar developer guide and have succesfully added a validation function, I just don't know how to query the system to see if there already exists an account with the same name. Can anyone help?

I am on version 7.6 Enterprise.

Here is what I have so far. I created a new file in custom/modules/Accounts/clients/base/views/create-actions/create-actions.js with the following contents:

({
    extendsFrom: 'CreateActionsView',


    initialize: function (options) {
        this._super('initialize', [options]);


        //add validation tasks
        this.model.addValidationTask('check_name', _.bind(this._doValidateUniqueName, this));
    },


    _doValidateUniqueName: function(fields, errors, callback) {        
        var accounts = app.data.createBeanCollection("Accounts");
       accounts.fetch({
          filter: [{'name':{'$equals':this.model.get('name')}}],
       });
        
        if (???) // How do I use the results of the fetch here?
        {
            errors['name'] = errors['name'] || {};
            errors['name'].required = true; // I plan on changing this to a custom error message
        }

        callback(null, fields, errors);
    },
})

The code is called correctly, I just don't know how to use the results of the accounts.fetch to determine if there are any accounts with the same name already.

Parents
  • Hello Brett,

    Step 1: Create an API

    /custom/modules/Accounts/clients/base/api/duplicatename.php

    ---begin source

    <?php

        //if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');       

        //https://community.sugarcrm.com/thread/22999

        class duplicatename extends SugarApi

        {   

          public function registerApiRest()

          {

          return array(

                'duplicatename' => array(

                    // What type of HTTP request to match against, we support GET/PUT/POST/DELETE

                    'reqType' => 'POST',           

                    //set authentication

                    //'noLoginRequired' => false,           

                    // This is the path you are hoping to match, it also accepts wildcards of ? and <module>

                    'path' => array('Accounts','duplicatename'),                           

                    //These take elements from the path and use them to populate $args

                    'pathVars' => array('', ''),           

                    // This is the method name in this class that the url maps to

                    'method' => 'duplicatename',           

                    //short help string to be displayed in the help documentation

                    'shortHelp' => 'Name is unique.',

                    'longHelp' => '',

                ),

            );

          }

          public function duplicatename($api,$args)

          {

          global $sugar_config, $db;

          $name= $args['name'];

          $recordId    = $args['id'];

          //Write the logic to query the database with the same id       

          $duplicateCheckQuery = $db->query("SELECT DISTINCT COUNT(id) AS totalcount FROM [dbo].[accounts] a WHERE a.[id]<>'".$recordId."' AND a.[name]='".$name."' AND a.deleted=0");         

       

          $duplicateCheck = $db->fetchByAssoc($duplicateCheckQuery);

          COUNT'.$duplicateCheck['totalcount']);

          if($duplicateCheck['totalcount'] > 0)

          {   

            return "true";

          } else {

            return "false";

          }   

          } 

        }

    ?>

    ---end source

    STEP 2: Then in your create-actions.js  -->custom/modules/Accounts/clients/base/views/create-actions/create-actions.js

    This is okay but change your name:

    this.model.addValidationTask('name', _.bind(this.doCheckNameDuplicate_Validate, this));

    INSERT CODE IN YOUR CREATE-ACTIONS.JS

    doCheckNameDuplicate: function(fields, errors, callback) { 

    if (!_.isEmpty(this.model.get('name'))) {

    var account_id = this.model.get('id');

    var name = this.model.get('name');

    dataArray = {name : this.model.get('name'), id: this.model.get('id')}

    app.api.call('create',app.api.buildURL('Accounts/duplicatename'),dataArray,{ 

       success:function(response){   

          result=response;  

         if(result == 'true'){   

          errors['name'] = errors['name'] || {};

         errors['name'].custom_message_name = true; 

      }   

    callback(null, fields, errors);   

    },  

    error: function(err){

      app.alert.show('Validate', {

      level  : 'error',

      messages : 'FAILED SERIVED REQUESTED',

      autoClose : false,

    });  

    callback(null, fields, errors); 

    }

    });

    } else {

    callback(null, fields, errors);

    }

    },

  • Peter,

    Thank you for your detailed answer with code. It was very helpful. In the end I didn't implement it exactly as you laid out but you got me pointed in the right direction. I was able to leverage the built in app.data.createBeanCollection method and fetched the bean collection records with a filter applied. This approach cut down the step of creating my own custom api REST endpoint.

    To hopefully help others in the future here is all of my code:

    Step 1.

    Create a custom create-actions controller

    ./custom/modules/Accounts/clients/base/views/create-actions/create-actions.js

    ({
        extendsFrom: 'CreateActionsView',
    
    
        initialize: function (options) {
            this._super('initialize', [options]);
         
            //add custom message key
            app.error.errorName2Keys['cstm_accountNameExists'] = 'CSTM_ERROR_ACCOUNT_NAME_EXISTS';
    
    
            //add validation tasks
            this.model.addValidationTask('cstm_check_account_name', _.bind(this.cstm_doCheckAccountName, this));
        },
    
        cstm_doCheckAccountName: function(fields, errors, callback)
        {     
            var account_name = this.model.get('name');
            if (account_name)
            {
                var accounts = app.data.createBeanCollection("Accounts");
                accounts.fetch({
                    filter: [{'name':{'$equals':account_name}}],
                    success: function(data){
                        if ((typeof(data) !== 'undefined') && (typeof(data.models) !== 'undefined') && (data.models instanceof Array) && (data.models.length > 0))
                        {
                            errors['name'] = errors['name'] || {};
                            errors['name'].cstm_accountNameExists = true;
                        }
                        callback(null, fields, errors);
                    },
                    error: function(err){
                        app.alert.show('Validate', {
                            level  : 'error',
                            messages : 'Unique name validation failed.',
                            autoClose : false,
                        });
                        callback(null, fields, errors);
                    }
                });
            }
            else
            {
                callback(null, fields, errors);
            }
        },
    })
    

    Step 2.

    Create custom error message

    ./custom/Extension/application/Ext/Language/en_us.err_custom_message.php

    <?php
    
    $app_strings['CSTM_ERROR_ACCOUNT_NAME_EXISTS'] = 'Error. Account name already exists.';
    

    Step 3.

    Do a repair/rebuild

    You should now have custom validation when creating an account that will block saving the record if the account name is not unique.

    References:

    http://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_7.6/UI_Model/Views/Examples/Adding_Field…

    Angel's Blog: SugarCRM Quick Hit: SugarBean and JavaScript

Reply
  • Peter,

    Thank you for your detailed answer with code. It was very helpful. In the end I didn't implement it exactly as you laid out but you got me pointed in the right direction. I was able to leverage the built in app.data.createBeanCollection method and fetched the bean collection records with a filter applied. This approach cut down the step of creating my own custom api REST endpoint.

    To hopefully help others in the future here is all of my code:

    Step 1.

    Create a custom create-actions controller

    ./custom/modules/Accounts/clients/base/views/create-actions/create-actions.js

    ({
        extendsFrom: 'CreateActionsView',
    
    
        initialize: function (options) {
            this._super('initialize', [options]);
         
            //add custom message key
            app.error.errorName2Keys['cstm_accountNameExists'] = 'CSTM_ERROR_ACCOUNT_NAME_EXISTS';
    
    
            //add validation tasks
            this.model.addValidationTask('cstm_check_account_name', _.bind(this.cstm_doCheckAccountName, this));
        },
    
        cstm_doCheckAccountName: function(fields, errors, callback)
        {     
            var account_name = this.model.get('name');
            if (account_name)
            {
                var accounts = app.data.createBeanCollection("Accounts");
                accounts.fetch({
                    filter: [{'name':{'$equals':account_name}}],
                    success: function(data){
                        if ((typeof(data) !== 'undefined') && (typeof(data.models) !== 'undefined') && (data.models instanceof Array) && (data.models.length > 0))
                        {
                            errors['name'] = errors['name'] || {};
                            errors['name'].cstm_accountNameExists = true;
                        }
                        callback(null, fields, errors);
                    },
                    error: function(err){
                        app.alert.show('Validate', {
                            level  : 'error',
                            messages : 'Unique name validation failed.',
                            autoClose : false,
                        });
                        callback(null, fields, errors);
                    }
                });
            }
            else
            {
                callback(null, fields, errors);
            }
        },
    })
    

    Step 2.

    Create custom error message

    ./custom/Extension/application/Ext/Language/en_us.err_custom_message.php

    <?php
    
    $app_strings['CSTM_ERROR_ACCOUNT_NAME_EXISTS'] = 'Error. Account name already exists.';
    

    Step 3.

    Do a repair/rebuild

    You should now have custom validation when creating an account that will block saving the record if the account name is not unique.

    References:

    http://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_7.6/UI_Model/Views/Examples/Adding_Field…

    Angel's Blog: SugarCRM Quick Hit: SugarBean and JavaScript

Children