2

I am using stripe payment method, I want to add billing zip filed in cc form.
How can I add this field??

  • getting error on this line $paymentData = $inputParam->getData('additional_data'); – 3434 Feb 15 at 13:07
2

Save Payment Method with additional Data (show custom field on payment check)

First create your schema file inside Ibnab/Additional/Setup/InstallSchema.php :

<?php
namespace Ibnab\Additional\Setup;
use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;
class InstallSchema implements InstallSchemaInterface
{
    public function install(SchemaSetupInterface $setup, ModuleContextInterface $context)
    {
        $setup->startSetup();   
        $setup->getConnection()->addColumn(
            $setup->getTable('quote_payment'),
            'bankowner',
            [
                'type' => 'text',
                'nullable' => true  ,
                'comment' => 'Bank',
            ]
        );
        $setup->getConnection()->addColumn(
            $setup->getTable('sales_order_payment'),
            'bankowner',
            [
                'type' => 'text',
                'nullable' => true  ,
                'comment' => 'Bank',
            ]
        );
        $setup->endSetup();
  }
}

We will add this behavior on bank transfert methode , ok let's remap offline-payments٫js inside Ibnab/Additional/view/frontend/requirejs-config.js :

 var config = {
    map: {
        '*': {
          'Magento_OfflinePayments/js/view/payment/offline-payments':       'Ibnab_Additional/js/view/payment/offline-payments',
        }
    }
}

now you need copy the original file from magento vendor and pas in your module with some change (Ibnab/Additional/view/frontend/web/js/view/payment/offline-payments.js):

define(
    [
        'uiComponent',
        'Magento_Checkout/js/model/payment/renderer-list'
    ],
    function (
        Component,
        rendererList
    ) {
        'use strict';
        rendererList.push(
            {
                type: 'checkmo',
                component: 'Magento_OfflinePayments/js/view/payment/method-renderer/checkmo-method'
            },
            {
                type: 'banktransfer',
                component: 'Ibnab_Additional/js/view/payment/method-renderer/banktransfer-method'
            },
            {
                type: 'cashondelivery',
                component: 'Magento_OfflinePayments/js/view/payment/method-renderer/cashondelivery-method'
            },
            {
                type: 'purchaseorder',
                component: 'Magento_OfflinePayments/js/view/payment/method-renderer/purchaseorder-method'
            }
        );
        /** Add view logic here if needed */
        return Component.extend({});
    }
);

we have changed the banktransfert renderer :

  {
            type: 'banktransfer',
            component: 'Ibnab_Additional/js/view/payment/method-renderer/banktransfer-method'
  }

and create other one from original file in vendor (Ibnab/Additional/view/frontend/web/js/view/payment/method-renderer/banktransfer-method.js) :

 define(
     [
         'ko',
         'Magento_Checkout/js/view/payment/default',
         'jquery'
     ],
     function (ko, Component,$) {
         'use strict';
         return Component.extend({
             defaults: {
                 template: 'Ibnab_Additional/payment/banktransfer'
             },
             getData: function() {
                 return {
                     'method': this.item.method,
                     'additional_data': {
                         'bankowner': $('#banktransfer_bankowner').val()
                     }
                 };
             },
             /**
              * Get value of instruction field.
              * @returns {String}
              */
             getInstructions: function () {
                 return window.checkoutConfig.payment.instructions[this.item.method];
             }
         });
     }
 );

In the banktransfer-method.js we have changed the path to our new html template (Ibnab/Additional/view/frontend/web/template/payment/banktransfer.html) :

defaults: {
            template: 'Ibnab_Additional/payment/banktransfer'
        }

And we have added the value of bank account owner to additional data bu using the id :

getData: function() {
            return {
                'method': this.item.method,
                'additional_data': {
                    'bankowner': $('#banktransfer_bankowner').val()
                }
            };
        }

And that is the code of our html template (the original code is inside vendor) :

<div class="payment-method" data-bind="css: {'_active': (getCode() == isChecked())}">
<div class="payment-method-title field choice">
    <input type="radio"
           name="payment[method]"
           class="radio"
           data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()" />
    <label data-bind="attr: {'for': getCode()}" class="label"><span data-bind="text: getTitle()"></span></label>
</div>
<div class="payment-method-content">
<p data-bind="html: getInstructions()"></p>
<fieldset data-bind="attr: {class: 'fieldset payment items allbank ' + getCode(), id: 'payment_form_' + getCode()}">
<div class="field _required">
    <label data-bind="attr: {for: getCode() + '_bankowner'}" class="label">
        <span><!-- ko i18n: 'Account Owner'--><!-- /ko --></span>
    </label>
    <div class="control">
        <input data-validate="{'required-entry':true}" type="text" name="payment[bankowner]" class="input-text" value=""
               data-bind="attr: {
                                id: getCode() + '_bankowner',
                                title: $t('Account Owner'),
                                'data-container': getCode() + '-bankowner',
                                'data-validate': JSON.stringify({'required':true})},
                                valueUpdate: 'keyup' "/>
    </div>
