Magento 2: cómo agregar un campo personalizado al pago y luego enviarlo

49

Todos los tutoriales solo cubren la adición de campos, pero el valor de guardado de estos archivos se omite #mindblown. No sé por qué, es la parte más importante de agregar cualquier campo o formulario.

Traté de seguir los documentos de Magento , pero ... apesta.

Para fines de prueba, trato de agregar otros campos a la dirección de envío, solo para ignorar los ámbitos personalizados, los conjuntos de datos personalizados, los proveedores de datos personalizados y otras cosas indocumentadas, lo que me parece demasiado extraño.

No tengo idea de qué significa que esa forma es "estática" o "dinámica". Para mí, todos los formularios de pago se construyen dinámicamente sobre las plantillas de KnockoutJS, pero ... cuando trato de forma "estática", puedo agregar entradas aquí (¿es una forma estática o no?).

Primero trato de depurar por qué los observables Knockout simplemente ignoran mis campos durante el análisis y envío de datos. Descubrí que mis campos tienen un nameparámetro vacío , pero no puedo manejar una forma de solucionar este problema. En mi opinión, se debe pasar al procesador de componentes de la interfaz de usuario a través del inputNameparámetro, al igual que cualquier otra opción como disabled, placeholderetc. (otros parámetros funcionan bien, verifiqué la configuración generada desde mi XML para inicializar el módulo de pago y se ve bien para mí)

En segundo lugar, intenté usar la forma "dinámica" con la creación de complementos LayoutProcessory pasar exactamente los mismos datos ... y ahora tengo campos con names, pero el envío aún no funciona en absoluto.

Después de profundizar en JS, descubrí que la preparación de esta solicitud se mantiene en el module-checkout/view/frontend/web/js/model/shipping-save-processor/default.jsarchivo, que depende de module-checkout/view/frontend/web/js/model/quote.jsdónde se definan / creen los observables Knockout.

Actualice de alguna manera module-checkout/view/frontend/web/js/model/address-converter.jsestos observables y depende de module-checkout/view/frontend/web/js/model/new-customer-address.jsdónde finalmente encontré algunas opciones de configuración interesantes: lista de todos los campos de dirección.

Cuando agrego mis campos aquí, los scripts comienzan a analizarlos y enviarlos, OFC obtengo 500, b / c backend no los reconoce ... (no pregunte, no soy un desarrollador de backend)

Entonces aquí vienen mis preguntas:

  • ¿Es una forma correcta de manejar este tipo de personalización? (B / C se ve raro para mí)
  • ¿Cómo enviar valores de campos no relacionados con nuevas direcciones? No vi una configuración similar en ningún lado. En mi caso, me gustaría enviar un comentario de pedido (área de texto) y una solicitud de factura (casilla de verificación). Ambos no deben guardarse como una dirección, porque algunos usuarios pueden querer guardar esta dirección para usarla en el futuro.
  • ¿Existe alguna documentación sobre formas "estáticas" y "dinámicas" o algunos ejemplos / comparación? ¿Vale la pena pensarlo de esta manera?

Pregunta existencial adicional:

  • ¿Por qué esto es tan inconsistente? ¿Por qué tengo que definir toneladas de parámetros en archivos XML / PHP, mientras que Magento solo puede generar una entrada y luego tengo que manejar todo por mi cuenta?
igloczek
fuente
3
Magento Devdocs ha agregado recientemente algunos documentos nuevos sobre el uso de componentes de la interfaz de usuario. En realidad, estamos en el proceso de escribir una guía completamente nueva ... pero aún tenemos mucho camino por recorrer. Eche un vistazo a devdocs.magento.com/guides/v2.1/ui_comp_guide/bk-ui_comps.html . Desafortunadamente, aún no hemos completado los temas sobre las fuentes de datos, que es lo que parece que más necesita. Hay un tema sobre el flujo de configuración que usa Componentes de la interfaz de usuario, que podría ayudar. Trabajaré para encontrar más respuestas.
tanberry
¿Por qué tiene que ser una pesadilla agregar un campo simple en el pago? Simplemente no puedo entender. Y casi todo es tan difícil
slayerbleast
@slayerbleast World está cambiando, la representación del lado del servidor está muriendo. Entonces es diferente, no más difícil sin ningún motivo.
igloczek

