SugarCRM: Replace Alert Email Template variables using custom code

In this post I will share with you how to replace/parse an alert email template using custom code.
This is useful if we are sending emails using logic hook but needed to use email templates which contains variables that should be replaced by actual values of the record.

There are two types of Alert Email Template that we will work on. First is Email and secord is Workflow type.

1. Email Templates (Type is Email)
This is pretty simple and I found couple of tutorials for this.
(Lets assume that variables in the email template are for Contact)

// Call email template class
$template = new EmailTemplate();
// Retrieve email template using id
$template->retrieve(<EMAIL_TEMPLATE_ID>);
// Parse the body of email template
$template->body_html = $template->parse_template_bean($template->body_html, $contact->module_dir, $contact);

* We use the parse_template_function and we passed the following parameters:
- first is the body of the email template
- second is the module of the object we will use
- third is the contact object

 

2. Email Templates (Type is Workflow)
Now this is different from the first one because variables in this template are in this format (e.g. {::future::Cases::case_number::).
This is how we replace variables using the SugarCRM way.
- We need to get first the Email template

// Call email template class
$template = new EmailTemplate();
// Retrieve email template using id
$template->retrieve(<EMAIL_TEMPLATE_ID>);

- Now check the Base Module of the template (we use the Case module as example)

// Retrieve case
$case = new aCase();
$case->retrieve(<CASE_ID>);

* The Base Module is important so we know what object to pass

- Now use the codes below to call the function that parses this variables (You can do this also for subject)

// Include alert utils file
include_once('include/workflow/alert_utils.php');
// Call this function to parse email body
$body = parse_alert_template($case, $template->body_html, );

* the alert_utils.php contains function that SugarCRM uses to construct and send Alerts on the Workflow (this is not a class)
- first parameter is the object
- second parameter is the body of the email template

Reference:

http://urdhva-tech.blogspot.sg/2013/07/how-to-parse-email-template-variable-in.html

SugarCRM: Dynamically make a field required based on another field

In this post, we will provide the steps on how to make a certain field required when a field is set to a specific value.
We will use Cases module in this example and we will set Description field to required when the Status field is set to Closed.

1. Go to custom/Extension/modules/Cases/Ext/Dependencies and create custom_dependency.php (You can set any name for the file)

2. Add the following codes on the file:

$dependencies['Leads']['status'] = array(
    'hooks' => array("edit"), // this is where you want it to fire
    'trigger' => 'true', // to fire when fields change
    'triggerFields' => array('status'), // field that will trigger this when changed
    'onload' => true, // fire when page is loaded
    'actions' => array( // actions we want to run, you can set multiple dependency action here
        array(
        'name' => 'SetRequired', // function to trigger
        'params' => array( // the params for the set required action
            'target' => 'description', // the field id
            'label' => 'description_label', // the field label id
            'value' => 'equal($status, "Closed")', // the SugarLogic for it to trigger if the field is required or not
            ),
        ),
    ),
);

Formula used here is the same as the formula you set for fields in Studio when you want to add dependency.

For complete reference on what actions you can use, click this link.

SugarCRM: Manage custom status on History and Activities subpanel

The status options of Activities modules (Calls, Meetings, Tasks) are built in sugar dropdowns and are hard coded so that they will appear in either Activities subpanel or History subpanel.

This post will help you on how to manage custom status and set the conditions if it should appear on Activities or in History subpanel.

In this example, we will add a new status “Cancelled” to Task module. When task is set to this, it should appear in History subpanel to indicate that no further action is required. Make sure to add the new status first on Dropdown Editor.

The Easiest way: (not upgrade safe)

1. Go to modules/Tasks/metadata/subpanels/ForActivities.php and update the where condition for the subpanel.

'where' => "(tasks.status != 'Completed' AND tasks.status != 'Deferred' AND tasks.status != 'Cancelled')",

* We don’t want to include Cancelled tasks in Activities subpanel

2. Go to modules/Tasks/metadata/subpanels/ForHistory.php and update the where condition as well

'where' => "(tasks.status='Completed' OR tasks.status='Deferred' OR tasks.status='Cancelled')",

* This time we want to include all Cancelled tasks to be fetched and shown in History subpanel

3. Run Repair and Rebuild and we’re done.

The Upgrade safe way:

1. We need to make a copy of ForActivities.php and ForHistory.php from modules/Tasks/metadata/subpanels/ in custom/modules/Tasks/metadata/subpanels/ if not existing. We will rename the files as ForActivities2.php and ForHistory2.php. (You can set the name whatever you want)

2. Follow instruction on the Easiest way part and apply this to our new custom files. :)

