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

Renon Stewart
fuente

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


}
Chris
fuente
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

Renon Stewart
fuente
@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
Aquí hay un problema similar. magento.stackexchange.com/questions/251458/…
Ajwad Syed
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')
       ]);
   }
}
dan.kocherga
fuente
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;
    }

}
Renon Stewart
fuente
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
Sohel Rana
fuente
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