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

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • rabii
    Active Community Member
    • Jun 2016
    • 1250

    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 $entity, UpdateParams $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.


    Rabii
    Web Dev
  • item
    Active Community Member
    • Mar 2017
    • 1476

    #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


    If you could give the project a star on GitHub. EspoCrm believe our work truly deserves more recognition. Thanks.​

    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...