Respuestas:

55

Intentaré responder a sus preguntas.

  1. No se . Esta no es una forma correcta de agregar atributos personalizados al formulario de dirección de envío. No necesitas editar new-customer-address.js. De hecho, este archivo JS enumera todos los atributos de dirección predefinidos y coincide con la interfaz de back-end correspondiente, \Magento\Quote\Api\Data\AddressInterfacepero Magento proporciona la capacidad de pasar cualquier atributo personalizado al back-end sin modificar los componentes de back-end / frontend .

    El componente JS mencionado tiene customAttributespropiedad. Sus atributos personalizados se manejarán automáticamente si $dataScopePrefixson ' shippindAddress.custom_attributes'.

  2. Si entendí su pregunta correctamente, tiene datos que no forman parte de la dirección del cliente, pero también debe enviarlos al backend. La respuesta a esta pregunta es:

    Depende . Por ejemplo, puede elegir el siguiente enfoque: agregar un formulario personalizado a la página de pago que incluya todos sus campos adicionales (like comment, invoice request etc) , agregar lógica JS que manejará este formulario en función de algunos eventos y proporcionar un servicio personalizado que recibirá los datos de la interfaz y la tienda en algún lugar para uso futuro.

  3. Toda la documentación oficial relacionada con el pago se encuentra en http://devdocs.magento.com/guides/v2.1/howdoi/checkout/checkout_overview.html . El término estático se refiere a los formularios donde todos los campos ya son conocidos / predefinidos (por ejemplo: el formulario siempre tendrá 2 campos de texto con etiquetas predefinidas) y no puede cambiar en función de algunas configuraciones en el back-end.

    Dichos formularios se pueden declarar usando layout XML configuration. Por otro lado, el término dinámico se refiere a los formularios cuyo conjunto de campos puede cambiar (por ejemplo: el formulario de pago puede tener más / menos campos en función de la configuración).

    En este caso, la única forma de declarar dicho formulario es usar el LayoutProcessorcomplemento.

  4. :) Magento intenta cubrir la mayor cantidad posible de casos de uso que pueden ser significativos para los comerciantes durante el uso / personalización de Magento. A veces esto lleva a una situación en la que algunos casos de uso simples se vuelven más complejos.

Espero que esto ayude.

================================================== =======================

OK ... Vamos a escribir un código;)

  1. Código PHP que inserta un campo adicional en LayoutProcessor

========

/**
 * @author aakimov
 */
$customAttributeCode = 'custom_field';
$customField = [
    'component' => 'Magento_Ui/js/form/element/abstract',
    'config' => [
        // customScope is used to group elements within a single form (e.g. they can be validated separately)
        'customScope' => 'shippingAddress.custom_attributes',
        'customEntry' => null,
        'template' => 'ui/form/field',
        'elementTmpl' => 'ui/form/element/input',
        'tooltip' => [
            'description' => 'Yes, this works. I tested it. Sacrificed my lunch break but verified this approach.',
        ],
    ],
    'dataScope' => 'shippingAddress.custom_attributes' . '.' . $customAttributeCode,
    'label' => 'Custom Attribute',
    'provider' => 'checkoutProvider',
    'sortOrder' => 0,
    'validation' => [
       'required-entry' => true
    ],
    'options' => [],
    'filterBy' => null,
    'customEntry' => null,
    'visible' => true,
];

$jsLayout['components']['checkout']['children']['steps']['children']['shipping-step']['children']['shippingAddress']['children']['shipping-address-fieldset']['children'][$customAttributeCode] = $customField;

return $jsLayout;

Como ya mencioné, esto agregará su campo a la customAttributespropiedad del objeto de dirección JS. Esta propiedad fue diseñada para contener atributos de dirección EAV personalizados y está relacionada con el \Magento\Quote\Model\Quote\Address\CustomAttributeListInterface::getAttributesmétodo.

