Magento 2 - Como adicionar um campo personalizado ao checkout e enviá-lo

49

Todos os tutoriais estão cobrindo apenas a adição de campos, mas o valor de salvamento desses arquivos é ignorado #mindblown. Não sei por que, é a parte mais importante da adição de qualquer campo ou formulário.

Eu tentei seguir os documentos do Magento , mas ... é uma merda.

Para fins de teste, tento adicionar outros campos ao endereço de entrega, apenas para ignorar escopos personalizados, conjuntos de dados personalizados, provedores de dados personalizados e outras coisas não documentadas, o que parece muito estranho para mim.

Não tenho idéia do que significa que o formulário é "estático" ou "dinâmico". Para mim, todos os formulários de checkout são construídos dinamicamente sobre os modelos do KnockoutJS, mas ... quando tento o modo "estático", sou capaz de adicionar entradas aqui (por isso é um formulário estático ou não?).

Primeiro, tento depurar por que os observáveis ​​do Knockout simplesmente ignoram meus campos durante a análise e o envio de dados. Descobri que meus campos têm nameparâmetro vazio , mas não consigo gerenciar uma maneira de corrigir esse problema. Na IMO, ele deve ser passado para o renderizador do componente da interface do usuário por meio de inputNameparâmetro, o mesmo que outras opções disabled, placeholderetc. (outros parâmetros funcionam bem, verifiquei a configuração gerada a partir do meu XML para a inicialização do módulo de checkout e fica bem para mim)

Segundo, tentei usar o modo "dinâmico" com a criação de plug-in LayoutProcessore a transmissão exatamente dos mesmos dados ... e agora tenho campos com names, mas o envio ainda não funciona.

Depois de pesquisar no JS, descobri que a preparação dessa solicitação é mantida em module-checkout/view/frontend/web/js/model/shipping-save-processor/default.jsarquivo, o que depende de module-checkout/view/frontend/web/js/model/quote.jsonde os observáveis ​​do Knockout são definidos / criados.

De alguma forma, module-checkout/view/frontend/web/js/model/address-converter.jsatualizo esses observáveis ​​e depende de module-checkout/view/frontend/web/js/model/new-customer-address.jsonde finalmente encontrei algumas opções interessantes de configuração - lista de todos os campos de endereço.

Quando adiciono meus campos aqui, os scripts começam a analisar e enviá-los, OFC eu recebo 500, o back-end b / c não os reconhece ... (não pergunte, eu não sou um desenvolvedor de back-end)

Então, aqui estão minhas perguntas:

  • É uma maneira correta de lidar com esse tipo de personalização? (b / c parece estranho para mim)
  • Como enviar valores de campos não relacionados a novos endereços? Não vi configuração semelhante em nenhum lugar. No meu caso, gostaria de enviar um comentário do pedido (área de texto) e solicitação de fatura (caixa de seleção). Ambos não devem ser salvos como um endereço, porque alguns usuários podem querer salvar esse endereço para uso futuro.
  • Existe alguma documentação sobre formulários "estáticos" e "dinâmicos" ou alguns exemplos / comparação? Vale a pena pensar dessa maneira?

Pergunta existencial adicional:

  • Por que isso é tão inconsistente? Por que eu tenho que definir vários parâmetros em arquivos XML / PHP, enquanto o Magento pode apenas renderizar uma entrada e então eu tenho que lidar com tudo sozinho?
igloczek
fonte
3
O Magento Devdocs adicionou recentemente alguns novos documentos sobre o uso de componentes da interface do usuário. Na verdade, estamos no processo de escrever um novo guia inteiro ... mas ainda temos um caminho a percorrer. Por favor, dê uma olhada em devdocs.magento.com/guides/v2.1/ui_comp_guide/bk-ui_comps.html . Infelizmente, ainda não concluímos os tópicos sobre fontes de dados, o que parece ser o que você mais precisa. Há um tópico no fluxo de configuração usando os Componentes da UI, que pode ajudar. Vou trabalhar para encontrar mais respostas.
tanberry
Por que tem que ser um pesadelo adicionar um campo simples no checkout? Eu simplesmente não consigo entender. E quase tudo é tão difícil
slayerbleast
@slayerbleast O mundo está mudando, a renderização do lado do servidor está morrendo. Portanto, é diferente, não é mais difícil, sem qualquer motivo.
igloczek

Respostas:

55

