| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
11 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -56,5 +56,8 @@ pages: | |||
| 56 | 56 | - label: Customize the list of shipping methods | |
| 57 | 57 | url: /howdoi/checkout/checkout_shipping_methods.html | |
| 58 | 58 | ||
| 59 | + - label: Add a custom field for an offline payment method | ||
| 60 | + url: /howdoi/checkout/checkout_payment_new_field.html | ||
| 61 | + | ||
| 59 | 62 | - label: Customize the Admin design | |
| 60 | 63 | url: /howdoi/admin/customize_admin.html | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -54,12 +54,6 @@ To add your SSH key to the local configuration: | |||
| 54 | 54 | {:.bs-callout-info} | |
| 55 | 55 | You can specify multiple SSH keys by adding multiple `IdentityFile` entries to your configuration. | |
| 56 | 56 | ||
| 57 | - 1. Reload your SSH configuration to apply the changes. | ||
| 58 | - | ||
| 59 | - ```bash | ||
| 60 | - source ~/.ssh/config | ||
| 61 | - ``` | ||
| 62 | - | ||
| 63 | 57 | {:.ref-header} | |
| 64 | 58 | Next step | |
| 65 | 59 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -33,7 +33,7 @@ Edge ACLs create IP address lists for managing access to your site. In this exam | |||
| 33 | 33 | ||
| 34 | 34 | 1. Click **Stores** > Settings > **Configuration** > **Advanced** > **System**. | |
| 35 | 35 | ||
| 36 | - 1. Expand **Full Page Cache** > **Fastly Configuration** > **ACL**. | ||
| 36 | + 1. Expand **Full Page Cache** > **Fastly Configuration** > **Edge ACL**. | ||
| 37 | 37 | ||
| 38 | 38 | 1. Create the ACL container: | |
| 39 | 39 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -39,3 +39,4 @@ You can customize the default checkout in multiple ways. This tutorial includes | |||
| 39 | 39 | - [Add a new input form to checkout]({{ page.baseurl }}/howdoi/checkout/checkout_form.html) | |
| 40 | 40 | - [Add a new field in address form]({{ page.baseurl }}/howdoi/checkout/checkout_new_field.html) | |
| 41 | 41 | - [Add custom shipping address renderer]({{ page.baseurl }}/howdoi/checkout/checkout_address.html) | |
| 42 | + - [Add a custom field for an offline payment method]({{ page.baseurl }}/howdoi/checkout/checkout_payment_new_field.html) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,362 @@ | |||
| 1 | + --- | ||
| 2 | + layout: tutorial | ||
| 3 | + group: how-do-i | ||
| 4 | + subgroup: | ||
| 5 | + title: Add a custom field for an offline payment method | ||
| 6 | + contributor_name: Ziffity | ||
| 7 | + contributor_link: https://www.ziffity.com/ | ||
| 8 | + subtitle: Customize Checkout | ||
| 9 | + menu_order: 101 | ||
| 10 | + level3_subgroup: checkout-tutorial | ||
| 11 | + functional_areas: | ||
| 12 | + - Checkout | ||
| 13 | + --- | ||
| 14 | + | ||
| 15 | + This topic describes how to add a custom field to an offline payment method in the payment step of the checkout. The custom field allows the buyer to enter a comment about a purchase order. | ||
| 16 | + | ||
| 17 | + ## Prerequisites | ||
| 18 | + | ||
| 19 | + {:.bs-callout-info} | ||
| 20 | + The `Purchase Order` payment method must be enabled in the storefront for this task. Ensure this payment method is enabled by navigating to **Stores** > **Settings** > **Configuration** > **Sales** > **Payment Methods** > **Other Payment Methods** > **Purchase Order** in the Admin. | ||
| 21 | + | ||
| 22 | + You must perform following steps to add a custom field to an offline payment method: | ||
| 23 | + | ||
| 24 | + 1. [Create a new module](#create-module). | ||
| 25 | + 1. [Add a `db_schema.xml` file](#add-db-schema). | ||
| 26 | + 1. [Add a `requirejs` file to the module](#add-require-js). | ||
| 27 | + 1. [Override the vendor files](#override-vendor-files). | ||
| 28 | + 1. [Add an Observer](#add-observer). | ||
| 29 | + 1. [Compile and deploy the module](#compile-deploy). | ||
| 30 | + 1. [Verify that the module works](#verify-implementation). | ||
| 31 | + | ||
| 32 | + Let’s go through each step. | ||
| 33 | + | ||
| 34 | + ## Step 1: Create a new module {#create-module} | ||
| 35 | + | ||
| 36 | + [Create a new module](https://devdocs.magento.com/videos/fundamentals/create-a-new-module/) named `Learning/CustomField` and register it. | ||
| 37 | + | ||
| 38 | + ## Step 2 Add a `db_schema.xml` file {#add-db-schema} | ||
| 39 | + | ||
| 40 | + Add the `paymentpocomment` column in the `quote_payment` and `sales_order_payment` tables using the [declarative schema]({{page.baseurl}}/extension-dev-guide/declarative-schema/db-schema.html) method. | ||
| 41 | + | ||
| 42 | + Create the `app/code/Learning/CustomField/etc/db_schema.xml` and define the declarative schema as follows: | ||
| 43 | + | ||
| 44 | + ```xml | ||
| 45 | + <schema xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
| 46 | + xsi:noNamespaceSchemaLocation="urn:magento:framework:Setup/Declaration/Schema/etc/schema.xsd"> | ||
| 47 | + <table name="quote_payment" resource="checkout" engine="innodb" comment="Sales Flat Quote Payment"> | ||
| 48 | + <column xsi:type="text" name="paymentpocomment" nullable="true" comment="PO Comment"/> | ||
| 49 | + </table> | ||
| 50 | + <table name="sales_order_payment" resource="sales" engine="innodb" comment="Sales Flat Order Payment"> | ||
| 51 | + <column xsi:type="text" name="paymentpocomment" nullable="true" comment="PO Comment"/> | ||
| 52 | + </table> | ||
| 53 | + </schema> | ||
| 54 | + ``` | ||
| 55 | + | ||
| 56 | + ## Step 3: Add a requirejs file to the module {#add-require-js} | ||
| 57 | + | ||
| 58 | + Create the `app/code/Learning/CustomField/view/frontend/requirejs-config.js` file and add the following code: | ||
| 59 | + | ||
| 60 | + ```js | ||
| 61 | + var config = { | ||
| 62 | + map: { | ||
| 63 | + '*': { | ||
| 64 | + 'Magento_OfflinePayments/js/view/payment/offline-payments':'Learning_CustomField/js/view/payment/offline-payments', | ||
| 65 | + } | ||
| 66 | + } | ||
| 67 | + } | ||
| 68 | + ``` | ||
| 69 | + | ||
| 70 | + ## Step 4: Override the vendor files {#override-vendor-files} | ||
| 71 | + | ||
| 72 | + We must override the behavior of the following files to display the custom field: | ||
| 73 | + | ||
| 74 | + - [Magento_OfflinePayments/view/frontend/web/js/view/payment/offline-payments.js](#offline-payment) | ||
| 75 | + - [Magento_OfflinePayments/view/frontend/web/js/view/payment/method-renderer/purchaseorder-method.js](#purchaseorder-method) | ||
| 76 | + - [Magento_OfflinePayments/view/frontend/web/template/payment/purchaseorder-form.html](#purchaseorder-form) | ||
| 77 | + | ||
| 78 | + ### Override the `offline-payments.js` {#offline-payment} | ||
| 79 | + | ||
| 80 | + Override the `Magento_OfflinePayments/view/frontend/web/js/view/payment/offline-payments.js` file to change the renderer of the Purchase Order payment method. | ||
| 81 | + | ||
| 82 | + Create the `app/code/Learning/CustomField/view/frontend/web/js/view/payment/offline-payments.js` file and add the following code: | ||
| 83 | + | ||
| 84 | + ```js | ||
| 85 | + define( | ||
| 86 | + [ | ||
| 87 | + 'uiComponent', | ||
| 88 | + 'Magento_Checkout/js/model/payment/renderer-list' | ||
| 89 | + ], | ||
| 90 | + function ( | ||
| 91 | + Component, | ||
| 92 | + rendererList | ||
| 93 | + ) { | ||
| 94 | + 'use strict'; | ||
| 95 | + rendererList.push( | ||
| 96 | + { | ||
| 97 | + type: 'checkmo', | ||
| 98 | + component: 'Magento_OfflinePayments/js/view/payment/method-renderer/checkmo-method' | ||
| 99 | + }, | ||
| 100 | + { | ||
| 101 | + type: 'banktransfer', | ||
| 102 | + component: 'Magento_OfflinePayments/js/view/payment/method-renderer/banktransfer-method' | ||
| 103 | + }, | ||
| 104 | + { | ||
| 105 | + type: 'cashondelivery', | ||
| 106 | + component: 'Magento_OfflinePayments/js/view/payment/method-renderer/cashondelivery-method' | ||
| 107 | + }, | ||
| 108 | + { | ||
| 109 | + type: 'purchaseorder', | ||
| 110 | + component: 'Learning_CustomField/js/view/payment/method-renderer/purchaseorder-method' | ||
| 111 | + } | ||
| 112 | + ); | ||
| 113 | + /** Add view logic here if needed */ | ||
| 114 | + return Component.extend({}); | ||
| 115 | + } | ||
| 116 | + ); | ||
| 117 | + ``` | ||
| 118 | + | ||
| 119 | + ### Override the `purchaseorder-method.js` {#purchaseorder-method} | ||
| 120 | + | ||
| 121 | + It is also necessary to override the `Magento_OfflinePayments/view/frontend/web/js/view/payment/method-renderer/purchaseorder-method.js` file. | ||
| 122 | + | ||
| 123 | + The `template` path value used in this file must be altered to use the custom template. Also, the logic to get the `additional_data` is implemented in this file. | ||
| 124 | + | ||
| 125 | + Create the `app/code/Learning/CustomField/view/frontend/web/js/view/payment/method-renderer/purchaseorder-method.js` file and add the following code: | ||
| 126 | + | ||
| 127 | + ```js | ||
| 128 | + define([ | ||
| 129 | + 'Magento_Checkout/js/view/payment/default', | ||
| 130 | + 'jquery', | ||
| 131 | + 'mage/validation' | ||
| 132 | + ], function (Component, $) { | ||
| 133 | + 'use strict'; | ||
| 134 | + | ||
| 135 | + return Component.extend({ | ||
| 136 | + defaults: { | ||
| 137 | + template: 'Learning_CustomField/payment/purchaseorder-form', | ||
| 138 | + purchaseOrderNumber: '' | ||
| 139 | + }, | ||
| 140 | + | ||
| 141 | + /** @inheritdoc */ | ||
| 142 | + initObservable: function () { | ||
| 143 | + this._super() | ||
| 144 | + .observe('purchaseOrderNumber'); | ||
| 145 | + | ||
| 146 | + return this; | ||
| 147 | + }, | ||
| 148 | + | ||
| 149 | + /** | ||
| 150 | + * @return {Object} | ||
| 151 | + */ | ||
| 152 | + getData: function () { | ||
| 153 | + return { | ||
| 154 | + method: this.item.method, | ||
| 155 | + 'po_number': this.purchaseOrderNumber(), | ||
| 156 | + 'additional_data': { | ||
| 157 | + 'po_number': $('#po_number').val(), | ||
| 158 | + 'paymentpocomment': $('#purchaseorder_paymentpocomment').val(), | ||
| 159 | + } | ||
| 160 | + }; | ||
| 161 | + }, | ||
| 162 | + | ||
| 163 | + /** | ||
| 164 | + * @return {jQuery} | ||
| 165 | + */ | ||
| 166 | + validate: function () { | ||
| 167 | + var form = 'form[data-role=purchaseorder-form]'; | ||
| 168 | + | ||
| 169 | + return $(form).validation() && $(form).validation('isValid'); | ||
| 170 | + } | ||
| 171 | + }); | ||
| 172 | + }); | ||
| 173 | + ``` | ||
| 174 | + | ||
| 175 | + ### Override the `purchaseorder-form.html` {#purchaseorder-form} | ||
| 176 | + | ||
| 177 | + We must override the `Magento_OfflinePayments/view/frontend/web/template/payment/purchaseorder-form.html` template file to add the custom input field (**Purchase Order Comment**). | ||
| 178 | + | ||
| 179 | + Create the `app/code/Learning/CustomField/view/frontend/web/template/payment/purchaseorder-form.html` file and add the following code: | ||
| 180 | + | ||
| 181 | + {% collapsible Show code %} | ||
| 182 | + | ||
| 183 | + ```html | ||
| 184 | + <div class="payment-method" data-bind="css: {'_active': (getCode() == isChecked())}"> | ||
| 185 | + <div class="payment-method-title field choice"> | ||
| 186 | + <input type="radio" | ||
| 187 | + name="payment[method]" | ||
| 188 | + class="radio" | ||
| 189 | + data-bind="attr: {'id': getCode()}, value: getCode(), checked: isChecked, click: selectPaymentMethod, visible: isRadioButtonVisible()"/> | ||
| 190 | + <label data-bind="attr: {'for': getCode()}" class="label"> | ||
| 191 | + <span data-bind="text: getTitle()"></span> | ||
| 192 | + </label> | ||
| 193 | + </div> | ||
| 194 | + | ||
| 195 | + <div class="payment-method-content"> | ||
| 196 | + <!-- ko foreach: getRegion('messages') --> | ||
| 197 | + <!-- ko template: getTemplate() --><!-- /ko --> | ||
| 198 | + <!--/ko--> | ||
| 199 | + <div class="payment-method-billing-address"> | ||
| 200 | + <!-- ko foreach: $parent.getRegion(getBillingAddressFormName()) --> | ||
| 201 | + <!-- ko template: getTemplate() --><!-- /ko --> | ||
| 202 | + <!--/ko--> | ||
| 203 | + </div> | ||
| 204 | + <form id="purchaseorder-form" class="form form-purchase-order" data-role="purchaseorder-form"> | ||
| 205 | + <fieldset class="fieldset payment method" data-bind='attr: {id: "payment_form_" + getCode()}'> | ||
| 206 | + <div class="field field-number required"> | ||
| 207 | + <label for="po_number" class="label"> | ||
| 208 | + <span><!-- ko i18n: 'Purchase Order Number'--><!-- /ko --></span> | ||
| 209 | + </label> | ||
| 210 | + <div class="control"> | ||
| 211 | + <div class="name-info"> | ||
| 212 | + <input type="text" id="po_number" name="payment[po_number]" placeholder="Purchase Order Number" data-validate="{required:true}" data-bind='attr: {title: $t("Purchase Order Number")},value: purchaseOrderNumber' class="input-text"/> | ||
| 213 | + <input type="text" id="purchaseorder_paymentpocomment" name="payment[paymentpocomment]" class="input-text" placeholder="Purchase Order Comment" value="" data-bind="attr: {title: $t('Purchase Order Comment'),'data-container': getCode() + '-paymentpocomment',valueUpdate: 'keyup' "/> | ||
| 214 | + </div> | ||
| 215 | + </div> | ||
| 216 | + </div> | ||
| 217 | + </fieldset> | ||
| 218 | + </form> | ||
| 219 | + <div class="checkout-agreements-block"> | ||
| 220 | + <!-- ko foreach: $parent.getRegion('before-place-order') --> | ||
| 221 | + <!-- ko template: getTemplate() --><!-- /ko --> | ||
| 222 | + <!--/ko--> | ||
| 223 | + </div> | ||
| 224 | + <div class="actions-toolbar" id="review-buttons-container"> | ||
| 225 | + <div class="primary"> | ||
| 226 | + <button class="action primary checkout" | ||
| 227 | + type="submit" | ||
| 228 | + data-bind=" | ||
| 229 | + click: placeOrder, | ||
| 230 | + attr: {title: $t('Place Order')}, | ||
| 231 | + enable: (getCode() == isChecked()), | ||
| 232 | + css: {disabled: !isPlaceOrderActionAllowed()} | ||
| 233 | + " | ||
| 234 | + data-role="review-save"> | ||
| 235 | + <span data-bind="i18n: 'Place Order'"></span> | ||
| 236 | + </button> | ||
| 237 | + </div> | ||
| 238 | + </div> | ||
| 239 | + </div> | ||
| 240 | + </div> | ||
| 241 | + ``` | ||
| 242 | + {% endcollapsible %} | ||
| 243 | + | ||
| 244 | + ## Step 5: Add an Observer {#add-observer} | ||
| 245 | + | ||
| 246 | + Create an Observer file to save the custom field data to the order. For the Observer file an `events.xml` file is required to call the observer for a particular event. For this example, the `checkout_onepage_controller_success_action` event is used. | ||
| 247 | + | ||
| 248 | + Create the `app/code/Learning/CustomField/etc/frontend/events.xml` file and add the following code: | ||
| 249 | + | ||
| 250 | + ```xml | ||
| 251 | + <?xml version="1.0"?> | ||
| 252 | + | ||
| 253 | + <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> | ||
| 254 | + <event name="checkout_onepage_controller_success_action"> | ||
| 255 | + <observer name="paymentfields_paymentfields_observer_frontend_sales_orderpaymentsavebefore" instance="Learning\CustomField\Observer\Frontend\Sales\OrderPaymentSaveBefore" /> | ||
| 256 | + </event> | ||
| 257 | + </config> | ||
| 258 | + ``` | ||
| 259 | + | ||
| 260 | + Then create the `app/code/Learning/CustomField/Observer/Frontend/Sales/OrderPaymentSaveBefore.php` file. | ||
| 261 | + | ||
| 262 | + {% collapsible Show code %} | ||
| 263 | + | ||
| 264 | + ```php?start_inline=1 | ||
| 265 | + <?php | ||
| 266 | + | ||
| 267 | + namespace Learning\CustomField\Observer\Frontend\Sales; | ||
| 268 | + | ||
| 269 | + use Magento\Framework\Event\Observer as EventObserver; | ||
| 270 | + use Magento\Framework\Event\ObserverInterface; | ||
| 271 | + use Magento\OfflinePayments\Model\Purchaseorder; | ||
| 272 | + use Magento\Framework\App\Request\DataPersistorInterface; | ||
| 273 | + | ||
| 274 | + class OrderPaymentSaveBefore implements \Magento\Framework\Event\ObserverInterface | ||
| 275 | + { | ||
| 276 | + protected $order; | ||
| 277 | + protected $logger; | ||
| 278 | + protected $_serialize; | ||
| 279 | + protected $quoteRepository; | ||
| 280 | + | ||
| 281 | + public function __construct( | ||
| 282 | + \Magento\Sales\Api\Data\OrderInterface $order, | ||
| 283 | + \Magento\Quote\Api\CartRepositoryInterface $quoteRepository, | ||
| 284 | + \Psr\Log\LoggerInterface $logger, | ||
| 285 | + \Magento\Framework\Serialize\Serializer\Serialize $serialize | ||
| 286 | + ) { | ||
| 287 | + $this->order = $order; | ||
| 288 | + $this->quoteRepository = $quoteRepository; | ||
| 289 | + $this->logger = $logger; | ||
| 290 | + $this->_serialize = $serialize; | ||
| 291 | + } | ||
| 292 | + /** | ||
| 293 | + * Execute observer | ||
| 294 | + * | ||
| 295 | + * @param \Magento\Framework\Event\Observer $observer | ||
| 296 | + * @return void | ||
| 297 | + */ | ||
| 298 | + public function execute(\Magento\Framework\Event\Observer $observer) | ||
| 299 | + { | ||
| 300 | + $orderids = $observer->getEvent()->getOrderIds(); | ||
| 301 | + if(!$orderids){ | ||
| 302 | + foreach ($orderids as $orderid) { | ||
| 303 | + $order = $this->_order->load($orderid); | ||
| 304 | + $method = $order->getPayment()->getMethod(); | ||
| 305 | + if($method == 'purchaseorder') { | ||
| 306 | + $quote_id = $order->getQuoteId(); | ||
| 307 | + $quote = $this->quoteRepository->get($quote_id); | ||
| 308 | + $paymentQuote = $quote->getPayment(); | ||
| 309 | + $paymentOrder = $order->getPayment(); | ||
| 310 | + $paymentOrder->setData('paymentpocomment',$paymentQuote->getPaymentpocomment()); | ||
| 311 | + $paymentOrder->save(); | ||
| 312 | + } | ||
| 313 | + } | ||
| 314 | + } | ||
| 315 | + } | ||
| 316 | + } | ||
| 317 | + ``` | ||
| 318 | + {% endcollapsible %} | ||
| 319 | + | ||
| 320 | + ## Step 6: Compile and deploy the module {#compile-deploy} | ||
| 321 | + | ||
| 322 | + Run the following sequence of commands to compile and deploy your custom module. | ||
| 323 | + | ||
| 324 | + 1. Enable the new module. | ||
| 325 | + | ||
| 326 | + ```bash | ||
| 327 | + bin/magento module:enable Learning_CustomField | ||
| 328 | + ``` | ||
| 329 | + | ||
| 330 | + 1. Install the new module. | ||
| 331 | + | ||
| 332 | + ```bash | ||
| 333 | + bin/magento setup:upgrade | ||
| 334 | + ``` | ||
| 335 | + | ||
| 336 | + 1. Compile the code. | ||
| 337 | + | ||
| 338 | + ```bash | ||
| 339 | + bin/magento setup:di:compile | ||
| 340 | + ``` | ||
| 341 | + | ||
| 342 | + 1. Deploy the static files. | ||
| 343 | + | ||
| 344 | + ```bash | ||
| 345 | + bin/magento setup:static-content:deploy | ||
| 346 | + ``` | ||
| 347 | + | ||
| 348 | + ## Step 7: Verify that the module works {#verify-implementation} | ||
| 349 | + | ||
| 350 | + Use the following steps to verify your changes work as expected. | ||
| 351 | + | ||
| 352 | + 1. Go to the storefront as a guest user and add a product to the cart. | ||
| 353 | + | ||
| 354 | + 1. Go to the checkout page and select the **Purchase Order** payment. | ||
| 355 | + | ||
| 356 | + 1. Verify that the **Purchase Order Comment** field is visible. | ||
| 357 | + | ||
| 358 | +  | ||
| 359 | + | ||
| 360 | + 1. Fill the purchase order comment field in the checkout and place an order. | ||
| 361 | + | ||
| 362 | + 1. Verify that the entered value is stored in the `paymentpocomment` column of the `sales_order_payment` table. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments