1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25:
26:
27:
28: class Mage_Shipping_Model_Shipping
29: {
30: 31: 32:
33: const XML_PATH_STORE_ADDRESS1 = 'shipping/origin/street_line1';
34: const XML_PATH_STORE_ADDRESS2 = 'shipping/origin/street_line2';
35: const XML_PATH_STORE_CITY = 'shipping/origin/city';
36: const XML_PATH_STORE_REGION_ID = 'shipping/origin/region_id';
37: const XML_PATH_STORE_ZIP = 'shipping/origin/postcode';
38: const XML_PATH_STORE_COUNTRY_ID = 'shipping/origin/country_id';
39:
40: 41: 42: 43: 44:
45: protected $_orig = null;
46:
47: 48: 49: 50: 51:
52: protected $_result = null;
53:
54: 55: 56: 57: 58:
59: protected $_availabilityConfigField = 'active';
60:
61: 62: 63: 64: 65:
66: public function getResult()
67: {
68: if (empty($this->_result)) {
69: $this->_result = Mage::getModel('shipping/rate_result');
70: }
71: return $this->_result;
72: }
73:
74: 75: 76: 77: 78: 79:
80: public function setOrigData($data)
81: {
82: $this->_orig = $data;
83: }
84:
85: 86: 87: 88: 89:
90: public function resetResult()
91: {
92: $this->getResult()->reset();
93: return $this;
94: }
95:
96: 97: 98: 99: 100:
101: public function getConfig()
102: {
103: return Mage::getSingleton('shipping/config');
104: }
105:
106: 107: 108: 109: 110: 111: 112:
113: public function collectRates(Mage_Shipping_Model_Rate_Request $request)
114: {
115: $storeId = $request->getStoreId();
116: if (!$request->getOrig()) {
117: $request
118: ->setCountryId(Mage::getStoreConfig(self::XML_PATH_STORE_COUNTRY_ID, $request->getStore()))
119: ->setRegionId(Mage::getStoreConfig(self::XML_PATH_STORE_REGION_ID, $request->getStore()))
120: ->setCity(Mage::getStoreConfig(self::XML_PATH_STORE_CITY, $request->getStore()))
121: ->setPostcode(Mage::getStoreConfig(self::XML_PATH_STORE_ZIP, $request->getStore()));
122: }
123:
124: $limitCarrier = $request->getLimitCarrier();
125: if (!$limitCarrier) {
126: $carriers = Mage::getStoreConfig('carriers', $storeId);
127:
128: foreach ($carriers as $carrierCode => $carrierConfig) {
129: $this->collectCarrierRates($carrierCode, $request);
130: }
131: } else {
132: if (!is_array($limitCarrier)) {
133: $limitCarrier = array($limitCarrier);
134: }
135: foreach ($limitCarrier as $carrierCode) {
136: $carrierConfig = Mage::getStoreConfig('carriers/' . $carrierCode, $storeId);
137: if (!$carrierConfig) {
138: continue;
139: }
140: $this->collectCarrierRates($carrierCode, $request);
141: }
142: }
143:
144: return $this;
145: }
146:
147: 148: 149: 150: 151: 152: 153:
154: public function collectCarrierRates($carrierCode, $request)
155: {
156:
157: $carrier = $this->getCarrierByCode($carrierCode, $request->getStoreId());
158: if (!$carrier) {
159: return $this;
160: }
161: $carrier->setActiveFlag($this->_availabilityConfigField);
162: $result = $carrier->checkAvailableShipCountries($request);
163: if (false !== $result && !($result instanceof Mage_Shipping_Model_Rate_Result_Error)) {
164: $result = $carrier->proccessAdditionalValidation($request);
165: }
166: 167: 168: 169:
170: if (false !== $result){
171: if (!$result instanceof Mage_Shipping_Model_Rate_Result_Error) {
172: if ($carrier->getConfigData('shipment_requesttype')) {
173: $packages = $this->composePackagesForCarrier($carrier, $request);
174: if (!empty($packages)) {
175: $sumResults = array();
176: foreach ($packages as $weight => $packageCount) {
177: $request->setPackageWeight($weight);
178: $result = $carrier->collectRates($request);
179: if (!$result) {
180: return $this;
181: } else {
182: $result->updateRatePrice($packageCount);
183: }
184: $sumResults[] = $result;
185: }
186: if (!empty($sumResults) && count($sumResults) > 1) {
187: $result = array();
188: foreach ($sumResults as $res) {
189: if (empty($result)) {
190: $result = $res;
191: continue;
192: }
193: foreach ($res->getAllRates() as $method) {
194: foreach ($result->getAllRates() as $resultMethod) {
195: if ($method->getMethod() == $resultMethod->getMethod()) {
196: $resultMethod->setPrice($method->getPrice() + $resultMethod->getPrice());
197: continue;
198: }
199: }
200: }
201: }
202: }
203: } else {
204: $result = $carrier->collectRates($request);
205: }
206: } else {
207: $result = $carrier->collectRates($request);
208: }
209: if (!$result) {
210: return $this;
211: }
212: }
213: if ($carrier->getConfigData('showmethod') == 0 && $result->getError()) {
214: return $this;
215: }
216:
217: if (method_exists($result, 'sortRatesByPrice')) {
218: $result->sortRatesByPrice();
219: }
220: $this->getResult()->append($result);
221: }
222: return $this;
223: }
224:
225: 226: 227: 228: 229: 230: 231: 232:
233: public function composePackagesForCarrier($carrier, $request)
234: {
235: $allItems = $request->getAllItems();
236: $fullItems = array();
237:
238: $maxWeight = (float) $carrier->getConfigData('max_package_weight');
239:
240: foreach ($allItems as $item) {
241: if ($item->getProductType() == Mage_Catalog_Model_Product_Type::TYPE_BUNDLE
242: && $item->getProduct()->getShipmentType()
243: ) {
244: continue;
245: }
246:
247: $qty = $item->getQty();
248: $changeQty = true;
249: $checkWeight = true;
250: $decimalItems = array();
251:
252: if ($item->getParentItem()) {
253: if (!$item->getParentItem()->getProduct()->getShipmentType()) {
254: continue;
255: }
256: $qty = $item->getIsQtyDecimal()
257: ? $item->getParentItem()->getQty()
258: : $item->getParentItem()->getQty() * $item->getQty();
259: }
260:
261: $itemWeight = $item->getWeight();
262: if ($item->getIsQtyDecimal() && $item->getProductType() != Mage_Catalog_Model_Product_Type::TYPE_BUNDLE) {
263: $stockItem = $item->getProduct()->getStockItem();
264: if ($stockItem->getIsDecimalDivided()) {
265: if ($stockItem->getEnableQtyIncrements() && $stockItem->getQtyIncrements()) {
266: $itemWeight = $itemWeight * $stockItem->getQtyIncrements();
267: $qty = round(($item->getWeight() / $itemWeight) * $qty);
268: $changeQty = false;
269: } else {
270: $itemWeight = $itemWeight * $item->getQty();
271: if ($itemWeight > $maxWeight) {
272: $qtyItem = floor($itemWeight / $maxWeight);
273: $decimalItems[] = array('weight' => $maxWeight, 'qty' => $qtyItem);
274: $weightItem = Mage::helper('core')->getExactDivision($itemWeight, $maxWeight);
275: if ($weightItem) {
276: $decimalItems[] = array('weight' => $weightItem, 'qty' => 1);
277: }
278: $checkWeight = false;
279: } else {
280: $itemWeight = $itemWeight * $item->getQty();
281: }
282: }
283: } else {
284: $itemWeight = $itemWeight * $item->getQty();
285: }
286: }
287:
288: if ($checkWeight && $maxWeight && $itemWeight > $maxWeight) {
289: return array();
290: }
291:
292: if ($changeQty && !$item->getParentItem() && $item->getIsQtyDecimal()
293: && $item->getProductType() != Mage_Catalog_Model_Product_Type::TYPE_BUNDLE
294: ) {
295: $qty = 1;
296: }
297:
298: if (!empty($decimalItems)) {
299: foreach ($decimalItems as $decimalItem) {
300: $fullItems = array_merge($fullItems,
301: array_fill(0, $decimalItem['qty'] * $qty, $decimalItem['weight'])
302: );
303: }
304: } else {
305: $fullItems = array_merge($fullItems, array_fill(0, $qty, $itemWeight));
306: }
307: }
308: sort($fullItems);
309:
310: return $this->_makePieces($fullItems, $maxWeight);
311: }
312:
313: 314: 315: 316: 317: 318: 319: 320:
321: protected function _makePieces($items, $maxWeight)
322: {
323: $pieces = array();
324: if (!empty($items)) {
325: $sumWeight = 0;
326:
327: $reverseOrderItems = $items;
328: arsort($reverseOrderItems);
329:
330: foreach ($reverseOrderItems as $key => $weight) {
331: if (!isset($items[$key])) {
332: continue;
333: }
334: unset($items[$key]);
335: $sumWeight = $weight;
336: foreach ($items as $key => $weight) {
337: if (($sumWeight + $weight) < $maxWeight) {
338: unset($items[$key]);
339: $sumWeight += $weight;
340: } elseif (($sumWeight + $weight) > $maxWeight) {
341: $pieces[] = (string)(float)$sumWeight;
342: break;
343: } else {
344: unset($items[$key]);
345: $pieces[] = (string)(float)($sumWeight + $weight);
346: $sumWeight = 0;
347: break;
348: }
349: }
350: }
351: if ($sumWeight > 0) {
352: $pieces[] = (string)(float)$sumWeight;
353: }
354: $pieces = array_count_values($pieces);
355: }
356:
357: return $pieces;
358: }
359:
360: 361: 362: 363: 364: 365: 366:
367: public function collectRatesByAddress(Varien_Object $address, $limitCarrier = null)
368: {
369:
370: $request = Mage::getModel('shipping/rate_request');
371: $request->setAllItems($address->getAllItems());
372: $request->setDestCountryId($address->getCountryId());
373: $request->setDestRegionId($address->getRegionId());
374: $request->setDestPostcode($address->getPostcode());
375: $request->setPackageValue($address->getBaseSubtotal());
376: $request->setPackageValueWithDiscount($address->getBaseSubtotalWithDiscount());
377: $request->setPackageWeight($address->getWeight());
378: $request->setFreeMethodWeight($address->getFreeMethodWeight());
379: $request->setPackageQty($address->getItemQty());
380: $request->setStoreId(Mage::app()->getStore()->getId());
381: $request->setWebsiteId(Mage::app()->getStore()->getWebsiteId());
382: $request->setBaseCurrency(Mage::app()->getStore()->getBaseCurrency());
383: $request->setPackageCurrency(Mage::app()->getStore()->getCurrentCurrency());
384: $request->setLimitCarrier($limitCarrier);
385:
386: $request->setBaseSubtotalInclTax($address->getBaseSubtotalInclTax());
387:
388: return $this->collectRates($request);
389: }
390:
391: 392: 393: 394: 395: 396:
397: public function setCarrierAvailabilityConfigField($code = 'active')
398: {
399: $this->_availabilityConfigField = $code;
400: return $this;
401: }
402:
403: 404: 405: 406: 407: 408: 409:
410: public function getCarrierByCode($carrierCode, $storeId = null)
411: {
412: if (!Mage::getStoreConfigFlag('carriers/'.$carrierCode.'/'.$this->_availabilityConfigField, $storeId)) {
413: return false;
414: }
415: $className = Mage::getStoreConfig('carriers/'.$carrierCode.'/model', $storeId);
416: if (!$className) {
417: return false;
418: }
419: $obj = Mage::getModel($className);
420: if ($storeId) {
421: $obj->setStore($storeId);
422: }
423: return $obj;
424: }
425:
426: 427: 428: 429: 430: 431:
432: public function requestToShipment(Mage_Sales_Model_Order_Shipment $orderShipment)
433: {
434: $admin = Mage::getSingleton('admin/session')->getUser();
435: $order = $orderShipment->getOrder();
436: $address = $order->getShippingAddress();
437: $shippingMethod = $order->getShippingMethod(true);
438: $shipmentStoreId = $orderShipment->getStoreId();
439: $shipmentCarrier = $order->getShippingCarrier();
440: $baseCurrencyCode = Mage::app()->getStore($shipmentStoreId)->getBaseCurrencyCode();
441: if (!$shipmentCarrier) {
442: Mage::throwException('Invalid carrier: ' . $shippingMethod->getCarrierCode());
443: }
444: $shipperRegionCode = Mage::getStoreConfig(self::XML_PATH_STORE_REGION_ID, $shipmentStoreId);
445: if (is_numeric($shipperRegionCode)) {
446: $shipperRegionCode = Mage::getModel('directory/region')->load($shipperRegionCode)->getCode();
447: }
448:
449: $recipientRegionCode = Mage::getModel('directory/region')->load($address->getRegionId())->getCode();
450:
451: $originStreet1 = Mage::getStoreConfig(self::XML_PATH_STORE_ADDRESS1, $shipmentStoreId);
452: $originStreet2 = Mage::getStoreConfig(self::XML_PATH_STORE_ADDRESS2, $shipmentStoreId);
453: $storeInfo = new Varien_Object(Mage::getStoreConfig('general/store_information', $shipmentStoreId));
454:
455: if (!$admin->getFirstname() || !$admin->getLastname() || !$storeInfo->getName() || !$storeInfo->getPhone()
456: || !$originStreet1 || !Mage::getStoreConfig(self::XML_PATH_STORE_CITY, $shipmentStoreId)
457: || !$shipperRegionCode || !Mage::getStoreConfig(self::XML_PATH_STORE_ZIP, $shipmentStoreId)
458: || !Mage::getStoreConfig(self::XML_PATH_STORE_COUNTRY_ID, $shipmentStoreId)
459: ) {
460: Mage::throwException(
461: Mage::helper('sales')->__('Insufficient information to create shipping label(s). Please verify your Store Information and Shipping Settings.')
462: );
463: }
464:
465:
466: $request = Mage::getModel('shipping/shipment_request');
467: $request->setOrderShipment($orderShipment);
468: $request->setShipperContactPersonName($admin->getName());
469: $request->setShipperContactPersonFirstName($admin->getFirstname());
470: $request->setShipperContactPersonLastName($admin->getLastname());
471: $request->setShipperContactCompanyName($storeInfo->getName());
472: $request->setShipperContactPhoneNumber($storeInfo->getPhone());
473: $request->setShipperEmail($admin->getEmail());
474: $request->setShipperAddressStreet(trim($originStreet1 . ' ' . $originStreet2));
475: $request->setShipperAddressStreet1($originStreet1);
476: $request->setShipperAddressStreet2($originStreet2);
477: $request->setShipperAddressCity(Mage::getStoreConfig(self::XML_PATH_STORE_CITY, $shipmentStoreId));
478: $request->setShipperAddressStateOrProvinceCode($shipperRegionCode);
479: $request->setShipperAddressPostalCode(Mage::getStoreConfig(self::XML_PATH_STORE_ZIP, $shipmentStoreId));
480: $request->setShipperAddressCountryCode(Mage::getStoreConfig(self::XML_PATH_STORE_COUNTRY_ID, $shipmentStoreId));
481: $request->setRecipientContactPersonName(trim($address->getFirstname() . ' ' . $address->getLastname()));
482: $request->setRecipientContactPersonFirstName($address->getFirstname());
483: $request->setRecipientContactPersonLastName($address->getLastname());
484: $request->setRecipientContactCompanyName($address->getCompany());
485: $request->setRecipientContactPhoneNumber($address->getTelephone());
486: $request->setRecipientEmail($address->getEmail());
487: $request->setRecipientAddressStreet(trim($address->getStreet1() . ' ' . $address->getStreet2()));
488: $request->setRecipientAddressStreet1($address->getStreet1());
489: $request->setRecipientAddressStreet2($address->getStreet2());
490: $request->setRecipientAddressCity($address->getCity());
491: $request->setRecipientAddressStateOrProvinceCode($address->getRegionCode());
492: $request->setRecipientAddressRegionCode($recipientRegionCode);
493: $request->setRecipientAddressPostalCode($address->getPostcode());
494: $request->setRecipientAddressCountryCode($address->getCountryId());
495: $request->setShippingMethod($shippingMethod->getMethod());
496: $request->setPackageWeight($order->getWeight());
497: $request->setPackages($orderShipment->getPackages());
498: $request->setBaseCurrencyCode($baseCurrencyCode);
499: $request->setStoreId($shipmentStoreId);
500:
501: return $shipmentCarrier->requestToShipment($request);
502: }
503: }
504: