SugarCRM by default has build in modules so, one can fulfill their business requirement by using the modules like Leads, Contacts, Accounts, Activities(Notes, Emails, Meetings, Calls), Opportunities, Cases and more. However, some times business need cannot be fulfilled by the built-in modules. In these cases we need to customize the platform and create a custom module. This article is meant to be a SugarCRM customization tutorial on creation of new module. The platform provides a tool called ‘Module Builder’ to build a custom module which can be found in admin section. With the help of module builder, one can only create the module without any logic hooks or business logic. So to build components at one place, we need to develop the package which can be installed.
So before proceeding ahead one need to have a basic knowledge of the manifest package in SugarCRM. A manifest file should save with the name “manifest.php”. $manifest variable that defines the basic properties of the module loadable package. So there are various properties which we need to include while creating the manifest file.
- acceptable_sugar_versions – defines in which version of SugarCRM you are going to install your package sugar version. Here we have ‘exact_matches’ and ‘regex_matches’.
- acceptable_sugar_flavors – It defines the 4 flavors community, professional, enterprise editions. Adding these all edition you can installed your package any of SugarCRM edition.
- name – Defines the name of the package.
- key– Defines the unique identifier for package.
- description – Defines the description of the package.
- is_uninstallable – Defines whether package can be uninstalled or not. Here you need to give values in ‘true’ or ‘false’. True defines you can uninstall your package you want and false will disable the uninstall feature.
- type– you can give values like module ,langpack, theme , patch.
- version – Defines the version of the package. It can be “1.0”, “1.1”.
These properties are important while developing the manifest file. They should be defined in $manifest array.
The attributes which we need to define in $installdefs array variable those are.
copy – An array defines where the created files should be copied when you are installing the package. A source and destination path must be specified for the each file.
In the copy variable you can define the language ,layoutdefs, vardefs, logic_hookscustom_fields creation.
Module Creation
First create a folder with name <PackageName>. Follow the steps of creating the package.
Create the manifest.php in the same folder as Package, give properties name, version, id in $manifest array variable and from and to in copy index as per your requirement. This manifest file is used for the package. Example of the manifest file
$manifest = array ( 0 => array ( 'acceptable_sugar_versions' => array ( 0 => '6.5.24', ), ), 1 => array ( 'acceptable_sugar_flavors' => array ( 0 => 'CE', 1 => 'PRO', 2 => 'ENT', ), ), 'readme' => '', 'key' => 'VN', 'author' => '', 'description' => '', 'icon' => '', 'is_uninstallable' => true, 'name' => 'project_Veon', 'published_date' => '2018-03-15 12:00:12', 'type' => 'module', 'version' => 1.0, 'remove_tables' => 'prompt', ); $installdefs = array ( 'id' => 'project_Veon', 'copy' => array ( 0 => array ( 'from' => '<basepath>/Veon', 'to' => 'custom/modulebuilder/packages/Veon', ), ), );
Here “Veon” is the Package Name.
Here we can see the files LICENSE and README file. Create these text files as you required.
Then create the folders named ‘modules, ‘language’ and file manifest.php (this file for module) inside the Veon. Example of the manifest file for the module –
$manifest = array ( 0 => array ( 'acceptable_sugar_versions' => array ( 0 => '', ), ), 1 => array ( 'acceptable_sugar_flavors' => array ( 0 => 'CE', 1 => 'PRO', 2 => 'ENT', ), ), 'readme' => '', 'key' => 'VN', 'author' => '', 'description' => '', 'icon' => '', 'is_uninstallable' => true, 'name' => 'Veon', 'published_date' => '2018-03-15 12:00:12', 'type' => 'module', 'version' => 1521115212, 'remove_tables' => 'prompt', );
Create a folder inside the modules with the same name which you have given in ‘from’ and ‘to’ in the copy array. Save folder name with “Sales” name.
Ex – Veon/modules/Sales
Inside the Sales folder we need to create the folders metadata, Dashlets and language along with three php files (relationships.php, vardefs.php, config.php).
Ex – Veon /modules/Sales/metadata
Ex – Veon /modules/Sales/language
Ex – Veon /modules/Sales/Dashlets
You can see folders and php file which we go through one by one.
Config.php –
$config = array ( 'assignable' => true, 'security_groups' => true, 'acl' => true, 'has_tab' => true, 'studio' => true, 'audit' => true, 'templates' => array ( 'basic' => 1, ), 'label' => 'Sales', 'importable' => true, );
Here we can provide basic properties for the module like Label Name, Importable, etc.
relationships.php–
If you want to make relationship with your module to some other module then you can write your code here or else can be empty php file.
$relationships = array ( );
Vardefs.php –
If you want to create the fields then you can create in this file. But here custom fields have not created.
$vardefs = array ( 'fields' => array ( ), 'relationships' => array ( ), );
In this file, we can create the fields that you require with this module.
metadata –
In this folder you need to define your entire view files like editviewdefs.php, listviewdefs.php, detailviewdefs.php and some other files. So let’s start to create these file.
editviewdefs.php –
In this file you need to define the edit view of your module. ‘name’, ‘assigned_user_name’, ‘description’ are fields that are created by default in the SugarCRM for all the modules
$module_name = 'VN_Sales'; $viewdefs[$module_name]['EditView'] = array( 'templateMeta' => array( 'maxColumns' => '2', 'widths' => array( array('label' => '10', 'field' => '30'), array('label' => '10', 'field' => '30') ), ), 'panels' => array( 'default' => array( array( 'name', 'assigned_user_name', ), array( 'description', ), ), ), );
detailviewdefs.php –
In this file you need to define the detail view of your module. For this code will be
$module_name = 'VN_Sales'; $viewdefs[$module_name]['DetailView'] = array( 'templateMeta' => array( 'form' => array( 'buttons' => array( 'EDIT', 'DUPLICATE', 'DELETE', 'FIND_DUPLICATES', ) ), 'maxColumns' => '2', 'widths' => array( array('label' => '10', 'field' => '30'), array('label' => '10', 'field' => '30') ), ), 'panels' => array( array( 'name', 'assigned_user_name', ), array( array( 'name' => 'date_entered', 'customCode' => '{$fields.date_entered.value} {$APP.LBL_BY} {$fields.created_by_name.value}', 'label' => 'LBL_DATE_ENTERED', ), array( 'name' => 'date_modified', 'customCode' => '{$fields.date_modified.value} {$APP.LBL_BY} {$fields.modified_by_name.value}', 'label' => 'LBL_DATE_MODIFIED', ), ), array( 'description', ), ) );
listviewdefs.php –
In this file you need to define the list view of your module.
if (!defined('sugarEntry') || !sugarEntry) { die('Not A Valid Entry Point'); } $module_name = 'VN_Sales'; $listViewDefs[$module_name] = array( 'NAME' => array( 'width' => '32', 'label' => 'LBL_NAME', 'default' => true, 'link' => true ), 'ASSIGNED_USER_NAME' => array( 'width' => '9', 'label' => 'LBL_ASSIGNED_TO_NAME', 'module' => 'Employees', 'id' => 'ASSIGNED_USER_ID', 'default' => true ), );
searchdefs.php-
In this file you need to define the search view of your module. For this code will be.
$module_name = 'VN_Sales'; $searchdefs[$module_name] = array( 'templateMeta' => array( 'maxColumns' => '3', 'maxColumnsBasic' => '4', 'widths' => array('label' => '10', 'field' => '30'), ), 'layout' => array( 'basic_search' => array( 'name', array('name' => 'current_user_only', 'label' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool'), ), 'advanced_search' => array( 'name', array( 'name' => 'assigned_user_id', 'label' => 'LBL_ASSIGNED_TO', 'type' => 'enum', 'function' => array('name' => 'get_user_array', 'params' => array(false)) ), ), ), );
SearchFields.php –
In this file you need to define the fields for search view.
if (!defined('sugarEntry') || !sugarEntry) { die('Not A Valid Entry Point'); } $module_name = 'VN_Sales'; $searchFields[$module_name] = array( 'name' => array('query_type' => 'default'), 'current_user_only' => array( 'query_type' => 'default', 'db_field' => array('assigned_user_id'), 'my_items' => true, 'vname' => 'LBL_CURRENT_USER_FILTER', 'type' => 'bool' ), 'assigned_user_id' => array('query_type' => 'default'), //Range Search Support 'range_date_entered' => array('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), 'start_range_date_entered' => array( 'query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true ), 'end_range_date_entered' => array( 'query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true ), 'range_date_modified' => array('query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true), 'start_range_date_modified' => array( 'query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true ), 'end_range_date_modified' => array( 'query_type' => 'default', 'enable_range_search' => true, 'is_date_field' => true ), //Range Search Support );
dashletviewdefs.php-
In this file you need to define the dashlets view of your module. For this code will be.
if (!defined('sugarEntry') || !sugarEntry) { die('Not A Valid Entry Point'); } global $current_user; $dashletData['VN_SalesDashlet']['searchFields'] = array( 'date_entered' => array('default' => ''), 'date_modified' => array('default' => ''), 'assigned_user_id' => array( 'type' => 'assigned_user_name', 'default' => $current_user->name ) ); $dashletData['VN_SalesDashlet']['columns'] = array( 'name' => array( 'width' => '40', 'label' => 'LBL_LIST_NAME', 'link' => true, 'default' => true ), 'date_entered' => array( 'width' => '15', 'label' => 'LBL_DATE_ENTERED', 'default' => true ), 'date_modified' => array( 'width' => '15', 'label' => 'LBL_DATE_MODIFIED' ), 'created_by' => array( 'width' => '8', 'label' => 'LBL_CREATED' ), 'assigned_user_name' => array( 'width' => '8', 'label' => 'LBL_LIST_ASSIGNED_USER' ), );
popupdefs.php-.
It will define the search from and list view in popups.
if (!defined('sugarEntry') || !sugarEntry) { die('Not A Valid Entry Point'); } $module_name = 'VN_Sales'; $object_name = 'VN_Sales'; $_module_name = 'vn_sales'; $popupMeta = array( 'moduleMain' => $module_name, 'varName' => $object_name, 'orderBy' => $_module_name . '.name', 'whereClauses' => array( 'name' => $_module_name . '.name', ), 'searchInputs' => array($_module_name . '_number', 'name', 'priority', 'status'), );
quickcreatedefs.php-
In subpanels you can create the record. This view definition you need to define in metadata.
$module_name = 'VN_Sales'; $viewdefs[$module_name]['QuickCreate'] = array( 'templateMeta' => array( 'maxColumns' => '2', 'widths' => array( array('label' => '10', 'field' => '30'), array('label' => '10', 'field' => '30') ), ), 'panels' => array( 'default' => array( array( 'name', 'assigned_user_name', ), ), ), );
metafiles.php-
In this file you need to define the location of metadata definition files EditView, DetailView, List View, and Popup code which will check the presence of these files.
$module_name = 'VN_Sales'; $metafiles[$module_name] = array( 'detailviewdefs' => 'modules/' . $module_name . '/metadata/detailviewdefs.php', 'editviewdefs' => 'modules/' . $module_name . '/metadata/editviewdefs.php', 'listviewdefs' => 'modules/' . $module_name . '/metadata/listviewdefs.php', 'searchdefs' => 'modules/' . $module_name . '/metadata/searchdefs.php', 'popupdefs' => 'modules/' . $module_name . '/metadata/popupdefs.php', 'searchfields' => 'modules/' . $module_name . '/metadata/SearchFields.php', );
Create a folder inside the metadata folder named “subpanels”. Inside this folder create a file default.php
EX – Veon\modules\Sales\metadata\subpanels\default.php
if (!defined('sugarEntry') || !sugarEntry) { die('Not A Valid Entry Point'); } $module_name = 'VN_Sales'; $subpanel_layout = array( 'top_buttons' => array( array('widget_class' => 'SubPanelTopCreateButton'), array('widget_class' => 'SubPanelTopSelectButton', 'popup_module' => $module_name), ), 'where' => '', 'list_fields' => array( 'name' => array( 'vname' => 'LBL_NAME', 'widget_class' => 'SubPanelDetailViewLink', 'width' => '45%', ), 'date_modified' => array( 'vname' => 'LBL_DATE_MODIFIED', 'width' => '45%', ), 'edit_button' => array( 'vname' => 'LBL_EDIT_BUTTON', 'widget_class' => 'SubPanelEditButton', 'module' => $module_name, 'width' => '4%', ), 'remove_button' => array( 'vname' => 'LBL_REMOVE', 'widget_class' => 'SubPanelRemoveButton', 'module' => $module_name, 'width' => '5%', ), ), );
Create a folder inside the Sales(<Module>) folder named “Dashlets”. In this folder you need to create a folder with name “VN_SalesDashlet”.
Note*-
- “VN” is the key for the package.
- “Sales” is the module name
EX- Veon\modules\Sales\Dashlets\VN_SalesDashlet
Inside this folder you need to create two files with names “VN_SalesDashlet.meta.php” and “VN_SalesDashlet.php”
Sample Code –
VN_SalesDashlet.meta.php
if (!defined('sugarEntry') || !sugarEntry) { die('Not A Valid Entry Point'); } global $app_strings; $dashletMeta['VN_SalesDashlet'] = array( 'module' => 'VN_Sales', 'title' => translate('LBL_HOMEPAGE_TITLE', 'VN_Sales'), 'description' => 'A customizable view into VN_Sales', 'category' => 'Module Views' );
VN_SalesDashlet.php
if (!defined('sugarEntry') || !sugarEntry) { die('Not A Valid Entry Point'); } require_once('include/Dashlets/DashletGeneric.php'); require_once('modules/VN_Sales/VN_Sales.php'); class <module_name > Dashlet extends DashletGeneric { function __construct($id, $def = null) { global $current_user, $app_strings; require('modules/VN_Sales/metadata/dashletviewdefs.php'); parent::__construct($id, $def); if (empty($def['title'])) { $this->title = translate('LBL_HOMEPAGE_TITLE', 'VN_Sales'); } $this->searchFields = $dashletData['VN_SalesDashlet']['searchFields']; $this->columns = $dashletData['VN_SalesDashlet']['columns']; $this->seedBean = new VN_Sales(); } }
Now you need to create the language folder inside the modules. This language file defines the name of your field. You need to create the en_us.lang.php file.
EX- Veon\modules\Sales\modules\Sales\language
$mod_strings = array ( 'LBL_ASSIGNED_TO_ID' => 'Assigned User Id', 'LBL_ASSIGNED_TO_NAME' => 'Assigned to', 'LBL_SECURITYGROUPS' => 'Security Groups', 'LBL_SECURITYGROUPS_SUBPANEL_TITLE' => 'Security Groups', 'LBL_ID' => 'ID', 'LBL_DATE_ENTERED' => 'Date Created', 'LBL_DATE_MODIFIED' => 'Date Modified', 'LBL_MODIFIED' => 'Modified By', 'LBL_MODIFIED_ID' => 'Modified By Id', 'LBL_MODIFIED_NAME' => 'Modified By Name', 'LBL_CREATED' => 'Created By', 'LBL_CREATED_ID' => 'Created By Id', 'LBL_DESCRIPTION' => 'Description', 'LBL_DELETED' => 'Deleted', 'LBL_NAME' => 'Name', 'LBL_CREATED_USER' => 'Created by User', 'LBL_MODIFIED_USER' => 'Modified by User', 'LBL_LIST_NAME' => 'Name', 'LBL_EDIT_BUTTON' => 'Edit', 'LBL_REMOVE' => 'Remove', 'LBL_LIST_FORM_TITLE' => 'Sales List', 'LBL_MODULE_NAME' => 'Sales', 'LBL_MODULE_TITLE' => 'Sales', 'LBL_HOMEPAGE_TITLE' => 'My Sales', 'LNK_NEW_RECORD' => 'Create Sales', 'LNK_LIST' => 'View Sales', 'LNK_IMPORT_VN_SALES' => 'Import Sales', 'LBL_SEARCH_FORM_TITLE' => ' Sales', 'LBL_HISTORY_SUBPANEL_TITLE' => 'View History', 'LBL_ACTIVITIES_SUBPANEL_TITLE' => 'Activities', 'LBL_VN_SALES_SUBPANEL_TITLE' => 'Sales', 'LBL_NEW_FORM_TITLE' => 'New Sales', );
Fields or label whatever you will see in SugarCRM those are defined here.
Now one more folder to be created in Sales folder with name ‘language’. Inside this language you need to create the application folder for creating the en_us.lang.php.
EX – Veon\language\application
$app_list_strings['moduleList']['VN_Sales'] = 'Sales';
Now you need to select all folders and files in root and compressed it to zip file.
Now you have created the zip file so you can installed it SugarCRM .
Installation in SugarCRM
First open your Instance. In right side you will get Administrator, click on Admin. In the Developer Tools you will find Module Loader.
Click on the Module loader. Click the “Choose File” button in module upload panel.
After choosing the file it will look like this. Click on the Upload button for Uploading Package.
After uploading your package, it will show in the Uploaded Package Panel.
Now click on the install Button for installing package. Completion of installation it will look like this.
So the package is installed successfully.
Now you will get your package in Module Builder you need to deploy your package.
Here you can see package “Veon” has successfully installed. Click on the Veon and deploy it. After Deployed Package Do Repair. If we don’t do repair and rebuilt it may possible that we cannot see our code change effect. So it is also recommended to do cache clear.
After repairing and rebuilt you will find Sales module in modules list. If you are not finding then go to the Admin > Display Modules and Subpanels. There you will get Display Module and Hidden Module if your module is in hidden module then drag it in display panel and save it.