Field Validation stops working unexpectedly

I've written a field validation in the Meetings module that checks to see if there is another meeting for the Assigned to user within 30 minutes of the start or finish of the time.  It works BEAUTIFULLY for like, 12 hours.  Then the "Save" button just freezes gray and I'm unable to save any more meetings.  This is a Dev box so I dont even have CRON enabled.  If I do a quick rebuild and repair, it starts working again for a few hours since it rebuld all the JS files.  Then suddenly out of nowhere the bug returns.  Here is my custom record.js/create.js

I'm using an ajax call to pass some variables to a PHP entrypoint and doing some raw queries inside the entrypoint, passing back a value of TRUE or FALSE.  I've tried making this a synchronous ajax call thinking that the save wasnt waiting for the ajax call to complete but that didnt help either. 

Any ideas?  Francesca Shiekh HALP!  

({
    extendsFrom: 'MeetingsRecordView',

    initialize: function (options) {

        this._super('initialize', [options]);
          
          
          
          //add custom message key
        app.error.errorName2Keys['custom_message'] = 'Invalid dates';

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

     
     
    _doValidateMeeting: function(fields, errors, callback) {
          
          var recordID = this.model.get('id');
          var displayMSG = "false";
          var date_start = this.model.get('date_start');
          var date_end = this.model.get('date_end');
          var assigned_user_id = this.model.get('assigned_user_id');
          //console.log(this.model.get('date_start'));
          
          function ajaxcall(id)
          {
               $.ajax({ 
                                   type: 'POST', 
                                   async: false,
                                   url: 'index.php?entryPoint=checkMeetingDate',
                                   data: {recordID: id, date_start:date_start, date_end:date_end, assigned_user_id:assigned_user_id},
                                   dataType: "json",
                                   success: function(response)
                                   {
                                        console.log('We have success!');               
                                     if(response.is_valid === "TRUE")
                                      {
                                        ajaxResultTrue("true");
                                        console.log("Result was true");
                                        }
                                        else
                                        {
                                             ajaxResultFalse("false");
                                             console.log("Result was false");
                                        }
                                    
                                   }
               });
          }
          
          function ajaxResultTrue(result)
          {
               errors['date_start'] = errors['date_start'] || {};
                    errors['date_start'].custom_message = true;
                    errors['date_end'] = errors['date_start'] || {};
                    errors['date_end'].custom_message = true;
                    app.alert.show('message-id', {
                         level: 'error',
                         messages: 'You have a conflicting Meeting within 30 minutes of this Meeting.  Please choose another time',
                         autoClose: true,
                         autoCloseDelay: 10000,
                         
                              });
               callback(null, fields, errors);
          }
          
          function ajaxResultFalse(result)
          {
               callback(null, fields, errors);
          }
          
          
          ajaxcall(recordID);     

       
    },
     
     
     
     


})

Here is the entrypoint:

<?php

if (!defined('sugarEntry') || !sugarEntry)
          die('Not A Valid Entry Point');
          
          global $current_user,$db, $sugar_config;
          
          $meeting_id = $_POST['recordID'];
          $date_start_post = $_POST['date_start'];
          $date_end_post = $_POST['date_end'];
          $assigned_user_id = $_POST['assigned_user_id'];
          
          
          $date_start_array = explode('T', $date_start_post);
          $date_start_day = $date_start_array[0];
          $date_start_time = $date_start_array[1];
          $date_start_time_array = explode('-', $date_start_time);
          $date_start_time = $date_start_time_array[0];
          $date_start_interval = $date_start_time_array[1];
          $date_start_interval = str_replace('0','',$date_start_interval);
          $date_start_interval = str_replace(':','',$date_start_interval);
          
          $date_start = $date_start_day . ' ' . $date_start_time;
          
          
          //  Take the posted start date and format it correctly
          $date_end_array = explode('T', $date_end_post);
          $date_end_day = $date_end_array[0];
          $date_end_time = $date_end_array[1];
          $date_end_time_array = explode('-', $date_end_time);
          $date_end_time = $date_end_time_array[0];
          $date_end_interval = $date_end_time_array[1];
          $date_end_interval = str_replace('0','',$date_end_interval);
          $date_end_interval = str_replace(':','',$date_end_interval);
          
          $date_end = $date_end_day . ' ' . $date_end_time;
          
          $GLOBALS['log']->fatal("Made it inside the Ajax call! - $assigned_user_id");
          $GLOBALS['log']->fatal("Date start POST = $date_start");
          $GLOBALS['log']->fatal("Date start interval = $date_start_interval");
          
          $meeting = BeanFactory::getBean("Meetings", $meeting_id);
          
          //$date_start = $meeting->date_start;
          //$date_end = $meeting->date_end;
          
          
          $GLOBALS['log']->fatal(" Start date is : $date_start");
          $GLOBALS['log']->fatal(" End date is : $date_end");
          
          $begin = new DateTime($date_start);
          $end = new DateTime($date_end);
          $minutes = '30';
          
          $begin->modify('+'.$date_start_interval.' hours');
          $begin->modify('-'.$minutes.' minutes');
          $end->modify('+'.$date_start_interval.' hours');
          $end->modify('+'.$minutes.' minutes');
          $begin_result = $begin->format('Y-m-d H:i:s');
          $end_result = $end->format('Y-m-d H:i:s');
          
          $GLOBALS['log']->fatal("Query Start date is : $begin_result");
          $GLOBALS['log']->fatal("Query End date is : $end_result");
          
          //$GLOBALS['log']->fatal("New Start date is : $begin_result and the new End Date is $end_result");
          
          $query = "SELECT id from meetings WHERE assigned_user_id = '$assigned_user_id' AND id != '$meeting_id' AND deleted = '0' AND
                            ((date_start BETWEEN '$begin_result' AND '$end_result')
                            OR
                            (date_end BETWEEN '$begin_result' AND '$end_result')
                            )
                         ";
          $queryExec = $db->query($query);
          
          $queryResult = $db->fetchByAssoc($queryExec);
          $queryResultID = $queryResult['id'];
          
          $GLOBALS['log']->fatal("The result is: $queryResultID");
          
          
          if($queryResultID != '')
          {
               $data = array("is_valid" => "TRUE");
          }
          else
          {
               $data = array("is_valid" => "FALSE");
          }
          
          $json_data = json_encode($data);
          
          
          echo $json_data;

?>
  • is there a reason you are doing this as an ajax call to an entry point instead of an End Point (i.e. a custom API), I also don't quite understand why you are echoing your results rather than returning them.

    Check out the documentation here:

    http://support.sugarcrm.com/Documentation/Sugar_Developer/Sugar_Developer_Guide_8.0/Integration/Web_Services/REST_API/Ex… 

    I would recommend you change it to an end point.

    HTH,

    FrancescaS

  • Thanks Francesca the legend for such a quick response!  So sorry to Tag you.  I'm under a huge deadline to get this finished and ive been banging my head off it for 3 days!  It works perfect then just randomly stops working hours later. I'll change this to an endpoint like you said and see what happens.  I know, tsk tsk on me for still using deprecated entrypoints.  Force of habit and familiarity. Easy copypasta code from a previous customization to save time.   

    I was echoing and logging plain text everywhere.  I was logging everything at every stage to try to find where it eventually stopped working after that short period of time.  Bad form.  You caught me >.<    

  • Man the learning curve and documentation for Custom endpoints is awful.  Finally got it working though.  I won't know for 24 hours or so if this fixes the original problem of the save button just breaking unexpectedly but I followed your advice.  Something tells me that the AJAX call wasnt returning fast enough as the save function doesnt wait for AJAX to return any results.  For the kids following along at home:

    Javascript:

    _doValidateMeeting: function(fields, errors, callback) {

       var recordID = this.model.get('id');
       var date_start = this.model.get('date_start');
       var date_end = this.model.get('date_end');
       var assigned_user_id = this.model.get('assigned_user_id');

       App.api.call('GET', App.api.buildURL('MyEndpoint/CheckMeetings/'+recordID+'/'+date_start+'/'+date_end+'/'+assigned_user_id), null , {
       success: function (data) {
       var result = JSON.parse(data);
       if(result.is_valid === "TRUE")
       {
          errors['date_start'] = errors['date_start'] || {};
          errors['date_start'].custom_message = true;
          errors['date_end'] = errors['date_start'] || {};
          errors['date_end'].custom_message = true;
          app.alert.show('message-id', {
             level: 'error',
             messages: 'You have a conflicting Meeting within 30 minutes of this Meeting. Please choose another time',
             autoClose: true,
             autoCloseDelay: 10000,

             });
          callback(null, fields, errors);
          console.log("Result was true");
       }
       else
       {
          callback(null, fields, errors);
          console.log("Result was false");
          console.log(data);
       }
    },
    error: function (e) {
    throw e;
    callback(null, fields, errors);
    }

    });


    },

    Endpoint registerApiRest() array:

    public function registerApiRest()
    {
       return array(
             'MyGetEndpoint' => array(
             //request type
             'reqType' => array('GET'),

             //set authentication
             'noLoginRequired' => false,

             //endpoint pathinfo
             'path' => array('MyEndpoint', 'CheckMeetings', '?', '?', '?', '?'),

             //endpoint variables
             'pathVars' => array('', '', 'record_id', 'date_start', 'date_end', 'assigned_user_id'),

             //method to call
             'method' => 'ConfirmDate',

             //short help string to be displayed in the help documentation
             'shortHelp' => 'Custom API to check meeting date conflicts',

             //long help to be displayed in the help documentation
             'longHelp' => 'custom/clients/base/api/help/CheckMeetings_ConfirmDate_help.html',

             ),
       );

    }

    As far as the method 'ConfirmDate' the code stayed almost exact the same.  I just changed 4 lines 

    $meeting_id = $args['record_id'];
    $date_start_post = $args['date_start'];
    $date_end_post = $args['date_end'];
    $assigned_user_id = $args['assigned_user_id'];

  • Wear a helmet, 'cause the curves just keep on comin'!

  • Custom Endpoint solved my problem.  I'm pretty sure the Save button was waiting for the callback from the Ajax call which by nature proceeds without finishing.  There must have been a timing issue where the save button logic was waiting for the callback but the ajax call wasnt finished so it resulted in a JS error that made the save button stale.