SuiteCRM 开发 – 添加批量操作 代码示例

本周,SuiteCRM 的首席 SuiteCRM 开发人员 Clemente Raposo 将带您了解如何在 SuiteCRM 8 中向模块添加自定义批量操作。

批量操作配置允许您将操作添加到列表视图的批量操作下拉菜单中。除了指定标签和操作处理程序之外,SuiteCRM 开发此配置还内置了应对其他几种情况的支持:设置最小和/或最大记录选择限制、打开记录面板以进行额外输入、在运行操作之前显示记录选择模式、在执行之前显示确认模式、在操作后重定向到新视图以及在完成后刷新当前列表视图。

在今天的示例中,我们将演示如何添加批量操作以打开记录面板以进行其他输入。我们将使用一个示例,将“动态重命名”操作引入商机模块列表视图中的批量操作菜单。

对于那些渴望开始的人,你可以从下面的视频中找到代码示例:

<?php

namespace Symfony\Component\DependencyInjection\Loader\Configurator;

use Symfony\Component\DependencyInjection\ContainerBuilder;

return static function (ContainerBuilder $container): void {

    // 1. Retrieve the actions for opportunities from the symfony container parameters
    $actions = $container->getParameter('module.listview.bulk_action') ?? [];
    $modules = $actions['modules'] ?? [];
    $opportunities = $modules['opportunities'] ?? [];
    $bulkActions = $opportunities['actions'] ?? [];


    // 2. Add the dynamic rename action definition
    $bulkActions['opportunity-dynamic-rename'] = [
        'key' => 'opportunity-dynamic-rename',
        'labelKey' => 'LBL_DYNAMIC_RENAME', // New label, defined in public/legacy/custom/Extension/application/Ext/Language
        'asyncProcess' => 'true',
        'modes' => ['list', 'detail', 'edit'],
        'acl' => ['view', 'edit'],
        'params' => [
            'allowAll' => false,
            'min' => 2,
            'max' => 10,
            'recordPanel' => [
                'title' => 'LBL_DYNAMIC_RENAME',
                'fields' => [
                    [
                        "name" => "prefix",
                        "label" => "LBL_PREFIX",
                        "fieldDefinition" => [
                            "name" => "prefix",
                            "vname" => "LBL_PREFIX",
                            "type" => "varchar",
                            "len" => "255",
                        ],
                        "type" => "varchar",
                    ]
                ],
                'mode' => 'massupdate',
                'actions' => [
                    [
                        'key' => 'cancel',
                        'labelKey' => 'LBL_CANCEL',
                        'modes' => ['massupdate']
                    ],
                    [
                        'key' => 'bulk-action',
                        'labelKey' => 'LBL_SUBMIT_BUTTON_LABEL',
                        'modes' => ['massupdate'],
                        'klass' => ['btn', 'btn-danger', 'btn-sm'],
                        'params' => [
                            'allowAll' => false,
                            'min' => 2,
                            'max' => 10,
                            'bulkAction' => 'opportunity-dynamic-rename',
                            'displayConfirmation' => true,
                            'confirmationLabel' => 'LBL_BULK_ACTION_MASS_UPDATE_CONFIRMATION'
                        ]

                    ]
                ]


            ]

        ]
    ];

    // 3. Add back to the symfony container parameters
    $opportunities['actions'] = $bulkActions;
    $modules['opportunities'] = $opportunities;
    $actions['modules'] = $modules;
    $container->setParameter('module.listview.bulk_action', $actions);
};

extensions/defaultExt/config/modules/Opportunities/listview/actions/dynamic-rename.php

<?php
    
namespace App\Extension\defaultExt\modules\Opportunities\Process\Service\BulkActions;

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

class DynamicRenameBulkAction extends LegacyHandler implements ProcessHandlerInterface
{
    protected const MSG_OPTIONS_NOT_FOUND = 'Process options is not defined';

    protected const PROCESS_TYPE = 'bulk-opportunity-dynamic-rename';

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

    /**
     * @inheritDoc
     */
    public function getHandlerKey(): string
    {
        return $this->getProcessType();
    }

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

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

