Comment ajouter un bouton personnalisé à la vue Admin des commandes client dans Magento2

12

entrez la description de l'image ici

Comment ajouter un bouton personnalisé à la vue des commandes client dans magento2, car certains événements ont été supprimés en faveur des plugins.

  • Suppression de certains événements (les plugins doivent être utilisés à la place):

Voir le journal des modifications de Magento2

Renon Stewart
la source

Réponses:

19

La solution la plus propre que j'ai vue jusqu'à présent est d'utiliser un plugin ciblant 'beforeSetLayout'

Cela peut cibler le bloc exact, enregistrer la vérification de la demande actuelle et éviter également que le plugin ne soit sur 'getOrderId' qui, dans mon cas, ne pouvait pas être utilisé car j'avais besoin d'appeler getOrderId dans ma méthode de plugin.

Donc, cela en di.xml

   <type name="Magento\Sales\Block\Adminhtml\Order\View">
    <plugin name="addMyButton" type="My\Module\Plugin\Block\Adminhtml\Order\View"/>
   </type>

Et puis ceci dans le fichier My \ Module \ Plugin \ Block \ Adminhtml \ Order \ View.php

public function beforeSetLayout(\Magento\Sales\Block\Adminhtml\Order\View $view)
{
    $message ='Are you sure you want to do this?';
    $url = '/mymodule/controller/action/id/' . $view->getOrderId();


    $view->addButton(
        'order_myaction',
        [
            'label' => __('My Action'),
            'class' => 'myclass',
            'onclick' => "confirmSetLocation('{$message}', '{$url}')"
        ]
    );


}
Chris
la source
A fonctionné comme un charme
Raul Sanchez
17

Après avoir essayé de nombreuses façons différentes, c'est la seule solution que j'ai pu trouver qui semble fonctionner sans affecter les autres modules. J'adorerais voir d'autres solutions.

Option 1

Créez un plugin dans Company / Module / etc / adminhtml / di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="Magento\Backend\Block\Widget\Button\Toolbar">
        <plugin name="MagePal_TestBed::pluginBefore" type="MagePal\TestBed\Plugin\PluginBefore" />
    </type>
</config>

Puis dans Plugin / PluginBefore.php

namespace MagePal\TestBed\Plugin;

class PluginBefore
{
    public function beforePushButtons(
        \Magento\Backend\Block\Widget\Button\Toolbar\Interceptor $subject,
        \Magento\Framework\View\Element\AbstractBlock $context,
        \Magento\Backend\Block\Widget\Button\ButtonList $buttonList
    ) {

        $this->_request = $context->getRequest();
        if($this->_request->getFullActionName() == 'sales_order_view'){
              $buttonList->add(
                'mybutton',
                ['label' => __('My Button'), 'onclick' => 'setLocation(window.location.href)', 'class' => 'reset'],
                -1
            );
        }

    }
}

Option 2

Créez un plugin dans Company / Module / etc / adminhtml / di.xml

<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <type name="\Magento\Sales\Block\Adminhtml\Order\View">
        <plugin name="MagePal_TestBed::pluginBeforeView" type="MagePal\TestBed\Plugin\PluginBeforeView" />
    </type>
</config>

Puis dans Plugin / PluginBeforeView.php

namespace MagePal\TestBed\Plugin;

class PluginBeforeView
{

    public function beforeGetOrderId(\Magento\Sales\Block\Adminhtml\Order\View $subject){
        $subject->addButton(
                'mybutton',
                ['label' => __('My Buttion'), 'onclick' => 'setLocation(window.location.href)', 'class' => 'reset'],
                -1
            );

        return null;
    }

}

Voir le code source complet

Renon Stewart
la source
@rs J'ai essayé 2ème option, et il provoque une erreur - Warning: call_user_func_array() expects parameter 2 to be array, object given in D:\new\OpenServer\domains\graffiticaps-m2.loc\vendor\magento\framework\Interception\Interceptor.php on line 144, puisque la méthode __callPlugin () ajoute ce que beforeGetOrderId()méthode renvoie à des arguments de getOrderId()méthode. \ vendor \ magento \ framework \ Interception \ Interceptor.php [ligne 124] - $arguments = $beforeResult;. Je pense donc qu'il doit être renvoyé ailleurs, mais pas d'objet, ce qui signifie $ subject
Kate Suykovskaya
1
Je viens de tester sur Magento 2.0.2 ... Jetez un œil à ma mise à jour pour l'option # 2 .... Voir github.com/magepal/stackexchange/tree/develop/91071
Renon Stewart
Existe-t-il un moyen d'appeler ajax en cliquant sur ce bouton?
nuwaus
@nuwaus ... vous pouvez changer le 'onclick' en 'onclick = "processAjax ()" "puis y ajouter votre fonction ajax ou une autre liaison jquery en un clic
Renon Stewart
voici un problème similaire. magento.stackexchange.com/questions/251458/…
Ajwad Syed
9

Créer un fichier DI app/code/YourVendor/YourModule/etc/di.xml::

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <virtualType name="SalesOrderViewWidgetContext" type="\Magento\Backend\Block\Widget\Context">
        <arguments>
            <argument name="buttonList" xsi:type="object">YourVendor\YourModule\Block\Adminhtml\Order\View\ButtonList
            </argument>
        </arguments>
    </virtualType>
    <type name="Magento\Sales\Block\Adminhtml\Order\View">
        <arguments>
            <argument name="context" xsi:type="object">SalesOrderViewWidgetContext</argument>
        </arguments>
    </type>
</config>

Ce que nous faisons ici, c'est:

  1. Définissez un contextargument personnalisé dans le Order\Viewbloc. Ce contexte est défini comme un type virtuel.
  2. Définissez le type virtuel pour un contexte de widget. Nous définissons un buttonListargument personnalisé avec notre propre classe de liste de boutons.

