WooCommerce calculate shipping via REST API - php

My implementation in app is just like my WooCommerce website. I want to achieve following points for calculating shipping:
Check if address is required or not for calculating shipping address?
If address is entered by user, how to check if this address falling between shipping method crieteria? Give error to user if entered address is not valid as per shipping method.
Once user enter valid address, calculate cost of all shipping methods.
Show all shipping methods to user in app with its cost with default method selected.
When user switch between shipping methods, it should save and sync with website too and get cart total as per selected method.
Till now what I achieve is point 4. I am able to get all shipping methods calculated via website but if not calculated via website then it returns me null there.
Here is my API code:
function register_get_cart_shipping() {
register_rest_route(
'custom-plugin', '/getCartShipping/',
array(
'methods' => ['GET'],
'callback' => 'getCartShipping',
)
);
function getCartShipping() {
$chosen_methods = WC()->session->get('chosen_shipping_methods');
$count = 0;
foreach( WC()->session->get('shipping_for_package_0')['rates'] as $method_id => $rate ){
$data[$count]->rate_id = $rate->id;
$data[$count]->method_id = $rate->method_id;
$data[$count]->instance_id = $rate->instance_id;
$data[$count]->label = $rate->label;
$data[$count]->cost = $rate->cost;
$data[$count]->taxes = $rate->taxes;
$data[$count]->chosen = $chosen_methods['rate_id'];
if($chosen_methods['rate_id'] == $rate->id ){
$data[$count]->isSelected = true;
} else {
$data[$count]->isSelected = false;
}
$count++;
}
return $data;
}
}
Also for point 5, when user switch between shipping methods, I am using this code but it doesn't update selected shipping method on website. Here is the code:
function updateCartShipping($request) {
$rate_id["rate_id"] = "table_rate:10:4";
// $rate_id["rate_id"] = "table_rate:9:3";
// $rate_id["rate_id"] = $request['shippingID'];
WC()->session->set('chosen_shipping_methods', $rate_id);
return "OK";
}
I also don't know which method id to set as a shipping method. It seems mysterious to me.
Any help will be appreciated. Thanks!

Related

Shopware 6 change shipping method programmatically in checkout on order submission

I have two of same shipping methods with different price matrix, depending on customer distance, one of the two shipping method should be selected. This has to be done programmatically on checkout order confirmation, I looked at the cart collector, but it's about changing price of an item. I didn't find anything covered in documentation regarding shipping method change.
Following is my attempt to change it onOrderValidation.
private function getShippingMethod(string $id, Context $context): ?ShippingMethodEntity
{
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter("id", $id));
$criteria->setLimit(1);
$result = $this->shippingMethodRepository->search($criteria, $context);
return $result->getEntities()->first();
}
public function onOrderValidation(BuildValidationEvent $event)
{
$cart = $this->cartService->getCart($this->salesChannelContext->getToken(), $this->salesChannelContext);
$delivery = $cart->getDeliveries()->first();
//test
$shippingMethod = $this->getShippingMethod($this->getShippingMethodZoneXId(), $event->getContext());
$delivery->setshippingMethod($shippingMethod);
$cartDeliveries = new DeliveryCollection();
$cartDeliveries->add($delivery);
$cart->addDeliveries($cartDeliveries);
$this->cartService->setCart($cart);
...
}
In the above code I have cart object, and delivery. I get the shipping method which I need to set, but it doesn't get updated.
Also i need to recalculate shipping price, what is the correct way to do it. any suggestion will be appreciated.
Update: I have also tried from shopware doc collect/process, but that also didn't work.
public function collect(CartDataCollection $data, Cart $original, SalesChannelContext $context, CartBehavior $behavior): void
{
$shippingMethod = $this->getShippingMethod($this->getShippingMethodZoneXId(), $context->getContext());
$shippingMethodId = $shippingMethod->getId();
$key = self::buildShippingKey($shippingMethodId);
$data->set($key, $shippingMethod);
}
public function process(CartDataCollection $data, Cart $original, Cart $toCalculate, SalesChannelContext $context, CartBehavior $behavior): void
{
// change delviery
$deliveries = $this->builder->build($toCalculate, $data, $context, $behavior);
$deliveryOriginal = $deliveries->first();
if($deliveryOriginal === null) {
return;
}
$shippingMethod = $this->getShippingMethod($this->getShippingMethodZoneXId(), $context->getContext());
$deliveries->first()->setShippingMethod($shippingMethod);
$this->deliveryCalculator->calculate($data, $toCalculate, $deliveries, $context);
$toCalculate->setDeliveries($deliveries);
}
I completely ended up with another approach, none of the above seem to work for me. Item price updation was taking place but not shipment.
So here's what you need, this contextSwitcher dependency i injected and it did the job. update() method that can be used to switch shipment method.
SalesChannelContextSwitcher $contextSwitcher,

