Magento2 | PWA | GraphQL

Add Cash Date for Cash on delivery payment method Magento2


In this post we wiil check how to add cash date when cashondelivery payment method is selected in checkout page Magento2.

Let's start by creating custom module.

You can find complete module on Github at Magelearn_CashDate




Create folder inside app/code/Magelearn/CashDate

Add registration.php file in it:

<?php
\Magento\Framework\Component\ComponentRegistrar::register(
    \Magento\Framework\Component\ComponentRegistrar::MODULE,
    'Magelearn_CashDate',
    __DIR__
);

Add composer.json file in it:

{
    "name": "magelearn/module-cash-date",
    "description": "Add cash date for cash on delivery payment method. Add date-time field on checkout page only when cash on delivery payment method selected.",
    "type": "magento2-module",
    "require": {},
    "authors": [
        {
            "name": "vijay rami",
            "email": "vijaymrami@gmail.com"
        }
    ],
    "license": "proprietary",
    "minimum-stability": "dev",
    "autoload": {
        "files": [
            "registration.php"
        ],
        "psr-4": {
            "Magelearn\\CashDate\\": ""
        }
    }
}

Add etc/module.xml file in it:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
    <module name="Magelearn_CashDate" setup_version="1.0.0">
        <sequence>
            <module name="Magento_OfflinePayment"/>
            <module name="Magento_Checkout"/>
            <module name="Magento_Quote"/>
        </sequence>
    </module>
</config>

We will add some basic configuration by giving system configuration options to display cash date or not.

Add etc/adminhtml/system.xml file.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Config:etc/system_file.xsd">
    <system>
        <section id="magelearn_cashdate" translate="label" type="text" sortOrder="1300" showInDefault="1" showInWebsite="1" showInStore="1">
            <label>Cash on Delivery Date Settings</label>
            <tab>sales</tab>
            <resource>Magelearn_CashDate::cashdate</resource>
            <group id="general" type="text"  sortOrder="10" showInDefault="1" showInWebsite="1" showInStore="1">
                <label>Extension Settings</label>
                <field id="required_cash_date" translate="label" type="select" sortOrder="40" showInDefault="1" showInWebsite="1" showInStore="1" canRestore="1">
                    <label>Required Cash Date</label>
                    <source_model>Magento\Config\Model\Config\Source\Yesno</source_model>
                </field>
            </group>
        </section>
    </system>
</config>

Add etc/config.xml file.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Store:etc/config.xsd">
    <default>
        <magelearn_cashdate>
            <general>
                <required_cash_date>1</required_cash_date>
            </general>
        </magelearn_cashdate>
    </default>
</config>

Now add etc/frontend/di.xml file to add additional variables in window.checkoutConfig for frontend.

<?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\Checkout\Model\CompositeConfigProvider">
        <arguments>
            <argument name="configProviders" xsi:type="array">
                <item name="cash_date_config_provider" xsi:type="object">Magelearn\CashDate\Model\CashDateConfigProvider</item>
            </argument>
        </arguments>
 	</type>
</config>

Now add Magelearn/CashDate/Model/CashDateConfigProvider.php file.

<?php
 
namespace Magelearn\CashDate\Model;
 
use Magento\Checkout\Model\ConfigProviderInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Store\Model\ScopeInterface;
use Magento\Authorization\Model\UserContextInterface;
 
class CashDateConfigProvider implements ConfigProviderInterface
{
    /**
     *  Config Paths
     */
    const XPATH_REQUIRED_CASH_DATE  = 'magelearn_cashdate/general/required_cash_date';
	
	/**
     * @var \Magento\Authorization\Model\UserContextInterface
     */
    private $userContext;
	
	 /**
     * @var \Magento\Framework\App\Action\Context
     */
    private $context;
	
    /**
     * @var ScopeConfigInterface
     */
    private $scopeConfig;
 
    /**
     * @param ScopeConfigInterface $scopeConfig
     */
    public function __construct(
    	UserContextInterface $userContext,
    	\Magento\Checkout\Model\Session $session,
        ScopeConfigInterface $scopeConfig
    )
    {
    	$this->userContext = $userContext;
        $this->scopeConfig = $scopeConfig;
        $this->session = $session;
    }
 
    public function isCashDateRequired()
    {
        return $this->scopeConfig->getValue(
            self::XPATH_REQUIRED_CASH_DATE,
            ScopeInterface::SCOPE_STORE
        );
    }
	
    public function getConfig()
    {
        $show_cash_date = $this->isCashDateRequired();
        return [
            'show_cash_date' => $show_cash_date
        ];
    }
}

Here first we will check how to display delivery_date on frontend checkouot page when cash on delivery payment method is selected.

