Cómo agregar un botón personalizado a la vista de orden de venta de administrador en Magento2


12

ingrese la descripción de la imagen aquí

Cómo agregar un botón personalizado a la vista de pedido de ventas en magento2, ya que algunos de los eventos se eliminaron en favor de los complementos.

  • Se eliminaron algunos eventos (los complementos deben usarse en su lugar):
    • adminhtml_widget_container_html_before ( uso en magento 1.x )
    • admin_session_user_logout
    • model_config_data_save_before
    • ...

Ver registro de cambios de Magento2

Respuestas:


18

La solución más limpia que he visto hasta ahora es usar un complemento dirigido a 'beforeSetLayout'

Esto puede apuntar al bloque exacto, guardar la verificación de la solicitud actual y también evita que el complemento esté en 'getOrderId', que en mi caso no se pudo usar, ya que necesitaba llamar a getOrderId en mi método de complemento.

Entonces esto en di.xml

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

Y luego esto en el archivo 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}')"
        ]
    );


}

Trabajó como un encanto
Raul Sanchez

17

Después de probar muchas formas diferentes, esta es la única solución que pude encontrar que parece funcionar sin afectar a otros módulos. Me encantaría ver otras soluciones.

Opción 1

Cree un complemento en Empresa / Módulo / 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>

Luego en 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
            );
        }

    }
}

opcion 2

Cree un complemento en Empresa / Módulo / 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>

Luego en 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;
    }

}

Ver código fuente completo


@rs He intentado la segunda opción y causa un error 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, ya que el método __callPlugin () agrega qué beforeGetOrderId()método regresa a los argumentos del getOrderId()método. \ vendor \ magento \ framework \ Interception \ Interceptor.php [línea 124] - $arguments = $beforeResult;. Así que creo que debe devolverse algo más, pero no un objeto, lo que significa $ subject
Kate Suykovskaya

1
Acabo de probar en Magento 2.0.2 ... Echa un vistazo a mi actualización para la opción # 2 ... Ver github.com/magepal/stackexchange/tree/develop/91071
Renon Stewart

¿Hay alguna forma de llamar a ajax al hacer clic en este botón?
nuwaus

@nuwaus ... podría cambiar 'onclick' a 'onclick = "processAjax ()" "y luego agregar su función ajax allí o alguna otra al hacer clic jquery vinculante
Renon Stewart


9

Crear archivo 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>

Lo que hacemos aquí es:

  1. Establecer contextargumento personalizado en el Order\Viewbloque. Este contexto se define como un tipo virtual.
  2. Definir tipo virtual para un contexto de widget. Establecemos buttonListargumentos personalizados con nuestra propia clase de lista de botones.

Implemente su clase de lista de botones:

<?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')
       ]);
   }
}

1
¡Gracias por esta solución! Creo que este es el mejor y el más elegante.
eInyzant

Esto se veía agradable, elegante y fácil de entender, pero desafortunadamente no funciona. En Magento 2.3.4 al hacer clic en un orden, arroja un errorException occurred during order load
Gianni Di Falco

3

Esta es una de las mejores soluciones que he visto hasta ahora sin usar complementos

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;
    }

}

Hay un error en adminhtml_sales_order_view.xmldebería sersales_order_view.xml
Zaheerabbas

No hay necesidad enpublic function __construct
Serhii Koval

2

Crear di.xml siguiente ubicación

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

El contenido debe ser

<? 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>

Crear Context.php después de la ubicación

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

El contenido debe ser

Aprendizaje del espacio de nombres \ RewriteSales \ Plugin \ Widget;


Contexto de clase
{
    función pública 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' => __ ('Botón personalizado'),
                    'onclick' => 'setLocation (\' '. $ this-> getCustomUrl ().' \ ')',
                    'class' => 'barco'
                ]
            );
        }

        return $ buttonList;
    }

    función pública getCustomUrl ()
    {
        $ objectManager = \ Magento \ Framework \ App \ ObjectManager :: getInstance ();
        $ urlManager = $ objectManager-> get ('Magento \ Framework \ Url');
        return $ urlManager-> getUrl ('ventas / * / personalizado');
    }
}

Borrar el caché de Magento y ejecutar el comando de actualización

Configuración de bin bin / magento: actualización

Corrígeme si estoy equivocado, pero de todas mis pruebas hasta ahora, el preferencetipo es el equivalente a reescribir en magento 1. Por lo tanto, solo un módulo puede aprovecharlo
Renon Stewart

si. Pero no puede crear un complemento para la función protegida.
Sohel Rana

Simplemente actualice mi respuesta usando el complemento
Sohel Rana

1
En lugar de cargar el ObjectManager que podrías haber hecho$subject->getRequest()->getFullActionName()
Renon Stewart

agregue esto antes después de la función GetButtonList ....... protegido $ urlBuider; función pública __construct (\ Magento \ Framework \ UrlInterface $ urlBuilder) {$ this-> urlBuilder = $ urlBuilder; } Luego, en la función getCustomUrl () agregue esta línea solamente ..... devuelva $ this-> urlBuilder-> getUrl ('modulename / controllername / methodname', array ('parámetro' => parámetro_valor));
KA9
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.