Magento: Programatically update cart via event - php

I'm hooking into the sales_quote_save_after event disaptcher. Firstly as a test I'm trying to get the items in the cart and change their prices to 0. After I do that I'll be building in some other stuff.
I'm having trouble. I can change the unit price no problem, but when I go to recalculate the cart totals the prices are reverting back to the original price.
public function sales_quote_save_before($observer) {
if (Mage::registry('basket_observer_executed')) {
return $this;
}
$quote = $observer->getEvent()->getQuote();
foreach ($quote->getAllItems() as $item) {
if($item->getId()) {
$item->setCustomPrice(0);
}
}
Mage::register('basket_observer_executed', true);
$quote->save();
$quote->setTotalsCollectedFlag(false)->collectTotals();
}
Can anyone point me towards maintaining the new price whilst doing the recalculation of the totals?

I'd try using a different event. I always use checkout_cart_save_after for doing similar actions.Using the event I mentioned, use the following code:
$cart = $observer->getData('cart');
$quote = $cart->getData('quote');
$items = $quote->getAllVisibleItems();
foreach($items as $item)
{
$item->setCustomPrice(0);
$item->setOriginalCustomPrice(0);
$item->getProduct()->setIsSuperMode(true);
$item->save();
}
$quote->save();
$quote->setTotalsCollectedFlag(false)->collectTotals();

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,

WooCommerce: Old deleted item comes back when trying to change the quantity of other item in cart

I have created a custom popup cart using WooCommerce. It has functionalities like
Decrease a product
Increase a product
Remove a product
When I remove the product from the top it goes away. I am using this logic to do that using AJAX.
public function remove_item($key)
{
$this->refresh();
$remove = $this->woocommerce->cart->remove_cart_item($key);
$this->woocommerce->cart->calculate_totals();
if ($remove) {
$this->refresh();
return true;
} else {
return false;
}
}
Now I decrease the remaining item, from quantity 2 to 1. What I get back is the already deleted comes back with 1 quantity and the present item is set to 1.
public function set_item_quantity($key, $quantity)
{
if (!is_numeric($quantity)) {
return;
}
$job = $this->woocommerce->cart->set_quantity($key, $quantity, true);
$this->woocommerce->cart->calculate_totals();
if ($job) {
$this->refresh();
return true;
} else {
return false;
}
}
This is what refresh method looks like.
public function refresh()
{
$woocommerce = \WC();
$this->cart = $woocommerce->cart;
$this->woocommerce = $woocommerce;
$this->woocommerce->cart->calculate_totals();
}
This isn't a cache issue, as I have removed my cache plugin and it still gives me issues. The same doesn't happen when the cart has just one product.
Any help is appreciated. Thanks!

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 duplicating a product programmatically is not displaying in the frontend

I am new to magneto I have tried to duplicate a product programmatically and I have succeeded problem is the duplicated product is showing in magneto admin side while in the frontend the product is not displaying below is my code could you please tell me what is the issue it will be very helpful for me. I have created a separate module for it below is my code.
class Magentotutorial_Helloworld_IndexController extends Mage_Core_Controller_Front_Action {
public function indexAction() {
$final = $_POST['value'];
$obj = Mage::getModel('catalog/product');
$_product = $obj->load($final);
$newProduct = $_product->duplicate();
$newProduct->setStatus(1);
$newProduct->setSku('value'.$final);
$newProduct->setWebsiteIds($_product->getWebsiteIds());
$newProduct->getResource()->save($newProduct);
}
}
This function posted by you very well creates Duplicate product. However, it does not set the below attribute (due to which it's not VISIBLE in the frontend):
Navigate to Catalog > Manage Products > Duplicated Product > Inventory
Qty is 0 and Stock is "Out of Stock" - You will need to write below piece of code in the function to set this product to Stock: "In Stock" and Qty: [some default value] say, 100.
After the line which calls out $newProduct->setWebsiteIds($_product->getWebsiteIds());, you can insert the below lines:
$stockItem = Mage::getModel('cataloginventory/stock_item')->loadByProduct($newProduct->getId());
if ($stockItem->getId() > 0 && $stockItem->getManageStock())
{
$qty = 100; //set a default max value
$stockItem->setQty($qty);
$stockItem->setIsInStock((int)($qty > 0));
$stockItem->save();
}
You will need to run a Re-Index either Manually or Automate it
The product will display in the frontend. See Screenshot below:
[EDIT]
Use the below code and let me know if it works for you:
public function indexAction()
{
$productId = $this->getRequest()->getParam('value');
$productObject = Mage::getModel('catalog/product');
$_product = $productObject->load($productId);
$newProduct = $_product->duplicate();
$newProduct->setStatus(1);
//$newProduct->setName('Duplicate-' . $_product->getName());
$newProduct->setSku('value' . $productId);
$newProduct->setWebsiteIds($_product->getWebsiteIds());
$stockItem = Mage::getModel('cataloginventory/stock_item')->loadByProduct($newProduct->getId());
if ($stockItem->getId() > 0 && $stockItem->getManageStock())
{
$qty = 100;
$stockItem->setQty($qty);
$stockItem->setIsInStock((int)($qty > 0));
$stockItem->save();
}
$newProduct->getResource()->save($newProduct);
$indexers = Mage::getSingleton('index/indexer')->getProcessesCollection();
foreach ($indexers as $indexer)
{
$indexer->reindexEverything();
}
}
Hope this helps.
Happy Coding...

Categories