SugarCRM


In SugarCRM you can add Schedulers to execute repetitive tasks (like CRONs in LINUX). By default, SugarCRM comes with a list of predefined jobs, that can be setup via Admin -> Scheduler.
But if you want to implement a custom job and to be accessible in this module, you must do the following. The solution is implemented in an upgrade safe manner.

1. In custom/modules/Schedulers/ create a file named _AddJobsHere.php


// this file is actually included at the end of /modules/Schedulers/_AddJobsHere.php
//You can take a look on that file for more clarification

//create a new registered job
$job_strings[] = 'customJob';
function customJob(){
//this is where you put the custom code
}
?>

2. Create the language file for new job: custom/modules/Schedulers/language/en_us.lang.php . If the path doesn’t exists you must create the directory structure.

$mod_strings['LBL_CUSTOMJOB'] = 'This string will appear in dropdown list of job field when you create or edit a new job in Sheduler ';

?>

3. Perform a Quick repair and rebuild from Admin -> Repair area.

After that, in Amin -> Scheduler, if you click Create (or Edit an existing item), you will see that a new value appear corresponding “Job” dropdown list.

That’s all folks! :)

This tutorial is for those who:
* want to create one-to-many relationship between two modules without an intermediate table (like ModuleBuilder does)
* has a relate field in a module and want to display a subpanel to the related module
* what to make this using code, in an upgrade safe manner

If you are using SugarCRM and you want to create one-to-many relationship between two modules via ModuleBuilder an aditional table will be created even if that isn’t necesary(no need for a table now for this type of relationship).
Eliminating additional table will improove the application performance and will make more easy to maintain.

Let’s consider the following scenario:
We have two modules: Invoices and Accounts. In custom Invoice module we already have a related field, billing_account_id that makes connection with Account module. We want to display in a subpanel from Accounts module all the invoices that are related.

If you have a related field in Invoices does’t mean that you have the relationship too. So we’ll have to create 4 files for that:
* /custom/Extension/modules/inv_Invoices/Ext/Vardefs/inv_invoices_accounts.php – where have to add the relationship itself and a link field between Invoices and Accounts
* /custom/Extension/modules/Accounts/Ext/Vardefs/inv_invoices_accounts.php – where have to add a link fild between the two modules
* /custom/Extension/modules/Accounts/Ext/Layoutdefs/inv_invoices_accounts.php – definition for invoices subpannel
* /custom/Extension/modules/inv_Invoices/Ext/Language/en_us.inv_invoices_accounts.php – a language variable with the name of the subpanel

Let’s see the code:

* /custom/Extension/modules/inv_Invoices/Ext/Vardefs/inv_invoices_accounts.php
$dictionary['inv_Invoices']['fields']['accounts'] = array(
'name' => 'accounts',
'type' => 'link',
'relationship' => 'inv_invoices_accounts',
'module' => 'Accounts',
'bean_name' => 'Account',
'source' => 'non-db',
'vname' => 'LBL_ACCOUNTS',
);

$dictionary['inv_Invoices']['relationships']['inv_invoices_accounts'] = array(
'lhs_module' => 'Accounts',
'lhs_table' => 'accounts',
'lhs_key' => 'id',
'rhs_module' => 'inv_Invoices',
'rhs_table' => 'inv_invoices',
'rhs_key' => 'billing_account_id',
'relationship_type' => 'one-to-many',
);

* /custom/Extension/modules/Accounts/Ext/Vardefs/inv_invoices_accounts.php
$dictionary['Account']['fields']['inv_invoices'] = array(
'name' => 'inv_invoices',
'type' => 'link',
'relationship' => 'inv_invoices_accounts',
'module' => 'inv_Invoices',
'bean_name' => 'inv_Invoices',
'source' => 'non-db',
'vname' => 'LBL_INVOICES',
);

* /custom/Extension/modules/inv_Invoices/Ext/Language/en_us.inv_invoices_accounts.php
$mod_strings['LBL_INVOICES_SUBPANEL_TITLE'] = 'Invoices';

