In the UPS shipping method, when we type zip code the shipping rate will be automatically calculated based on the zip code provided. The same thing I have to customize in flatrate too. I have my custom function which returns the shipping rate on providing the zip code. I can call that function on providing the zip code in cart page (Summary Block). Please help me to write that code. I tried to find the ajax call running on typing the zip code. How can I add the same feature as in ups to flaterate. Anybody help please.
Magento 2.1 – Update Shipping Rate on Providing Zipcode in Cart Page
magento-2.1magento2shipping-methods
Related Solutions
Please add below code in .phtml file under your shipping calculator form for ajax call.
<script type="text/javascript">
//<![CDATA[
var coShippingEstimateForm = new VarienForm('your_form_id',true);
//]]>
function getEstimateShipping(){
if (coShippingEstimateForm.validator.validate()) {
new Ajax.Updater(
{ success:'result_container_id' }, "<?php echo $this->getUrl('your_route_name/your_controller/calculate') ?>", {
method:'post',
asynchronous:true,
evalScripts:false,
onSuccess:function(transport) {
var shiphtml = transport.responseText;
if(shiphtml != "" && shiphtml != null){
$('result_container_id').insert(shiphtml).show();
}else{
alert("No shipping method available");
}
$('submit').disabled = false;
},
onLoading:function(request, json){
$('submit').disabled = true;
},
parameters:jQuery('form').serialize(true)
}
);
}
}
</script>
Now you need to create a controller action to handle the ajax request. Please refer below code snippet for that.
public function calculateAction()
{
$country = (string) $this->getRequest()->getParam('country_id');
$postcode = (string) $this->getRequest()->getParam('estimate_postcode');
$qty = intval($this->getRequest()->getParam('qty'));
if($qty == 0 || $qty == null){
$qty = 1;
}
$currentProductId = $this->getRequest()->getPost('currunt_product');
$quote = Mage::getModel('sales/quote')->setStoreId(Mage::app()->getStore('default')->getId());
$_product = Mage::getModel('catalog/product')->load($currentProductId);
$params = $this->getRequest()->getParams();
$reqOb = new Varien_Object($params);
$_product->getStockItem()->setUseConfigManageStock(false);
$_product->getStockItem()->setManageStock(false);
$quote->addProduct($_product, $reqOb);
$quote->getShippingAddress()->setCountryId($country)->setPostcode($postcode);
$quote->getShippingAddress()->collectTotals();
$quote->getShippingAddress()->setCollectShippingRates(true);
$quote->getShippingAddress()->collectShippingRates();
$groups = $quote->getShippingAddress()->getGroupedAllShippingRates();
$shippingRates = array();
$shippingHtml = "";
$shippingBlock = new Mage_Checkout_Block_Cart_Shipping();
foreach($groups as $code=>$_rates){
$shippingHtml .= "<dt>" . $shippingBlock->getCarrierName($code) . "</dt><dd><ul>";
foreach ($_rates as $_rate) {
//if($_rate->getPrice() > 0) {
$shippingHtml .= "<li><label>";
$shippingHtml .= $_rate->getMethodTitle();
$shippingHtml .= " - ";
$shippingHtml .= Mage::helper('core')->currency($_rate->getPrice(), true, false);
$shippingHtml .= "</label></li>";
}
$shippingHtml .= "</ul></dd>";
}
$this->getResponse()->setBody($shippingHtml);
}
Let's say that the attribute code is called attribute_code
so the getter name is getAttributeCode()
.
You need to create an arround
plugin on the flatrate carrier model and UPS carrier model where you can check your conditions and return or not the shipping rate result.
You need to create a module and add this in the di.xml
file
<type name="Magento\OfflineShipping\Model\Carrier\Flatrate">
<plugin name="[module]-flatrate" type="[Vendor]\[Module]\Plugin\Flatrate" />
</type>
<type name="Magento\Ups\Model\Carrier">
<plugin name="[module]-ups" type="[Vendor]\[Module]\Plugin\Ups" />
</type>
Then create the file [Vendor]/[Module]/Plugin/Flatrate.php
<?php
namespace [Vendor]\[Module]\Plugin;
class Flatrate
{
public function arroundCollectRates(
\Magento\OfflineShipping\Model\Carrier\Flatrate $subject,
\Closure $proceed,
Magento\Quote\Model\Quote\Address\RateRequest $request
) {
$items = $request->getAllItems();
foreach ($items as $item) {
if ($item->getProduct()->getAttributeCode()) {
//if your attribute value is true don't show this method
return false;
}
}
return $proceed();
}
}
and this plugin class that handles UPS shipping method [Vendor]/[Module]/Plugin/Ups.php
<?php
namespace [Vendor]\[Module]\Plugin;
class Ups
{
public function arroundCollectRates(
\Magento\OfflineShipping\Model\Carrier\Ups $subject,
\Closure $proceed,
Magento\Quote\Model\Quote\Address\RateRequest $request
) {
$items = $request->getAllItems();
foreach ($items as $item) {
if ($item->getProduct()->getAttributeCode()) {
//if one attribute value is true show the method
return $proceed();
}
}
//if all the products had the value false don't show UPS.
return false;
}
}
But keep in mind that I didn't test the code so watch out for typos.
Best Answer
During checkout page initialization the checkout
shipping-rates-validator
registers all validators for shipping carriers.When a customer fills inputs on the address form, the checkout js component triggers validators for available shipping carriers, these validators have rules with required fields and if required field is changed by the customer the checkout js component calls
estimation-service
, which gets available rates from the backend.So, to proceed
estimation-service
call, when the customer changes zip code input, you need to specify validation rules in your own shipping validator.Your custom shipping carrier should have two js components:
shipping-rates-validator
andshipping-rates-validation-rules
and it might look like this (Custom_Shipping/view/frontend/web/js/model/shipping-rates-validation-rules.js
):And the rates validator (
Custom_Shipping/view/frontend/web/js/model/shipping-rates-validator
):Each time, when the customer will change zip code in address form input, the checkout js component will call
estimation-service
and your custom shipping provider can return rates based on provided zip code.