Передмова: Це покликане слугувати як письмовим спостереженням архітектури Magento для громади (і мене самого), так і актуальним питанням. Ми працюємо із сильно модифікованим кошиком та досвідом оформлення замовлень, але корінь цієї проблеми полягає в основній логіці Magento.
Фон
Ми створили купон на безкоштовну доставку, використовуючи стандартні функції цін на кошики для покупок. У купоні немає ніяких умов, і єдина дія, яка Free Shipping
встановлена For matching items only
. Оскільки немає ніяких умов, це буде встановлено free_shipping
в 1
протягом всіх продажів цитати пунктів.
Як це прийнято, ми також увімкнули спосіб доставки Безкоштовна доставка. Модель Freeshipping
перевізника надаватиме тарифи щоразу, коли запит має безкоштовну доставку або підсумкові збіги або перевищує поріг (але ми не використовуємо порогову опцію). Дивіться Mage_Shipping_Model_Carrier_Freeshipping::collectRates
:
$this->_updateFreeMethodQuote($request);
if (($request->getFreeShipping()) // <-- This is the condition we're relying on
|| ($request->getBaseSubtotalInclTax() >=
$this->getConfigData('free_shipping_subtotal'))
) {
/* Snip: Add $0.00 method to the result */
}
І Mage_Shipping_Model_Carrier_Freeshipping::_updateFreeMethodQuote
виглядає так:
protected function _updateFreeMethodQuote($request)
{
$freeShipping = false;
$items = $request->getAllItems();
$c = count($items);
for ($i = 0; $i < $c; $i++) {
if ($items[$i]->getProduct() instanceof Mage_Catalog_Model_Product) {
if ($items[$i]->getFreeShipping()) {
$freeShipping = true;
} else {
return;
}
}
}
if ($freeShipping) {
$request->setFreeShipping(true);
}
}
Отже, доки всі предмети free_shipping
встановили триєднувальну цінність (яку вони отримають завдяки купону), ми повинні отримати безкоштовну доставку. І ми робимо!
Проблема
Однак є головний побічний ефект: будь-які способи доставки, які покладаються на товар row_weight
(як у випадку з нашою спеціалізованою версією FedEx-оператора), не зможуть розрахувати належні тарифи доставки, оскільки для кожного товару row_weight
встановлено, 0
коли активна безкоштовна доставка.
Цікаво, що жоден із перевізників доставки за замовчуванням Magento насправді не покладається row_weight
, але ми дістанемося цього, після того як ми з'ясуємо, чому / коли row_weight
встановлено 0
.
З'ясування, чому row_weight
встановлено значення0
Цю частину насправді було легко викопати. Великий шматок з судноплавних розрахунків відбувається в Mage_Sales_Model_Quote_Address_Total_Shipping::collect
тому числі установки row_weight
на 0
:
public function collect(Mage_Sales_Model_Quote_Address $address)
{
parent::collect($address);
foreach ($items as $item) {
/* Snip: Handling virtual items and parent items */
if ($item->getHasChildren() && $item->isShipSeparately()) {
/* Snip: Handling items with children */
}
else {
if (!$item->getProduct()->isVirtual()) {
$addressQty += $item->getQty();
}
$itemWeight = $item->getWeight();
$rowWeight = $itemWeight*$item->getQty();
$addressWeight+= $rowWeight;
if ($freeAddress || $item->getFreeShipping()===true) {
$rowWeight = 0;
} elseif (is_numeric($item->getFreeShipping())) {
$freeQty = $item->getFreeShipping();
if ($item->getQty()>$freeQty) {
$rowWeight = $itemWeight*($item->getQty()-$freeQty);
}
else {
$rowWeight = 0;
}
}
$freeMethodWeight+= $rowWeight;
$item->setRowWeight($rowWeight);
}
}
Чому це не впливає на операторів за замовчуванням Magento
Якщо ви робите пошук регулярних виразів для /row_?weight/i
(наприклад getRowWeight
, setRowWeight
, setData('row_weight')
і т.д.) в Mage_Shipping
(прості носії) і Mage_Usa
(FedEx, UPS, і деякі інші носії), нічого не вискочить. Чому? Оскільки оператори за замовчуванням використовують загальну вагу адреси, а не вагу окремих елементів.
Наприклад, розглянемо Mage_Usa_Model_Shipping_Carrier_Fedex::setRequest
:
public function setRequest(Mage_Shipping_Model_Rate_Request $request)
{
$this->_request = $request;
$r = new Varien_Object();
/* Snip */
$weight = $this->getTotalNumOfBoxes($request->getPackageWeight());
$r->setWeight($weight);
if ($request->getFreeMethodWeight()!= $request->getPackageWeight()) {
$r->setFreeMethodWeight($request->getFreeMethodWeight());
}
І звідки береться запит ваги пакета? Відповідь Mage_Sales_Model_Quote_Address::requestShippingRates
:
public function requestShippingRates(Mage_Sales_Model_Quote_Item_Abstract $item = null)
{
/** @var $request Mage_Shipping_Model_Rate_Request */
$request = Mage::getModel('shipping/rate_request');
/* Snip */
$request->setPackageWeight($item ? $item->getRowWeight() : $this->getWeight());
Ми можемо ігнорувати використання $item->getRowWeight()
тут, оскільки requestShippingRates
викликається без надання конкретного елемента в якості параметра в Mage_Sales_Model_Quote_Address_Total_Shipping::collect
:
public function collect(Mage_Sales_Model_Quote_Address $address)
{
parent::collect($address);
foreach ($items as $item) {
/* Snip: Handling virtual items and parent items */
if ($item->getHasChildren() && $item->isShipSeparately()) {
/* Snip: Handling items with children */
}
else {
if (!$item->getProduct()->isVirtual()) {
$addressQty += $item->getQty();
}
$itemWeight = $item->getWeight();
$rowWeight = $itemWeight*$item->getQty();
$addressWeight+= $rowWeight;
if ($freeAddress || $item->getFreeShipping()===true) {
$rowWeight = 0;
} elseif (is_numeric($item->getFreeShipping())) {
$freeQty = $item->getFreeShipping();
if ($item->getQty()>$freeQty) {
$rowWeight = $itemWeight*($item->getQty()-$freeQty);
}
else {
$rowWeight = 0;
}
}
$freeMethodWeight+= $rowWeight;
$item->setRowWeight($rowWeight);
}
}
$address->setWeight($addressWeight);
$address->setFreeMethodWeight($freeMethodWeight);
$address->collectShippingRates();
Це повинно виглядати знайомим, так як це те ж саме місце , що кожен елемент row_weight
встановлюються в 0
разі безкоштовна доставка діє. Зверніть увагу, як $addressWeight
підсумовується кожен елемент $rowWeight
, але це зроблено раніше, row_weight
як встановлено0
.
В основному, адресна вага завжди буде загальною вагою всіх елементів, незалежно від free_shipping
значення кожного елемента. Оскільки оператори Magento за замовчуванням покладаються лише на вагу адреси, проблема з row_weight
не з’являється.
То навіщо нам це потрібно row_weight
Нам потрібно row_weight
тому що ми настроїли перевізник FedEx Magento, щоб обчислювати окремі тарифи на товари, які надходять з різного походження, навіть якщо вони їдуть до одного місця призначення (і, таким чином, є частиною однієї адреси). Наприклад, якщо ви живете в штаті Нью-Джерсі, дешевше (і швидше) доставити товар з Нью-Джерсі, ніж з Каліфорнії, - і якщо у вас є предмети як з Нью-Джерсі, так і з Каліфорнії, ви зможете побачити вартість (і приблизну оцінку) дата доставки) кожної вантажу.
Загалом, схоже, що ми можемо легко обійти цю проблему, ігноруючи row_weight
та використовуючи weight * qty
безпосередньо. Але це нас призводить до:
Питання
Чому Shipping
загальний обсяг встановлених row_weight
цін на продажі встановлюється, 0
якщо діє безкоштовна доставка? Здається, це ніде не використовується.
Подальші спостереження
Я знехтував згадати, що row_weight
насправді може бути не нульовим, але все ж меншим, ніж weight * qty
, якщо free_shipping
це число замість true
. Я припускаю, що мета цього - запропонувати рішення такого сценарію:
У мене в кошику є 3 предмети того самого товару, кожен предмет важить 2 фунти. Я застосовую купон на безкоштовну доставку, але він обмежений кількістю 2, тому він стосується лише двох предметів. Тепер, коли я дивлюсь на тарифи на доставку, я буду дивитись на тарифи на доставку за 2 фунти (2 + 0 + 0), а не за 6 фунтів (2 + 2 + 2).
Це, мабуть, має сенс, але в цьому є дві основні проблеми:
Жоден з операторів Magento за замовчуванням не працює так (вони використовують загальну вагу адреси, див. Вище).
Навіть якщо хтось із перевізників працював так, це означатиме, що я можу вибрати будь-який спосіб доставки (наприклад, доставка за ніч) і заплатити лише вагу 1 товару - це означає, що торговець повинен буде покрити вартість інших 2 товарів . Торговець мав би якось зрозуміти, що я заплатив лише вагу 1 предмета, а потім відвантажував інші 2 предмети, використовуючи більш економічний метод, фактично створюючи невідповідність між тим, що відображає Magento, і тим, як фактично були товари. відвантажений.