Создание нового модуля для open-source CRM EspoCRM

imageВ этой статье я хотел бы познакомить читателей с архитектурой весьма интересного open-source (GPL3) проекта EspoCRM на примере создания нового модуля для этой системы.Что такое CRM-система (Customer relationship management), думаю, многие уже давно знают. Особенность данной CRM-системы в том, что она написана как Single Page Application и поэтому довольно «шустрая».Простой дизайн и современные технологии программирования многим придутся по вкусу, а быстродействие данной CRM-системы приятно удивит. На сайте доступна демо-версия.Добиться высокой скорости работы помогло кэширование скриптов и шаблонов в Local Storage. Все view вместе с дочерними собираются в один большой HTML, который отображается на экране у пользователя.Система имеет мощный API, использующий JSON, а веб-интерфейс по сути является API-клиентом.Система не перегружена функционалом, но имеет все необходимое, а также неплохо настраивается.Создание нового модуляДля начала нужно создать рабочую директорию нового модуля (это будет пакет модуля) и поместить её в application/Espo/Modules: application/Espo/Modules/PM Структура каталогов нашего модуля должна быть следующая: application/Espo/Modules/PM/Controllers/ application/Espo/Modules/PM/Entities/ application/Espo/Modules/PM/Resources/ Описание метаданных При разработке PM мы должны описать две сущности — Project и ProjectTask. Для этого необходимо создать два JSON-файла со следующим содержанием: application/Espo/Modules/PM/Resources/metadata/scopes/Project.json { «entity»: true, «layouts»: true, «tab»: true, «acl»: true, «module»: «PM», «customizable»: true, «stream»: true, «importable»: true } application/Espo/Modules/PM/Resources/metadata/scopes/ProjectTask.json { «entity»: true, «layouts»: true, «tab»: false, «acl»: true, «module»: «PM», «customizable»: true, «stream»: true, «importable»: true } После этого мы должны описать поля и связи для наших сущностей в метаданных entityDefs.

application/Espo/Modules/PM/Resources/metadata/entityDefs/Project.json { «fields»: { «name»: { «type»: «varchar», «required»: true }, «status»: { «type»: «enum», «options»: [ «Draft», «Active», «Completed», «On Hold», «Dropped» ], «default»: «Active» }, «description»: { «type»: «text» }, «account»: { «type»: «link» }, «createdAt»: { «type»: «datetime», «readOnly»: true }, «modifiedAt»: { «type»: «datetime», «readOnly»: true }, «createdBy»: { «type»: «link», «readOnly»: true }, «modifiedBy»: { «type»: «link», «readOnly»: true }, «assignedUser»: { «type»: «link», «required»: true }, «teams»: { «type»: «linkMultiple» } }, «links»: { «createdBy»: { «type»: «belongsTo», «entity»: «User» }, «modifiedBy»: { «type»: «belongsTo», «entity»: «User» }, «assignedUser»: { «type»: «belongsTo», «entity»: «User» }, «teams»: { «type»: «hasMany», «entity»: «Team», «relationName»: «EntityTeam» }, «account»: { «type»: «belongsTo», «entity»: «Account», «foreign»: «projects» }, «projectTasks»: { «type»: «hasMany», «entity»: «ProjectTask», «foreign»: «project» } }, «collection»: { «sortBy»: «createdAt», «asc»: false, «boolFilters»: [ «onlyMy» ] } } application/Espo/Modules/PM/Resources/metadata/entityDefs/ProjectTask.json { «fields»: { «name»: { «type»: «varchar», «required»: true }, «status»: { «type»: «enum», «options»: [ «Not Started», «Started», «Completed», «Canceled» ], «default»: «Not Started» }, «dateStart»: { «type»: «date» }, «dateEnd»: { «type»: «date» }, «estimatedEffort»: { «type»: «float» }, «actualDuration»: { «type»: «float» }, «description»: { «type»: «text» }, «project»: { «type»: «link» }, «createdAt»: { «type»: «datetime», «readOnly»: true }, «modifiedAt»: { «type»: «datetime», «readOnly»: true }, «createdBy»: { «type»: «link», «readOnly»: true }, «modifiedBy»: { «type»: «link», «readOnly»: true }, «assignedUser»: { «type»: «link», «required»: true }, «teams»: { «type»: «linkMultiple» } }, «links»: { «createdBy»: { «type»: «belongsTo», «entity»: «User» }, «modifiedBy»: { «type»: «belongsTo», «entity»: «User» }, «assignedUser»: { «type»: «belongsTo», «entity»: «User» }, «teams»: { «type»: «hasMany», «entity»: «Team», «relationName»: «EntityTeam» }, «project»: { «type»: «belongsTo», «entity»: «Project», «foreign»: «projectTasks» } }, «collection»: { «sortBy»: «createdAt», «asc»: false, «boolFilters»: [ «onlyMy» ] } } Указываем, что будем использовать контроллер для CRUD. Файл помещаем в директорию clientDefs.

application/Espo/Modules/PM/Resources/metadata/clientDefs/Project.json { «controller»: «Controllers.Record» } application/Espo/Modules/PM/Resources/metadata/clientDefs/ProjectTask.json { «controller»: «Controllers.Record» } Контроллеры классов Для работы сущностей необходимо описать их контроллеры.application/Espo/Modules/PM/Controllers/Project.php

application/Espo/Modules/PM/Resources/i18n/en_US/Project.json { «labels»: { «Create Project»: «Create Project» }, «fields»: { «name»: «Name», «status»: «Status», «account»: «Account» }, «links»: { «projectTasks»: «Project Tasks» } } application/Espo/Modules/PM/Resources/i18n/en_US/ProjectTask.json { «labels»: { «Create ProjectTask»: «Create Project Task» }, «fields»: { «name»: «Name», «status»: «Status», «project»: «Project», «dateStart»: «Date Start», «dateEnd»: «Date End», «estimatedEffort»: «Estimated Effort (hrs)», «actualDuration»: «Actual Duration (hrs)» } } Последний штрих После осуществления всех вышеописанных действий переходим в панель Администратора и производим восстановление системы (Menu → Administration → Rebuild), а затем обновляем страницу.Теперь наш модуль Projects по умолчанию является скрытым; для отображения переходим в панель Администратора (Administration → User Interface) и делаем его видимым. При помощи Field Manager и Layout Manager можно легко добавить новые поля и настроить внешний вид отображения данных.Я по сути не имею отношения к проекту, я лишь довольный пользователь. Процесс создания модуля описан разработчиками и публикуется с их согласия. И разработчики, и я готовы ответить на все интересующие вопросы.

© Habrahabr.ru