El código anterior manejará automáticamente la persistencia del almacenamiento local en la interfaz. Puede obtener su valor de campo del almacenamiento local utilizando checkoutData.getShippingAddressFromData()(donde checkoutDataestá Magento_Checkout/js/checkout-data).

  1. Agregue mixin para cambiar el comportamiento de 'Magento_Checkout / js / action / set-shipping-information' (este componente es responsable del envío de datos entre los pasos de envío y facturación)

========

2.1. Crearyour_module_name/view/frontend/requirejs-config.js


/**
 * @author aakimov
 */
var config = {
    config: {
        mixins: {
            'Magento_Checkout/js/action/set-shipping-information': {
                '<your_module_name>/js/action/set-shipping-information-mixin': true
            }
        }
    }
};

2.2. Cree su_nombre_módulo / view / frontend / web / js / action / set-shipping-information-mixin.js


/**
 * @author aakimov
 */
/*jshint browser:true jquery:true*/
/*global alert*/
define([
    'jquery',
    'mage/utils/wrapper',
    'Magento_Checkout/js/model/quote'
], function ($, wrapper, quote) {
    'use strict';

    return function (setShippingInformationAction) {

        return wrapper.wrap(setShippingInformationAction, function (originalAction) {
            var shippingAddress = quote.shippingAddress();
            if (shippingAddress['extension_attributes'] === undefined) {
                shippingAddress['extension_attributes'] = {};
            }

            // you can extract value of extension attribute from any place (in this example I use customAttributes approach)
            shippingAddress['extension_attributes']['custom_field'] = shippingAddress.customAttributes['custom_field'];
            // pass execution to original action ('Magento_Checkout/js/action/set-shipping-information')
            return originalAction();
        });
    };
});
  1. Cree su_nombre_módulo / etc / extension_attributes.xml

========

<?xml version="1.0"?>
<!--
/**
 * @author aakimov
 */
-->
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Api/etc/extension_attributes.xsd">
    <extension_attributes for="Magento\Quote\Api\Data\AddressInterface">
        <attribute code="custom_field" type="string" />
    </extension_attributes>
</config>

Esto agregará un atributo de extensión al modelo de dirección en el lado del backend. Los atributos de extensión son uno de los puntos de extensión que proporciona Magento. Para acceder a sus datos en el backend puede usar:

// Magento will generate interface that includes your custom attribute
$value = $address->getExtensionAttributes()->getCustomField();

Espero que esto ayude y se agregará a la documentación oficial.

aakimov
fuente
Gracias por responder Alex! Lo intenté custom_attributes, pero no me funciona. Así es como se ve parte de LayoutProcessor.php` - gist.github.com/Igloczek/eaf4d2d7a0a04bd950110296ec3f7727 Pero shipping-info o incluso localStorage checkout-datano contiene estos datos en absoluto.
igloczek
Por favor vea mi respuesta actualizada arriba;)
aakimov
44
¡El documento oficial sobre este tema ya está disponible! devdocs.magento.com/guides/v2.1/howdoi/checkout/…
Alex
1
¿Se necesita un paso adicional para guardar los valores en el pedido?
Alex Hadley
Creo que si tiene un formulario estático, es mejor insertar el campo en LayoutProcessor a través de XML como en este ejemplo: devdocs.magento.com/guides/v2.1/howdoi/checkout/…
cjohansson
-1

En mi experiencia, m2 usa xml para definir componentes como campos, etc. Es una ayuda para la depuración, interactiva con datos más fácil. En el campo de front-enders, debe intentar anular las plantillas de pago y agregar sus propios campos personalizados allí. Con KO le ayuda la capacidad de trabajar y vincular datos desde la interfaz y el backend

mrtuvn
fuente
44
Es un consejo incorrecto, las plantillas de pago b / c no contienen y nunca deben contener campos de entrada agregados manualmente. Tenemos que usar KO para representar plantillas en regiones seleccionadas (todo se construye con componentes de la interfaz de usuario)
igloczek
¿Podría compartir un ejemplo de agregar componentes ui de campo personalizado en la interfaz de usuario?
mrtuvn
Como dice @igloczek, es un consejo incorrecto, porque las plantillas de pago nunca deben contener campos de entrada agregados manualmente.
diazwatson 01 de