Announcement

Collapse
No announcement yet.

Save Error Handlers: Throw backend exception, handle in frontend when saving a record

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Save Error Handlers: Throw backend exception, handle in frontend when saving a record

    As per the documentation the Save Error Handlers are pretty powerful when it come to throwing an error / conflict to the front end when a record is being save. as quoted below from documentation:

    In the backend the exception should is thrown with the reason parameter in the body. It can be done from a before-create or before-update record hooks.

    Only Conflict and Error exceptions are supported.
    Today i am sharing with you how you can implement such feature, let suppose that you want to force a rule to not assign more than 10 leads per each user in your system (excluding Administrator), follow steps below to do it:

    1 - Step one create a php class called BeforeUpdateUserAssignment.php under custom\Espo\Custom\Classes\RecordHooks\Lead (create these folders if they don't exist under custom folder) copy the code below:

    PHP Code:
    <?php


    namespace Espo\Custom\Classes\RecordHooks\Lead;

    use 
    Espo\Core\Record\Hook\UpdateHook;
    use 
    Espo\Core\Exceptions\ConflictSilent;
    use 
    Espo\Core\Exceptions\Error;
    use 
    Espo\Core\Utils\Json;
    use 
    Espo\ORM\EntityManager;

    use 
    Espo\Core\Record\UpdateParams;
    use 
    Espo\Entities\User as UserEntity;
    use 
    Espo\Modules\Crm\Entities\Lead as LeadEntity;

    use 
    Espo\ORM\Entity;


    /**
     * @implements UpdateHook<LeadEntity>
     */
    class BeforeUpdateUserAssignment implements UpdateHook
    {

        public function 
    __construct(private EntityManager $entityManager){}


        public function 
    process(Entity $entityUpdateParams $params): void
        
    {  

            if (
    $entity->get('assignedUserId')) {
                
    $user $this->entityManager
                             
    ->getEntityById(UserEntity::ENTITY_TYPE$entity->get('assignedUserId'));
            }

            
    /** @var LeadEntity $entity */
            
    if (
                !
    $entity->isAttributeChanged('assignedUserId')
                ||
                (
                    
    $entity->isAttributeChanged('assignedUserId') &&
                    
    $user &&
                    
    $user->isAdmin()
                )
            ) {
                return;
            }

            
    $this->processAssignment($entity);
        }

        private function 
    processAssignment(LeadEntity $entity): void
        
    {
            
    // Get the count of the leads for the new assigned user
            
    $count $this->entityManager
                
    ->getRDBRepository(LeadEntity::ENTITY_TYPE)
                ->
    where([
                    
    'assignedUserId' => $entity->get('assignedUserId'),
                ])
                ->
    count();
            
            
    // Check if the count is greater then or equals to 4, if true throw an Error Or ConflictSilent using parms in the body to catch in the front end
            
    if ($count >= 4) {

                throw 
    ConflictSilent::createWithBody(
                    
    'leadAssignment',
                    
    Json::encode([
                        
    'assignedUserName' => $entity->get('assignedUserName'),
                        
    'count' => $count,
                    ])
                );
            }
        }

    }
    ​​

    2 - Step two create a Lead.json (if it doesn't exist) under custom\Espo\Custom\Resources\metadata\recordDefs and copy the code below:

    PHP Code:
    {
        
    "beforeUpdateHookClassNameList": [
            
    "__APPEND__",
            
    "Espo\\Custom\\Classes\\RecordHooks\\Lead\\BeforeUp  dateUserAssignment"
        
    ]
    }
    ​  ​ 
    3 - Step three create a Lead.json (if it doesn't exist) under custom\Espo\Custom\Resources\metadata\clientDefs and copy the code below:

    PHP Code:
    {
        
    "saveErrorHandlers": {
            
    "leadAssignment""custom:handlers/lead/lead-assignment-handler"
        
    }
    }
    ​  ​ 
    4 - Final step create a file lead-assignment-handler.js under client\custom\src\handlers\lead (create these folders if they don't exist) and copy the code below:

    PHP Code:
    define('custom:handlers/lead/lead-assignment-handler', [], function () {

        return class {
            
    constructor(view) {
                
    /** @type {module:views/record/detail.Class} */
                
    this.view view;
            }

            
    process(data) {
                
    let assigneduser data.assignedUserName;
                
    let count data.count;

                
    // If you want you can display a warning instead which will be displayed for few second and disapear - see commented code
                // Espo.Ui.warning(assigneduser + ' has more than ' + count + ' Leads please reassign lead to another user', true);
                
    Espo.Ui.error(assigneduser ' has more than ' count ' Leads please reassign lead to another user'true);
            }
        }
    });
    ​​ 


    Please find attached a video showing how it works, in the video i have set it up to count the leads for every user not including condition as above to. Video was made before writing this new post with new code, however these conditions should change based on your needs, this is just to demonstrate how it works.

    The code used in the video is different and simply count the leads assigned for any user in the system and if the count is greater than or equals 4 it throw the error. The code above adds a condition to apply this to all users except the admin.

    Please note that even when clicking cancel it seems that the admin user is still assigned but it is not just refresh the page and system will reassign the assignedUser to previous one if there is one.

    Hope this helps.



  • #2
    Hi rabii,
    many thanks,
    just a clarification :
    on doc : "An array of hooks (applied for API calls). Should implement the Espo\Core\Record\Hook\ReadHook interface​"

    so my poor english and understand, this work for "inline-edit" ? for my comprehension, in espocrm all is API calls or i have not understand somewhere


    Comment


    • rabii
      rabii commented
      Editing a comment
      Yes you are right this works for inline-edit hence it can be done from a before-create or before-update Record Hooks.
      Last edited by rabii; 05-17-2023, 07:09 AM.
Working...
X