PageRenderTime 51ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/app/code/core/Mage/Sales/Model/Order.php

https://bitbucket.org/claudiu_marginean/magento-hg-mirror
PHP | 1882 lines | 1136 code | 193 blank | 553 comment | 207 complexity | 13d019cc0107595d189c36e4f0a359b4 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Sales
  23. * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Order model
  28. *
  29. * Supported events:
  30. * sales_order_load_after
  31. * sales_order_save_before
  32. * sales_order_save_after
  33. * sales_order_delete_before
  34. * sales_order_delete_after
  35. *
  36. * @author Magento Core Team <core@magentocommerce.com>
  37. */
  38. class Mage_Sales_Model_Order extends Mage_Sales_Model_Abstract
  39. {
  40. /**
  41. * XML configuration paths
  42. */
  43. const XML_PATH_EMAIL_TEMPLATE = 'sales_email/order/template';
  44. const XML_PATH_EMAIL_GUEST_TEMPLATE = 'sales_email/order/guest_template';
  45. const XML_PATH_EMAIL_IDENTITY = 'sales_email/order/identity';
  46. const XML_PATH_EMAIL_COPY_TO = 'sales_email/order/copy_to';
  47. const XML_PATH_EMAIL_COPY_METHOD = 'sales_email/order/copy_method';
  48. const XML_PATH_EMAIL_ENABLED = 'sales_email/order/enabled';
  49. const XML_PATH_UPDATE_EMAIL_TEMPLATE = 'sales_email/order_comment/template';
  50. const XML_PATH_UPDATE_EMAIL_GUEST_TEMPLATE = 'sales_email/order_comment/guest_template';
  51. const XML_PATH_UPDATE_EMAIL_IDENTITY = 'sales_email/order_comment/identity';
  52. const XML_PATH_UPDATE_EMAIL_COPY_TO = 'sales_email/order_comment/copy_to';
  53. const XML_PATH_UPDATE_EMAIL_COPY_METHOD = 'sales_email/order_comment/copy_method';
  54. const XML_PATH_UPDATE_EMAIL_ENABLED = 'sales_email/order_comment/enabled';
  55. /**
  56. * Order states
  57. */
  58. const STATE_NEW = 'new';
  59. const STATE_PENDING_PAYMENT = 'pending_payment';
  60. const STATE_PROCESSING = 'processing';
  61. const STATE_COMPLETE = 'complete';
  62. const STATE_CLOSED = 'closed';
  63. const STATE_CANCELED = 'canceled';
  64. const STATE_HOLDED = 'holded';
  65. const STATE_PAYMENT_REVIEW = 'payment_review';
  66. /**
  67. * Order statuses
  68. */
  69. const STATUS_FRAUD = 'fraud';
  70. /**
  71. * Order flags
  72. */
  73. const ACTION_FLAG_CANCEL = 'cancel';
  74. const ACTION_FLAG_HOLD = 'hold';
  75. const ACTION_FLAG_UNHOLD = 'unhold';
  76. const ACTION_FLAG_EDIT = 'edit';
  77. const ACTION_FLAG_CREDITMEMO= 'creditmemo';
  78. const ACTION_FLAG_INVOICE = 'invoice';
  79. const ACTION_FLAG_REORDER = 'reorder';
  80. const ACTION_FLAG_SHIP = 'ship';
  81. const ACTION_FLAG_COMMENT = 'comment';
  82. /**
  83. * Report date types
  84. */
  85. const REPORT_DATE_TYPE_CREATED = 'created';
  86. const REPORT_DATE_TYPE_UPDATED = 'updated';
  87. protected $_eventPrefix = 'sales_order';
  88. protected $_eventObject = 'order';
  89. protected $_addresses = null;
  90. protected $_items = null;
  91. protected $_payments = null;
  92. protected $_statusHistory = null;
  93. protected $_invoices;
  94. protected $_tracks;
  95. protected $_shipments;
  96. protected $_creditmemos;
  97. protected $_relatedObjects = array();
  98. protected $_orderCurrency = null;
  99. protected $_baseCurrency = null;
  100. /**
  101. * Array of action flags for canUnhold, canEdit, etc.
  102. *
  103. * @var array
  104. */
  105. protected $_actionFlag = array();
  106. /**
  107. * Flag: if after order placing we can send new email to the customer.
  108. *
  109. * @var bool
  110. */
  111. protected $_canSendNewEmailFlag = true;
  112. /**
  113. * Initialize resource model
  114. */
  115. protected function _construct()
  116. {
  117. $this->_init('sales/order');
  118. }
  119. /**
  120. * Clear order object data
  121. *
  122. * @param string $key data key
  123. * @return Mage_Sales_Model_Order
  124. */
  125. public function unsetData($key=null)
  126. {
  127. parent::unsetData($key);
  128. if (is_null($key)) {
  129. $this->_items = null;
  130. }
  131. return $this;
  132. }
  133. /**
  134. * Retrieve can flag for action (edit, unhold, etc..)
  135. *
  136. * @param string $action
  137. * @return boolean|null
  138. */
  139. public function getActionFlag($action)
  140. {
  141. if (isset($this->_actionFlag[$action])) {
  142. return $this->_actionFlag[$action];
  143. }
  144. return null;
  145. }
  146. /**
  147. * Set can flag value for action (edit, unhold, etc...)
  148. *
  149. * @param string $action
  150. * @param boolean $flag
  151. * @return Mage_Sales_Model_Order
  152. */
  153. public function setActionFlag($action, $flag)
  154. {
  155. $this->_actionFlag[$action] = (boolean) $flag;
  156. return $this;
  157. }
  158. /**
  159. * Return flag for order if it can sends new email to customer.
  160. *
  161. * @return bool
  162. */
  163. public function getCanSendNewEmailFlag()
  164. {
  165. return $this->_canSendNewEmailFlag;
  166. }
  167. /**
  168. * Set flag for order if it can sends new email to customer.
  169. *
  170. * @param bool $flag
  171. * @return Mage_Sales_Model_Order
  172. */
  173. public function setCanSendNewEmailFlag($flag)
  174. {
  175. $this->_canSendNewEmailFlag = (boolean) $flag;
  176. return $this;
  177. }
  178. /**
  179. * Load order by system increment identifier
  180. *
  181. * @param string $incrementId
  182. * @return Mage_Sales_Model_Order
  183. */
  184. public function loadByIncrementId($incrementId)
  185. {
  186. return $this->loadByAttribute('increment_id', $incrementId);
  187. }
  188. /**
  189. * Load order by custom attribute value. Attribute value should be unique
  190. *
  191. * @param string $attribute
  192. * @param string $value
  193. * @return Mage_Sales_Model_Order
  194. */
  195. public function loadByAttribute($attribute, $value)
  196. {
  197. $this->load($value, $attribute);
  198. return $this;
  199. }
  200. /**
  201. * Retrieve store model instance
  202. *
  203. * @return Mage_Core_Model_Store
  204. */
  205. public function getStore()
  206. {
  207. $storeId = $this->getStoreId();
  208. if ($storeId) {
  209. return Mage::app()->getStore($storeId);
  210. }
  211. return Mage::app()->getStore();
  212. }
  213. /**
  214. * Retrieve order cancel availability
  215. *
  216. * @return bool
  217. */
  218. public function canCancel()
  219. {
  220. if ($this->canUnhold()) { // $this->isPaymentReview()
  221. return false;
  222. }
  223. $allInvoiced = true;
  224. foreach ($this->getAllItems() as $item) {
  225. if ($item->getQtyToInvoice()) {
  226. $allInvoiced = false;
  227. break;
  228. }
  229. }
  230. if ($allInvoiced) {
  231. return false;
  232. }
  233. $state = $this->getState();
  234. if ($this->isCanceled() || $state === self::STATE_COMPLETE || $state === self::STATE_CLOSED) {
  235. return false;
  236. }
  237. if ($this->getActionFlag(self::ACTION_FLAG_CANCEL) === false) {
  238. return false;
  239. }
  240. /**
  241. * Use only state for availability detect
  242. */
  243. /*foreach ($this->getAllItems() as $item) {
  244. if ($item->getQtyToCancel()>0) {
  245. return true;
  246. }
  247. }
  248. return false;*/
  249. return true;
  250. }
  251. /**
  252. * Getter whether the payment can be voided
  253. * @return bool
  254. */
  255. public function canVoidPayment()
  256. {
  257. if ($this->canUnhold() || $this->isPaymentReview()) {
  258. return false;
  259. }
  260. $state = $this->getState();
  261. if ($this->isCanceled() || $state === self::STATE_COMPLETE || $state === self::STATE_CLOSED) {
  262. return false;
  263. }
  264. return $this->getPayment()->canVoid(new Varien_Object);
  265. }
  266. /**
  267. * Retrieve order invoice availability
  268. *
  269. * @return bool
  270. */
  271. public function canInvoice()
  272. {
  273. if ($this->canUnhold() || $this->isPaymentReview()) {
  274. return false;
  275. }
  276. $state = $this->getState();
  277. if ($this->isCanceled() || $state === self::STATE_COMPLETE || $state === self::STATE_CLOSED) {
  278. return false;
  279. }
  280. if ($this->getActionFlag(self::ACTION_FLAG_INVOICE) === false) {
  281. return false;
  282. }
  283. foreach ($this->getAllItems() as $item) {
  284. if ($item->getQtyToInvoice()>0 && !$item->getLockedDoInvoice()) {
  285. return true;
  286. }
  287. }
  288. return false;
  289. }
  290. /**
  291. * Retrieve order credit memo (refund) availability
  292. *
  293. * @return bool
  294. */
  295. public function canCreditmemo()
  296. {
  297. if ($this->hasForcedCanCreditmemo()) {
  298. return $this->getForcedCanCreditmemo();
  299. }
  300. if ($this->canUnhold() || $this->isPaymentReview()) {
  301. return false;
  302. }
  303. if ($this->isCanceled() || $this->getState() === self::STATE_CLOSED) {
  304. return false;
  305. }
  306. /**
  307. * We can have problem with float in php (on some server $a=762.73;$b=762.73; $a-$b!=0)
  308. * for this we have additional diapason for 0
  309. */
  310. if (abs($this->getTotalPaid()-$this->getTotalRefunded())<.0001) {
  311. return false;
  312. }
  313. if ($this->getActionFlag(self::ACTION_FLAG_EDIT) === false) {
  314. return false;
  315. }
  316. return true;
  317. }
  318. /**
  319. * Retrieve order hold availability
  320. *
  321. * @return bool
  322. */
  323. public function canHold()
  324. {
  325. $state = $this->getState();
  326. if ($this->isCanceled() || $this->isPaymentReview()
  327. || $state === self::STATE_COMPLETE || $state === self::STATE_CLOSED || $state === self::STATE_HOLDED) {
  328. return false;
  329. }
  330. if ($this->getActionFlag(self::ACTION_FLAG_HOLD) === false) {
  331. return false;
  332. }
  333. return true;
  334. }
  335. /**
  336. * Retrieve order unhold availability
  337. *
  338. * @return bool
  339. */
  340. public function canUnhold()
  341. {
  342. if ($this->getActionFlag(self::ACTION_FLAG_UNHOLD) === false || $this->isPaymentReview()) {
  343. return false;
  344. }
  345. return $this->getState() === self::STATE_HOLDED;
  346. }
  347. /**
  348. * Check if comment can be added to order history
  349. *
  350. * @return bool
  351. */
  352. public function canComment()
  353. {
  354. if ($this->getActionFlag(self::ACTION_FLAG_COMMENT) === false) {
  355. return false;
  356. }
  357. return true;
  358. }
  359. /**
  360. * Retrieve order shipment availability
  361. *
  362. * @return bool
  363. */
  364. public function canShip()
  365. {
  366. if ($this->canUnhold() || $this->isPaymentReview()) {
  367. return false;
  368. }
  369. if ($this->getIsVirtual() || $this->isCanceled()) {
  370. return false;
  371. }
  372. if ($this->getActionFlag(self::ACTION_FLAG_SHIP) === false) {
  373. return false;
  374. }
  375. foreach ($this->getAllItems() as $item) {
  376. if ($item->getQtyToShip()>0 && !$item->getIsVirtual()
  377. && !$item->getLockedDoShip())
  378. {
  379. return true;
  380. }
  381. }
  382. return false;
  383. }
  384. /**
  385. * Retrieve order edit availability
  386. *
  387. * @return bool
  388. */
  389. public function canEdit()
  390. {
  391. if ($this->canUnhold()) {
  392. return false;
  393. }
  394. $state = $this->getState();
  395. if ($this->isCanceled() || $this->isPaymentReview()
  396. || $state === self::STATE_COMPLETE || $state === self::STATE_CLOSED) {
  397. return false;
  398. }
  399. if (!$this->getPayment()->getMethodInstance()->canEdit()) {
  400. return false;
  401. }
  402. if ($this->getActionFlag(self::ACTION_FLAG_EDIT) === false) {
  403. return false;
  404. }
  405. return true;
  406. }
  407. /**
  408. * Retrieve order reorder availability
  409. *
  410. * @return bool
  411. */
  412. public function canReorder()
  413. {
  414. if ($this->canUnhold() || $this->isPaymentReview() || !$this->getCustomerId()) {
  415. return false;
  416. }
  417. $products = array();
  418. foreach ($this->getItemsCollection() as $item) {
  419. $products[] = $item->getProductId();
  420. }
  421. if (!empty($products)) {
  422. /*
  423. * @TODO ACPAOC: Use product collection here, but ensure that product is loaded with order store id, otherwise there'll be problems with isSalable()
  424. * for configurables, bundles and other composites
  425. *
  426. */
  427. /*
  428. $productsCollection = Mage::getModel('catalog/product')->getCollection()
  429. ->setStoreId($this->getStoreId())
  430. ->addIdFilter($products)
  431. ->addAttributeToSelect('status')
  432. ->load();
  433. foreach ($productsCollection as $product) {
  434. if (!$product->isSalable()) {
  435. return false;
  436. }
  437. }
  438. */
  439. foreach ($products as $productId) {
  440. $product = Mage::getModel('catalog/product')
  441. ->setStoreId($this->getStoreId())
  442. ->load($productId);
  443. if (!$product->getId() || !$product->isSalable()) {
  444. return false;
  445. }
  446. }
  447. }
  448. if ($this->getActionFlag(self::ACTION_FLAG_REORDER) === false) {
  449. return false;
  450. }
  451. return true;
  452. }
  453. /**
  454. * Check whether the payment is in payment review state
  455. * In this state order cannot be normally processed. Possible actions can be:
  456. * - accept or deny payment
  457. * - fetch transaction information
  458. *
  459. * @return bool
  460. */
  461. public function isPaymentReview()
  462. {
  463. return $this->getState() === self::STATE_PAYMENT_REVIEW;
  464. }
  465. /**
  466. * Check whether payment can be accepted or denied
  467. *
  468. * @return bool
  469. */
  470. public function canReviewPayment()
  471. {
  472. return $this->isPaymentReview() && $this->getPayment()->canReviewPayment();
  473. }
  474. /**
  475. * Check whether there can be a transaction update fetched for payment in review state
  476. *
  477. * @return bool
  478. */
  479. public function canFetchPaymentReviewUpdate()
  480. {
  481. return $this->isPaymentReview() && $this->getPayment()->canFetchTransactionInfo();
  482. }
  483. /**
  484. * Retrieve order configuration model
  485. *
  486. * @return Mage_Sales_Model_Order_Config
  487. */
  488. public function getConfig()
  489. {
  490. return Mage::getSingleton('sales/order_config');
  491. }
  492. /**
  493. * Place order payments
  494. *
  495. * @return Mage_Sales_Model_Order
  496. */
  497. protected function _placePayment()
  498. {
  499. $this->getPayment()->place();
  500. return $this;
  501. }
  502. /**
  503. * Retrieve order payment model object
  504. *
  505. * @return Mage_Sales_Model_Order_Payment
  506. */
  507. public function getPayment()
  508. {
  509. foreach ($this->getPaymentsCollection() as $payment) {
  510. if (!$payment->isDeleted()) {
  511. return $payment;
  512. }
  513. }
  514. return false;
  515. }
  516. /**
  517. * Declare order billing address
  518. *
  519. * @param Mage_Sales_Model_Order_Address $address
  520. * @return Mage_Sales_Model_Order
  521. */
  522. public function setBillingAddress(Mage_Sales_Model_Order_Address $address)
  523. {
  524. $old = $this->getBillingAddress();
  525. if (!empty($old)) {
  526. $address->setId($old->getId());
  527. }
  528. $this->addAddress($address->setAddressType('billing'));
  529. return $this;
  530. }
  531. /**
  532. * Declare order shipping address
  533. *
  534. * @param Mage_Sales_Model_Order_Address $address
  535. * @return Mage_Sales_Model_Order
  536. */
  537. public function setShippingAddress(Mage_Sales_Model_Order_Address $address)
  538. {
  539. $old = $this->getShippingAddress();
  540. if (!empty($old)) {
  541. $address->setId($old->getId());
  542. }
  543. $this->addAddress($address->setAddressType('shipping'));
  544. return $this;
  545. }
  546. /**
  547. * Retrieve order billing address
  548. *
  549. * @return Mage_Sales_Model_Order_Address
  550. */
  551. public function getBillingAddress()
  552. {
  553. foreach ($this->getAddressesCollection() as $address) {
  554. if ($address->getAddressType()=='billing' && !$address->isDeleted()) {
  555. return $address;
  556. }
  557. }
  558. return false;
  559. }
  560. /**
  561. * Retrieve order shipping address
  562. *
  563. * @return Mage_Sales_Model_Order_Address
  564. */
  565. public function getShippingAddress()
  566. {
  567. foreach ($this->getAddressesCollection() as $address) {
  568. if ($address->getAddressType()=='shipping' && !$address->isDeleted()) {
  569. return $address;
  570. }
  571. }
  572. return false;
  573. }
  574. /**
  575. * Order state setter.
  576. * If status is specified, will add order status history with specified comment
  577. * the setData() cannot be overriden because of compatibility issues with resource model
  578. *
  579. * @param string $state
  580. * @param string|bool $status
  581. * @param string $comment
  582. * @param bool $isCustomerNotified
  583. * @return Mage_Sales_Model_Order
  584. */
  585. public function setState($state, $status = false, $comment = '', $isCustomerNotified = null)
  586. {
  587. return $this->_setState($state, $status, $comment, $isCustomerNotified, true);
  588. }
  589. /**
  590. * Order state protected setter.
  591. * By default allows to set any state. Can also update status to default or specified value
  592. * ะกomplete and closed states are encapsulated intentionally, see the _checkState()
  593. *
  594. * @param string $state
  595. * @param string|bool $status
  596. * @param string $comment
  597. * @param bool $isCustomerNotified
  598. * @param $shouldProtectState
  599. * @return Mage_Sales_Model_Order
  600. */
  601. protected function _setState($state, $status = false, $comment = '', $isCustomerNotified = null, $shouldProtectState = false)
  602. {
  603. // attempt to set the specified state
  604. if ($shouldProtectState) {
  605. if ($this->isStateProtected($state)) {
  606. Mage::throwException(Mage::helper('sales')->__('The Order State "%s" must not be set manually.', $state));
  607. }
  608. }
  609. $this->setData('state', $state);
  610. // add status history
  611. if ($status) {
  612. if ($status === true) {
  613. $status = $this->getConfig()->getStateDefaultStatus($state);
  614. }
  615. $this->setStatus($status);
  616. $history = $this->addStatusHistoryComment($comment, false); // no sense to set $status again
  617. $history->setIsCustomerNotified($isCustomerNotified); // for backwards compatibility
  618. }
  619. return $this;
  620. }
  621. /**
  622. * Whether specified state can be set from outside
  623. * @param $state
  624. * @return bool
  625. */
  626. public function isStateProtected($state)
  627. {
  628. if (empty($state)) {
  629. return false;
  630. }
  631. return self::STATE_COMPLETE == $state || self::STATE_CLOSED == $state;
  632. }
  633. /**
  634. * Retrieve label of order status
  635. *
  636. * @return string
  637. */
  638. public function getStatusLabel()
  639. {
  640. return $this->getConfig()->getStatusLabel($this->getStatus());
  641. }
  642. /**
  643. * Add status change information to history
  644. * @deprecated after 1.4.0.0-alpha3
  645. *
  646. * @param string $status
  647. * @param string $comment
  648. * @param bool $isCustomerNotified
  649. * @return Mage_Sales_Model_Order
  650. */
  651. public function addStatusToHistory($status, $comment = '', $isCustomerNotified = false)
  652. {
  653. $history = $this->addStatusHistoryComment($comment, $status)
  654. ->setIsCustomerNotified($isCustomerNotified);
  655. return $this;
  656. }
  657. /*
  658. * Add a comment to order
  659. * Different or default status may be specified
  660. *
  661. * @param string $comment
  662. * @param string $status
  663. * @return Mage_Sales_Order_Status_History
  664. */
  665. public function addStatusHistoryComment($comment, $status = false)
  666. {
  667. if (false === $status) {
  668. $status = $this->getStatus();
  669. } elseif (true === $status) {
  670. $status = $this->getConfig()->getStateDefaultStatus($this->getState());
  671. } else {
  672. $this->setStatus($status);
  673. }
  674. $history = Mage::getModel('sales/order_status_history')
  675. ->setStatus($status)
  676. ->setComment($comment);
  677. $this->addStatusHistory($history);
  678. return $history;
  679. }
  680. /**
  681. * Place order
  682. *
  683. * @return Mage_Sales_Model_Order
  684. */
  685. public function place()
  686. {
  687. Mage::dispatchEvent('sales_order_place_before', array('order'=>$this));
  688. $this->_placePayment();
  689. Mage::dispatchEvent('sales_order_place_after', array('order'=>$this));
  690. return $this;
  691. }
  692. public function hold()
  693. {
  694. if (!$this->canHold()) {
  695. Mage::throwException(Mage::helper('sales')->__('Hold action is not available.'));
  696. }
  697. $this->setHoldBeforeState($this->getState());
  698. $this->setHoldBeforeStatus($this->getStatus());
  699. $this->setState(self::STATE_HOLDED, true);
  700. return $this;
  701. }
  702. /**
  703. * Attempt to unhold the order
  704. *
  705. * @return Mage_Sales_Model_Order
  706. * @throws Mage_Core_Exception
  707. */
  708. public function unhold()
  709. {
  710. if (!$this->canUnhold()) {
  711. Mage::throwException(Mage::helper('sales')->__('Unhold action is not available.'));
  712. }
  713. $this->setState($this->getHoldBeforeState(), $this->getHoldBeforeStatus());
  714. $this->setHoldBeforeState(null);
  715. $this->setHoldBeforeStatus(null);
  716. return $this;
  717. }
  718. /**
  719. * Cancel order
  720. *
  721. * @return Mage_Sales_Model_Order
  722. */
  723. public function cancel()
  724. {
  725. if ($this->canCancel()) {
  726. $this->getPayment()->cancel();
  727. $this->registerCancellation();
  728. Mage::dispatchEvent('order_cancel_after', array('order' => $this));
  729. }
  730. return $this;
  731. }
  732. /**
  733. * Prepare order totals to cancellation
  734. * @param string $comment
  735. * @param bool $graceful
  736. * @return Mage_Sales_Model_Order
  737. * @throws Mage_Core_Exception
  738. */
  739. public function registerCancellation($comment = '', $graceful = true)
  740. {
  741. if ($this->canCancel()) {
  742. $cancelState = self::STATE_CANCELED;
  743. foreach ($this->getAllItems() as $item) {
  744. if ($cancelState != self::STATE_PROCESSING && $item->getQtyToRefund()) {
  745. if ($item->getQtyToShip() > $item->getQtyToCancel()) {
  746. $cancelState = self::STATE_PROCESSING;
  747. } else {
  748. $cancelState = self::STATE_COMPLETE;
  749. }
  750. }
  751. $item->cancel();
  752. }
  753. $this->setSubtotalCanceled($this->getSubtotal() - $this->getSubtotalInvoiced());
  754. $this->setBaseSubtotalCanceled($this->getBaseSubtotal() - $this->getBaseSubtotalInvoiced());
  755. $this->setTaxCanceled($this->getTaxAmount() - $this->getTaxInvoiced());
  756. $this->setBaseTaxCanceled($this->getBaseTaxAmount() - $this->getBaseTaxInvoiced());
  757. $this->setShippingCanceled($this->getShippingAmount() - $this->getShippingInvoiced());
  758. $this->setBaseShippingCanceled($this->getBaseShippingAmount() - $this->getBaseShippingInvoiced());
  759. $this->setDiscountCanceled(abs($this->getDiscountAmount()) - $this->getDiscountInvoiced());
  760. $this->setBaseDiscountCanceled(abs($this->getBaseDiscountAmount()) - $this->getBaseDiscountInvoiced());
  761. $this->setTotalCanceled($this->getSubtotalCanceled() + $this->getTaxCanceled() + $this->getShippingCanceled() - $this->getDiscountCanceled());
  762. $this->setBaseTotalCanceled($this->getBaseSubtotalCanceled() + $this->getBaseTaxCanceled() + $this->getBaseShippingCanceled() - $this->getBaseDiscountCanceled());
  763. $this->_setState($cancelState, true, $comment);
  764. } elseif (!$graceful) {
  765. Mage::throwException(Mage::helper('sales')->__('Order does not allow to be canceled.'));
  766. }
  767. return $this;
  768. }
  769. /**
  770. * Retrieve tracking numbers
  771. *
  772. * @return array
  773. */
  774. public function getTrackingNumbers()
  775. {
  776. if ($this->getData('tracking_numbers')) {
  777. return explode(',', $this->getData('tracking_numbers'));
  778. }
  779. return array();
  780. }
  781. public function getShippingCarrier()
  782. {
  783. $carrierModel = $this->getData('shipping_carrier');
  784. if (is_null($carrierModel)) {
  785. $carrierModel = false;
  786. /**
  787. * $method - carrier_method
  788. */
  789. if ($method = $this->getShippingMethod()) {
  790. $data = explode('_', $method);
  791. $carrierCode = $data[0];
  792. $className = Mage::getStoreConfig('carriers/'.$carrierCode.'/model');
  793. if ($className) {
  794. $carrierModel = Mage::getModel($className);
  795. }
  796. }
  797. $this->setData('shipping_carrier', $carrierModel);
  798. }
  799. return $carrierModel;
  800. }
  801. /**
  802. * Send email with order data
  803. *
  804. * @return Mage_Sales_Model_Order
  805. */
  806. public function sendNewOrderEmail()
  807. {
  808. $storeId = $this->getStore()->getId();
  809. if (!Mage::helper('sales')->canSendNewOrderEmail($storeId)) {
  810. return $this;
  811. }
  812. // Get the destination email addresses to send copies to
  813. $copyTo = $this->_getEmails(self::XML_PATH_EMAIL_COPY_TO);
  814. $copyMethod = Mage::getStoreConfig(self::XML_PATH_EMAIL_COPY_METHOD, $storeId);
  815. // Start store emulation process
  816. $appEmulation = Mage::getSingleton('core/app_emulation');
  817. $initialEnvironmentInfo = $appEmulation->startEnvironmentEmulation($storeId);
  818. try {
  819. // Retrieve specified view block from appropriate design package (depends on emulated store)
  820. $paymentBlock = Mage::helper('payment')->getInfoBlock($this->getPayment())
  821. ->setIsSecureMode(true);
  822. $paymentBlock->getMethod()->setStore($storeId);
  823. $paymentBlockHtml = $paymentBlock->toHtml();
  824. } catch (Exception $exception) {
  825. // Stop store emulation process
  826. $appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);
  827. throw $exception;
  828. }
  829. // Stop store emulation process
  830. $appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);
  831. // Retrieve corresponding email template id and customer name
  832. if ($this->getCustomerIsGuest()) {
  833. $templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_GUEST_TEMPLATE, $storeId);
  834. $customerName = $this->getBillingAddress()->getName();
  835. } else {
  836. $templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_TEMPLATE, $storeId);
  837. $customerName = $this->getCustomerName();
  838. }
  839. $mailer = Mage::getModel('core/email_template_mailer');
  840. $emailInfo = Mage::getModel('core/email_info');
  841. $emailInfo->addTo($this->getCustomerEmail(), $customerName);
  842. if ($copyTo && $copyMethod == 'bcc') {
  843. // Add bcc to customer email
  844. foreach ($copyTo as $email) {
  845. $emailInfo->addBcc($email);
  846. }
  847. }
  848. $mailer->addEmailInfo($emailInfo);
  849. // Email copies are sent as separated emails if their copy method is 'copy'
  850. if ($copyTo && $copyMethod == 'copy') {
  851. foreach ($copyTo as $email) {
  852. $emailInfo = Mage::getModel('core/email_info');
  853. $emailInfo->addTo($email);
  854. $mailer->addEmailInfo($emailInfo);
  855. }
  856. }
  857. // Set all required params and send emails
  858. $mailer->setSender(Mage::getStoreConfig(self::XML_PATH_EMAIL_IDENTITY, $storeId));
  859. $mailer->setStoreId($storeId);
  860. $mailer->setTemplateId($templateId);
  861. $mailer->setTemplateParams(array(
  862. 'order' => $this,
  863. 'billing' => $this->getBillingAddress(),
  864. 'payment_html' => $paymentBlockHtml
  865. )
  866. );
  867. $mailer->send();
  868. $this->setEmailSent(true);
  869. $this->_getResource()->saveAttribute($this, 'email_sent');
  870. return $this;
  871. }
  872. /**
  873. * Send email with order update information
  874. *
  875. * @param boolean $notifyCustomer
  876. * @param string $comment
  877. * @return Mage_Sales_Model_Order
  878. */
  879. public function sendOrderUpdateEmail($notifyCustomer = true, $comment = '')
  880. {
  881. $storeId = $this->getStore()->getId();
  882. if (!Mage::helper('sales')->canSendOrderCommentEmail($storeId)) {
  883. return $this;
  884. }
  885. // Get the destination email addresses to send copies to
  886. $copyTo = $this->_getEmails(self::XML_PATH_UPDATE_EMAIL_COPY_TO);
  887. $copyMethod = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_COPY_METHOD, $storeId);
  888. // Check if at least one recepient is found
  889. if (!$notifyCustomer && !$copyTo) {
  890. return $this;
  891. }
  892. // Retrieve corresponding email template id and customer name
  893. if ($this->getCustomerIsGuest()) {
  894. $templateId = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_GUEST_TEMPLATE, $storeId);
  895. $customerName = $this->getBillingAddress()->getName();
  896. } else {
  897. $templateId = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_TEMPLATE, $storeId);
  898. $customerName = $this->getCustomerName();
  899. }
  900. $mailer = Mage::getModel('core/email_template_mailer');
  901. if ($notifyCustomer) {
  902. $emailInfo = Mage::getModel('core/email_info');
  903. $emailInfo->addTo($this->getCustomerEmail(), $customerName);
  904. if ($copyTo && $copyMethod == 'bcc') {
  905. // Add bcc to customer email
  906. foreach ($copyTo as $email) {
  907. $emailInfo->addBcc($email);
  908. }
  909. }
  910. $mailer->addEmailInfo($emailInfo);
  911. }
  912. // Email copies are sent as separated emails if their copy method is 'copy' or a customer should not be notified
  913. if ($copyTo && ($copyMethod == 'copy' || !$notifyCustomer)) {
  914. foreach ($copyTo as $email) {
  915. $emailInfo = Mage::getModel('core/email_info');
  916. $emailInfo->addTo($email);
  917. $mailer->addEmailInfo($emailInfo);
  918. }
  919. }
  920. // Set all required params and send emails
  921. $mailer->setSender(Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_IDENTITY, $storeId));
  922. $mailer->setStoreId($storeId);
  923. $mailer->setTemplateId($templateId);
  924. $mailer->setTemplateParams(array(
  925. 'order' => $this,
  926. 'comment' => $comment,
  927. 'billing' => $this->getBillingAddress()
  928. )
  929. );
  930. $mailer->send();
  931. return $this;
  932. }
  933. protected function _getEmails($configPath)
  934. {
  935. $data = Mage::getStoreConfig($configPath, $this->getStoreId());
  936. if (!empty($data)) {
  937. return explode(',', $data);
  938. }
  939. return false;
  940. }
  941. /*********************** ADDRESSES ***************************/
  942. public function getAddressesCollection()
  943. {
  944. if (is_null($this->_addresses)) {
  945. $this->_addresses = Mage::getResourceModel('sales/order_address_collection')
  946. ->setOrderFilter($this);
  947. if ($this->getId()) {
  948. foreach ($this->_addresses as $address) {
  949. $address->setOrder($this);
  950. }
  951. }
  952. }
  953. return $this->_addresses;
  954. }
  955. public function getAddressById($addressId)
  956. {
  957. foreach ($this->getAddressesCollection() as $address) {
  958. if ($address->getId()==$addressId) {
  959. return $address;
  960. }
  961. }
  962. return false;
  963. }
  964. public function addAddress(Mage_Sales_Model_Order_Address $address)
  965. {
  966. $address->setOrder($this)->setParentId($this->getId());
  967. if (!$address->getId()) {
  968. $this->getAddressesCollection()->addItem($address);
  969. }
  970. return $this;
  971. }
  972. public function getItemsCollection($filterByTypes = array(), $nonChildrenOnly = false)
  973. {
  974. if (is_null($this->_items)) {
  975. $this->_items = Mage::getResourceModel('sales/order_item_collection')
  976. ->setOrderFilter($this);
  977. if ($filterByTypes) {
  978. $this->_items->filterByTypes($filterByTypes);
  979. }
  980. if ($nonChildrenOnly) {
  981. $this->_items->filterByParent();
  982. }
  983. if ($this->getId()) {
  984. foreach ($this->_items as $item) {
  985. $item->setOrder($this);
  986. }
  987. }
  988. }
  989. return $this->_items;
  990. }
  991. /**
  992. * Get random items collection with related children
  993. *
  994. * @param int $limit
  995. * @return Mage_Sales_Model_Mysql4_Order_Item_Collection
  996. */
  997. public function getItemsRandomCollection($limit = 1)
  998. {
  999. return $this->_getItemsRandomCollection($limit);
  1000. }
  1001. /**
  1002. * Get random items collection without related children
  1003. *
  1004. * @param int $limit
  1005. * @return Mage_Sales_Model_Mysql4_Order_Item_Collection
  1006. */
  1007. public function getParentItemsRandomCollection($limit = 1)
  1008. {
  1009. return $this->_getItemsRandomCollection($limit, true);
  1010. }
  1011. /**
  1012. * Get random items collection with or without related children
  1013. *
  1014. * @param int $limit
  1015. * @param bool $nonChildrenOnly
  1016. * @return Mage_Sales_Model_Mysql4_Order_Item_Collection
  1017. */
  1018. protected function _getItemsRandomCollection($limit, $nonChildrenOnly = false)
  1019. {
  1020. $collection = Mage::getModel('sales/order_item')->getCollection()
  1021. ->setOrderFilter($this)
  1022. ->setRandomOrder();
  1023. if ($nonChildrenOnly) {
  1024. $collection->filterByParent();
  1025. }
  1026. $products = array();
  1027. foreach ($collection as $item) {
  1028. $products[] = $item->getProductId();
  1029. }
  1030. $productsCollection = Mage::getModel('catalog/product')
  1031. ->getCollection()
  1032. ->addIdFilter($products)
  1033. ->setVisibility(Mage::getSingleton('catalog/product_visibility')->getVisibleInSiteIds())
  1034. /* Price data is added to consider item stock status using price index */
  1035. ->addPriceData()
  1036. ->setPageSize($limit)
  1037. ->load();
  1038. foreach ($collection as $item) {
  1039. $product = $productsCollection->getItemById($item->getProductId());
  1040. if ($product) {
  1041. $item->setProduct($product);
  1042. }
  1043. }
  1044. return $collection;
  1045. }
  1046. public function getAllItems()
  1047. {
  1048. $items = array();
  1049. foreach ($this->getItemsCollection() as $item) {
  1050. if (!$item->isDeleted()) {
  1051. $items[] = $item;
  1052. }
  1053. }
  1054. return $items;
  1055. }
  1056. public function getAllVisibleItems()
  1057. {
  1058. $items = array();
  1059. foreach ($this->getItemsCollection() as $item) {
  1060. if (!$item->isDeleted() && !$item->getParentItemId()) {
  1061. $items[] = $item;
  1062. }
  1063. }
  1064. return $items;
  1065. }
  1066. public function getItemById($itemId)
  1067. {
  1068. return $this->getItemsCollection()->getItemById($itemId);
  1069. }
  1070. public function getItemByQuoteItemId($quoteItemId)
  1071. {
  1072. foreach ($this->getItemsCollection() as $item) {
  1073. if ($item->getQuoteItemId()==$quoteItemId) {
  1074. return $item;
  1075. }
  1076. }
  1077. return null;
  1078. }
  1079. public function addItem(Mage_Sales_Model_Order_Item $item)
  1080. {
  1081. $item->setOrder($this);
  1082. if (!$item->getId()) {
  1083. $this->getItemsCollection()->addItem($item);
  1084. }
  1085. return $this;
  1086. }
  1087. /**
  1088. * Whether the order has nominal items only
  1089. *
  1090. * @return bool
  1091. */
  1092. public function isNominal()
  1093. {
  1094. foreach ($this->getAllVisibleItems() as $item) {
  1095. if ('0' == $item->getIsNominal()) {
  1096. return false;
  1097. }
  1098. }
  1099. return true;
  1100. }
  1101. /*********************** PAYMENTS ***************************/
  1102. public function getPaymentsCollection()
  1103. {
  1104. if (is_null($this->_payments)) {
  1105. $this->_payments = Mage::getResourceModel('sales/order_payment_collection')
  1106. ->setOrderFilter($this);
  1107. if ($this->getId()) {
  1108. foreach ($this->_payments as $payment) {
  1109. $payment->setOrder($this);
  1110. }
  1111. }
  1112. }
  1113. return $this->_payments;
  1114. }
  1115. public function getAllPayments()
  1116. {
  1117. $payments = array();
  1118. foreach ($this->getPaymentsCollection() as $payment) {
  1119. if (!$payment->isDeleted()) {
  1120. $payments[] = $payment;
  1121. }
  1122. }
  1123. return $payments;
  1124. }
  1125. public function getPaymentById($paymentId)
  1126. {
  1127. foreach ($this->getPaymentsCollection() as $payment) {
  1128. if ($payment->getId()==$paymentId) {
  1129. return $payment;
  1130. }
  1131. }
  1132. return false;
  1133. }
  1134. public function addPayment(Mage_Sales_Model_Order_Payment $payment)
  1135. {
  1136. $payment->setOrder($this)
  1137. ->setParentId($this->getId());
  1138. if (!$payment->getId()) {
  1139. $this->getPaymentsCollection()->addItem($payment);
  1140. }
  1141. return $this;
  1142. }
  1143. public function setPayment(Mage_Sales_Model_Order_Payment $payment)
  1144. {
  1145. if (!$this->getIsMultiPayment() && ($old = $this->getPayment())) {
  1146. $payment->setId($old->getId());
  1147. }
  1148. $this->addPayment($payment);
  1149. return $payment;
  1150. }
  1151. /*********************** STATUSES ***************************/
  1152. /**
  1153. * Enter description here...
  1154. *
  1155. * @return Mage_Sales_Model_Entity_Order_Status_History_Collection
  1156. */
  1157. public function getStatusHistoryCollection($reload=false)
  1158. {
  1159. if (is_null($this->_statusHistory) || $reload) {
  1160. $this->_statusHistory = Mage::getResourceModel('sales/order_status_history_collection')
  1161. ->setOrderFilter($this)
  1162. ->setOrder('created_at', 'desc')
  1163. ->setOrder('entity_id', 'desc');
  1164. if ($this->getId()) {
  1165. foreach ($this->_statusHistory as $status) {
  1166. $status->setOrder($this);
  1167. }
  1168. }
  1169. }
  1170. return $this->_statusHistory;
  1171. }
  1172. /**
  1173. * Return collection of order status history items.
  1174. *
  1175. * @return array
  1176. */
  1177. public function getAllStatusHistory()
  1178. {
  1179. $history = array();
  1180. foreach ($this->getStatusHistoryCollection() as $status) {
  1181. if (!$status->isDeleted()) {
  1182. $history[] = $status;
  1183. }
  1184. }
  1185. return $history;
  1186. }
  1187. /**
  1188. * Return collection of visible on frontend order status history items.
  1189. *
  1190. * @return array
  1191. */
  1192. public function getVisibleStatusHistory()
  1193. {
  1194. $history = array();
  1195. foreach ($this->getStatusHistoryCollection() as $status) {
  1196. if (!$status->isDeleted() && $status->getComment() && $status->getIsVisibleOnFront()) {
  1197. $history[] = $status;
  1198. }
  1199. }
  1200. return $history;
  1201. }
  1202. public function getStatusHistoryById($statusId)
  1203. {
  1204. foreach ($this->getStatusHistoryCollection() as $status) {
  1205. if ($status->getId()==$statusId) {
  1206. return $status;
  1207. }
  1208. }
  1209. return false;
  1210. }
  1211. /**
  1212. * Set the order status history object and the order object to each other
  1213. * Adds the object to the status history collection, which is automatically saved when the order is saved.
  1214. * See the entity_id attribute backend model.
  1215. * Or the history record can be saved standalone after this.
  1216. *
  1217. * @param Mage_Sales_Model_Order_Status_History $status
  1218. * @return Mage_Sales_Model_Order
  1219. */
  1220. public function addStatusHistory(Mage_Sales_Model_Order_Status_History $history)
  1221. {
  1222. $history->setOrder($this);
  1223. $this->setStatus($history->getStatus());
  1224. if (!$history->getId()) {
  1225. $this->getStatusHistoryCollection()->addItem($history);
  1226. }
  1227. return $this;
  1228. }
  1229. /**
  1230. * Enter description here...
  1231. *
  1232. * @return string
  1233. */
  1234. public function getRealOrderId()
  1235. {
  1236. $id = $this->getData('real_order_id');
  1237. if (is_null($id)) {
  1238. $id = $this->getIncrementId();
  1239. }
  1240. return $id;
  1241. }
  1242. /**
  1243. * Get currency model instance. Will be used currency with which order placed
  1244. *
  1245. * @return Mage_Directory_Model_Currency
  1246. */
  1247. public function getOrderCurrency()
  1248. {
  1249. if (is_null($this->_orderCurrency)) {
  1250. $this->_orderCurrency = Mage::getModel('directory/currency')->load($this->getOrderCurrencyCode());
  1251. }
  1252. return $this->_orderCurrency;
  1253. }
  1254. /**
  1255. * Get formated price value including order currency rate to order website currency
  1256. *
  1257. * @param float $price
  1258. * @param bool $addBrackets
  1259. * @return string
  1260. */
  1261. public function formatPrice($price, $addBrackets = false)
  1262. {
  1263. return $this->formatPricePrecision($price, 2, $addBrackets);
  1264. }
  1265. public function formatPricePrecision($price, $precision, $addBrackets = false)
  1266. {
  1267. return $this->getOrderCurrency()->formatPrecision($price, $precision, array(), true, $addBrackets);
  1268. }
  1269. /**
  1270. * Retrieve text formated price value includeing order rate
  1271. *
  1272. * @param float $price
  1273. * @return string
  1274. */
  1275. public function formatPriceTxt($price)
  1276. {
  1277. return $this->getOrderCurrency()->formatTxt($price);
  1278. }
  1279. /**
  1280. * Retrieve order website currency for working with base prices
  1281. *
  1282. * @return Mage_Directory_Model_Currency
  1283. */
  1284. public function getBaseCurrency()
  1285. {
  1286. if (is_null($this->_baseCurrency)) {
  1287. $this->_baseCurrency = Mage::getModel('directory/currency')->load($this->getBaseCurrencyCode());
  1288. }
  1289. return $this->_baseCurrency;
  1290. }
  1291. /**
  1292. * Retrieve order website currency for working with base prices
  1293. * @deprecated please use getBaseCurrency instead.
  1294. *
  1295. * @return Mage_Directory_Model_Currency
  1296. */
  1297. public function getStoreCurrency()
  1298. {
  1299. return $this->getData('store_currency');
  1300. }
  1301. public function formatBasePrice($price)
  1302. {
  1303. return $this->formatBasePricePrecision($price, 2);
  1304. }
  1305. public function formatBasePricePrecision($price, $precision)
  1306. {
  1307. return $this->getBaseCurrency()->formatPrecision($price, $precision);
  1308. }
  1309. public function isCurrencyDifferent()
  1310. {
  1311. return $this->getOrderCurrencyCode() != $this->getBaseCurrencyCode();
  1312. }
  1313. /**
  1314. * Retrieve order total due value
  1315. *
  1316. * @return float
  1317. */
  1318. public function getTotalDue()
  1319. {
  1320. $total = $this->getGrandTotal()-$this->getTotalPaid();
  1321. $total = Mage::app()->getStore($this->getStoreId())->roundPrice($total);
  1322. return max($total, 0);
  1323. }
  1324. /**
  1325. * Retrieve order total due value
  1326. *
  1327. * @return float
  1328. */
  1329. public function getBaseTotalDue()
  1330. {
  1331. $total = $this->getBaseGrandTotal()-$this->getBaseTotalPaid();
  1332. $total = Mage::app()->getStore($this->getStoreId())->roundPrice($total);
  1333. return max($total, 0);
  1334. }
  1335. public function getData($key='', $index=null)
  1336. {
  1337. if ($key == 'total_due') {
  1338. return $this->getTotalDue();
  1339. }
  1340. if ($key == 'base_total_due') {
  1341. return $this->getBaseTotalDue();
  1342. }
  1343. return parent::getData($key, $index);
  1344. }
  1345. /**
  1346. * Retrieve order invoices collection
  1347. *
  1348. * @return unknown
  1349. */
  1350. public function getInvoiceCollection()
  1351. {
  1352. if (is_null($this->_invoices)) {
  1353. $this->_invoices = Mage::getResourceModel('sales/order_invoice_collection')
  1354. ->setOrderFilter($this);
  1355. if ($this->getId()) {
  1356. foreach ($this->_invoices as $invoice) {
  1357. $invoice->setOrder($this);
  1358. }
  1359. }
  1360. }
  1361. return $this->_invoices;
  1362. }
  1363. /**
  1364. * Retrieve order shipments collection
  1365. *
  1366. * @return unknown
  1367. */
  1368. public function getShipmentsCollection()
  1369. {
  1370. if (empty($this->_shipments)) {
  1371. if ($this->getId()) {
  1372. $this->_shipments = Mage::getResourceModel('sales/order_shipment_collection')
  1373. ->setOrderFilter($this)
  1374. ->load();
  1375. } else {
  1376. return false;
  1377. }
  1378. }
  1379. return $this->_shipments;
  1380. }
  1381. /**
  1382. * Retrieve order creditmemos collection
  1383. *
  1384. * @return unknown
  1385. */
  1386. public function getCreditmemosCollection()
  1387. {
  1388. if (empty($this->_creditmemos)) {
  1389. if ($this->getId()) {
  1390. $this->_creditmemos = Mage::getResourceModel('sales/order_creditmemo_collection')
  1391. ->setOrderFilter($this)
  1392. ->load();
  1393. } else {
  1394. return false;
  1395. }
  1396. }
  1397. return $this->_creditmemos;
  1398. }
  1399. /**
  1400. * Retrieve order tracking numbers collection
  1401. *
  1402. * @return unknown
  1403. */
  1404. public function getTracksCollection()
  1405. {
  1406. if (empty($this->_tracks)) {
  1407. $this->_tracks = Mage::getResourceModel('sales/order_shipment_track_collection')
  1408. ->setOrderFilter($this);
  1409. if ($this->getId()) {
  1410. $this->_tracks->load();
  1411. }
  1412. }
  1413. return $this->_tracks;
  1414. }
  1415. /**
  1416. * Check order invoices availability
  1417. *
  1418. * @return bool
  1419. */
  1420. public function hasInvoices()
  1421. {
  1422. return $this->getInvoiceCollection()->count();
  1423. }
  1424. /**
  1425. * Check order shipments availability
  1426. *
  1427. * @return bool
  1428. */
  1429. public function hasShipments()
  1430. {
  1431. return $this->getShipmentsCollection()->count();
  1432. }
  1433. /**
  1434. * Check order creditmemos availability
  1435. *
  1436. * @return bool
  1437. */
  1438. public function hasCreditmemos()
  1439. {
  1440. return $this->getCreditmemosCollection()->count();
  1441. }
  1442. /**
  1443. * Retrieve array of related objects
  1444. *
  1445. * Used for order saving
  1446. *
  1447. * @return array
  1448. */
  1449. public function getRelatedObjects()
  1450. {
  1451. return $this->_relatedObjects;
  1452. }
  1453. public function getCustomerName()
  1454. {
  1455. if ($this->getCustomerFirstname()) {
  1456. $customerName = $this->getCustomerFirstname() . ' ' . $this->getCustomerLastname();
  1457. }
  1458. else {
  1459. $customerName = Mage::helper('sales')->__('Guest');
  1460. }
  1461. return $customerName;
  1462. }
  1463. /**
  1464. * Add New object to related array
  1465. *
  1466. * @param Mage_Core_Model_Abstract $object
  1467. * @return Mage_Sales_Model_Order
  1468. */
  1469. public function addRelatedObject(Mage_Core_Model_Abstract $object)
  1470. {
  1471. $this->_relatedObjects[] = $object;
  1472. return $this;
  1473. }
  1474. /**
  1475. * Get formated order created date in store timezone
  1476. *
  1477. * @param string $format date format type (short|medium|long|full)
  1478. * @return string
  1479. */
  1480. public function getCreatedAtFormated($format)
  1481. {
  1482. return Mage::helper('core')->formatDate($this->getCreatedAtStoreDate(), $format, true);
  1483. }
  1484. public function getEmailCustomerNote()
  1485. {
  1486. if ($this->getCustomerNoteNotify()) {
  1487. return $this->getCustomerNote();
  1488. }
  1489. return '';
  1490. }
  1491. /**
  1492. * Processing object before save data
  1493. *
  1494. * @return Mage_Core_Model_Abstract
  1495. */
  1496. protected function _beforeSave()
  1497. {
  1498. parent::_beforeSave();
  1499. $this->_checkState();
  1500. if (!$this->getId()) {
  1501. $store = $this->getStore();
  1502. $name = array($store->getWebsite()->getName(),$store->getGroup()->getName(),$store->getName());
  1503. $this->setStoreName(implode("\n", $name));
  1504. }
  1505. if (!$this->getIncrementId()) {
  1506. $incrementId = Mage::getSingleton('eav/config')
  1507. ->getEntityType('order')
  1508. ->fetchNewIncrementId($this->getStoreId());
  1509. $this->setIncrementId($incrementId);
  1510. }
  1511. /**
  1512. * Process items dependency for new order
  1513. */
  1514. if (!$this->getId()) {
  1515. $itemsCount = 0;
  1516. foreach ($this->getAllItems() as $item) {
  1517. $parent = $item->getQuoteParentItemId();
  1518. if ($parent && !$item->getParentItem()) {
  1519. $item->setParentItem($this->getItemByQuoteItemId($parent));
  1520. } elseif (!$parent) {
  1521. $itemsCount++;
  1522. }
  1523. }
  1524. // Set items count
  1525. $this->setTotalItemCount($itemsCount);
  1526. }
  1527. if ($this->getCustomer()) {
  1528. $this->setCustomerId($this->getCustomer()->getId());
  1529. }
  1530. if ($this->hasBillingAddressId() &&

Large files files are truncated, but you can click here to view the full file