Vou tentar responder às suas perguntas.

  1. Não . Esta não é uma maneira correta de adicionar atributos personalizados ao formulário de endereço de entrega. Você não precisa editar new-customer-address.js. De fato, esse arquivo JS lista todos os atributos de endereço predefinidos e corresponde à interface de back-end correspondente, \Magento\Quote\Api\Data\AddressInterfacemas o Magento fornece a capacidade de transmitir quaisquer atributos personalizados para o back-end sem modificação dos componentes de back - end / front-end .

    O componente JS mencionado possui customAttributespropriedade. Seus atributos personalizados serão manipulados automaticamente se eles $dataScopePrefixforem ' shippindAddress.custom_attributes'.

  2. Se entendi sua pergunta corretamente, você tem dados que não fazem parte do endereço do cliente, mas também precisa enviá-los para o back-end. A resposta a esta pergunta é:

    Depende . Por exemplo, você pode escolher a seguinte abordagem: adicione formulário personalizado à página de check-out que inclui todos os seus campos extras (like comment, invoice request etc) , adicione lógica JS que manipulará esse formulário com base em alguns eventos e forneça um serviço personalizado que receberá os dados do front-end e do armazenamento em algum lugar para uso futuro.

  3. Toda a documentação oficial relacionada ao checkout está localizada em http://devdocs.magento.com/guides/v2.1/howdoi/checkout/checkout_overview.html . O termo estático refere-se aos formulários em que todos os campos já são conhecidos / predefinidos (por exemplo: formulário sempre terá 2 campos de texto com rótulos predefinidos) e não podem ser alterados com base em algumas configurações no back-end.

    Tais formulários podem ser declarados usando layout XML configuration. Por outro lado, termo dinâmico refere-se a formulários cujo conjunto de campos pode mudar (por exemplo: o formulário de checkout pode ter mais / menos campos com base nas definições de configuração).

    Nesse caso, a única maneira de declarar esse formulário é usar o LayoutProcessorplugin.

  4. :) O Magento tenta cobrir o maior número possível de casos de uso que possam ser significativos para os comerciantes durante o uso / personalização do Magento possível. Às vezes, isso leva à situação em que alguns casos de uso simples se tornam mais complexos.

Espero que isto ajude.

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

OK ... Vamos escrever algum código;)

  1. Código PHP que insere campo adicional no 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 já mencionei, isso adicionará seu campo à customAttributespropriedade do objeto de endereço JS. Esta propriedade foi projetada para conter atributos de endereço EAV personalizados e está relacionada ao \Magento\Quote\Model\Quote\Address\CustomAttributeListInterface::getAttributesmétodo

O código acima manipulará automaticamente a persistência de armazenamento local no frontend. Você pode obter o valor do seu campo no armazenamento local usando checkoutData.getShippingAddressFromData()(onde checkoutDataestá Magento_Checkout/js/checkout-data).

  1. Adicione mixin para alterar o comportamento de 'Magento_Checkout / js / action / set-shipping-information' (este componente é responsável pelo envio de dados entre as etapas de envio e cobrança do checkout)

========

2.1 Crioyour_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 Crie your_module_name / 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. Crie your_module_name / 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>

Isso adicionará um atributo de extensão ao endereço do modelo no back-end. Os atributos de extensão são um dos pontos de extensão que o Magento fornece. Para acessar seus dados no back-end, você pode usar:

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

Espero que isso ajude e será adicionado à documentação oficial.

aakimov
fonte
Obrigado pela resposta Alex! Eu tentei do custom_attributesjeito, mas não funciona para mim. É assim que parte do LayoutProcessor.php` se parece - gist.github.com/Igloczek/eaf4d2d7a0a04bd950110296ec3f7727 Mas shipping-info ou mesmo localStorage checkout-datanão contém esses dados.
igloczek
Por favor, veja minha resposta atualizada acima;)
aakimov 16/16
4
O documento oficial sobre este tópico já está disponível! devdocs.magento.com/guides/v2.1/howdoi/checkout/…
Alex
11
Existe uma etapa extra necessária para que os valores sejam salvos no pedido?
Alex Hadley
Eu acho que se você tiver um formulário estático, é melhor inserir um campo no LayoutProcessor via XML, como neste exemplo: devdocs.magento.com/guides/v2.1/howdoi/checkout/…
cjohansson
-1

Na minha experiência, o m2 usa xml para definir componentes como campos, etc. É uma ajuda para depuração, interativa com os dados mais fácil. No campo de front-end, você deve tentar substituir os modelos de check-out e adicionar seus próprios campos personalizados. Com o KO, você pode trabalhar e vincular dados de front-end e back-end

mrtuvn
fonte
4
É um conselho errado, os modelos de check-out b / c não contêm e nunca devem conter campos de entrada adicionados manualmente. Temos que usar KO para tornar modelos em regiões selecionadas (tudo é edificada usando componentes de UI)
igloczek
Você poderia compartilhar um exemplo de adicionar componentes de interface do usuário de campo personalizado no front-end?
mrtuvn 13/09/16
Como @igloczek diz: é um conselho errado, porque os modelos de checkout nunca devem conter campos de entrada adicionados manualmente.
Diazwatson #