Magento: изменить способ доставки в существующем заказе
Я пытаюсь изменить доставку по существующему заказу в Magento. Это отлично работает с серверной части администратора, даже если это довольно сложный процесс, так как мне приходится вручную обновлять множество полей/атрибутов заказа после того, как я установлю новый метод доставки для объекта адреса доставки и пересчитаю итоговые суммы предложения.
Моя проблема в том, что при запуске одного и того же кода на интерфейсе он вообще не работает, результаты сбора котировок отменят все изменения, которые я внес в адрес доставки, и я понятия не имею, как это решить или почему это работает из бэкэнда.
Вот как это выглядело:
$shippingAddress = $quote->getShippingAddress();
$shippingAddress->setShippingMethod('dynamicshipping_'.$shippingCode);
$shippingAddress->setCollectShippingRates(true);
$shippingAddress->collectShippingRates();
$quote->setUseCustomerBalance(1)->setTotalsCollectedFlag(false)->collectTotals()->save();
$order->setShippingHiddenTaxAmount($shippingAddress->getShippingHiddenTaxAmount());
$order->setBaseShippingHiddenTaxAmount($shippingAddress->getBaseShippingHiddenTaxAmount());
$order->setBaseShippingHiddenTaxAmnt($shippingAddress->getBaseShippingHiddenTaxAmnt());
$order->setShippingInclTax($shippingAddress->getShippingInclTax());
$order->setBaseShippingInclTax($shippingAddress->getBaseShippingInclTax());
$order->setShippingTaxAmount($shippingAddress->getShippingTaxAmount());
$order->setBaseShippingTaxAmount($shippingAddress->getBaseShippingTaxAmount());
$order->setShippingAmount($shippingAddress->getShippingAmount());
$order->setBaseShippingAmount($shippingAddress->getBaseShippingAmount());
$order->setShippingDiscountAmount($shippingAddress->getShippingDiscountAmount());
$order->setBaseShippingDiscountAmount($shippingAddress->getBaseShippingDiscountAmount());
$order->setGrandTotal($shippingAddress->getGrandTotal());
$order->setBaseGrandTotal($shippingAddress->getBaseGrandTotal());
$order->setShippingMethod('dynamicshipping_'.$shippingCode);
$order->setShippingDescription($shippingDescription);
$order->setServicePoint($servicePoint);
$order->save();
И, как я уже сказал, это отлично работало каждый раз с бэкэнда, но не при вызове с внешнего интерфейса.
Я пробовал варианты, такие как этот, чтобы попытаться уничтожить любые следы старого способа доставки, но безуспешно.
$quote->getShippingAddress()->removeAllShippingRates()
->setShippingMethod('dynamicshipping_'.$shippingCode)
->setShippingDescription($shippingDescription)
//->setBaseShippingAmount(0)
//->setBaseShippingTaxAmount(0)
//->setShippingTaxAmount(0)
//->setShippingInclTax(0)
->setCollectShippingRates(true)
//->unsetData('cached_items_all')
//->unsetData('cached_items_nominal')
//->unsetData('cached_items_nonnominal')
->collectShippingRates()
//->collectTotals()
->save();
Мне кажется, что в цитате используется более старая/другая копия адреса доставки, когда я звоню в collectTotals, независимо от того, что я сделай.
Какие-либо предложения или, возможно, понимание того, как это вообще возможно, что это работает в бэкэнде, но не во внешнем интерфейсе?
РЕДАКТИРОВАТЬ
После дополнительной отладки я вижу, что доставка действительно меняется как во внешнем, так и во внутреннем интерфейсе. Проблема в том, что плата изменится только при запуске этого кода через серверную часть. Очень странно. Он просто отказывается обновлять стоимость доставки.
1 answers
Похоже, у меня были некоторые проблемы с наблюдателем в collectTotals, и именно по этой причине он работал в бэкэнде, где событие не было запущено.
Полный код для справки, который я недавно изменил, чтобы использовать более надежный метод для копирования всех полей обратно в заказ.
/* @var $order Mage_Sales_Model_Order */
/* @var $quote Mage_Sales_Model_Quote */
$shippingAddress = $quote->getShippingAddress();
$shippingAddress->setShippingMethod('dynamicshipping_'.$shippingCode);
$shippingAddress->setShippingDescription($shippingDescription);
$shippingAddress->setCollectShippingRates(true)->collectShippingRates();
$quote->collectTotals();
if ($this->updateMagentoOrder($order, $quote)) {
// here's where I check if we successfully updated the authorized
// amount at the payment gateway, before saving anything
// wrapping the payment update and save in a try-catch
$quote->save();
$order->save();
}
И используя этот метод для обновления всех полей заказа:
/**
* Updates a Magento order based on quote changes
* will not save anything, up to the caller.
* deleting items not supported.
*
* @param $order Mage_Sales_Model_Order
* @param $quote Mage_Sales_Model_Quote
* @return bool
*/
public function updateMagentoOrder($order, $quote) {
if (!$order instanceof Mage_Sales_Model_Order || !$quote instanceof Mage_Sales_Model_Quote) {
return false;
}
try {
$converter = Mage::getSingleton('sales/convert_quote');
$converter->toOrder($quote, $order);
foreach ($quote->getAllItems() as $quoteItem) {
$orderItem = $converter->itemToOrderItem($quoteItem);
$quoteItemId = $quoteItem->getId();
$origOrderItem = empty($quoteItemId) ? null : $order->getItemByQuoteItemId($quoteItemId);
if ($origOrderItem) {
$origOrderItem->addData($orderItem->getData());
} else {
if ($quoteItem->getParentItem()) {
$orderItem->setParentItem(
$order->getItemByQuoteItemId($quoteItem->getParentItem()->getId())
);
$orderItem->setParentItemId($quoteItem->getParentItemId());
}
$order->addItem($orderItem);
}
}
if ($shippingAddress = $quote->getShippingAddress()) {
$converter->addressToOrder($shippingAddress, $order);
}
} catch (Exception $e) {
Mage::logException($e);
return false;
}
return true;
}
Для справки, описанный выше метод может зациклить $order->getAllItems()
и сначала выполнить $orderItem->cancel()->delete();
для них, но я не буду поддерживать удаление элементов прямо сейчас.
Часть cancel()
перед удалением предназначена для того, чтобы модуль CatalogInventory мог восстановить запасы. Он прослушивает событие sales_order_item_cancel
.