SuiteCRM 8.7 Detail View Button Implementation: Help with Authorization Error

I’m trying to add a legacy view from SuiteCRM 7 to SuiteCRM 8.7 but encountering the following error: “You are not authorized to view this page. Please contact your system administrator.”

In the legacy system, the view is mapped through the action_view_map.php file, located in the custom/application/ext/ActionViewMap folder. I have also created a class, MyRequiredAction, which extends LegacyHandler and implements ProcessHandlerInterface in SuiteCRM 8. Additionally, I updated the detailviewdefs.php file to include ‘recordactions’, and I can see a new button displayed with the correct label (taken from Suite 7’s lang.php file).


   public function run(Process $process)
    {
        $$options = $process->getOptions();
        $responseData = [
            'handler' => 'redirect',
            'params' => [
                'route' => $options['module'] . '/my-action/' . $options['id'],
                'queryParams' => [
                ]
            ]
        ];
        $process->setStatus('success');
        $process->setMessages([]);
        $process->setData($responseData);		
    }

However, when I click the button, I receive the “not authorized” error message.

I followed a similar pattern as the convert-lead action in the Leads module. Has anyone successfully implemented a legacy view triggered by a button click from the Detail View page in SuiteCRM 8.7? Any help would be greatly appreciated. Thank you!

Hey @Harshad, the view you want to redirect to is a “classic” view, right? are you able to access it directly just by using the url on the browser?

Thanks for the reply. I don’t want to display the classic view page. If you please go to leads module and check ‘Convert Lead’ button, the view I guess is ‘view.convertlead.php’ from legacy/modules/leads/views. I am trying to display a custom view.myaction.php from my legacy/custom/modules/MyModule/views folder similar to the converlead functionality. Need to understand if this implementation is possible for custom pages(not popup) in v8.

Yeah, that was kind of what I was trying to ask. Are you able to go to:

https://<suitecrm-host>/#/MyModule/myaction

Not yet. But will definitely share once I get that

Ok, thank you. The idea here is just to understand if the problem is with the custom page or if it is in the redirect.

If you are able to access that page above, then the problem is with the redirect.

I have successfully displayed a custom view from a legacy system in Suite8 by clicking a button. The URL is structured according to the new routing system.

This documentation page helped
SuiteCRM Developer Insights - Module Record Actions - SuiteCRM

Hey @Harshad, that is great, I’m glad to know.

1 Like

@Harshad can you please share the rest of the details, like a tutorial?

  • Where you place the legacy file
  • how you define the entry-point
  • anything else that is a piece of the puzzle

I’m sure this will be helpful for others in the future. Thanks!

Displaying a Custom View from SuiteCRM 7 in SuiteCRM 8

I wanted to share how to display a custom view from SuiteCRM 7 in the SuiteCRM 8 system. I referenced an article (and video) - SuiteCRM Developer Insights - Module Record Actions - SuiteCRM along with the code for ‘convertlead’ action from the legacy ‘Leads’ module to guide me through the process. Below are the steps I followed to successfully display a custom view:

  1. The first step is to copy the detailviewdefs.php file from the modules/Accounts/metadata/ directory to the custom/modules/Accounts/metadata/ directory. This ensures that any changes you make are upgrade-safe.
    After copying, add a new recordActions section in this file. You can define this action as follows:

    File path: custom/modules/Accounts/metadata/detailviewdefs.php

'recordActions' => [
          'actions' => [
              'print-as-pdf' => [
                  'key' => 'print-as-pdf',
                  'labelKey' => 'LBL_PRINT_AS_PDF',
                  'asyncProcess' => true,
                  'modes' => ['detail'],
                  'acl' => ['view'],
                  'aclModule' => 'AOS_PDF_Templates',
                  'params' => [
                      'selectModal' => [
                          'module' => 'AOS_PDF_Templates'
                      ]
                  ]
              ],
              'hello-world' => [
				  'key' => 'hello-world',
                  'labelKey' => 'LBL_HELLO_WORLD',
                  'asyncProcess' => true,
                  'modes' => ['detail','edit'],
			  ],
			  
          ]
      ],
  1. To ensure that the custom button displays properly, you need to add a label for it in the language file. Create or update the following file if it doesn’t already exist:

    File Path:
    custom/Extension/modules/Accounts/Ext/Language/en_us.lang.php

