SugarCRM Tutorial on categorizing records in two Subpanels for a single “One to Many” relationship

SugarCRM Tutorial on categorizing records in two Subpanels for a single “One to Many” relationship

We all know that when a one-to-many relationship exists between two modules, Sugar will create a subpanel in the Parent Module and a relationship table in the database to store the related records ids to load that records in the subpanel. This is pretty powerful but in some situations, there are requirements to create two subpanels with only one relationship and categorize the related records into those two subpanels. This blog will explain how to create two subpanels with one relationship and categorize related records into those subpanels. 

An Example Scenario:

Let’s take an example where your customer has a requirement to show Opportunities related to Accounts in two subpanels in one subpanel with all the open Opportunities and the other with all closed Opportunities.

Now let us see how to build two subpanels for Opportunities in Accounts modules by using standard relationship in the studio.

Step 1: Create Metadata for Custom subpanel.

We know that there is already a one-to-many SugarCRM standard relationship between Accounts and Opportunities in SugarCRM and the relationship metadata is defined in modules/Accounts/vardefs.php

Now to create a new subpanel and to categorise Closed opportunities and Open Opportunities let us create a file in following path and add the below code.

custom/Extension/modules/Accounts/Ext/Vardefs/<your_file_name>.php

<?php
$dictionary['Account']['fields']['accounts_closed_opportunities'] = array(
    'name' => 'accounts_closed_opportunities',
    'type' => 'link',
    'relationship' => 'accounts_opportunities',
    'source' => 'non-db',
    'module' => 'Opportunities',
    'bean_name' => 'Opportunity',
    'vname' => 'LBL_ACCOUNTS_CLOSED_OPPORTUNITIES_TITLE',
    'link-type' => 'many',
    'side' => 'left',
);

The above code defines a custom relationship metadata with a name and tells the system to use the relationship which is used by the one-to-many relationship between accounts and opportunities. So that the related records are loaded into this custom subpanel form accounts_opportunities table.

Step 2: Custom Subpanel Title

As we want to differentiate Open Opportunities and Closed Opportunities, Let us rename the new subpanel as Closed Opportunities. To do this create a file in  following path and add the below code.

custom/Extension/modules/Accounts/Ext/Language/en_us.<your_file_name>.php

<?php
   $mod_strings['LBL_ACCOUNTS_CLOSED_OPPORTUNITIES_TITLE'] = 'Closed Opportunities';
?>

The above code will set the label to the custom subpanel.

Step 3: Create Viewdefs for Custom Subpanel

To render the custom subpanel in Accounts record view, create a new file in following path and add the below code.

custom\Extension\modules\Accounts\Ext\clients\base\layouts\subpanels\<your_file_name>.php

<?php
$viewdefs['Accounts']['base']['layout']['subpanels']['components'][] = array (
  'layout' => 'subpanel',
  'label' => 'LBL_ACCOUNTS_CLOSED_OPPORTUNITIES_TITLE',
  'context' => 
  array (
    'link' => 'accounts_closed_opportunities',
  ),
);
?>

This code will give metadata for the subpanel layout.

Step 4: Rename Default Subpanel

Now it’s time  to rename our default subpanel to the Open Opportunities in Accounts module. To do this open the Sugar Instance as an admin user and go to Admin> Studio> Accounts> Subpanels> Opportunities and rename the stock subpanel from Opportunities to Open Opportunities because we are going to load open Opportunities into it.

Categorizing records in two Subpanels in SugarCRM

After this do Quick Repair and Rebuild now you will see a new custom subpanel in Accounts Record View.

Now you will see both the subpanels will load the same data, this is because we didn’t add the code to filter the Opportunities based on the sales stage.

To achieve this we need to add two more attributes namely link_class and link_file in the metadata files of both stock and custom subpanels. Here, link_class is the Class Name we are using for handling relationships and link_file is the path for the PHP file in which the class is defined.

Categorizing the related records for subpanels

Step 1: Adding attributes to relationship metadata

 As discussed in the above step, in this step we will add the two attributes for filtering data.

Open the relationship metadata file which was created before in following path and add these two attributes.

custom/Extension/modules/Accounts/Ext/Vardefs/<your_file_name>.php

The code will look like this,

<?php
$dictionary['Account']['fields']['accounts_closed_opportunities'] = array(
    'name' => 'accounts_closed_opportunities',
    'type' => 'link',
    'relationship' => 'accounts_opportunities',
    'source' => 'non-db',
    'module' => 'Opportunities',
    'bean_name' => 'Opportunity',
    'vname' => 'LBL_ACCOUNTS_CLOSED_OPPORTUNITIES_TITLE',
    'link-type' => 'many',
    'side' => 'left',
    'link_file' =>'custom/modules/Accounts/ClosedOpportunitiesForAccounts.php',
    'link_class' => 'ClosedOpportunitiesForAccounts', 
);

Do the same for stock relationship metadata. Create a new file in  the following path and add the below code.

custom\Extension\modules\Accounts\Ext\Vardefs\<file_name>.php 

<?php
$dictionary['Account']['fields']['opportunities']['link_file'] ='custom/modules/Accounts/OpenOpportunitiesForAccounts.php';
$dictionary['Account']['fields']['opportunities']['link_class'] = 'OpenOpportunitiesForAccounts';

In the above code, we are adding link_class and link_file attributes to stock relationship metadata.

Step 2: Filtering Related Records

Now create these classes in their defined paths to load the related records. Create a new file in  the following path and add the below code.

custom/modules/Accounts/ClosedOpportunitiesForAccounts.php

<?php
class ClosedOpportunitiesForAccounts extends Link2
{
    function __construct($linkName, $bean, $linkDef = false){
        parent::__construct($linkName, $bean, $linkDef = false);
    }
    function buildJoinSugarQuery($sugar_query, $options = array()){
        $closed_stages = array(
            'Closed Won',
            'Closed Lost',
        );
        $sugar_query->where()->in('sales_stage',$closed_stages);
      return $this->relationship->buildJoinSugarQuery($this, $sugar_query, $options);
    }
}

Sugar uses Link2 class which is defined in data/Link2.php for handling relationships, In the above code, we are extending Link2 class and overriding the buildJoinSugarQuery function to filter the records.

The buildJoinSugarQuery function has a SugarQuery object as an argument and we can make the query using that object like above.

Do the same for the stock relationship also by adding the below code in the following path.

custom/modules/Accounts/OpenOpportunitiesForAccounts.php

<?php
class OpenOpportunitiesForAccounts extends Link2
{
    function __construct($linkName, $bean, $linkDef = false){
        parent::__construct($linkName, $bean, $linkDef = false);
    }
    function buildJoinSugarQuery($sugar_query, $options = array()){
        $non_open_stages = array(
            'Closed Won',
            'Closed Lost',
        );
        $sugar_query->where()->notIn('sales_stage',$non_open_stages);
        return $this->relationship->buildJoinSugarQuery($this, $sugar_query, $options);
    }
}

Once all your files are in place do a quick repair and rebuild and you are done.

Step-by-step Guide: SugarCRM Subpanel Categorization

Now as shown in the above image we can see two Opportunities Subpanels, one with Open Opportunities Subpanel which filters only the Open Opportunities, and Closed Opportunities Subpanel which filters only Closed Opportunities. 

Conclusion

This customisation will be really useful where the customer wants to categorise the Opportunities based on their sales stages. Not only in Opportunities we can customise similarly for any modules in Sugar like for example where we need to categorise Meetings, Calls, Leads etc and this is completely Upgrade safe Customisation.