_result)) { $this->_result = Mage::getModel('shipping/rate_result'); } return $this->_result; } /** * Set shipping orig data * * @param array $data * @return null */ public function setOrigData($data) { $this->_orig = $data; } /** * Reset cached result * * @return Mage_Shipping_Model_Shipping */ public function resetResult() { $this->getResult()->reset(); return $this; } /** * Retrieve configuration model * * @return Mage_Shipping_Model_Config */ public function getConfig() { return Mage::getSingleton('shipping/config'); } /** * Retrieve all methods for supplied shipping data * * @todo make it ordered * @param Mage_Shipping_Model_Shipping_Method_Request $data * @return Mage_Shipping_Model_Shipping */ public function collectRates(Mage_Shipping_Model_Rate_Request $request) { $storeId = $request->getStoreId(); if (!$request->getOrig()) { $request ->setCountryId(Mage::getStoreConfig(self::XML_PATH_STORE_COUNTRY_ID, $request->getStore())) ->setRegionId(Mage::getStoreConfig(self::XML_PATH_STORE_REGION_ID, $request->getStore())) ->setCity(Mage::getStoreConfig(self::XML_PATH_STORE_CITY, $request->getStore())) ->setPostcode(Mage::getStoreConfig(self::XML_PATH_STORE_ZIP, $request->getStore())); } $limitCarrier = $request->getLimitCarrier(); if (!$limitCarrier) { $carriers = Mage::getStoreConfig('carriers', $storeId); foreach ($carriers as $carrierCode => $carrierConfig) { $this->collectCarrierRates($carrierCode, $request); } } else { if (!is_array($limitCarrier)) { $limitCarrier = array($limitCarrier); } foreach ($limitCarrier as $carrierCode) { $carrierConfig = Mage::getStoreConfig('carriers/' . $carrierCode, $storeId); if (!$carrierConfig) { continue; } $this->collectCarrierRates($carrierCode, $request); } } return $this; } /** * Collect rates of given carrier * * @param string $carrierCode * @param Mage_Shipping_Model_Rate_Request $request * @return Mage_Shipping_Model_Shipping */ public function collectCarrierRates($carrierCode, $request) { /* @var $carrier Mage_Shipping_Model_Carrier_Abstract */ $carrier = $this->getCarrierByCode($carrierCode, $request->getStoreId()); if (!$carrier) { return $this; } $carrier->setActiveFlag($this->_availabilityConfigField); $result = $carrier->checkAvailableShipCountries($request); if (false !== $result && !($result instanceof Mage_Shipping_Model_Rate_Result_Error)) { $result = $carrier->proccessAdditionalValidation($request); } /* * Result will be false if the admin set not to show the shipping module * if the delivery country is not within specific countries */ if (false !== $result){ if (!$result instanceof Mage_Shipping_Model_Rate_Result_Error) { if ($carrier->getConfigData('shipment_requesttype')) { $packages = $this->composePackagesForCarrier($carrier, $request); if (!empty($packages)) { $sumResults = array(); foreach ($packages as $weight => $packageCount) { //clone carrier for multi-requests $carrierObj = clone $carrier; $request->setPackageWeight($weight); $result = $carrierObj->collectRates($request); if (!$result) { return $this; } else { $result->updateRatePrice($packageCount); } $sumResults[] = $result; } if (!empty($sumResults) && count($sumResults) > 1) { $result = array(); foreach ($sumResults as $res) { if (empty($result)) { $result = $res; continue; } foreach ($res->getAllRates() as $method) { foreach ($result->getAllRates() as $resultMethod) { if ($method->getMethod() == $resultMethod->getMethod()) { $resultMethod->setPrice($method->getPrice() + $resultMethod->getPrice()); continue; } } } } } } else { $result = $carrier->collectRates($request); } } else { $result = $carrier->collectRates($request); } if (!$result) { return $this; } } if ($carrier->getConfigData('showmethod') == 0 && $result->getError()) { return $this; } // sort rates by price if (method_exists($result, 'sortRatesByPrice')) { $result->sortRatesByPrice(); } $this->getResult()->append($result); } return $this; } /** * Compose Packages For Carrier. * Devides order into items and items into parts if it's neccesary * * @param Mage_Shipping_Model_Carrier_Abstract $carrier * @param Mage_Shipping_Model_Rate_Request $request * @return array [int, float] */ public function composePackagesForCarrier($carrier, $request) { $allItems = $request->getAllItems(); $fullItems = array(); $maxWeight = (float) $carrier->getConfigData('max_package_weight'); foreach ($allItems as $item) { if ($item->getProductType() == Mage_Catalog_Model_Product_Type::TYPE_BUNDLE && $item->getProduct()->getShipmentType() ) { continue; } $qty = $item->getQty(); $changeQty = true; $checkWeight = true; $decimalItems = array(); if ($item->getParentItem()) { if (!$item->getParentItem()->getProduct()->getShipmentType()) { continue; } $qty = $item->getIsQtyDecimal() ? $item->getParentItem()->getQty() : $item->getParentItem()->getQty() * $item->getQty(); } $itemWeight = $item->getWeight(); if ($item->getIsQtyDecimal() && $item->getProductType() != Mage_Catalog_Model_Product_Type::TYPE_BUNDLE) { $stockItem = $item->getProduct()->getStockItem(); if ($stockItem->getIsDecimalDivided()) { if ($stockItem->getEnableQtyIncrements() && $stockItem->getQtyIncrements()) { $itemWeight = $itemWeight * $stockItem->getQtyIncrements(); $qty = round(($item->getWeight() / $itemWeight) * $qty); $changeQty = false; } else { $itemWeight = $itemWeight * $item->getQty(); if ($itemWeight > $maxWeight) { $qtyItem = floor($itemWeight / $maxWeight); $decimalItems[] = array('weight' => $maxWeight, 'qty' => $qtyItem); $weightItem = Mage::helper('core')->getExactDivision($itemWeight, $maxWeight); if ($weightItem) { $decimalItems[] = array('weight' => $weightItem, 'qty' => 1); } $checkWeight = false; } else { $itemWeight = $itemWeight * $item->getQty(); } } } else { $itemWeight = $itemWeight * $item->getQty(); } } if ($checkWeight && $maxWeight && $itemWeight > $maxWeight) { return array(); } if ($changeQty && !$item->getParentItem() && $item->getIsQtyDecimal() && $item->getProductType() != Mage_Catalog_Model_Product_Type::TYPE_BUNDLE ) { $qty = 1; } if (!empty($decimalItems)) { foreach ($decimalItems as $decimalItem) { $fullItems = array_merge($fullItems, array_fill(0, $decimalItem['qty'] * $qty, $decimalItem['weight']) ); } } else { $fullItems = array_merge($fullItems, array_fill(0, $qty, $itemWeight)); } } sort($fullItems); return $this->_makePieces($fullItems, $maxWeight); } /** * Make pieces * Compose packeges list based on given items, so that each package is as heavy as possible * * @param array $items * @param float $maxWeight * @return array */ protected function _makePieces($items, $maxWeight) { $pieces = array(); if (!empty($items)) { $sumWeight = 0; $reverseOrderItems = $items; arsort($reverseOrderItems); foreach ($reverseOrderItems as $key => $weight) { if (!isset($items[$key])) { continue; } unset($items[$key]); $sumWeight = $weight; foreach ($items as $key => $weight) { if (($sumWeight + $weight) < $maxWeight) { unset($items[$key]); $sumWeight += $weight; } elseif (($sumWeight + $weight) > $maxWeight) { $pieces[] = (string)(float)$sumWeight; break; } else { unset($items[$key]); $pieces[] = (string)(float)($sumWeight + $weight); $sumWeight = 0; break; } } } if ($sumWeight > 0) { $pieces[] = (string)(float)$sumWeight; } $pieces = array_count_values($pieces); } return $pieces; } /** * Collect rates by address * * @param Varien_Object $address * @param null|bool|array $limitCarrier * @return Mage_Shipping_Model_Shipping */ public function collectRatesByAddress(Varien_Object $address, $limitCarrier = null) { /** @var $request Mage_Shipping_Model_Rate_Request */ $request = Mage::getModel('shipping/rate_request'); $request->setAllItems($address->getAllItems()); $request->setDestCountryId($address->getCountryId()); $request->setDestRegionId($address->getRegionId()); $request->setDestPostcode($address->getPostcode()); $request->setPackageValue($address->getBaseSubtotal()); $request->setPackageValueWithDiscount($address->getBaseSubtotalWithDiscount()); $request->setPackageWeight($address->getWeight()); $request->setFreeMethodWeight($address->getFreeMethodWeight()); $request->setPackageQty($address->getItemQty()); $request->setStoreId(Mage::app()->getStore()->getId()); $request->setWebsiteId(Mage::app()->getStore()->getWebsiteId()); $request->setBaseCurrency(Mage::app()->getStore()->getBaseCurrency()); $request->setPackageCurrency(Mage::app()->getStore()->getCurrentCurrency()); $request->setLimitCarrier($limitCarrier); $request->setBaseSubtotalInclTax($address->getBaseSubtotalInclTax() + $address->getBaseExtraTaxAmount()); return $this->collectRates($request); } /** * Set part of carrier xml config path * * @param string $code * @return Mage_Shipping_Model_Shipping */ public function setCarrierAvailabilityConfigField($code = 'active') { $this->_availabilityConfigField = $code; return $this; } /** * Get carrier by its code * * @param string $carrierCode * @param null|int $storeId * @return bool|Mage_Core_Model_Abstract */ public function getCarrierByCode($carrierCode, $storeId = null) { if (!Mage::getStoreConfigFlag('carriers/'.$carrierCode.'/'.$this->_availabilityConfigField, $storeId)) { return false; } $className = Mage::getStoreConfig('carriers/'.$carrierCode.'/model', $storeId); if (!$className) { return false; } $obj = Mage::getModel($className); if ($storeId) { $obj->setStore($storeId); } return $obj; } /** * Prepare and do request to shipment * * @param Mage_Sales_Model_Order_Shipment $orderShipment * @return Varien_Object */ public function requestToShipment(Mage_Sales_Model_Order_Shipment $orderShipment) { $admin = Mage::getSingleton('admin/session')->getUser(); $order = $orderShipment->getOrder(); $address = $order->getShippingAddress(); $shippingMethod = $order->getShippingMethod(true); $shipmentStoreId = $orderShipment->getStoreId(); $shipmentCarrier = $order->getShippingCarrier(); $baseCurrencyCode = Mage::app()->getStore($shipmentStoreId)->getBaseCurrencyCode(); if (!$shipmentCarrier) { Mage::throwException('Invalid carrier: ' . $shippingMethod->getCarrierCode()); } $shipperRegionCode = Mage::getStoreConfig(self::XML_PATH_STORE_REGION_ID, $shipmentStoreId); if (is_numeric($shipperRegionCode)) { $shipperRegionCode = Mage::getModel('directory/region')->load($shipperRegionCode)->getCode(); } $recipientRegionCode = Mage::getModel('directory/region')->load($address->getRegionId())->getCode(); $originStreet1 = Mage::getStoreConfig(self::XML_PATH_STORE_ADDRESS1, $shipmentStoreId); $originStreet2 = Mage::getStoreConfig(self::XML_PATH_STORE_ADDRESS2, $shipmentStoreId); $storeInfo = new Varien_Object(Mage::getStoreConfig('general/store_information', $shipmentStoreId)); if (!$admin->getFirstname() || !$admin->getLastname() || !$storeInfo->getName() || !$storeInfo->getPhone() || !$originStreet1 || !Mage::getStoreConfig(self::XML_PATH_STORE_CITY, $shipmentStoreId) || !$shipperRegionCode || !Mage::getStoreConfig(self::XML_PATH_STORE_ZIP, $shipmentStoreId) || !Mage::getStoreConfig(self::XML_PATH_STORE_COUNTRY_ID, $shipmentStoreId) ) { Mage::throwException( Mage::helper('sales')->__('Insufficient information to create shipping label(s). Please verify your Store Information and Shipping Settings.') ); } /** @var $request Mage_Shipping_Model_Shipment_Request */ $request = Mage::getModel('shipping/shipment_request'); $request->setOrderShipment($orderShipment); $request->setShipperContactPersonName($admin->getName()); $request->setShipperContactPersonFirstName($admin->getFirstname()); $request->setShipperContactPersonLastName($admin->getLastname()); $request->setShipperContactCompanyName($storeInfo->getName()); $request->setShipperContactPhoneNumber($storeInfo->getPhone()); $request->setShipperEmail($admin->getEmail()); $request->setShipperAddressStreet(trim($originStreet1 . ' ' . $originStreet2)); $request->setShipperAddressStreet1($originStreet1); $request->setShipperAddressStreet2($originStreet2); $request->setShipperAddressCity(Mage::getStoreConfig(self::XML_PATH_STORE_CITY, $shipmentStoreId)); $request->setShipperAddressStateOrProvinceCode($shipperRegionCode); $request->setShipperAddressPostalCode(Mage::getStoreConfig(self::XML_PATH_STORE_ZIP, $shipmentStoreId)); $request->setShipperAddressCountryCode(Mage::getStoreConfig(self::XML_PATH_STORE_COUNTRY_ID, $shipmentStoreId)); $request->setRecipientContactPersonName(trim($address->getFirstname() . ' ' . $address->getLastname())); $request->setRecipientContactPersonFirstName($address->getFirstname()); $request->setRecipientContactPersonLastName($address->getLastname()); $request->setRecipientContactCompanyName($address->getCompany()); $request->setRecipientContactPhoneNumber($address->getTelephone()); $request->setRecipientEmail($address->getEmail()); $request->setRecipientAddressStreet(trim($address->getStreet1() . ' ' . $address->getStreet2())); $request->setRecipientAddressStreet1($address->getStreet1()); $request->setRecipientAddressStreet2($address->getStreet2()); $request->setRecipientAddressCity($address->getCity()); $request->setRecipientAddressStateOrProvinceCode($address->getRegionCode()); $request->setRecipientAddressRegionCode($recipientRegionCode); $request->setRecipientAddressPostalCode($address->getPostcode()); $request->setRecipientAddressCountryCode($address->getCountryId()); $request->setShippingMethod($shippingMethod->getMethod()); $request->setPackageWeight($order->getWeight()); $request->setPackages($orderShipment->getPackages()); $request->setBaseCurrencyCode($baseCurrencyCode); $request->setStoreId($shipmentStoreId); return $shipmentCarrier->requestToShipment($request); } }