<?php
$mod_strings['LBL_HELLO_WORLD'] = 'Hello World';
  1. Run Quick Repair & Rebuild , then execute the following command from root directory to clear the cache:

    php bin/console cache:clear

  2. Refresh the detailview page of an accounts. We should see a new button in the list as follows.

  1. Add a new action view map by creating a file at the following path:
    custom/Extension/modules/Accounts/Ext/ActionViewMap/hello_world.php , and include the following code.
<?php
$action_view_map['hello-world'] = 'helloworld';
  1. Create a new custom view by adding a file at the following path:
    custom/modules/Accounts/views/view.helloworld.php , and include the following content.
<?php

require_once('include/MVC/View/SugarView.php');
class CustomAccountsViewHelloworld extends SugarView{
	
	public function __construct(){		
		parent::__construct();
	}	
	public function display(){
		echo 'Hello world';
	}
}
  1. Create a new RecordAction by adding a file at the following path:
    extensions/defaultExt/modules/Accounts/Process/Service/RecordActions/HelloWorldAction.php , and include the following content.
<?php 

namespace App\Extension\defaultExt\modules\Accounts\Process\Service\RecordActions;

use ApiPlatform\Exception\InvalidArgumentException;
use App\Module\Service\ModuleNameMapperInterface;
use App\Engine\LegacyHandler\LegacyHandler;
use App\Process\Entity\Process;
use App\Process\Service\ProcessHandlerInterface;

class HelloWorldAction extends LegacyHandler implements ProcessHandlerInterface
{
	protected const MSG_OPTIONS_NOT_FOUND = 'Process options are not defined';
    protected const MSG_INVALID_TYPE = 'Invalid type';
    public const PROCESS_TYPE = 'record-hello-world';
	
	private $moduleNameMapper;
	
	public function __construct(ModuleNameMapperInterface $moduleNameMapper)
    {
        $this->moduleNameMapper = $moduleNameMapper;
    }
	
	public function getProcessType(): string
	{
        return self::PROCESS_TYPE;
    }

	public function getHandlerKey(): string{
		return $this->getProcessType();
	}
	
    public function configure(Process $process): void
    {
        $process->setId(self::PROCESS_TYPE);
        $process->setAsync(false);
    }
	
    public function requiredAuthRole(): string
    {
        return 'ROLE_USER';
    }
	
    public function getRequiredACLs(Process $process): array
    {
        $options = $process->getOptions();
        $module = $options['module'] ?? '';
        $id = $options['id'] ?? '';

        return [
            $module => [
                [
                    'action' => 'view',
                    'record' => $id
                ],
            ],
        ];
    }

   public function validate(Process $process): void
    {

       if (empty($process->getOptions())) {
            throw new InvalidArgumentException(self::MSG_OPTIONS_NOT_FOUND);
       }

        $options = $process->getOptions();

        if (empty($options['module']) || empty($options['action'])) {
            throw new InvalidArgumentException(self::MSG_OPTIONS_NOT_FOUND);
        }

        if (empty($options['id'])) {
            throw new InvalidArgumentException(self::MSG_OPTIONS_NOT_FOUND);
        }
    }
	
    public function run(Process $process)
    {
       $options = $process->getOptions();
        ['id' => $accountId] = $options;

        $responseData = [
            'handler' => 'redirect',
            'params' => [
                'route' =>$options['module'] . '/hello-world/' .$accountId,
                'queryParams' => [
                ]
            ]
        ];

        $process->setStatus('success');
        $process->setMessages([]);
        $process->setData($responseData);
    }	
}
  1. Run Quick Repair & Rebuild , then visit the page by clicking the “Hello World” button.

Please Note: This is a very simple solution, there is a lot of potential to improve this solution

3 Likes