New button triggering workflow

Is it possible to add a button beside edit in detail view that triggers a workflow or changes status of lead so that this change triggers a workflow

This will much easier in a future version of SuiteCRM when my PowerWorfklows add-on is integrated into core, I am working on that right now. You will just need to select an option in the Workdflow definition saying it is meant to be triggered by the user using a button.

So i need power workflow add on?

No, you need to wait for the future version of SuiteCRM v8 that has the feature, or develop it today using code.

What I do is just put a check box field in the record like β€œactivate workflow”. When checked, the workflow runs and then re-sets the checkbox back to unchecked.

Works like a charm.

1 Like

that is a great idea but it is a requirement to put a button

I was able to add a button on the detail view page and trigger a legacy action. The following post helps on how we can add a button and call functions/objects from the legacy.

This is what I implemented

<?php

namespace App\Extension\defaultExt\modules\Leads\Services;

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

class AssignLeadAction implements ProcessHandlerInterface
{
    protected const MSG_OPTIONS_NOT_FOUND = 'Process options are not defined';
    protected const PROCESS_TYPE = 'record-assign-lead';

    /**
     * @var ModuleNameMapperInterface
     */
    private $moduleNameMapper;

    /**
     * MergeRecordsBulkAction constructor.
     * @param ModuleNameMapperInterface $moduleNameMapper
     */
    public function __construct(ModuleNameMapperInterface $moduleNameMapper)
    {
        $this->moduleNameMapper = $moduleNameMapper;
    }

    /**
     * @inheritDoc
     */
    public function getProcessType(): string
    {
        return self::PROCESS_TYPE;
    }

    /**
     * @inheritDoc
     */
    public function requiredAuthRole(): string
    {
        return 'ROLE_USER';
    }

    /**
     * @inheritDoc
     */
    public function getRequiredACLs(Process $process): array
    {
        $options = $process->getOptions();
        $module = $options['module'] ?? '';
        $id = $options['id'] ?? '';

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

    }

    /**
     * @inheritDoc
     */
    public function configure(Process $process): void
    {
        //This process is synchronous
        //We aren't going to store a record on db
        //thus we will use process type as the id
        $process->setId(self::PROCESS_TYPE);
        $process->setAsync(false);
    }

    /**
     * @inheritDoc
     */
    public function validate(Process $process): void
    {
       
    }

    /**
     * @inheritDoc
     */
    public function run(Process $process)
    {
        $options = $process->getOptions();
       $leadid=$options['record']['attributes']['id'];
       $leadbean=BeanFactory::getBean('Leads',$leadid);

       $leadbean->status="Assigned";
        $responseData = [
            'handler' => 'redirect',
            'params' => [
                'route' => $options['module'] . '/convert-lead/' . $options['id'],
                'queryParams' => [
                ]
            ]
        ];
        $process->setStatus('success');
        $process->setMessages([]);
        $process->setData($responseData);
    }
}

this is my code but when pressing the button unexpected error when calling action appears

I tried to implement the functionality on my machine. I could get it successfully working. The following are the code changes:

  1. public\legacy\custom\Extension\application\Ext\Language\en_us.lang.php
<?php
$app_strings['LBL_ASSIGN_STATUS_CONFIRMATION']='Are you sure to change the status of this lead?';
  1. extensions\defaultExt\config\modules\Leads\recordview\actions\assign_lead.php
<?php

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Symfony\Component\DependencyInjection\ContainerBuilder;

return static function (ContainerBuilder $container): void {


    $actions = $container->getParameter('module.recordview.actions') ?? [];
    $modules = $actions['modules'] ?? [];
    $leads = $modules['leads'] ?? [];
    $recordActions = $leads['actions'] ?? [];



    $recordActions['leads-assign'] = [
        'key' => 'leads-assign',
        'labelKey' => 'LBL_ASSIGN', 
        'asyncProcess' => 'true',
        'modes' => ['detail', 'edit'],
        'params' => [
			'displayConfirmation' => true, 
			'confirmationLabel' => 'LBL_ASSIGN_STATUS_CONFIRMATION',
			'module' => 'leads',
        ]
    ];


    $leads['actions'] = $recordActions;
    $modules['leads'] = $leads;
    $actions['modules'] = $modules;
    $container->setParameter('module.recordview.actions', $actions);
};
  1. extensions\defaultExt\modules\Leads\Process\Service\RecordActions\AssignLeadAction.php
<?php 

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

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

class AssignLeadAction 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-leads-assign';
	
	private $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' => $leadsId] = $options;
		
         $this->init();


        $lead = \BeanFactory::getBean('Leads', $leadsId);



        if (empty($lead)) {
            $this->close();

            return [
                'status' => 'error',
                'data' => [],
                'messages' => [
                    'LBL_RECORD_NOT_FOUND'
                ]
            ];
        }


        $lead->status = 'Converted';

        $lead->save();


        $responseData = [
            'reload' => true,
        ];


        // Close legacy handler
        $this->close();

        $process->setStatus('success');
        $process->setMessages([]);
        $process->setData($responseData);	
		
		
    }
	
}
  1. Quick repair & rebuid and run the command: php bin/console cache:clear

image

It changed the status and reload the page to display the updated lead record.

in addition to this i add button in button in detailviewdefs?

No. Because we are injecting the record action. One more thing I forgot to mention about the button label. Please add a label LBL_ASSIGN in custom/extension/modules/leads/ext/language/en_us.lang.php.

i tried this code and it is working thank you so much for the help i just have a small question is it an option to add the button next to edit button not in actions menu

<?php

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Symfony\Component\DependencyInjection\ContainerBuilder;

return static function (ContainerBuilder $container): void {


    $actions = $container->getParameter('module.recordview.actions') ?? [];
    $modules = $actions['modules'] ?? [];
    $leads = $modules['leads'] ?? [];
    $recordActions = $leads['actions'] ?? [];



    $recordActions['leads-assign'] = [
        'key' => 'leads-assign',
        "display" => "hide",
         "asyncProcess" => true,
        'labelKey' => 'LBL_ASSIGN', 
        'modes' => ['detail', 'edit'],
        'params' => [
			'displayConfirmation' => true, 
			'confirmationLabel' => 'LBL_ASSIGN_STATUS_CONFIRMATION',
			'module' => 'leads',
        ],
        'acl'=>["view"],
        "aclModule" =>"Leads",
        "displayLogic" => [
                        "leads_assign_visibility" => [
                            "modes" => [
                                0 => "detail",
                                1 => "edit",
                                2 => "create",
                            ],
                            "params" => [
                                "activeOnFields" => [
                                    "assign_flag_c" => [
                                        'operator'=>'equal',
                                        'value'=> 0,
                                    ],
                                ],
                            ],
                        ],
        ]
    ];


    $leads['actions'] = $recordActions;
    $modules['leads'] = $leads;
    $actions['modules'] = $modules;
    $container->setParameter('module.recordview.actions', $actions);
};

this change in code correct if i want button to be only visible in case flag=0