Magento 1.9 remove tax on checkout when user enter VAT

I'm trying to make magento modification when user enter vat number on checkout remove tax from order.
I found a code on stackoverflow which support on magento older version but it not work with new version 1.9,
I made few modifications for work the condition and return 0,even it return 0 checkout still shows tax.
here is my code which is on file
/app/code/core/Mage/Tax/Model/Calculation.php line number 268
public function getRate($request)
{
if (!$request->getCountryId() || !$request->getCustomerClassId() || !$request->getProductClassId()) {
return 0;
}
//my code
$ctax= Mage::getSingleton('checkout/session')->getQuote()->getCustomerTaxvat();
if ($this->getCustomer() && $ctax !='') {
//echo 'test';
return 0;
}
//end my code
$cacheKey = $this->_getRequestCacheKey($request);
if (!isset($this->_rateCache[$cacheKey])) {
$this->unsRateValue();
$this->unsCalculationProcess();
$this->unsEventModuleId();
Mage::dispatchEvent('tax_rate_data_fetch', array(
'request' => $request));
if (!$this->hasRateValue()) {
$rateInfo = $this->_getResource()->getRateInfo($request);
$this->setCalculationProcess($rateInfo['process']);
$this->setRateValue($rateInfo['value']);
} else {
$this->setCalculationProcess($this->_formCalculationProcess());
}
$this->_rateCache[$cacheKey] = $this->getRateValue();
$this->_rateCalculationProcess[$cacheKey] = $this->getCalculationProcess();
}
return $this->_rateCache[$cacheKey];
}
Anyone can help me to make tax 0 when user enters vat number on checkout, Thanks a lot
I've managed to solve my problem by following this thread : Modify tax rate on cart quote items and recalculate
I have added an Observer to the event sales_quote_collect_totals_before.
And here is the content of my observer, very simple :
public function removetax($observer)
{
$customer_id = Mage::getSingleton('customer/session')->getId();
$customer = Mage::getModel("customer/customer")->load($customer_id);
if($customer->getIsTaxExempt() == 1)
{
$items = $observer->getEvent()->getQuote()->getAllVisibleItems();
foreach($items as $item)
$item->getProduct()->setTaxClassId(0);
}
}
If customer is tax exempt, I grab the current cart content and for each item, I set the product tax class to 0. It is mandatory to not save the product or the item. The aim here is to set a value for the following calculation, not to save it in the database. Tax classes need to stay to the initial value in the db.
You can use sales_quote_collect_totals_before event.
then you have to define logic for remove tax on checkout page.
This link you can refer.
Go to Calculation.php and find the calcTaxAmount() and add billing condditions
public function calcTaxAmount($price, $taxRate, $priceIncludeTax = false, $round = true)
{
$billing = Mage::getModel('checkout/session')->getQuote()->getCustomerTaxvat();
if($billing !="")
{
return 0;
}
}

Magento Order Creation Programatically only working on one shipping method

