Я пытаюсь изменить доставку существующего заказа в Magento. Это прекрасно работает в бэкэнде администратора, даже если это довольно сложный процесс, так как мне приходится вручную обновлять многие поля / атрибуты заказа после того, как я установил новый метод доставки для объекта адреса доставки и пересчитал итоговые значения предложения.
Моя проблема заключается в том, что при запуске одного и того же кода во внешнем интерфейсе он не работает вообще, цитата collectTotals отменит все изменения, которые я внес в shippingAddress, и я понятия не имею, как его решить или почему он работает из бэкенд.
Вот как это выглядело:
$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, независимо от того, что я делаю.
Любые предложения, или, возможно, понимание того, как это вообще возможно, работает в бэкэнде, но не во внешнем интерфейсе?
РЕДАКТИРОВАТЬ
После дополнительной отладки я вижу, что доставка меняется как во внешнем, так и во внутреннем интерфейсе. Проблема в том, что плата будет меняться только при запуске этого кода через бэкэнд. Очень странно. Он просто отказывается обновлять стоимость доставки.
Похоже, у меня были некоторые проблемы с наблюдателем на 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
событие.
Других решений пока нет …