</div>
</fieldset>
    <!-- ko foreach: getRegion('messages') -->
    <!-- ko template: getTemplate() --><!-- /ko -->
    <!--/ko-->
    <div class="payment-method-billing-address">
        <!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->
    </div>      
    <div class="checkout-agreements-block">
        <!-- ko foreach: $parent.getRegion('before-place-order') -->
            <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->
    </div>
    <div class="actions-toolbar">
        <div class="primary">
            <button class="action primary checkout"
                    type="submit"
                    data-bind="
                    click: placeOrder,
                    attr: {'title': $t('Place Order')},
                    enable: (getCode() == isChecked()),
                    css: {disabled: !isPlaceOrderActionAllowed()}
                    "
                    disabled>
                <span data-bind="i18n: 'Place Order'"></span>
            </button>
        </div>
    </div>
 </div>
 </div>

Our custom input text is with name name="payment[bankowner]" :

<fieldset data-bind="attr: {class: 'fieldset payment items allbank ' + getCode(), id: 'payment_form_' + getCode()}">
    <div class="field _required">
        <label data-bind="attr: {for: getCode() + '_bankowner'}" class="label">
            <span><!-- ko i18n: 'Account Owner'--><!-- /ko --></span>
        </label>
        <div class="control">
            <input data-validate="{'required-entry':true}" type="text" name="payment[bankowner]" class="input-text" value=""
                   data-bind="attr: {
                                    id: getCode() + '_bankowner',
                                    title: $t('Account Owner'),
                                    'data-container': getCode() + '-bankowner',
                                    'data-validate': JSON.stringify({'required':true})},
                                    valueUpdate: 'keyup' "/>
      </div>
    </div>
    </fieldset>

Now is the time to add observer (Ibnab/Additional/etc/events.xml):

    <?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd">
    <event name="sales_order_payment_save_before">
        <observer name="save_bank_infos" instance="Ibnab\Additional\Observer\SaveBankInfoToOrderObserver"/>
    </event>
</config>

is very clear the system will declanche this event on before order payment save (Ibnab/Additional/Observer/SaveBankInfoToOrderObserver.php) :

    <?php
namespace Ibnab\Additional\Observer;
use Magento\Framework\Event\Observer as EventObserver;
use Magento\Framework\Event\ObserverInterface;
use Magento\OfflinePayments\Model\Banktransfer;
class SaveBankInfoToOrderObserver implements ObserverInterface {
    protected $_inputParamsResolver;
    protected $_quoteRepository;
    protected $logger;
    protected $_state;
    public function __construct(\Magento\Webapi\Controller\Rest\InputParamsResolver $inputParamsResolver, \Magento\Quote\Model\QuoteRepository $quoteRepository, \Psr\Log\LoggerInterface $logger,\Magento\Framework\App\State $state) {
        $this->_inputParamsResolver = $inputParamsResolver;
        $this->_quoteRepository = $quoteRepository;
        $this->logger = $logger;
        $this->_state = $state;
    }
    public function execute(EventObserver $observer) {
        $inputParams = $this->_inputParamsResolver->resolve();
        if($this->_state->getAreaCode() != \Magento\Framework\App\Area::AREA_ADMINHTML){
        foreach ($inputParams as $inputParam) {
            if ($inputParam instanceof \Magento\Quote\Model\Quote\Payment) {
                $paymentData = $inputParam->getData('additional_data');
                $paymentOrder = $observer->getEvent()->getPayment();
                $order = $paymentOrder->getOrder();
                $quote = $this->_quoteRepository->get($order->getQuoteId());
                $paymentQuote = $quote->getPayment();
                $method = $paymentQuote->getMethodInstance()->getCode();
                if ($method == Banktransfer::PAYMENT_METHOD_BANKTRANSFER_CODE) {
                    if(isset($paymentData['bankowner'])){
                    $paymentQuote->setData('bankowner', $paymentData['bankowner']);
                    $paymentOrder->setData('bankowner', $paymentData['bankowner']);
                    }
                }
            }
        }
       }
    }
}

We have use one way to get value of our input text from additional data of payment quote with inputParamsResolver :

$inputParams = $this->_inputParamsResolver->resolve();

we have use foreach clause the extract the value and push inside payment qoute and payment order. So now if you create an order the value of your custom field will be saved in column bankowner of quote_payment and sales_order_payment table . But how you can show it in order view (inside admin) , you can add layout (Ibnab/Additional/view/adminhtml/layout/sales_order_view.xml) and push :

    <?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>
        <referenceContainer name="payment_additional_info">
            <block class="Ibnab\Additional\Block\Info\BanktransferInfo" name="ibnab_banktransfert_infos" template="Ibnab_Additional::info/banktransferinfo.phtml" />
        </referenceContainer>
    </body>
</page>

Now create you .phtml (Ibnab/Additional/view/adminhtml/templates/info/banktransferinfo.phtml):

    <?php
use Magento\OfflinePayments\Model\Banktransfer;
$payment = $block->getOrder()->getPayment();
$method = $payment->getMethodInstance()->getCode();
?>
<?php if ($method == Banktransfer::PAYMENT_METHOD_BANKTRANSFER_CODE) :?>
<div class="admin__page-section-item-content">
    <strong><?php echo __('Account Name:') ?></strong>
    <span class="price"><?php echo $payment->getData('bankowner'); ?></span>                        
</div>
<?php endif; ?>

we will show the account now just if bank transfert method :

<?php if ($method == Banktransfer::PAYMENT_METHOD_BANKTRANSFER_CODE) :?>

This is one of the example of adding custom field in payment method. I hope this will help

  • Do we also need to add the node in checkout_index_index.xml? If yes could you share that as well – Abhishek Mar 25 at 14:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.