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: 29: 30: 31: 32: 33:
34: class Mage_Checkout_Model_Type_Multishipping extends Mage_Checkout_Model_Type_Abstract
35: {
36: 37: 38: 39: 40:
41: protected $_quoteShippingAddressesItems;
42:
43: 44: 45:
46: public function __construct()
47: {
48: parent::__construct();
49: $this->_init();
50: }
51:
52: 53: 54: 55: 56: 57:
58: protected function _init()
59: {
60: 61: 62:
63: $quote = $this->getQuote();
64: if (!$this->getCustomer()->getId()) {
65: return $this;
66: }
67:
68: if ($this->getCheckoutSession()->getCheckoutState() === Mage_Checkout_Model_Session::CHECKOUT_STATE_BEGIN) {
69: $this->getCheckoutSession()->setCheckoutState(true);
70: 71: 72:
73: $addresses = $quote->getAllAddresses();
74: foreach ($addresses as $address) {
75: $quote->removeAddress($address->getId());
76: }
77:
78: if ($defaultShipping = $this->getCustomerDefaultShippingAddress()) {
79: $quote->getShippingAddress()->importCustomerAddress($defaultShipping);
80:
81: foreach ($this->getQuoteItems() as $item) {
82: 83: 84: 85:
86: if ($item->getParentItemId() || $item->getProduct()->getIsVirtual()) {
87: continue;
88: }
89: $quote->getShippingAddress()->addItem($item);
90: }
91: }
92:
93: if ($this->getCustomerDefaultBillingAddress()) {
94: $quote->getBillingAddress()
95: ->importCustomerAddress($this->getCustomerDefaultBillingAddress());
96: foreach ($this->getQuoteItems() as $item) {
97: if ($item->getParentItemId()) {
98: continue;
99: }
100: if ($item->getProduct()->getIsVirtual()) {
101: $quote->getBillingAddress()->addItem($item);
102: }
103: }
104: }
105: $this->save();
106: }
107: return $this;
108: }
109:
110: 111: 112: 113: 114: 115:
116: public function getQuoteShippingAddressesItems()
117: {
118: if ($this->_quoteShippingAddressesItems !== null) {
119: return $this->_quoteShippingAddressesItems;
120: }
121: $items = array();
122: $addresses = $this->getQuote()->getAllAddresses();
123: foreach ($addresses as $address) {
124: foreach ($address->getAllItems() as $item) {
125: if ($item->getParentItemId()) {
126: continue;
127: }
128: if ($item->getProduct()->getIsVirtual()) {
129: $items[] = $item;
130: continue;
131: }
132: if ($item->getQty() > 1) {
133: for ($i = 0, $n = $item->getQty(); $i < $n; $i++) {
134: if ($i == 0) {
135: $addressItem = $item;
136: } else {
137: $addressItem = clone $item;
138: }
139: $addressItem->setQty(1)
140: ->setCustomerAddressId($address->getCustomerAddressId())
141: ->save();
142: $items[] = $addressItem;
143: }
144: } else {
145: $item->setCustomerAddressId($address->getCustomerAddressId());
146: $items[] = $item;
147: }
148: }
149: }
150: $this->_quoteShippingAddressesItems = $items;
151: return $items;
152: }
153:
154: 155: 156: 157: 158: 159: 160:
161: public function removeAddressItem($addressId, $itemId)
162: {
163: $address = $this->getQuote()->getAddressById($addressId);
164:
165: if ($address) {
166: $item = $address->getValidItemById($itemId);
167: if ($item) {
168: if ($item->getQty()>1 && !$item->getProduct()->getIsVirtual()) {
169: $item->setQty($item->getQty()-1);
170: } else {
171: $address->removeItem($item->getId());
172: }
173:
174: 175: 176:
177: $address->setCollectShippingRates((boolean) $this->getCollectRatesFlag());
178:
179: if (count($address->getAllItems()) == 0) {
180: $address->isDeleted(true);
181: }
182:
183: if ($quoteItem = $this->getQuote()->getItemById($item->getQuoteItemId())) {
184: $newItemQty = $quoteItem->getQty()-1;
185: if ($newItemQty > 0 && !$item->getProduct()->getIsVirtual()) {
186: $quoteItem->setQty($quoteItem->getQty()-1);
187: } else {
188: $this->getQuote()->removeItem($quoteItem->getId());
189: }
190: }
191: $this->save();
192: }
193: }
194: return $this;
195: }
196:
197: 198: 199: 200: 201: 202: 203: 204: 205: 206: 207: 208: 209: 210:
211: public function setShippingItemsInformation($info)
212: {
213: if (is_array($info)) {
214: $allQty = 0;
215: $itemsInfo = array();
216: foreach ($info as $itemData) {
217: foreach ($itemData as $quoteItemId => $data) {
218: $allQty += $data['qty'];
219: $itemsInfo[$quoteItemId] = $data;
220: }
221: }
222:
223: $maxQty = (int)Mage::getStoreConfig('shipping/option/checkout_multiple_maximum_qty');
224: if ($allQty > $maxQty) {
225: Mage::throwException(Mage::helper('checkout')->__('Maximum qty allowed for Shipping to multiple addresses is %s', $maxQty));
226: }
227: $quote = $this->getQuote();
228: $addresses = $quote->getAllShippingAddresses();
229: foreach ($addresses as $address) {
230: $quote->removeAddress($address->getId());
231: }
232:
233: foreach ($info as $itemData) {
234: foreach ($itemData as $quoteItemId => $data) {
235: $this->_addShippingItem($quoteItemId, $data);
236: }
237: }
238:
239: 240: 241: 242:
243: foreach ($quote->getAllItems() as $_item) {
244: if (!$_item->getProduct()->getIsVirtual() &&
245: !$_item->getParentItem() &&
246: !$_item->getMultishippingQty()
247: ) {
248: $quote->removeItem($_item->getId());
249: }
250: }
251:
252: if ($billingAddress = $quote->getBillingAddress()) {
253: $quote->removeAddress($billingAddress->getId());
254: }
255:
256: if ($customerDefaultBilling = $this->getCustomerDefaultBillingAddress()) {
257: $quote->getBillingAddress()->importCustomerAddress($customerDefaultBilling);
258: }
259:
260: foreach ($quote->getAllItems() as $_item) {
261: if (!$_item->getProduct()->getIsVirtual()) {
262: continue;
263: }
264:
265: if (isset($itemsInfo[$_item->getId()]['qty'])) {
266: if ($qty = (int)$itemsInfo[$_item->getId()]['qty']) {
267: $_item->setQty($qty);
268: $quote->getBillingAddress()->addItem($_item);
269: } else {
270: $_item->setQty(0);
271: $quote->removeItem($_item->getId());
272: }
273: }
274:
275: }
276:
277: $this->save();
278: Mage::dispatchEvent('checkout_type_multishipping_set_shipping_items', array('quote'=>$quote));
279: }
280: return $this;
281: }
282:
283: 284: 285: 286: 287: 288: 289:
290: protected function _addShippingItem($quoteItemId, $data)
291: {
292: $qty = isset($data['qty']) ? (int) $data['qty'] : 1;
293:
294: $addressId = isset($data['address']) ? $data['address'] : false;
295: $quoteItem = $this->getQuote()->getItemById($quoteItemId);
296:
297: if ($addressId && $quoteItem) {
298: 299: 300:
301: if ($qty === 0) {
302: return $this;
303: }
304: $quoteItem->setMultishippingQty((int)$quoteItem->getMultishippingQty()+$qty);
305: $quoteItem->setQty($quoteItem->getMultishippingQty());
306: $address = $this->getCustomer()->getAddressById($addressId);
307: if ($address->getId()) {
308: if (!$quoteAddress = $this->getQuote()->getShippingAddressByCustomerAddressId($address->getId())) {
309: $quoteAddress = Mage::getModel('sales/quote_address')->importCustomerAddress($address);
310: $this->getQuote()->addShippingAddress($quoteAddress);
311: }
312:
313: $quoteAddress = $this->getQuote()->getShippingAddressByCustomerAddressId($address->getId());
314: if ($quoteAddressItem = $quoteAddress->getItemByQuoteItemId($quoteItemId)) {
315: $quoteAddressItem->setQty((int)($quoteAddressItem->getQty()+$qty));
316: } else {
317: $quoteAddress->addItem($quoteItem, $qty);
318: }
319: 320: 321:
322: $quoteAddress->setCollectShippingRates((boolean) $this->getCollectRatesFlag());
323: }
324: }
325: return $this;
326: }
327:
328: 329: 330: 331: 332: 333:
334: public function updateQuoteCustomerShippingAddress($addressId)
335: {
336: if ($address = $this->getCustomer()->getAddressById($addressId)) {
337: $this->getQuote()->getShippingAddressByCustomerAddressId($addressId)
338: ->setCollectShippingRates(true)
339: ->importCustomerAddress($address)
340: ->collectTotals();
341: $this->getQuote()->save();
342: }
343: return $this;
344: }
345:
346: 347: 348: 349: 350: 351:
352: public function setQuoteCustomerBillingAddress($addressId)
353: {
354: if ($address = $this->getCustomer()->getAddressById($addressId)) {
355: $this->getQuote()->getBillingAddress($addressId)
356: ->importCustomerAddress($address)
357: ->collectTotals();
358: $this->getQuote()->collectTotals()->save();
359: }
360: return $this;
361: }
362:
363: 364: 365: 366: 367: 368:
369: public function setShippingMethods($methods)
370: {
371: $addresses = $this->getQuote()->getAllShippingAddresses();
372: foreach ($addresses as $address) {
373: if (isset($methods[$address->getId()])) {
374: $address->setShippingMethod($methods[$address->getId()]);
375: } elseif (!$address->getShippingMethod()) {
376: Mage::throwException(Mage::helper('checkout')->__('Please select shipping methods for all addresses'));
377: }
378: }
379: $this->save();
380: return $this;
381: }
382:
383: 384: 385: 386: 387: 388:
389: public function setPaymentMethod($payment)
390: {
391: if (!isset($payment['method'])) {
392: Mage::throwException(Mage::helper('checkout')->__('Payment method is not defined'));
393: }
394: $quote = $this->getQuote();
395: $quote->getPayment()->importData($payment);
396:
397: if (!$quote->isVirtual() && $quote->getShippingAddress()) {
398: $quote->getShippingAddress()->setCollectShippingRates(true);
399: $quote->setTotalsCollectedFlag(false)->collectTotals();
400: }
401: $quote->save();
402: return $this;
403: }
404:
405: 406: 407: 408: 409: 410: 411:
412: protected function _prepareOrder(Mage_Sales_Model_Quote_Address $address)
413: {
414: $quote = $this->getQuote();
415: $quote->unsReservedOrderId();
416: $quote->reserveOrderId();
417: $quote->collectTotals();
418:
419: $convertQuote = Mage::getSingleton('sales/convert_quote');
420: $order = $convertQuote->addressToOrder($address);
421: $order->setQuote($quote);
422: $order->setBillingAddress(
423: $convertQuote->addressToOrderAddress($quote->getBillingAddress())
424: );
425:
426: if ($address->getAddressType() == 'billing') {
427: $order->setIsVirtual(1);
428: } else {
429: $order->setShippingAddress($convertQuote->addressToOrderAddress($address));
430: }
431:
432: $order->setPayment($convertQuote->paymentToOrderPayment($quote->getPayment()));
433: if (Mage::app()->getStore()->roundPrice($address->getGrandTotal()) == 0) {
434: $order->getPayment()->setMethod('free');
435: }
436:
437: foreach ($address->getAllItems() as $item) {
438: $_quoteItem = $item->getQuoteItem();
439: if (!$_quoteItem) {
440: throw new Mage_Checkout_Exception(Mage::helper('checkout')->__('Item not found or already ordered'));
441: }
442: $item->setProductType($_quoteItem->getProductType())
443: ->setProductOptions(
444: $_quoteItem->getProduct()->getTypeInstance(true)->getOrderOptions($_quoteItem->getProduct())
445: );
446: $orderItem = $convertQuote->itemToOrderItem($item);
447: if ($item->getParentItem()) {
448: $orderItem->setParentItem($order->getItemByQuoteItemId($item->getParentItem()->getId()));
449: }
450: $order->addItem($orderItem);
451: }
452:
453: return $order;
454: }
455:
456: 457: 458: 459: 460:
461: protected function _validate()
462: {
463: $quote = $this->getQuote();
464: if (!$quote->getIsMultiShipping()) {
465: Mage::throwException(Mage::helper('checkout')->__('Invalid checkout type.'));
466: }
467:
468:
469: $paymentMethod = $quote->getPayment()->getMethodInstance();
470: if (!empty($paymentMethod) && !$paymentMethod->isAvailable($quote)) {
471: Mage::throwException(Mage::helper('checkout')->__('Please specify payment method.'));
472: }
473:
474: $addresses = $quote->getAllShippingAddresses();
475: foreach ($addresses as $address) {
476: $addressValidation = $address->validate();
477: if ($addressValidation !== true) {
478: Mage::throwException(Mage::helper('checkout')->__('Please check shipping addresses information.'));
479: }
480: $method= $address->getShippingMethod();
481: $rate = $address->getShippingRateByCode($method);
482: if (!$method || !$rate) {
483: Mage::throwException(Mage::helper('checkout')->__('Please specify shipping methods for all addresses.'));
484: }
485: }
486: $addressValidation = $quote->getBillingAddress()->validate();
487: if ($addressValidation !== true) {
488: Mage::throwException(Mage::helper('checkout')->__('Please check billing address information.'));
489: }
490: return $this;
491: }
492:
493: 494: 495: 496: 497:
498: public function createOrders()
499: {
500: $orderIds = array();
501: $this->_validate();
502: $shippingAddresses = $this->getQuote()->getAllShippingAddresses();
503: $orders = array();
504:
505: if ($this->getQuote()->hasVirtualItems()) {
506: $shippingAddresses[] = $this->getQuote()->getBillingAddress();
507: }
508:
509: try {
510: foreach ($shippingAddresses as $address) {
511: $order = $this->_prepareOrder($address);
512:
513: $orders[] = $order;
514: Mage::dispatchEvent(
515: 'checkout_type_multishipping_create_orders_single',
516: array('order'=>$order, 'address'=>$address)
517: );
518: }
519:
520: foreach ($orders as $order) {
521: $order->place();
522: $order->save();
523: if ($order->getCanSendNewEmailFlag()){
524: $order->sendNewOrderEmail();
525: }
526: $orderIds[$order->getId()] = $order->getIncrementId();
527: }
528:
529: Mage::getSingleton('core/session')->setOrderIds($orderIds);
530: Mage::getSingleton('checkout/session')->setLastQuoteId($this->getQuote()->getId());
531:
532: $this->getQuote()
533: ->setIsActive(false)
534: ->save();
535:
536: Mage::dispatchEvent('checkout_submit_all_after', array('orders' => $orders, 'quote' => $this->getQuote()));
537:
538: return $this;
539: } catch (Exception $e) {
540: Mage::dispatchEvent('checkout_multishipping_refund_all', array('orders' => $orders));
541: throw $e;
542: }
543: }
544:
545: 546: 547: 548: 549:
550: public function save()
551: {
552: $this->getQuote()->collectTotals()
553: ->save();
554: return $this;
555: }
556:
557: 558: 559: 560: 561:
562: public function reset()
563: {
564: $this->getCheckoutSession()->setCheckoutState(Mage_Checkout_Model_Session::CHECKOUT_STATE_BEGIN);
565: return $this;
566: }
567:
568: 569: 570: 571: 572:
573: public function validateMinimumAmount()
574: {
575: return !(Mage::getStoreConfigFlag('sales/minimum_order/active')
576: && Mage::getStoreConfigFlag('sales/minimum_order/multi_address')
577: && !$this->getQuote()->validateMinimumAmount());
578: }
579:
580: 581: 582: 583: 584:
585: public function getMinimumAmountDescription()
586: {
587: $descr = Mage::getStoreConfig('sales/minimum_order/multi_address_description');
588: if (empty($descr)) {
589: $descr = Mage::getStoreConfig('sales/minimum_order/description');
590: }
591: return $descr;
592: }
593:
594: public function getMinimumAmountError()
595: {
596: $error = Mage::getStoreConfig('sales/minimum_order/multi_address_error_message');
597: if (empty($error)) {
598: $error = Mage::getStoreConfig('sales/minimum_order/error_message');
599: }
600: return $error;
601: }
602:
603: 604: 605: 606: 607: 608: 609: 610:
611: public function isCheckoutAvailable()
612: {
613: return Mage::helper('checkout')->isMultishippingCheckoutAvailable();
614: }
615:
616: 617: 618: 619: 620: 621:
622: public function getOrderIds($asAssoc = false)
623: {
624: $idsAssoc = Mage::getSingleton('core/session')->getOrderIds();
625: return $asAssoc ? $idsAssoc : array_keys($idsAssoc);
626: }
627: }
628: