There is the same bug on Magento 1.6. This fix is working and I hope to work on Magento 1.7 too.
Open app/code/core/Mage/SalesRule/Model/Validator.php
and add below this:
protected $_baseRoundingDeltas = array();
this code:
protected $_address = null;
also in protected function _getAddress
below this:
if ($item instanceof Mage_Sales_Model_Quote_Address_Item) {
$address = $item->getAddress();
add this:
} elseif ($this->_address) {
$address = $this->_address;
and finally in public function reset
above this:
return $this;
add this:
$this->_address = $address;
Figured I'd take a stab at this... ;)
Quite an interesting question you've posed here so here's why I think they did it, however I'm still working to track down when this particular case comes into play.
Going over the USPS carrier method, it looks like International Requests to their API provide itemized weights for each product. This is the only carrier that I can find that does this. Find the full method below, and the highlighted section below that.
protected function _formIntlShipmentRequest(Varien_Object $request)
{
$packageParams = $request->getPackageParams();
$height = $packageParams->getHeight();
$width = $packageParams->getWidth();
$length = $packageParams->getLength();
$girth = $packageParams->getGirth();
$packageWeight = $request->getPackageWeight();
if ($packageParams->getWeightUnits() != Zend_Measure_Weight::POUND) {
$packageWeight = Mage::helper('usa')->convertMeasureWeight(
$request->getPackageWeight(),
$packageParams->getWeightUnits(),
Zend_Measure_Weight::POUND
);
}
if ($packageParams->getDimensionUnits() != Zend_Measure_Length::INCH) {
$length = round(Mage::helper('usa')->convertMeasureDimension(
$packageParams->getLength(),
$packageParams->getDimensionUnits(),
Zend_Measure_Length::INCH
));
$width = round(Mage::helper('usa')->convertMeasureDimension(
$packageParams->getWidth(),
$packageParams->getDimensionUnits(),
Zend_Measure_Length::INCH
));
$height = round(Mage::helper('usa')->convertMeasureDimension(
$packageParams->getHeight(),
$packageParams->getDimensionUnits(),
Zend_Measure_Length::INCH
));
}
if ($packageParams->getGirthDimensionUnits() != Zend_Measure_Length::INCH) {
$girth = round(Mage::helper('usa')->convertMeasureDimension(
$packageParams->getGirth(),
$packageParams->getGirthDimensionUnits(),
Zend_Measure_Length::INCH
));
}
$container = $request->getPackagingType();
switch ($container) {
case 'VARIABLE':
$container = 'VARIABLE';
break;
case 'FLAT RATE ENVELOPE':
$container = 'FLATRATEENV';
break;
case 'FLAT RATE BOX':
$container = 'FLATRATEBOX';
break;
case 'RECTANGULAR':
$container = 'RECTANGULAR';
break;
case 'NONRECTANGULAR':
$container = 'NONRECTANGULAR';
break;
default:
$container = 'VARIABLE';
}
$shippingMethod = $request->getShippingMethod();
list($fromZip5, $fromZip4) = $this->_parseZip($request->getShipperAddressPostalCode());
// the wrap node needs for remove xml declaration above
$xmlWrap = new SimpleXMLElement('<?xml version = "1.0" encoding = "UTF-8"?><wrap/>');
$method = '';
$service = $this->getCode('service_to_code', $shippingMethod);
if ($service == 'Priority') {
$method = 'Priority';
$rootNode = 'PriorityMailIntlRequest';
$xml = $xmlWrap->addChild($rootNode);
} else if ($service == 'First Class') {
$method = 'FirstClass';
$rootNode = 'FirstClassMailIntlRequest';
$xml = $xmlWrap->addChild($rootNode);
} else {
$method = 'Express';
$rootNode = 'ExpressMailIntlRequest';
$xml = $xmlWrap->addChild($rootNode);
}
$xml->addAttribute('USERID', $this->getConfigData('userid'));
$xml->addAttribute('PASSWORD', $this->getConfigData('password'));
$xml->addChild('Option');
$xml->addChild('Revision', self::DEFAULT_REVISION);
$xml->addChild('ImageParameters');
$xml->addChild('FromFirstName', $request->getShipperContactPersonFirstName());
$xml->addChild('FromLastName', $request->getShipperContactPersonLastName());
$xml->addChild('FromFirm', $request->getShipperContactCompanyName());
$xml->addChild('FromAddress1', $request->getShipperAddressStreet2());
$xml->addChild('FromAddress2', $request->getShipperAddressStreet1());
$xml->addChild('FromCity', $request->getShipperAddressCity());
$xml->addChild('FromState', $request->getShipperAddressStateOrProvinceCode());
$xml->addChild('FromZip5', $fromZip5);
$xml->addChild('FromZip4', $fromZip4);
$xml->addChild('FromPhone', $request->getShipperContactPhoneNumber());
if ($method != 'FirstClass') {
if ($request->getReferenceData()) {
$referenceData = $request->getReferenceData() . ' P' . $request->getPackageId();
} else {
$referenceData = $request->getOrderShipment()->getOrder()->getIncrementId()
. ' P'
. $request->getPackageId();
}
$xml->addChild('FromCustomsReference', 'Order #' . $referenceData);
}
$xml->addChild('ToFirstName', $request->getRecipientContactPersonFirstName());
$xml->addChild('ToLastName', $request->getRecipientContactPersonLastName());
$xml->addChild('ToFirm', $request->getRecipientContactCompanyName());
$xml->addChild('ToAddress1', $request->getRecipientAddressStreet1());
$xml->addChild('ToAddress2', $request->getRecipientAddressStreet2());
$xml->addChild('ToCity', $request->getRecipientAddressCity());
$xml->addChild('ToProvince', $request->getRecipientAddressStateOrProvinceCode());
$xml->addChild('ToCountry', $this->_getCountryName($request->getRecipientAddressCountryCode()));
$xml->addChild('ToPostalCode', $request->getRecipientAddressPostalCode());
$xml->addChild('ToPOBoxFlag', 'N');
$xml->addChild('ToPhone', $request->getRecipientContactPhoneNumber());
$xml->addChild('ToFax');
$xml->addChild('ToEmail');
if ($method != 'FirstClass') {
$xml->addChild('NonDeliveryOption', 'Return');
}
if ($method == 'FirstClass') {
if (stripos($shippingMethod, 'Letter') !== false) {
$xml->addChild('FirstClassMailType', 'LETTER');
} else if (stripos($shippingMethod, 'Flat') !== false) {
$xml->addChild('FirstClassMailType', 'FLAT');
} else{
$xml->addChild('FirstClassMailType', 'PARCEL');
}
}
if ($method != 'FirstClass') {
$xml->addChild('Container', $container);
}
$shippingContents = $xml->addChild('ShippingContents');
$packageItems = $request->getPackageItems();
// get countries of manufacture
$countriesOfManufacture = array();
$productIds = array();
foreach ($packageItems as $itemShipment) {
$item = new Varien_Object();
$item->setData($itemShipment);
$productIds[]= $item->getProductId();
}
$productCollection = Mage::getResourceModel('catalog/product_collection')
->addStoreFilter($request->getStoreId())
->addFieldToFilter('entity_id', array('in' => $productIds))
->addAttributeToSelect('country_of_manufacture');
foreach ($productCollection as $product) {
$countriesOfManufacture[$product->getId()] = $product->getCountryOfManufacture();
}
$packagePoundsWeight = $packageOuncesWeight = 0;
// for ItemDetail
foreach ($packageItems as $itemShipment) {
$item = new Varien_Object();
$item->setData($itemShipment);
$itemWeight = $item->getWeight() * $item->getQty();
if ($packageParams->getWeightUnits() != Zend_Measure_Weight::POUND) {
$itemWeight = Mage::helper('usa')->convertMeasureWeight(
$itemWeight,
$packageParams->getWeightUnits(),
Zend_Measure_Weight::POUND
);
}
if (!empty($countriesOfManufacture[$item->getProductId()])) {
$countryOfManufacture = $this->_getCountryName(
$countriesOfManufacture[$item->getProductId()]
);
} else {
$countryOfManufacture = '';
}
$itemDetail = $shippingContents->addChild('ItemDetail');
$itemDetail->addChild('Description', $item->getName());
$ceiledQty = ceil($item->getQty());
if ($ceiledQty < 1) {
$ceiledQty = 1;
}
$individualItemWeight = $itemWeight / $ceiledQty;
$itemDetail->addChild('Quantity', $ceiledQty);
$itemDetail->addChild('Value', $item->getCustomsValue() * $item->getQty());
list($individualPoundsWeight, $individualOuncesWeight) = $this->_convertPoundOunces($individualItemWeight);
$itemDetail->addChild('NetPounds', $individualPoundsWeight);
$itemDetail->addChild('NetOunces', $individualOuncesWeight);
$itemDetail->addChild('HSTariffNumber', 0);
$itemDetail->addChild('CountryOfOrigin', $countryOfManufacture);
list($itemPoundsWeight, $itemOuncesWeight) = $this->_convertPoundOunces($itemWeight);
$packagePoundsWeight += $itemPoundsWeight;
$packageOuncesWeight += $itemOuncesWeight;
}
$additionalPackagePoundsWeight = floor($packageOuncesWeight / self::OUNCES_POUND);
$packagePoundsWeight += $additionalPackagePoundsWeight;
$packageOuncesWeight -= $additionalPackagePoundsWeight * self::OUNCES_POUND;
if ($packagePoundsWeight + $packageOuncesWeight / self::OUNCES_POUND < $packageWeight) {
list($packagePoundsWeight, $packageOuncesWeight) = $this->_convertPoundOunces($packageWeight);
}
$xml->addChild('GrossPounds', $packagePoundsWeight);
$xml->addChild('GrossOunces', $packageOuncesWeight);
if ($packageParams->getContentType() == 'OTHER' && $packageParams->getContentTypeOther() != null) {
$xml->addChild('ContentType', $packageParams->getContentType());
$xml->addChild('ContentTypeOther ', $packageParams->getContentTypeOther());
} else {
$xml->addChild('ContentType', $packageParams->getContentType());
}
$xml->addChild('Agreement', 'y');
$xml->addChild('ImageType', 'PDF');
$xml->addChild('ImageLayout', 'ALLINONEFILE');
if ($method == 'FirstClass') {
$xml->addChild('Container', $container);
}
// set size
if ($packageParams->getSize()) {
$xml->addChild('Size', $packageParams->getSize());
}
// set dimensions
$xml->addChild('Length', $length);
$xml->addChild('Width', $width);
$xml->addChild('Height', $height);
if ($girth) {
$xml->addChild('Girth', $girth);
}
$xml = $xmlWrap->{$rootNode}->asXML();
return $xml;
}
Particular section:
$packagePoundsWeight = $packageOuncesWeight = 0;
// for ItemDetail
foreach ($packageItems as $itemShipment) {
$item = new Varien_Object();
$item->setData($itemShipment);
$itemWeight = $item->getWeight() * $item->getQty();
if ($packageParams->getWeightUnits() != Zend_Measure_Weight::POUND) {
$itemWeight = Mage::helper('usa')->convertMeasureWeight(
$itemWeight,
$packageParams->getWeightUnits(),
Zend_Measure_Weight::POUND
);
}
if (!empty($countriesOfManufacture[$item->getProductId()])) {
$countryOfManufacture = $this->_getCountryName(
$countriesOfManufacture[$item->getProductId()]
);
} else {
$countryOfManufacture = '';
}
$itemDetail = $shippingContents->addChild('ItemDetail');
$itemDetail->addChild('Description', $item->getName());
$ceiledQty = ceil($item->getQty());
if ($ceiledQty < 1) {
$ceiledQty = 1;
}
$individualItemWeight = $itemWeight / $ceiledQty;
$itemDetail->addChild('Quantity', $ceiledQty);
$itemDetail->addChild('Value', $item->getCustomsValue() * $item->getQty());
list($individualPoundsWeight, $individualOuncesWeight) = $this->_convertPoundOunces($individualItemWeight);
$itemDetail->addChild('NetPounds', $individualPoundsWeight);
$itemDetail->addChild('NetOunces', $individualOuncesWeight);
$itemDetail->addChild('HSTariffNumber', 0);
$itemDetail->addChild('CountryOfOrigin', $countryOfManufacture);
list($itemPoundsWeight, $itemOuncesWeight) = $this->_convertPoundOunces($itemWeight);
$packagePoundsWeight += $itemPoundsWeight;
$packageOuncesWeight += $itemOuncesWeight;
}
To me, it appears Magento is recalculating the package weight based on the actual item weights, and not leveraging the address weight. I wonder if the package items being passed do not have their weight zeroed, because that would lead to false item weights considering the rates response would be based on bad weight data.
Shot in the dark though.
Best Answer
Create a module with the following
config.xml
:This is the rewritten class in
Shipping/Onepage/Block/Method.php
, which removes all other methods if free shipping is available:Source: http://www.blog.magepsycho.com/hide-other-shipping-methods-when-free-shipping-is-enabled/