I am using the code below as part of a script to create Magento Orders programatically. The script works fine when I use
freeshipping_freeshipping
as the shipping method. However, when I choose any other shipping method such as a custom shipping method,flatrate_flatrate or usps_1 e.t.c, it gives me the error:
"Please Specify a shipping method"
I have searched everywhere but was unable to find a solution. Any help would be highly appreciated, thanks.
$shippingAddress->setCollectShippingRates(true)->collectShippingRates()
->setShippingMethod($shipping_method);
Edit:
I got it to work with flatrate for non US orders and an extension freeadminshipping on both US and non US orders. However, still unable to use any of the UPS or USPS shipping methods.
This method create Order and I have use this in my project it working. In your code please remove shipping method set code and try I hope that work fine for you. otherwise you can use below my code.
public function createOrderAction($paymentMethod) {
try {
$checkout_session = Mage::getSingleton('checkout/session');
$cq = $checkout_session->getQuote();
$cq->assignCustomer(Mage::getSingleton('customer/session')->getCustomer());
$quoteObj = Mage::getModel('sales/quote')->load($checkout_session->getQuoteId()); // Mage_Sales_Model_Quote
//Mage::getSingleton('checkout/session')->getQuote()->getShippingAddress()
$items = $quoteObj->getAllItems();
$quoteObj->reserveOrderId();
// set payment method
$quotePaymentObj = $quoteObj->getPayment(); // Mage_Sales_Model_Quote_Payment
$quotePaymentObj->setMethod($paymentMethod);
$quoteObj->setPayment($quotePaymentObj);
// convert quote to order
$convertQuoteObj = Mage::getSingleton('sales/convert_quote');
$quoteObj->setShippingAddress($cq->getShippingAddress());
$quoteObj->setBillingAddress($cq->getBillingAddress());
$orderObj = $convertQuoteObj->addressToOrder($quoteObj->getShippingAddress());
$orderPaymentObj = $convertQuoteObj->paymentToOrderPayment($quotePaymentObj);
// convert quote addresses
$orderObj->setBillingAddress($convertQuoteObj->addressToOrderAddress($quoteObj->getBillingAddress()));
$orderObj->setShippingAddress($convertQuoteObj->addressToOrderAddress($quoteObj->getShippingAddress()));
// set payment options
$orderObj->setPayment($convertQuoteObj->paymentToOrderPayment($quoteObj->getPayment()));
// convert quote items
foreach ($items as $item) {
// #var $item Mage_Sales_Model_Quote_Item
$orderItem = $convertQuoteObj->itemToOrderItem($item);
$orderItem->setWholesaler($item->getWholesaler());
$orderItem->setComment($item->getComment());
$options = array();
if ($productOptions = $item->getProduct()->getTypeInstance(true)->getOrderOptions($item->getProduct())) {
$options = $productOptions;
}
if ($addOptions = $item->getOptionByCode('additional_options')) {
$options['additional_options'] = unserialize($addOptions->getValue());
}
if ($options) {
$orderItem->setProductOptions($options);
}
if ($item->getParentItem()) {
$orderItem->setParentItem($orderObj->getItemByQuoteItemId($item->getParentItem()->getId()));
}
$orderObj->addItem($orderItem);
}
$orderObj->setCanShipPartiallyItem(false);
$orderObj->place();
$quoteObj->setIsActive(0)->save();
$orderObj->save();
$orderObj->sendNewOrderEmail();
return $orderObj->getId();
} catch (Exception $e){
Mage::log($e->getMessage());
Mage::log($e->getTraceAsString());
}
}

Magento change shipping rate in one page checkout for COD