3. To make our changes work, we have to override the Activities and History subpanel setup and use our custom files. In this example, we will start with the Leads module.

Go to custom/Extension/modules/Leads/Ext/Layoutdefs/ and create a a file override_subpanel.php (You can set the name whatever you want) and add the following codes:

$layout_defs['Leads']['subpanel_setup']['activities']['collection_list']['tasks']['subpanel_name'] = 'ForActivities2';
$layout_defs['Leads']['subpanel_setup']['history']['collection_list']['tasks']['subpanel_name'] = 'ForHistory2';

You will notice that we are overriding the subpanel setup of Activities and History subpanel for Leads module which is set in modules/Leads/metadata/subpaneldefs.php

* We need to apply this on every module that we want our changes for Tasks in Activities and History subpanel.

4. Run Repair and Rebuild and we’re done.

Changes are applicable to Meetings and Calls module as well. You just need to follow the instructions and change the module name used for the directories.

Reference: Tips & Tricks – Custom Activity Status Dropdowns

SugarCRM: Database Tables

List of tables used by sugar:

email_addr_bean_rel - table that relates the record id and email address id. This is where the id of the parent is stored (ex. bean_id=Parent ID).

email_addresses – actual table where the email address is saved (email_addr_bean_rel.email_address_id = email_addresses.id)

saved_report – reports created in sugar

users_signatures – stores user’s email signatures

 

(Incomplete list. Continuously updated.)

SugarCRM: Add a Sub Menu to a Module in Main Menu

This is how you add a new option under a module in the Main Menu on top of the screen.

Lets say you want to add an option “Process Leads” under the Leads module.  To do this:

1. Create a new file in custom/Extension/modules/Leads/Ext/Menus. If the Menus folder doesn’t exist, just make one. We can name the file menu.php.

2. On menu.php file, input codes below:

<?php
global $module_menu;

// This will add the new option
$module_menu[]=Array("index.php?module=Leads&action=ProcessLeads", "Process Leads", "");
?>

In the example above, we assume that the action ProcessLeads is an existing file under custom/modules/Leads with the name ProcessLeads.php but you can also map actions with files.

3.  Just run Repair and Rebuild then logout to see the changes.

SugarCRM: Custom Module Edit View Template

<?php
require_once(‘include/MVC/View/views/view.edit.php’);

class Custom<MODULE_NAME>ViewEdit extends ViewEdit {
    /**
    * @see SugarView::display()
    */
    protected function _displayJavascript() {
        // Call the parent handler
        parent::_displayJavascript();
    }

    /**
    * @see SugarView::display()
    */
    public function preDisplay() {
        // Call parent
        parent::preDisplay();
    }
}
?>

SugarCRM: Make other field in Listview as a link to Detailview

Sometimes you dont need to use the name in a module as a link in Listview to redirect you to the Detailview of the record. If you want to set other fields in Listview as the link that will redirect you to Detailview, then follow this simple steps:

1. Go to custom/modules/<MODULE_NAME>/metadata/listviewdefs.php (If not existing, copy file from modules/<MODULE_NAME>/metadata/listviewdefs.php)
2. Find the field name that you want to make as the link. For example, use Billing City. It will look something like this:

'BILLING_ADDRESS_CITY' =>
array (
'width' => '10%',
'label' => 'LBL_LIST_CITY',
'default' => true,
),

3. You need to add the the link attribute and set it to true.

'BILLING_ADDRESS_CITY' =>
array (
'width' => '10%',
'label' => 'LBL_LIST_CITY',
'link' => true,
'default' => true,
),

* If you want to make the name just plain text, comment the link attribute of the field in the same file.
4. Run Quick Repair and Rebuild in Administration page.

This is an upgrade safe way of making a field as a link to go to Detailview.