For that, first we will add requirejs-config.js file and override Magento_OfflinePayments/js/view/payment/method-renderer/cashondelivery-method.js 

We will call our custom html file and add our custom form file to display delivery date with calender datepicker option.

Add Magelearn/CashDate/view/frontend/requirejs-config.js file.

var config = {
    "map": {
        '*': {
            'Magento_OfflinePayments/js/view/payment/method-renderer/cashondelivery-method':
                'Magelearn_CashDate/js/payment/method-renderer/cashondelivery-method'
        }
    }
};

Add Magelearn/CashDate/view/frontend/web/js/payment/method-renderer/cashondelivery-method.js

/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */

/* @api */
define([
    'Magento_Checkout/js/view/payment/default',
    'jquery',
    'mage/validation'
], function (Component,$) {
    'use strict';
    return Component.extend({
        defaults: {
            template: 'Magelearn_CashDate/payment/cashondelivery',
            cashDate:''
        },

        /**
         * Returns payment method instructions.
         *
         * @return {*}
         */
        getInstructions: function () {
            return window.checkoutConfig.payment.instructions[this.item.method];
        },
        showCashDate: function () {
            return window.checkoutConfig.show_cash_date;
        },
        /** @inheritdoc */
        initObservable: function () {
            this._super()
                .observe('cashDate');

            return this;
        },

        /**
         * @return {Object}
         */
        getData: function () {
            console.log(this.cashDate());
            return {
                method: this.item.method,
                /*'cash_date': this.cashDate(),*/
                'additional_data': {
                    'cash_date':this.cashDate()
                }
            };
        },

        /**
         * @return {jQuery}
         */
        validate: function () {
            var form = 'form[data-role=cashondelivery-form]';

            return $(form).validation() && $(form).validation('isValid');
        }
    });
});

Copy file from vendor/magento/module-offline-payments/view/frontend/web/template/payment/cashondelivery.html and add it at Magelearn/CashDate/view/frontend/web/template/payment/cashondelivery.html file.

<!--
/**
 * Copyright © Magento, Inc. All rights reserved.
 * See COPYING.txt for license details.
 */
-->
<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">
        <!-- ko foreach: getRegion('messages') -->
        <!-- ko template: getTemplate() --><!-- /ko -->
        <!--/ko-->
        <div class="cashondelivery-date" data-bind="attr: {'id': getCode() + '-form'}">
        	<!-- ko if: showCashDate() == true -->
            <!-- ko template: 'Magelearn_CashDate/payment/form' --><!-- /ko -->
            <!-- /ko -->
        </div>
        <div class="payment-method-billing-address">
            <!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) -->
            <!-- ko template: getTemplate() --><!-- /ko -->
            <!--/ko-->
        </div>
        <p data-bind="html: getInstructions()"></p>
        <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>

As per highlighted code above add Magelearn/CashDate/view/frontend/web/template/payment/form.html file.

<form id="cashondelivery-form" class="form form-cashondelivery-order" data-role="cashondelivery-form">
    <fieldset class="fieldset payment method" data-bind='attr: {id: "payment_form_" + getCode()}'>
        <div class="field field-number required">
            <label for="cash_date" class="label">
                <span>Checkout Date</span>
            </label>
            <div class="control">
                <input type="datetime-local"
                       id="cash_date"
                       name="payment[cash_date]"
                       data-validate="{required:true}"
                       data-bind='
                                attr: {title: $t("Checkout Date")},
                                value: cashDate'
                       class="input-text"/>
            </div>
        </div>
    </fieldset>
</form>

After adding above files, cash date will be display on checkout payment page when "cashondelivery" payment mathod selected.

Now add etc/di.xml file.

Here we will override Magento\OfflinePayments\Model\Cashondelivery and write our custom logic to call own module file. Also add plugin to add Additional Information about cash_date for Cash on delivery payment method.

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd">
    <preference for="Magento\OfflinePayments\Model\Cashondelivery" type="Magelearn\CashDate\Model\Cash" />
    <type name="Magento\Quote\Model\Quote\Payment">
        <plugin name="quotePayment" type="Magelearn\CashDate\Plugin\QuotePaymentPlugin"/>
    </type>
</config>

Now add app/code/Magelearn/CashDate/Plugin/QuotePaymentPlugin.php file.

<?php

namespace Magelearn\CashDate\Plugin;

class QuotePaymentPlugin{