My question is quite simple. I need to change the shipping rate cost in one page checkout to "0" once the user select COD as payment method in one page checkout. I think I can do this easely with an observer. Could you please helpme to know what event should I observe?.
Can I use checkout_controller_onepage_save_shipping_method ?. Any kind of help will be highly appreciated!!
Details Posted By OP as answer
I override the Mage_Checkout_Model_Type_Onepage class and modify the savePayment method. Then I did this:
1.- A first try:
public function savePayment($data)
{
.....
....
$payment = $quote->getPayment();
$payment->importData($data);
$quote->save();
//My custom code
if($data['method']=='cashondelivery'){
$shipping = $quote->getShippingAddress();
$address = $quote->getBillingAddress();
$shipping->addData($address)->setShippingMethod('flatrate_flatrate');
}
Where my flatrate_flatrate is 0. Unfortunately it doesn't work well. This snippet set to 0 my Grant Total.
My second try was:
public function savePayment($data)
{
.....
....
$payment = $quote->getPayment();
$payment->importData($data);
$quote->save();
//My custom code
if($data['method']=='cashondelivery'){
$this->getQuote()->getShippingAddress()->setShippingAmount(0);
$this->getQuote()->getShippingAddress()->setBaseShippingAmount(0);
}
This code works but only a few times, I don't understand why ??.. Could somebody helpme to fix this please?. Any kind of help will be highly appreciated.
Kind regards!
Ok. Now I have this and it works but it doesn't update the grand total amount. Even the order is processed with the normal shipping cost. I mean, finally it doesn't update anything. Could somebody in someway give me a hand on this please?.
if($data['method']=='cashondelivery'){
$quote->getShippingAddress()->setShippingMethod('flatrate_flatrate');
$quote->getShippingAddress()->setShippingAmount(0);
$quote->getShippingAddress()->setBaseShippingAmount(0);
$quote->getShippingAddress()->setShippingInclTax(0);
$quote->getShippingAddress()->setBaseShippingInclTax(0);
$quote->collectTotals();
$quote->save();
}
Warming regards!
Ok, I did something crazy but it seems it works (at least partially). I override Mage_Checkout_OnepageController too and add it a new method call actualizaShippingMethodAction.
It looks like this:
public function actualizaShippingMethodAction()
{
if ($this->_expireAjax()) {
return;
}
if ($this->getRequest()->isPost()) {
$data = $this->getRequest()->getPost('shipping_method', '');
$result = $this->getOnepage()->saveShippingMethod($data);
// $result will contain error data if shipping method is empty
if (!$result) {
$this->getOnepage()->getQuote()->collectTotals();
}
$this->getOnepage()->getQuote()->collectTotals()->save();
}
}
Now in my original class that is overriding (Mage_Checkout_Model_Type_Onepage) I did this.
if($data['method']=='cashondelivery'){
$cliente = new Varien_Http_Client();
$_configuracion = array('maxredirects'=>5, 'timeout'=>30);
$llamada = Mage::getBaseUrl()."checkout/onepage/actualizaShippingMethod/";
$cliente->setUri($llamada)
->setConfig($_configuracion)
->setMethod(Zend_Http_Client::POST)
->setParameterPost('shipping_method','flatrate_flatrate');
$respuesta = $cliente->request();
$quote->getShippingAddress()->setShippingAmount(0);
$quote->getShippingAddress()->setBaseShippingAmount(0);
$quote->getShippingAddress()->setShippingInclTax(0);
$quote->getShippingAddress()->setBaseShippingInclTax(0);
$quote->collectTotals()->save();
}
$this->getCheckout()
->setStepData('payment', 'complete', true)
->setStepData('review', 'allow', true);
return array();
Now the order is passing without shipping cost as spected but the order review (summary) is not updating the final costs. And I thinks this solution has a bug because if the user returns and select another payment method the shipping cost is 0 again.
Any kind of help, whatever, will be highly, highly appreciated
THANKS
Finally I have a solution and I think is an answer to the original question. If not please pardon me.
Forget to override savePayment($data) on Mage_Checkout_Model_Type_Onepage. Just focus on overriding Mage_Checkout_OnepageController, and add to the savePaymentAction() method the following code.
$data = $this->getRequest()->getPost('payment', array());
/*Custom code*/
if($data['method']=='cashondelivery'){//Only if payment method is cashondelivery
$result = $this->getOnepage()->savePayment($data);
// get section and redirect data
$redirectUrl = $this->getOnepage()->getQuote()->getPayment()->getCheckoutRedirectUrl();
if (empty($result['error']) && !$redirectUrl) {
$this->loadLayout('checkout_onepage_review');
$result['goto_section'] = 'review';
$result['update_section'] = array(
'name' => 'review',
'html' => $this->_getReviewHtml()
);
}
if ($redirectUrl) {
$result['redirect'] = $redirectUrl;
}
//Update totals for Shipping Methods
$resultado = $this->getOnepage()->saveShippingMethod('flatrate_flatrate');
$this->getOnepage()->getQuote()->collectTotals()->save();
}else{
$result = $this->getOnepage()->savePayment($data);
// get section and redirect data
$redirectUrl = $this->getOnepage()->getQuote()->getPayment()->getCheckoutRedirectUrl();
if (empty($result['error']) && !$redirectUrl) {
$this->loadLayout('checkout_onepage_review');
$result['goto_section'] = 'review';
$result['update_section'] = array(
'name' => 'review',
'html' => $this->_getReviewHtml()
);
}
if ($redirectUrl) {
$result['redirect'] = $redirectUrl;
}
//Return the original values according with the initial user sellection
//I use a session variable to store the original selection
$shippingMethod = Mage::getSingleton('core/session')->getShippingInicial();
$resultado = $this->getOnepage()->saveShippingMethod($shippingMethod);
$this->getOnepage()->getQuote()->collectTotals()->save();
}
} catch (Mage_Payment_Exception $e) {
if ($e->getFields()) {
...
Then you have to override saveShippingMethodAction() and add the following code.
...
$result = $this->getOnepage()->saveShippingMethod($data);
//We store the Shipping Method initial selection
Mage::getSingleton('core/session')->setShippingInicial($data);
// $result will contain error data if shipping method is empty
if (!$result) { ...
If you test this you will find that it works as expected. But now it takes 2 loading times to correctly show the total costs in the review part. I read this question (IWD one page checkout extension Magento: review refresh) but it doesn't help a lot.
Could somebody point me in the right direction to update the review part twice?.
WARMING REGARDS!
Could somebody have an idea how to achieve this?. Regards!

Magento disable tax when customer enter vat number on checkout

I have magento 1.7 site and i'm tiring to remove that tax from customers if they enter an tax number on checkout page.
i have two countries Netherlands and Belgium for tax rules both have 10% taxes.the default country is Belgium.
i need to remove the tax adding when Belgium customer enter there vat number on checkout page.
i tired using tax rules but no luck.
anyone have idea about how to do that using magento backend or using code level.any answers i appreciated.
thank you
Over ride Magento's Tax Model getRate() function is how we did something similar.
class My_Module_Model_Tax_Calculation extends Mage_Tax_Model_Calculation
{
public function getRate($request)
{
if (!$request->getCountryId() || !$request->getCustomerClassId() || !$request->getProductClassId()) {
return 0;
}
$country_id = $request->getCountryId();
if ($country_id == 'BE' && $this->getCustomer() && $this->getCustomer()->getTaxvat()) {
return 0;
}
$cacheKey = $this->_getRequestCacheKey($request);
if (!isset($this->_rateCache[$cacheKey])) {
$this->unsRateValue();
$this->unsCalculationProcess();
$this->unsEventModuleId();
Mage::dispatchEvent('tax_rate_data_fetch', array('request'=>$request));
if (!$this->hasRateValue()) {
$rateInfo = $this->_getResource()->getRateInfo($request);
$this->setCalculationProcess($rateInfo['process']);
$this->setRateValue($rateInfo['value']);
} else {
$this->setCalculationProcess($this->_formCalculationProcess());
}
$this->_rateCache[$cacheKey] = $this->getRateValue();
$this->_rateCalculationProcess[$cacheKey] = $this->getCalculationProcess();
}
return $this->_rateCache[$cacheKey];
}
}

Categories