SugarCRM: Downgrading SugarCRM instance

This post will help you how to downgrade your sugar instance. This has some additional steps which is not provided in the SugarCRM instructions.

You should have the original instance and database dump in your server, then proceed to the following steps below:

1. First of all, create the database that the downgraded version will use. Then dump the original database to this new database.

2. Download the SugarCRM installer depending on the version and edition you want. The edition of the original instance and the one you will download should be the same.

3. Create a new installation of the SugarCRM installer you downloaded.

NOTE: Do not use the database we created in No. 1 yet.

4. After installing, copy the ./custom folder and the ./upload folder from the original instance and replace those folders in the new installed edition.

NOTE: Customers below version 6.4.0 should copy the ./custom/ and ./cache/ directories.

5. If there custom modules deployed in the original instance, locate and copy the folders of the custom modules in ./modules folder and paste it in ./modules folder of the new installed edition.

6. Copy the config.php and config_override.php in the root folder of the original instance and replace those files in the new installed edition

7. Update the database settings in config.php file with the correct details. You will now use the database you create in No. 1. Update the db_name with the name of the database you created.

When you load the new instance in your browser, it will show an error. This is because the version of the instance is not the same with the version of the database you created in No. 1, to fix this…

8. Go to config.php and look for the keyword sugar_version. Then go to mysql, use the database we created in No. 1, and type the query below:

select * from config where name='sugar_version'

This is the version of the database. The value of the record should be the same with the sugar_version in the config.php so you must update the sugar_version in the database.
9. If the new instance is now loading, go to Admin > Repair > Quick Repair and Rebuild
That’s it. You’ve already downgraded your sugar instance.

Reference:

http://support.sugarcrm.com/04_Find_Answers/02KB/02Administration/100Converting_Editions/Downgrading_Sugar_Editions

SugarCRM: Fix for module name not appearing in Main Menu (InBOX25 issue)

This is a common issue when you install the InBOX25 plugin in sugarcrm. Even if you put the Iframeapp module in the displayed module list sometimes it doesn’t appear in the main menu. To fix this, add the code below in <sugar>/custom/include/language/en_us.lang.php

$GLOBALS['app_list_strings']['moduleList']['Iframeapp'] = 'InBOX25';

This will set the name of the module and will make it appear in the main menu on top of the screen.

SugarCRM: Send Email with attachment using SugarPHPMailer Class

This post will teach you how to send an email in logic hook. I will use the SugarPHPMailer class that SugarCRM uses in sending emails.

// include Email class
include_once('include/SugarPHPMailer.php');
include_once('include/utils/db_utils.php'); // for from_html function

$mail = new SugarPHPMailer();
// Add details
$mail->From = "no-reply@example.com";
$mail->FromName = "Example Company";
// Clear recipients
$mail->ClearAllRecipients();
$mail->ClearReplyTos();
// Add recipient
$mail->AddAddress('johndope@email.com', 'John Dope');
// Add subject
$mail->Subject = "Welcome";
// Add mail content
$mail->Body_html = from_html("<YOUR_EMAIL_CONTENT_HERE>");
$mail->Body = wordwrap("<YOUR_EMAIL_CONTENT_HERE>",900);
$mail->isHTML(true); // set to true if content has html tags

// This portion will get all the attachments from related notes
include_once('module/Notes/Note.php');
$note = new Note();
$where = "notes.parent_id = '<ID_OF_THE_RECORD>'";
// Get full list gets all attachments of all notes related to the record
$attachments = $note->get_full_list("", $where, true);
$all_attachments = array();
$all_attachments = array_merge($all_attachments, $attachments);
// Loop through record
foreach($all_attachments as $attachment) {
     $file_name = $attachment->filename;
     $location = "upload/{$attachment->id}";
     $mime_type = $attachment->file_mime_type;
     // Add attachment to email
     $mail->AddAttachment($location, $file_name, 'base64', $mime_type);
}

// Prepare for sending
$mail->prepForOutbound();
$mail->setMailerForSystem();

//Send mail, log if there is error
if (!$mail->Send()) {
    $GLOBALS['log']->fatal("ERROR: Mail sending failed!");
}

You can also send this to many recipients by calling the AddAddress function again with different email and user.