    /**
     * Import data array to payment method object,
     * Method calls quote totals collect because payment method availability
     * can be related to quote totals
	 * 
     * @param \Magento\Quote\Model\Quote\Payment $subject
     * @param array $data
     * @return array
     */
    public function beforeImportData(\Magento\Quote\Model\Quote\Payment $subject, array $data){
        if (array_key_exists('additional_data', $data)) {
            $subject->setAdditionalInformation('cash_date',$data['additional_data']['cash_date']);
            $subject->setData('cash_date',$data['additional_data']['cash_date']);
			$subject->setAdditionalData(NULL);
        }
        return [$data];
    }

}

Now add app/code/Magelearn/CashDate/Model/Cash.php file.

<?php

namespace Magelearn\CashDate\Model;

/**
* Cash on delivery payment method model
*
 * @method \Magento\Quote\Api\Data\PaymentMethodExtensionInterface getExtensionAttributes()
*
 * @api
* @since 100.0.2
*/

class Cash  extends \Magento\Payment\Model\Method\AbstractMethod
{
    const PAYMENT_METHOD_CASHONDELIVERY_CODE = 'cashondelivery';

    /**
     * Payment method code
     *
     * @var string
     */
    protected $_code = self::PAYMENT_METHOD_CASHONDELIVERY_CODE;

    /**
     * Cash On Delivery payment block paths
     *
     * @var string
     */
    protected $_formBlockType = \Magento\OfflinePayments\Block\Form\Cash::class;

    /**
     * Info  block path
     *
     * @var string
     */
    protected $_infoBlockType = \Magelearn\CashDate\Block\Info\Cashondelivery::class;

    /**
     * Availability option
     *
     * @var bool
     */
    protected $_isOffline = true;

    /**
     * Get instructions text from config
     *
     * @return string
     */

    public function getInstructions(){
        return trim($this->getConfigData('instructions'));
    }

}

In above file we have override Magento\OfflinePayments\Model\Cashondelivery file and as per highlighted code, we have override Info block path \Magento\Payment\Block\Info\Instructions class with our custom module block path \Magelearn\CashDate\Block\Info\Cashondelivery.

For that we will add app/code/Magelearn/CashDate/Block/Info/Cashondelivery.php file.

<?php

namespace Magelearn\CashDate\Block\Info;

class Cashondelivery extends \Magento\Payment\Block\Info
{
	/**
     * Payment rendered specific information
     *
     * @var \Magento\Framework\DataObject
     */
    protected $_paymentSpecificInformation;
	/**
     * Instructions text
     *
     * @var string
     */
    protected $_instructions;
    /**
     * @var string
     */
    protected $_cashDate;


    protected $_template = 'Magelearn_CashDate::info/cashondelivery.phtml';
	
	/**
     * Get instructions text from order payment
     * (or from config, if instructions are missed in payment)
     *
     * @return string
     */
    public function getInstructions()
    {
        if ($this->_instructions === null) {
            $this->_instructions = $this->getInfo()->getAdditionalInformation(
                'instructions'
            ) ?: trim($this->getMethod()->getConfigData('instructions'));
        }
        return $this->_instructions;
    }
	
    /**
     * Enter description here...
     *
     * @return string
     */
    public function getCashDate()
    {
        if ($this->_cashDate === null) {
            $this->_convertAdditionalData();
           // $this->_cashDate=$this->getInfo()->getCashDate();
        }
        return $this->_cashDate;
    }

    protected function _convertAdditionalData(){

        $this->_cashDate = $this->getInfo()->getAdditionalInformation('cash_date');
        return $this;
    }
	/**
     * Retrieve info model
     *
     * @return \Magento\Payment\Model\InfoInterface
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function getInfo()
    {
        $info = $this->getData('info');
        if (!$info instanceof \Magento\Payment\Model\InfoInterface) {
            throw new \Magento\Framework\Exception\LocalizedException(
                __('We cannot retrieve the payment info model object.')
            );
        }
        return $info;
    }

    /**
     * Retrieve payment method model
     *
     * @return \Magento\Payment\Model\MethodInterface
     */
    public function getMethod()
    {
        return $this->getInfo()->getMethodInstance();
    }
    /**
     * @return string
     */
    public function toPdf()
    {
        $this->setTemplate('Magelearn_CashDate::info/pdf/cashondelivery.phtml');
        return $this->toHtml();
    }
	/**
     * Getter for children PDF, as array. Analogue of $this->getChildHtml()
     *
     * Children must have toPdf() callable
     * Known issue: not sorted
     * @return array
     */
    public function getChildPdfAsArray()
    {
        $result = [];
        foreach ($this->getLayout()->getChildBlocks($this->getNameInLayout()) as $child) {
            if (method_exists($child, 'toPdf') && is_callable([$child, 'toPdf'])) {
                $result[] = $child->toPdf();
            }
        }
        return $result;
    }