Atention, we supose that we already have the definition for the related field in Invoice module vardefs.php :
$dictionary['inv_Invoices']['fields'] = array (
'billing_account_name'=>
array(
'name'=>'billing_account_name',
'rname'=>'name',
'group'=>'billing_address',
'id_name'=>'billing_account_id',
'vname'=>'LBL_BILLING_ACCOUNT_NAME',
'type'=>'relate',
'link'=>'billing_accounts',
'table'=>'billing_accounts',
'isnull'=>'true',
'module'=>'Accounts',
'importable' => 'required',
'required'=>true,

),
'billing_account_id' =>
array(
'name'=>'billing_account_id',
'type'=>'id',
'group'=>'billing_address',
'vname'=>'LBL_BILLING_ACCOUNT_ID',
'table' => 'accounts',
'isnull' => 'true',
'module' => 'Accounts',
'dbType' => 'id',
'reportable' => false,
'massupdate' => false,
'duplicate_merge' => 'disabled',
),
);

At the end, you’ll have to make a “quick repair and rebuid” and in Acounts modules you’ll have to see the Invoices subpanel(if the curent account was assingned to an invoice).

That’a all folks :)

In SugarCRM, a relate field can be added to EditView form using a popup from where you can select the desired entry.

In popup, you also have posibility to perform a search to filter the results from related module.
The nice part is that you can automatically send a filtering parameter using “initial_filter” from editviewdefs.php definition. So, for related field you have to add those lines:
'displayParams' => array(
'initial_filter' => "&account_name_advanced=John%20Doe",
)

That means that the popup it will open with “Account Name” prefilled with “John Doe” value. Be aware that target field is account_name but in “initial_value” the name is account_name_advanced.

This is great, but what if I want to send to pop-up a value of a field that has already been filled, not just a hardcoded value? Let suppose I have an invoice module and in EditView I have an “Acount Name” (related with Accounts) and “Payment responsible” (related with contacts). When I choose payment responsible I what to filter the results in popup by Account name. That makes sense.

To achieve this, in editviewdefs.php you must have:
array (
'name' => 'contact',
'displayParams' => array(
'initial_filter' => "&account_name_advanced=\" + document.getElementById(\"billing_account_name\").value + \"",
),
'label' => 'LBL_PAYMENT_RESPONSIBLE',
)

billing_account_name is actually the field name of “Account name”.
To understand how this works you can look at the HTML source and search the open_popup() function that is trigged by Contact button. Actually, the “initial_filter” value is a parameter in open_popup() javascript function.
So we can interfere in javascript and call a particular value from form(that we suppose is filled) using javascript function getElementById.

That’s all folks :)

In SugarCRM, global links ( such as Employees, Admin, Support, About) are defined in /include/globalControlLinks.php file. Those links appear in top right corner of the screen, usualy after “Welcome, Administrator [Log Out]” message.

If you have to modify, remove or add some new links there is an upgrade safe method to do that in /custom folder.

You just have to create a file, if not exists, at location /custom/include/globalControlLinks.php.

To remove, for example, the “Support” link you must add the following line of code:

unset($global_control_links['training']);

To add some new link you have to write somethink like:

$global_control_links['dobre_link'] = array('linkinfo' => array('Dobre.name'=>'http://www.dobre.name/'));

You can also write this code in an upgrade safe manner in /custom/application/Ext/GlobalLinks/links.ext.php
You must remember that last one has priority in front of /custom/include/globalControlLinks.php, that has priority in front of /include/globalControlLinks.php :)

To do that in an upgrade safe manner you must add some files in /custom directory.

The many-to-many relationship involves the existence of a new table that make connection of other to tables.
Lets suppose that we have many products that can be assigned to many categories. Our tables are categories and products, and the new relationship table will be products_categories. SugarCRM will automatically create the new table if the relationship definition is correctly described.

The definition for many-to-many relationship in SugarCRM is stored in $dictionary array so you have to add a new structure to it.

So, you have to add two files in “custom” directory ():

  • product_categoriesMetaData.php – in /custom/metadata/
  • products_categories.php – in /custom/Extension/application/Ext/TableDictionary/

product_categoriesMetaData.php will contain the new $dictionary array with definition of many-to-many relationship, and can be described like this:

$dictionary["products_categories"] = array (
'true_relationship_type' => 'many-to-many',
'from_studio' => false,
'relationships' =>
array (
'products_categories' =>
array (
'lhs_module' => 'Categories',
'lhs_table' => 'categories',
'lhs_key' => 'id',
'rhs_module' => 'Products',
'rhs_table' => 'products',
'rhs_key' => 'id',
'relationship_type' => 'many-to-many',
'join_table' => 'products_categories',
'join_key_lhs' => 'categories_id',
'join_key_rhs' => 'products_id',
),
),
'table' => 'products_categories',
'fields' =>
array (
0 =>
array (
'name' => 'id',
'type' => 'varchar',
'len' => 36,
),
1 =>
array (
'name' => 'date_modified',
'type' => 'datetime',
),
2 =>
array (
'name' => 'deleted',
'type' => 'bool',
'len' => '1',
'default' => '0',
'required' => true,
),
3 =>
array (
'name' => 'categories_id',
'type' => 'varchar',
'len' => 36,
),
4 =>
array (
'name' => 'products_id',
'type' => 'varchar',
'len' => 36,
),
),
'indices' =>
array (
0 =>
array (
'name' => 'products_categories_pk',
'type' => 'primary',
'fields' =>
array (
0 => 'id',
),
),
1 =>
array (
'name' => 'products_categories_alt',
'type' => 'alternate_key',
'fields' =>
array (
0 => 'categories_id',
1 => 'products_id',
),
),
),
);

products_categories.php file from TableDictionary folder will actually make a reference to the above file to be executed and its content will be:

include('custom/metadata/products_categoriesMetaData.php');

After that, you have to go in SugarCRM administration panel and execute a “Quick Repair and Rebuild”.

At the end of the screen you’ll be noticed to execute an SQL query about a “CREATE TABLE” statement. This will actually create the new “products_categories” table.

The database layer in SugarCrm is designed in such a way that it is very agnostic, so you should never need to make calls to the actual database later functions, but rather use the exposed class methods for doing all the work needed. In listing bellow we making a query from the users table, iterating through the results, and making and updating the records if needed.

$db = DBManagerFactory::getInstance();
$res = $db->query("select * from users");
while ( $row = $db->fetchByAssoc($res) ) {
  // make some updates
  if ( $row['status'] != 'Active' ) {
      $db -> query("update users set is_admin = 0 where id = '{$row['id']}'");
  }
}

In SugarCRM it is possible to customize the way EditView template it’s displayed. In this article we explore how can add a header or a footer to the view.

What must be done?

In your <module_name> folder you have to edit editviewdefs.php from the metadata directory and adding this lines of code:

'form' => array(
      'footerTpl'=>'modules/lqd_Invoices/tpls/EditViewFooter.tpl',
      'headerTpl'=>'modules/lqd_Invoices/tpls/EditViewHeader.tpl',
      ),

to the $viewdefs array.

The fragment of your code must looks like:

$viewdefs [$module_name] =
array (
  'EditView' =>
  array (
    'templateMeta' =>
    array (
      'maxColumns' => '2',
      'widths' =>
      array (
        0 => array ('label' => '10', 'field' => '30'),
        1 => array ('label' => '10', 'field' => '30'),
      ),
      'form' => array(
 'footerTpl'=>'modules/lqd_Invoices/tpls/EditViewFooter.tpl',
 'headerTpl'=>'modules/lqd_Invoices/tpls/EditViewHeader.tpl',
 ),
      'useTabs' => false,
      'syncDetailEditViews' => true,
    )

Then you have to create in <module_name>/tpl/ the two files: EditViewFooter.tpl and EditViewHeader.tpl .

You can add your custom code here now, but don’t forget to include the generic header and footer tlp.

Your code must look like:

EditViewHeader.tpl
{$my_widget_for_header}
bla bla bla
{{include file='include/EditView/header.tpl'}}</pre>
EditViewFooter.tpl
{$my_widget_for_footer}
bla bla bla
{{include file='include/EditView/footer.tpl'}}

Don’t forget to do a “Quick Rebuild and Repair” from Administration.

That’s all :)