Announcement

Collapse
No announcement yet.

custom entity type Person as attendee

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

  • custom entity type Person as attendee

    Hello,

    is possible to have a cutom entity as attendees in Meeting and Call ?

    Thanks
    Attached Files

  • #2
    Hello item, here's how I added a custom entity "Service Tech" as a possible meeting attendee (see the attached image)

    1) Go to Administration > Entity Manager > Meeting > Relationships and create a new many-to-many relationship between Meeting and Service Tech
    With this action Espo will automatically:
    a) Create a new database table meeting-service-tech to link both entities in a many to many relationship
    b) Create a custom entityDefs metadata file for Meeting and for Service Tech with the new relationship specification
    c) Create new language file under your default language for the labels.

    2) Create a custom clientDefs metadata file for Meeting, specifying a custom view to be used to render the Meeting's Attendees panel.
    custom/Espo/Custom/Resources/metadata/clientDefs/Meeting.json

    Code:
    {
        "sidePanels":{
            "detail":[
                {
                    "name":"attendees",
                    "label":"Attendees",
    [COLOR=#FFA500]              "view":"custom:views/meeting/record/panels/attendees",[/COLOR]
                    "options":{
                        "fieldList":[
                            "users",
                            "contacts",
                            "leads"
                        ]
                    },
                    "sticked": true,
                    "isForm": true,
                    "notRefreshable": true
                }
            ],
            "detailSmall":[
                {
                    "name":"attendees",
                    "label":"Attendees",
    [COLOR=#FFA500]              "view":"custom:views/meeting/record/panels/attendees",[/COLOR]
                    "sticked": true,
                    "isForm": true,
                    "notRefreshable": true
                }
            ],
            "edit":[
                {
                    "name":"attendees",
                    "label":"Attendees",
    [COLOR=#FFA500]              "view":"custom:views/meeting/record/panels/attendees",[/COLOR]
                    "sticked": true,
                    "isForm": true,
                    "notRefreshable": true
                }
            ],
            "editSmall":[
                {
                    "name":"attendees",
                    "label":"Attendees",
    [COLOR=#FFA500]              "view":"custom:views/meeting/record/panels/attendees",[/COLOR]
                    "sticked": true,
                    "isForm": true,
                    "notRefreshable": true
                }
            ]
        }
    }
    3) Create the custom view script to render the modified Attendees panel.
    client/custom/src/views/meeting/record/panels/attendees.js
    Code:
    Espo.define('[COLOR=#FFA500]custom:views/meeting/record/panels/attendees[/COLOR]', 'crm:views/meeting/record/panels/attendees', function (Dep) {
    
        return Dep.extend({
    
            setupFields: function () {
                this.fieldList = [];
    
                this.fieldList.push('users');
    
                if (this.getAcl().check('Contact') && !this.getMetadata().get('scopes.Contact.disabled')) {
                    this.fieldList.push('contacts');
                }
                if (this.getAcl().check('Lead') && !this.getMetadata().get('scopes.Lead.disabled')) {
                    this.fieldList.push('leads');
                }
                if (this.getAcl().check('ServiceTech') && !this.getMetadata().get('scopes.ServiceTech.disabled')) {
                    this.fieldList.push('serviceTechs');
                }
            }
    
        });
    
    });
    4) Go to Administration > Rebuild and refresh the page.

    To do the same for Call repeat Steps 1 and 2 for Call only, the front-end view client/custom/src/views/meeting/record/panels/attendees is the same for both entities.

    Saludos
    Last edited by telecastg; 04-28-2020, 05:09 PM.

    Comment


    • #3
      telecastg nice wonderfull ..
      i have now the front-end .. i think missing back-end (field accept/decline/tentative), loadAdditionalColum.. this i will look core code for see how do. and post my result
      Many thanks.

      Comment


      • telecastg
        telecastg commented
        Editing a comment
        You're welcome

    • #4
      Hello telecastg

      progress this work, i can change value of "status" and it's reflected in database..

      meeting.json
      PHP Code:
      {
      "fields": {
      "parent": {
      "entityList": [
      "Account",
      "Lead",
      "Contact",
      "Opportunity",
      "Case",
      "Patient"
      ]
      },
      "patients": {
      "type""linkMultiple",
      "layoutDetailDisabled"false,
      "layoutMassUpdateDisabled"false,
      "importDisabled"false,
      "noLoad"false,
      "isCustom"true,
      "view""crm:views/meeting/fields/contacts",
      "columns": {
      "status""acceptanceStatus"
      },
      "additionalAttributeList": ["columns"],
      "orderBy""name"
      }
      },
      "links": {
      "patients": {
      "type""hasMany",
      "foreign""meetings",
      "entity""Patient",
      "audited"false,
      "isCustom"true,
      "additionalColumns": {
      "status": {
      "type""varchar",
      "len""36",
      "default""None"
      }
      },
      "columnAttributeMap": {
      "status""acceptanceStatus"
      }
      }
      }

      patient.json
      PHP Code:

      "acceptanceStatus": {
      "type""varchar",
      "notStorable"true,
      "exportDisabled"true,
      "disabled"true
      },
      "acceptanceStatusMeetings": {
      "type""enum",
      "notStorable"true,
      "directUpdateDisabled"true,
      "layoutAvailabilityList": ["filters"],
      "importDisabled"true,
      "exportDisabled"true,
      "view""crm:views/lead/fields/acceptance-status",
      "link""meetings",
      "column""status"
      }

      "meetings": {
      "type""hasMany",
      "foreign""patients",
      "entity""Meeting",
      "layoutRelationshipsDisabled"true,
      "audited"false,
      "isCustom"true,
      "columnAttributeMap": {
      "status""acceptanceStatus"
      }



      Comment


      • #5
        Hello,

        https://github.com/espocrm/espocrm/b...ities.php#L404

        There and another place in same file, we need to add to "switch" another case with custom entity..

        PHP Code:


        switch ($scope) {
        case 
        'Contact':
        $link 'contacts';
        break;
        case 
        'Lead':
        $link 'leads';
        break;
        case 
        'User':
        $link 'users';
        break;
        case 
        'Patient':
        $link 'patients';
        break;

        i don't know how upgrade safe. i think with 6.2 and Defs, this can be refactoring and make full compatible with modification.. maybe feature request

        Comment


        • #6
          Hello item , I think that the only way to modify the Activities Service class in an "upgrade safe" way is to actually create a custom Service class, extended from the core "Activities.php" Service class and then create a new "program flow" to invoke that class.

          These diagrams are my interpretation of Espo's program flow, and how Activities are handled now, so as you can see, to invoke a custom Service class, you would need to implement a custom Back-end Controller class that invokes the custom Service class, and possibly a custom router that directs to the custom Back-end Controller when a user clicks a button.

          Click image for larger version  Name:	Program Flow Overview.PNG Views:	0 Size:	13.8 KB ID:	68593Click image for larger version  Name:	Activities Flow Overview.PNG Views:	0 Size:	10.1 KB ID:	68594​

          Unfortunately, I don't have any code samples since we haven't customized Activities but hopefully this might help you with this project.

          Comment


          • #7
            Hello @telecastg,

            Yes i have do that .. and it's work
            i have just copy past activities.php to custom path and make changement in 3 function

            but with 6.2, i think this can be more easy to customize out-of-box https://docs.espocrm.com/development/orm/#defs
            switch/case can use these new function so no need to do what i have do (hard writed Account/Lead/Contact/...)

            Why i do this : because, without that, patients activity is not listed in activities panels on side panel
            Need to reproduce to Call and Task.


            PHP Code:
            <?php
            /************************************************** **********************
            * This file is part of EspoCRM.
            *
            * EspoCRM - Open Source CRM application.
            * Copyright (C) 2014-2021 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
            * Website: https://www.espocrm.com
            *
            * EspoCRM is free software: you can redistribute it and/or modify
            * it under the terms of the GNU General Public License as published by
            * the Free Software Foundation, either version 3 of the License, or
            * (at your option) any later version.
            *
            * EspoCRM is distributed in the hope that it will be useful,
            * but WITHOUT ANY WARRANTY; without even the implied warranty of
            * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
            * GNU General Public License for more details.
            *
            * You should have received a copy of the GNU General Public License
            * along with EspoCRM. If not, see http://www.gnu.org/licenses/.
            *
            * The interactive user interfaces in modified source and object code versions
            * of this program must display Appropriate Legal Notices, as required under
            * Section 5 of the GNU General Public License version 3.
            *
            * In accordance with Section 7(b) of the GNU General Public License version 3,
            * these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
            ************************************************** **********************/

            namespace Espo\Custom\Services;

            use 
            Espo\Core\Exceptions\Error;
            use 
            Espo\Core\Exceptions\NotFound;
            use 
            Espo\Core\Exceptions\Forbidden;

            use 
            Espo\ORM\{
            Entity,
            QueryParams\Select,
            };


            class 
            Activities extends \Espo\Modules\Crm\Services\Activities {



            protected function 
            isPerson($scope)
            {
            return 
            in_array($scope, ['Contact''Lead''User''Patient']) ||
            $this->getMetadata()->get(['scopes'$scope'type']) === 'Person';
            }


            protected function 
            getActivitiesMeetingQuery(
            Entity $entity, array $statusList = [], $isHistory false$additinalSelectParams null
            ) {
            $scope $entity->getEntityType();
            $id $entity->id;

            $methodName 'getActivities' $scope 'MeetingQuery';

            if (
            method_exists($this$methodName)) {
            return 
            $this->$methodName($entity$statusList$isHistory$additinalSelectParams);
            }

            $selectManager $this->getSelectManagerFactory()->create('Meeting');

            $baseSelectParams = [
            'from' => 'Meeting',
            'select' => [
            'id',
            'name',
            [
            'dateStart''dateStart'],
            [
            'dateEnd''dateEnd'],
            [
            'dateStartDate''dateStartDate'],
            [
            'dateEndDate''dateEndDate'],
            [
            'VALUE:Meeting''_scope'],
            'assignedUserId',
            'assignedUserName',
            'parentType',
            'parentId',
            'status',
            'createdAt',
            [
            'VALUE:''hasAttachment'],
            ],
            'whereClause' => [],
            ];

            if (!empty(
            $statusList)) {
            $baseSelectParams['whereClause'][] = [
            'status' => $statusList
            ];
            }

            $selectParams $baseSelectParams;

            if (
            $scope == 'Account') {
            $selectParams['whereClause'][] = [
            'OR' => [
            [
            'parentId' => $id,
            'parentType' => 'Account'
            ],
            [
            'accountId' => $id
            ]
            ]
            ];
            } else if (
            $scope == 'Lead' && $entity->get('createdAccountId')) {
            $selectParams['whereClause'][] = [
            'OR' => [
            [
            'parentId' => $id,
            'parentType' => 'Lead'
            ],
            [
            'accountId' => $entity->get('createdAccountId')
            ]
            ]
            ];
            } else {
            $selectParams['whereClause']['parentId'] = $id;
            $selectParams['whereClause']['parentType'] = $scope;
            }

            $selectManager->applyAccess($selectParams);

            $selectParams $selectManager->mergeSelectParams($selectParams$additinalSelectParams);

            $query Select::fromRaw($selectParams);

            if (!
            $this->isPerson($scope)) {
            return 
            $query;
            }

            $queryList = [$query];

            $link null;

            switch (
            $scope) {
            case 
            'Contact':
            $link 'contacts';
            break;
            case 
            'Lead':
            $link 'leads';
            break;
            case 
            'User':
            $link 'users';
            break;
            case 
            'Patient':
            $link 'patients';
            }

            //$GLOBALS['log']->warning( 'JE SUIS ICI' );
            if (!$link) {
            return 
            $queryList;
            }

            $selectParams $baseSelectParams;

            $selectManager->addJoin($link$selectParams);

            $selectParams['whereClause'][$link .'.id'] = $id;
            $selectParams['whereClause'][] = [
            'OR' => [
            'parentType!=' => $scope,
            'parentId!=' => $id,
            'parentType' => null,
            'parentId' => null,
            ]
            ];

            $selectManager->applyAccess($selectParams);

            $selectParams $selectManager->mergeSelectParams($selectParams$additinalSelectParams);

            $query Select::fromRaw($selectParams);

            $queryList[] = $query;

            return 
            $queryList;
            }

            protected function 
            getActivitiesCallQuery(
            Entity $entity, array $statusList = [], $isHistory false$additinalSelectParams null
            ) {
            $scope $entity->getEntityType();
            $id $entity->id;

            $methodName 'getActivities' .$scope 'CallQuery';

            if (
            method_exists($this$methodName)) {
            return 
            $this->$methodName($entity$statusList$isHistory$additinalSelectParams);
            }

            $selectManager $this->getSelectManagerFactory()->create('Call');

            $baseSelectParams = [
            'from' => 'Call',
            'select' => [
            'id',
            'name',
            [
            'dateStart''dateStart'],
            [
            'dateEnd''dateEnd'],
            [
            'VALUE:''dateStartDate'],
            [
            'VALUE:''dateEndDate'],
            [
            'VALUE:Call''_scope'],
            'assignedUserId',
            'assignedUserName',
            'parentType',
            'parentId',
            'status',
            'createdAt',
            [
            'VALUE:''hasAttachment'],
            ],
            'whereClause' => [],
            ];

            if (!empty(
            $statusList)) {
            $baseSelectParams['whereClause'][] = [
            'status' => $statusList
            ];
            }

            $selectParams $baseSelectParams;

            if (
            $scope == 'Account') {
            $selectParams['whereClause'][] = [
            'OR' => [
            [
            'parentId' => $id,
            'parentType' => 'Account'
            ],
            [
            'accountId' => $id
            ]
            ]
            ];
            } else if (
            $scope == 'Lead' && $entity->get('createdAccountId')) {
            $selectParams['whereClause'][] = [
            'OR' => [
            [
            'parentId' => $id,
            'parentType' => 'Lead'
            ],
            [
            'accountId' => $entity->get('createdAccountId')
            ]
            ]
            ];
            } else {
            $selectParams['whereClause']['parentId'] = $id;
            $selectParams['whereClause']['parentType'] = $scope;
            }

            $selectManager->applyAccess($selectParams);

            $selectParams $selectManager->mergeSelectParams($selectParams$additinalSelectParams);

            $query Select::fromRaw($selectParams);

            if (!
            $this->isPerson($scope)) {
            return 
            $query;
            }

            $queryList = [$query];

            $link null;

            switch (
            $scope) {
            case 
            'Contact':
            $link 'contacts';
            break;
            case 
            'Lead':
            $link 'leads';
            break;
            case 
            'User':
            $link 'users';
            break;
            }

            if (!
            $link) {
            return 
            $queryList;
            }

            $selectParams $baseSelectParams;
            $selectManager->addJoin($link$selectParams);
            $selectParams['whereClause'][$link .'.id'] = $id;
            $selectParams['whereClause'][] = [
            'OR' => [
            'parentType!=' => $scope,
            'parentId!=' => $id,
            'parentType' => null,
            'parentId' => null,
            ]
            ];

            $selectManager->applyAccess($selectParams);

            $selectParams $selectManager->mergeSelectParams($selectParams$additinalSelectParams);

            $query Select::fromRaw($selectParams);

            $queryList[] = $query;

            return 
            $queryList;
            }

            }

            Comment


            • #8
              but with 6.2, i think this can be more easy to customize out-of-box https://docs.espocrm.com/development/orm/#defs
              switch/case can use these new function so no need to do what i have do (hard writed Account/Lead/Contact/...)
              I couldn't follow the instructions, if you use this new feature, could you please post a code example ?, I wish that the official documentation would have more actual samples when describing features so it would be easier to understand.

              Comment


              • #9
                Hello telecastg,

                patiente, waiting 6.2 to test

                but look this :

                PHP Code:
                <?php
                if ($scope == 'Account') {
                $selectParams['whereClause'][] = [
                'OR' => [
                [
                'parentId' => $id,
                'parentType' => 'Account'
                ],
                [
                'accountId' => $id
                ]
                ]
                ];
                } else if (
                $scope == 'Lead' && $entity->get('createdAccountId')) {
                $selectParams['whereClause'][] = [
                'OR' => [
                [
                'parentId' => $id,
                'parentType' => 'Lead'
                ],
                [
                'accountId' => $entity->get('createdAccountId')
                ]
                ]
                ];
                } else {
                $selectParams['whereClause']['parentId'] = $id;
                $selectParams['whereClause']['parentType'] = $scope;
                }
                this can be rewrite .. so (without big brainstorming ) :

                PHP Code:

                $selectParams
                ['whereClause'][] = [
                'OR' => [
                [
                'parentId' => $id,
                'parentType' => $scope
                ],
                [
                'accountId' => $id
                ]
                ]
                ]; 
                The goal is not have Account, Lead, Contact : hard coded
                Last edited by item; 03-14-2021, 11:01 PM.

                Comment

              Working...
              X