Is there any way to make purchase order optional in checkout page??
4 Answers
I had to this very same thing today - you need to remove the validation from the input itself as described above by localising;
/m2root/app/design/frontend/NameSpace/Theme/Magento_OfflinePayments/web/template/payment/purchaseorder-form.html
Change;
<input type="text"
id="po_number"
name="payment[po_number]"
data-validate="{required:true}"
data-bind='
attr: {title: $t("Purchase Order Number")},
value: purchaseOrderNumber'
class="input-text"/>
To;
<input type="text"
id="po_number"
name="payment[po_number]"
data-validate="{required:false}"
data-bind='
attr: {title: $t("Purchase Order Number")},
value: purchaseOrderNumber'
class="input-text"/>
That gets you passed client-side javascript validation, but you additionally need to override the validation function in model class;
Magento\OfflinePayments\Model\Purchaseorder
Use a plugin. In your custom modules /etc/di.xml file add;
<type name="Magento\OfflinePayments\Model\Purchaseorder">
<plugin name="purchase_order_validate" type="ModuleNamespace\ModuleName\Plugin\Model\Purchaseorder" />
</type>
Then create the file
ModuleNamespace\ModuleName\Plugin\Model\Purchaseorder.php
With this - note I've added a helper class in as in my instance I need to make it required based on a customer attribute - you can leave that bit out if you dont need it.
namespace ModuleNamespace\ModuleName\Plugin\Model;
use Magento\Framework\Exception\LocalizedException;
class Purchaseorder {
protected $cHelper;
public function __construct(
\ModuleNamespace\ModuleName\Helper\Customer $cHelper
) {
$this->cHelper = $cHelper;
}
public function aroundvalidate($subject,$proceed)
{
// Use whatever function you want if you want to conditionally make PO number required
$needsValidation = $this->cHelper->getIsPoNumRequired();
if(!$needsValidation) {
// Validation avoided here
return $this;
}
// Still here? You will get empty PO number validation then
if (empty($subject->getInfoInstance()->getPoNumber())) {
throw new LocalizedException(__('Purchase order number is a required field.'));
}
return $this;
}
}
- 611
- 3
- 11
-
it is not working – gajjala sandeep Oct 01 '19 at 12:36
-
you must have missed a step - this definitely works. please check again. – pixiemedia Oct 23 '19 at 21:55
-
@piximedia why you used helper class in the above code and didn't mention the helper – Jack Dec 02 '19 at 09:21
-
Hi Jack, as I say in the code, that is an example of how you could use a helper to use a condition to control whether the PO number is required or not - in our use case only certain customer types need to enter a PO – pixiemedia Dec 03 '19 at 12:15
-
Thanks for this works like a charm. Guys if you don't need a helper and just need the po number to not be checked at all then you can just change the whole content of the aroundvalidate function to: return $this; – Sanne Jan 13 '20 at 15:13
You can edit below file to make Purchase Order Number optional
copy
mage2root/vendor/magento/module-offline-payments/view/frontend/web/template/payment/purchaseorder-form.html
to
app/design/frontend/{Package}/{theme}/Magento_OfflinePayments/web/template/payment/purchaseorder-form.html
in the above file, you need to remove data-validate="{required:true}" from input box.
After that you need to clear cache, Remove static content and if in production module, deploy content
- 5,856
- 2
- 14
- 36
-
-
what is not working ? template overriding working ? can see your changes on front ? – Pawan May 14 '19 at 17:00
-
I know this is an old question, but the problem is still relevant. The backend validation in the above answers don't seem to work anymore with M2.4.3 (at least not with me). I wish there would be a core configuration option to make it optional, but I guess we will have to make a workaround for now.
After some digging in the M2 source code I made a solution, which is not the prettiest but it works! You will still have to override the template for the frontend validation, please see the other answers for that.
The backend validation of the PO number field takes place in Magento\OfflinePayments\Plugin\ValidatePurchaseOrderNumber
public function beforeSubmit(
QuoteManagement $subject,
Quote $quote,
array $orderData = []
): void {
$payment = $quote->getPayment();
if ($payment->getMethod() === Purchaseorder::PAYMENT_METHOD_PURCHASEORDER_CODE
&& empty($payment->getPoNumber())) {
throw new LocalizedException(__('Purchase order number is a required field.'));
}
}
So I've overwritten the class in a module and made the method body empty:
namespace CompanyName\OptionalPoNumber\Plugin\Model;
use Magento\OfflinePayments\Plugin\ValidatePurchaseOrderNumber;
use Magento\Quote\Model\Quote;
use Magento\Quote\Model\QuoteManagement;
class ValidatePurchaseOrderNumberOverride extends ValidatePurchaseOrderNumber
{
public function beforeSubmit(
QuoteManagement $subject,
Quote $quote,
array $orderData = []
): void {}
}
di.xml:
<?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\Plugin\ValidatePurchaseOrderNumber" type="CompanyName\OptionalPoNumber\Plugin\Model\ValidatePurchaseOrderNumberOverride" />
</config>
- 63
- 7
@jrswgtr's answer is not the recommended way to disable the backend logic. Preferences should be avoided if possible. The recommended way would be to disable the plugin in di.xml:
<?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\Quote\Model\QuoteManagement">
<plugin name="validate_purchase_order_number" disabled="true"/>
</type>
</config>
- 1