        return [
            $module => [
                [
                    'action' => 'edit',
                    'ids' => $ids
                ],
            ],
        ];
    }


    /**
     * @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
    {
        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);
        }
    }

    /**
     * @inheritDoc
     */
    public function run(Process $process)
    {
        $options = $process->getOptions();
        $attributes = $options['payload']['panelRecord']['attributes'] ?? [];

        if (empty($attributes)) {
            $process->setStatus('error');
            $process->setMessages(['LBL_BULK_ACTION_MASS_UPDATE_NO_FIELDS']);

            return;
        }

        $result = $this->renameRecords($process);

        $responseData = [
            'reload' => true,
            'dataUpdated' => true,
            'reloadGlobalRecentlyViewed' => true,
            'reloadRecentlyViewed' => true,
            'reloadFavorites' => true
        ];

        $process->setData($responseData);

        $process->setStatus('success');
        $process->setMessages($result['messages'] ?? ['LBL_BULK_ACTION_MASS_UPDATE_SUCCESS']);
        if (!$result) {
            $process->setStatus('error');
            $process->setMessages(['LBL_ACTION_ERROR']);
        }

        $process->setData($responseData);
    }

    /**
     * @param Process $process
     * @return array
     */
    protected function renameRecords(Process $process): array
    {
        $this->init();
        $options = $process->getOptions();

        $attributes = $options['payload']['panelRecord']['attributes'] ?? [];

        /* MORE OPTIONS - Handle when criteria is sent
            if (is_array($options['criteria'])) {
                $criteria = $options['criteria'];
                $sort = $options['sort'] ?? [];
            }
        */

        $notFound = [];
        $failed = [];

        $prefix = $attributes['prefix'];
        $count = count($options['ids']);

        if (is_array($options['ids']) && $count) {

            foreach ($options['ids'] as $id) {
                /** @var \Opportunity $opportunity */
                $opportunity = \BeanFactory::getBean('Opportunities', $id);

                if (empty($opportunity)) {
                    $notFound[] = $id;
                    continue;
                }

                try {
                    $opportunity->name = $prefix . $opportunity->name;
                    $opportunity->save();
                } catch (Exception $e) {
                    $failed[] = $id;
                }
            }
        }

        $totalFailed = count($failed) + count($notFound);

        $this->close();

        if ($count === $totalFailed) {
            return [
                'success' => false,
                'messages' => ['LBL_BULK_ACTION_MASS_UPDATE_NO_RECORDS']
            ];
        }

        if ($totalFailed > 0) {

            return [
                'success' => true,
                'messages' => ['LBL_BULK_ACTION_MASS_UPDATE_NO_RECORDS']
            ];
        }

        return [
            'success' => true,
            'messages' => ['LBL_BULK_ACTION_MASS_UPDATE_SUCCESS']
        ];
    }
}

extensions/defaultExt/modules/Opportunities/Process/Service/BulkActions/DynamicRenameBulkAction.php

<?php

$app_strings['LBL_RENAME'] = 'Rename';
$app_strings['LBL_DYNAMIC_RENAME'] = 'Dynamic Rename';
$app_strings['LBL_PREFIX'] = 'Prefix';

public/legacy/custom/Extension/application/Ext/Language/en_us.dynamic_rename.php

以上内容可作为如何在 SuiteCRM 8 中向模块添加批量操作的示例。

如果您正在寻找更多开发见解,SalesAgility 的开发团队已创建了由讲师指导的大师班。专为开发人员设计,涵盖 SuiteCRM 8.x 和 SuiteCRM 7.x,请前往大师班了解更多信息。

关于SuiteCRM

SuiteCRM 是全球最受欢迎的 CRM 应用程序之一。我们功能丰富的企业级 Salesforce 替代方案可让您的销售团队更智能地销售、营销和服务。以大幅降低的成本提供 CRM 的所有优势,同时享受开源的自由和灵活性。

您可以在自己的服务器、公有云/私有云中下载并托管 SuiteCRM,或者试用我们的 SAAS 产品SuiteCRM Hosted。这是终极自由,让您完全掌控业务数据。在此免费试用 SuiteCRM 。

帮助支持 SuiteCRM 项目!

滚动至顶部
扫码添加微信联系我们 关闭