Pendahuluan: Ini dimaksudkan untuk berfungsi sebagai observasi tertulis dari arsitektur Magento untuk komunitas (dan saya sendiri), serta pertanyaan aktual. Kami sedang bekerja dengan pengalaman kereta dan checkout yang sangat dimodifikasi, tetapi akar masalah ini adalah dalam logika inti Magento.
Latar Belakang
Kami telah membuat kupon pengiriman gratis menggunakan fungsionalitas aturan harga keranjang belanja standar. Tidak ada ketentuan pada kupon, dan satu-satunya tindakan adalah yang Free Shipping
diatur ke For matching items only
. Karena tidak ada kondisi, ini akan ditetapkanfree_shipping
ke1
untuk semua item kutipan penjualan.
Seperti kebiasaan, kami juga telah mengaktifkan metode pengiriman Pengiriman Gratis. Model Freeshipping
operator akan memberikan tarif setiap kali permintaan pengiriman gratis atau subtotal cocok atau melebihi ambang batas (tetapi kami tidak menggunakan opsi ambang batas). Lihat 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 */
}
Dan Mage_Shipping_Model_Carrier_Freeshipping::_updateFreeMethodQuote
terlihat seperti ini:
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);
}
}
Jadi, selama semua item telah free_shipping
ditetapkan ke nilai yang sebenarnya (karena mereka akan, karena kupon), kita harus mendapatkan pengiriman gratis. Dan kami melakukannya!
Masalah
Namun, ada efek samping utama: metode pengiriman apa pun yang bergantung pada item row_weight
(seperti halnya dengan versi kustom dari operator FedEx kami) akan gagal menghitung tarif pengiriman yang tepat karena setiap item row_weight
diatur ke0
saat pengiriman gratis aktif.
Yang cukup menarik, tidak satu pun dari operator pengiriman default Magento yang benar-benar bergantung row_weight
, tetapi kita akan membahasnya setelah kita mencari tahu mengapa / kapan row_weight
diatur ke0
.
Mencari tahu mengapa row_weight
diatur ke0
Bagian ini sebenarnya cukup mudah digali. Sejumlah besar perhitungan pengiriman terjadi di Mage_Sales_Model_Quote_Address_Total_Shipping::collect
, termasuk pengaturan row_weight
untuk 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);
}
}
Mengapa ini tidak memengaruhi operator bawaan Magento
Jika Anda melakukan pencarian regex untuk /row_?weight/i
(misalnya getRowWeight
, setRowWeight
, setData('row_weight')
, dll) di Mage_Shipping
(operator sederhana) danMage_Usa
(FedEx, UPS, dan beberapa operator lain), tidak ada yang muncul. Mengapa? Karena operator default menggunakan berat alamat total, bukan bobot masing-masing item.
Sebagai contoh, mari kita lihat 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());
}
Dan dari mana permintaan mendapatkan berat paket? Jawabannya ada di 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());
Kami dapat mengabaikan penggunaan di $item->getRowWeight()
sini karena requestShippingRates
dipanggil tanpa memberikan item tertentu sebagai parameter di 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();
Ini seharusnya terlihat akrab, karena ini adalah tempat yang sama dengan setiap item row_weight
diatur 0
jika pengiriman gratis berlaku. Perhatikan bagaimana $addressWeight
meringkas setiap item $rowWeight
, tetapi hal itu dilakukan sebelum row_weight
diatur ke0
.
Pada dasarnya, bobot alamat akan selalu menjadi berat total semua item, terlepas dari free_shipping
nilai setiap item. Karena operator bawaan Magento hanya mengandalkan bobot alamat, masalah dengan row_weight
tidak muncul.
Jadi mengapa kita perlu row_weight
Kita butuh row_weight
karena kami telah menyesuaikan pembawa FedEx Magento untuk menghitung tarif terpisah untuk item yang berasal dari asal yang berbeda, bahkan jika mereka pergi ke tujuan yang sama (dan karenanya merupakan bagian dari alamat yang sama). Misalnya, jika Anda tinggal di NJ, lebih murah (dan lebih cepat) untuk mengirim barang dari NJ daripada dari CA - dan jika Anda memiliki barang dari NJ dan CA dalam pesanan Anda, Anda dapat melihat biaya (dan perkiraan tanggal pengiriman) dari setiap pengiriman.
Secara keseluruhan, sepertinya kita dapat dengan mudah mengatasi masalah ini dengan mengabaikan row_weight
dan menggunakan weight * qty
secara langsung. Tapi, itu menuntun kita ke:
Pertanyaan
Mengapa Shipping
total mengatur row_weight
item kutipan penjualan 0
jika pengiriman gratis berlaku? Ini tampaknya tidak digunakan di mana pun.
Pengamatan lebih lanjut
Saya lupa menyebutkan bahwa row_weight
sebenarnya bisa menjadi nol, tetapi masih kurang dari weight * qty
, jika free_shipping
angka bukan true
. Saya berasumsi tujuan dari ini adalah untuk memberikan solusi untuk skenario seperti ini:
Saya memiliki 3 item produk yang sama di troli saya, masing-masing item dengan berat 2 lbs. Saya menerapkan kupon pengiriman gratis, tetapi terbatas pada jumlah 2, jadi itu hanya berlaku untuk 2 item. Sekarang, ketika saya melihat tarif pengiriman, saya akan melihat tarif pengiriman untuk 2 lbs (2 + 0 + 0) daripada 6 lbs (2 + 2 + 2).
Ini tampaknya masuk akal, tetapi ada dua masalah utama:
Tak satu pun dari operator Magento default berfungsi seperti ini (mereka menggunakan berat total alamat, lihat di atas).
Bahkan jika beberapa operator bekerja seperti ini, itu berarti saya bisa memilih metode pengiriman apa pun (mis. Pengiriman semalam) dan hanya membayar untuk berat 1 barang - artinya, pedagang harus menanggung biaya 2 barang lainnya . Terserah pedagang untuk entah bagaimana mengetahui bahwa saya hanya membayar untuk berat 1 item, dan kemudian mengirimkan 2 item lainnya menggunakan metode yang lebih hemat biaya, secara efektif menciptakan ketidakcocokan antara apa yang ditampilkan Magento dan bagaimana item sebenarnya dikirim keluar.