    /**
     * Get some specific information in format of array($label => $value)
     *
     * @return array
     */
    public function getSpecificInformation()
    {
        return $this->_prepareSpecificInformation()->getData();
    }

    /**
     * Render the value as an array
     *
     * @param mixed $value
     * @param bool $escapeHtml
     * @return array
     */
    public function getValueAsArray($value, $escapeHtml = false)
    {
        if (empty($value)) {
            return [];
        }
        if (!is_array($value)) {
            $value = [$value];
        }
        if ($escapeHtml) {
            foreach ($value as $_key => $_val) {
                $value[$_key] = $this->escapeHtml($_val);
            }
        }
        return $value;
    }

    /**
     * Prepare information specific to current payment method
     *
     * @param null|\Magento\Framework\DataObject|array $transport
     * @return \Magento\Framework\DataObject
     */
    protected function _prepareSpecificInformation($transport = null)
    {
        if (null === $this->_paymentSpecificInformation) {
            if (null === $transport) {
                $transport = new \Magento\Framework\DataObject();
            } elseif (is_array($transport)) {
                $transport = new \Magento\Framework\DataObject($transport);
            }
            $this->_paymentSpecificInformation = $transport;
        }
        return $this->_paymentSpecificInformation;
    }
}

In above file, we have added some necessary function from magento/module-payment/Block/Info/Instructions.php file as well as magento/module-payment/Block/Info.php file.

As per highlighted code in above file, we will add Magelearn/CashDate/view/frontend/templates/info/cashondelivery.phtml file.

<?php
/**
 * @var $block \Magelearn\CashDate\Block\Info\Cashondelivery
 */
?>
<dl class="payment-method cashondelivery">
    <dt class="title"><?= $block->escapeHtml($block->getMethod()->getTitle()) ?></dt>
    <?php if ($block->getCashDate()): ?>
        <dd class="content">
            <b><?= $block->escapeHtml(__('Checkout Date')) ?></b>
            <?= $block->escapeHtml($block->getCashDate()) ?>
        </dd>
    <?php endif; ?>
    <?php if ($block->getInstructions()) : ?>
	    <dd class="content"><?= /* @noEscape */ nl2br($block->escapeHtml($block->getInstructions())) ?></dd>
	<?php endif; ?>
</dl>

We will also same file for adminhtml at Magelearn/CashDate/view/adminhtml/templates/info/cashondelivery.phtml

<?php

/**
* @var $block \Magelearn\CashDate\Block\Info\Cashondelivery
*/
?>
<?= $block->escapeHtml($block->getMethod()->getTitle()) ?>
<?php if ($block->getInstructions()) : ?>
    <table>
        <tbody>
            <tr>
                <td>
                	<?= /* @noEscape */ nl2br($block->escapeHtml($block->getInstructions())) ?>
                	<?php if ($block->getCashDate()): ?>
					    <br /><?= $block->escapeHtml(__('Checkout Date: ')) ?>
					    <?= $block->escapeHtml($block->getCashDate()) ?>
					<?php endif; ?>
                </td>
            </tr>
        </tbody>
    </table>
<?php endif; ?>

And Magelearn/CashDate/view/adminhtml/templates/info/pdf/cashondelivery.phtml file.

<?php
/**
 * @var $block \Magelearn\CashDate\Block\Info\Cashondelivery
 */
?>
<?= $block->escapeHtml($block->getMethod()->getTitle()) ?>{{pdf_row_separator}}
<?php if ($block->getCashDate()): ?>
    <?= $block->escapeHtml(__('Checkout Date: ')) ?>
    <?= $block->escapeHtml($block->getCashDate()) ?>
    {{pdf_row_separator}}
<?php endif; ?>
<?php if ($block->getInstructions()): ?>
	<?= /* @noEscape */ nl2br($block->escapeHtml($block->getInstructions())) ?>
	{{pdf_row_separator}}
<?php endif; ?>
<?php if ($specificInfo = $block->getSpecificInformation()) : ?>
    <?php foreach ($specificInfo as $label => $value) : ?>
        <?= $block->escapeHtml($label) ?>:
        <?= $block->escapeHtml(implode(' ', $block->getValueAsArray($value))) ?>
        {{pdf_row_separator}}
    <?php endforeach; ?>
<?php endif;?>

<?= $block->escapeHtml(implode('{{pdf_row_separator}}', $block->getChildPdfAsArray())) ?>

After adding above files, cash date information will be display on order view page at front end and also in admin.

You can check your Database's quote_payment and sales_order_payment tables. That cash_date information will be available in additional_information column.

It will also display on order mail template (all mail template) and in print PDF (for all PDFs).

0 Comments On "Add Cash Date for Cash on delivery payment method Magento2 "

Back To Top