Implémentez votre classe de liste de boutons:

<?php
namespace YourVendor\YourModule\Block\Adminhtml\Order\View;

class ButtonList extends \Magento\Backend\Block\Widget\Button\ButtonList
{
   public function __construct(\Magento\Backend\Block\Widget\Button\ItemFactory $itemFactory)
   {
       parent::__construct($itemFactory);
       $this->add('mybutton', [
           'label' => __('My button label')
       ]);
   }
}
dan.kocherga
la source
1
Merci pour cette solution! Je pense que c'est le meilleur et le plus élégant.
eInyzant
Cela avait l'air agréable, élégant et facile à comprendre, mais malheureusement cela ne fonctionne pas. Dans Magento 2.3.4 lorsque vous cliquez dans une commande, cela génère une erreurException occurred during order load
Gianni Di Falco
3

C'est l'une des meilleures solutions que j'ai vues jusqu'à présent sans utiliser de plugins

MagePal / CustomButton / view / adminhtml / layout / sales_order_view.xml

<?xml version="1.0"?>
<page xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
    <body>
        <referenceBlock name="sales_order_edit">
            <block class="MagePal\CustomButton\Block\Adminhtml\Order\View\Buttons" name="custom_buttons">
                <action method="addButtons"/>
            </block>
        </referenceBlock>
    </body>
</page>

MagePal / CustomButton / Block / Adminhtml / Order / View / Buttons.php

namespace MagePal\CustomButton\Block\Adminhtml\Order\View;

class Buttons extends \Magento\Sales\Block\Adminhtml\Order\View
{    
    public function __construct(
        \Magento\Backend\Block\Widget\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Sales\Model\Config $salesConfig,
        \Magento\Sales\Helper\Reorder $reorderHelper,
        array $data = []
    ) {
        parent::__construct($context, $registry, $salesConfig, $reorderHelper, $data);
    }

    public function addButtons()
    {
        $parentBlock = $this->getParentBlock();

        if(!$parentBlock instanceof \Magento\Backend\Block\Template || !$parentBlock->getOrderId()) {
            return;
        }

        $buttonUrl = $this->_urlBuilder->getUrl(
            'adminhtml/custombutton/new',
            ['order_id' => $parentBlock->getOrderId()]
        );

        $this->getToolbar()->addChild(
              'create_custom_button',
              \Magento\Backend\Block\Widget\Button::class,
              ['label' => __('Custom Button'), 'onclick' => 'setLocation(\'' . $buttonUrl . '\')']
            );
        }
        return $this;
    }

}
Renon Stewart
la source
Il y a une erreur dans adminhtml_sales_order_view.xmldevrait êtresales_order_view.xml
Zaheerabbas
Il n'y a pas besoin depublic function __construct
Serhii Koval
2

Créer l'emplacement di.xml suivant

app / code / Learning / RewriteSales / etc / di.xml

Le contenu doit être

<? xml version = "1.0"?>
<config xmlns: xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi: noNamespaceSchemaLocation = "urn: magento: framework: ObjectManager / etc / config.xsd">
    <type name = "Magento \ Backend \ Block \ Widget \ Context">
        <plugin name = "add_custom_button_sales_veiw" type = "Learning \ RewriteSales \ Plugin \ Widget \ Context" sortOrder = "1" />
    </type>
</config>

Créer Context.php après la loaction

app / code / Apprentissage / RewriteSales / Plugin / Widget / Context.php

Le contenu doit être

espace de noms Learning \ RewriteSales \ Plugin \ Widget;


Contexte de classe
{
    fonction publique afterGetButtonList (
        \ Magento \ Backend \ Block \ Widget \ Context $ subject,
        $ buttonList
    )
    {
        $ objectManager = \ Magento \ Framework \ App \ ObjectManager :: getInstance ();
        $ request = $ objectManager-> get ('Magento \ Framework \ App \ Action \ Context') -> getRequest ();
        if ($ request-> getFullActionName () == 'sales_order_view') {
            $ buttonList-> add (
                'custom_button',
                [
                    'label' => __ ('Bouton personnalisé'),
                    'onclick' => 'setLocation (\' '. $ this-> getCustomUrl ().' \ ')',
                    'class' => 'bateau'
                ]
            );
        }

        return $ buttonList;
    }

    fonction publique getCustomUrl ()
    {
        $ objectManager = \ Magento \ Framework \ App \ ObjectManager :: getInstance ();
        $ urlManager = $ objectManager-> get ('Magento \ Framework \ Url');
        return $ urlManager-> getUrl ('sales / * / custom');
    }
}

Vider le cache Magento et exécuter la commande de mise à jour

configuration de php bin / magento: mise à niveau
Sohel Rana
la source
Corrigez-moi si je me trompe, mais d'après tous mes tests, le preferencetype est l'équivalent de la réécriture dans magento 1. Par conséquent, un seul module peut en profiter
Renon Stewart
Oui. Mais vous ne pouvez pas créer de plugin pour une fonction protégée.
Sohel Rana
Il suffit de mettre à jour ma réponse en utilisant le plugin
Sohel Rana
1
Au lieu de charger le gestionnaire d'objets, vous auriez pu le faire$subject->getRequest()->getFullActionName()
Renon Stewart
ajoutez ceci avant la fonction afterGetButtonList ....... protected $ urlBuider; fonction publique __construct (\ Magento \ Framework \ UrlInterface $ urlBuilder) {$ this-> urlBuilder = $ urlBuilder; } Ensuite, dans la fonction getCustomUrl (), ajoutez cette ligne uniquement ..... retournez $ this-> urlBuilder-> getUrl ('modulename / controllername / methodname', array ('parameter' => parameter_value));
KA9