PageRenderTime 76ms CodeModel.GetById 36ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/chrisroseuk/magento19_dev
PHP | 2263 lines | 1186 code | 201 blank | 876 comment | 210 complexity | c599dd3d6a7be4079e30ebe86095a59a MD5 | raw file
Possible License(s): CC-BY-SA-3.0
  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) 2014 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. * @method Mage_Sales_Model_Resource_Order _getResource()
  37. * @method Mage_Sales_Model_Resource_Order getResource()
  38. * @method string getState()
  39. * @method string getStatus()
  40. * @method Mage_Sales_Model_Order setStatus(string $value)
  41. * @method string getCouponCode()
  42. * @method Mage_Sales_Model_Order setCouponCode(string $value)
  43. * @method string getProtectCode()
  44. * @method Mage_Sales_Model_Order setProtectCode(string $value)
  45. * @method string getShippingDescription()
  46. * @method Mage_Sales_Model_Order setShippingDescription(string $value)
  47. * @method int getIsVirtual()
  48. * @method Mage_Sales_Model_Order setIsVirtual(int $value)
  49. * @method int getStoreId()
  50. * @method Mage_Sales_Model_Order setStoreId(int $value)
  51. * @method int getCustomerId()
  52. * @method Mage_Sales_Model_Order setCustomerId(int $value)
  53. * @method float getBaseDiscountAmount()
  54. * @method Mage_Sales_Model_Order setBaseDiscountAmount(float $value)
  55. * @method float getBaseDiscountCanceled()
  56. * @method Mage_Sales_Model_Order setBaseDiscountCanceled(float $value)
  57. * @method float getBaseDiscountInvoiced()
  58. * @method Mage_Sales_Model_Order setBaseDiscountInvoiced(float $value)
  59. * @method float getBaseDiscountRefunded()
  60. * @method Mage_Sales_Model_Order setBaseDiscountRefunded(float $value)
  61. * @method float getBaseGrandTotal()
  62. * @method Mage_Sales_Model_Order setBaseGrandTotal(float $value)
  63. * @method float getBaseShippingAmount()
  64. * @method Mage_Sales_Model_Order setBaseShippingAmount(float $value)
  65. * @method float getBaseShippingCanceled()
  66. * @method Mage_Sales_Model_Order setBaseShippingCanceled(float $value)
  67. * @method float getBaseShippingInvoiced()
  68. * @method Mage_Sales_Model_Order setBaseShippingInvoiced(float $value)
  69. * @method float getBaseShippingRefunded()
  70. * @method Mage_Sales_Model_Order setBaseShippingRefunded(float $value)
  71. * @method float getBaseShippingTaxAmount()
  72. * @method Mage_Sales_Model_Order setBaseShippingTaxAmount(float $value)
  73. * @method float getBaseShippingTaxRefunded()
  74. * @method Mage_Sales_Model_Order setBaseShippingTaxRefunded(float $value)
  75. * @method float getBaseSubtotal()
  76. * @method Mage_Sales_Model_Order setBaseSubtotal(float $value)
  77. * @method float getBaseSubtotalCanceled()
  78. * @method Mage_Sales_Model_Order setBaseSubtotalCanceled(float $value)
  79. * @method float getBaseSubtotalInvoiced()
  80. * @method Mage_Sales_Model_Order setBaseSubtotalInvoiced(float $value)
  81. * @method float getBaseSubtotalRefunded()
  82. * @method Mage_Sales_Model_Order setBaseSubtotalRefunded(float $value)
  83. * @method float getBaseTaxAmount()
  84. * @method Mage_Sales_Model_Order setBaseTaxAmount(float $value)
  85. * @method float getBaseTaxCanceled()
  86. * @method Mage_Sales_Model_Order setBaseTaxCanceled(float $value)
  87. * @method float getBaseTaxInvoiced()
  88. * @method Mage_Sales_Model_Order setBaseTaxInvoiced(float $value)
  89. * @method float getBaseTaxRefunded()
  90. * @method Mage_Sales_Model_Order setBaseTaxRefunded(float $value)
  91. * @method float getBaseToGlobalRate()
  92. * @method Mage_Sales_Model_Order setBaseToGlobalRate(float $value)
  93. * @method float getBaseToOrderRate()
  94. * @method Mage_Sales_Model_Order setBaseToOrderRate(float $value)
  95. * @method float getBaseTotalCanceled()
  96. * @method Mage_Sales_Model_Order setBaseTotalCanceled(float $value)
  97. * @method float getBaseTotalInvoiced()
  98. * @method Mage_Sales_Model_Order setBaseTotalInvoiced(float $value)
  99. * @method float getBaseTotalInvoicedCost()
  100. * @method Mage_Sales_Model_Order setBaseTotalInvoicedCost(float $value)
  101. * @method float getBaseTotalOfflineRefunded()
  102. * @method Mage_Sales_Model_Order setBaseTotalOfflineRefunded(float $value)
  103. * @method float getBaseTotalOnlineRefunded()
  104. * @method Mage_Sales_Model_Order setBaseTotalOnlineRefunded(float $value)
  105. * @method float getBaseTotalPaid()
  106. * @method Mage_Sales_Model_Order setBaseTotalPaid(float $value)
  107. * @method float getBaseTotalQtyOrdered()
  108. * @method Mage_Sales_Model_Order setBaseTotalQtyOrdered(float $value)
  109. * @method float getBaseTotalRefunded()
  110. * @method Mage_Sales_Model_Order setBaseTotalRefunded(float $value)
  111. * @method float getDiscountAmount()
  112. * @method Mage_Sales_Model_Order setDiscountAmount(float $value)
  113. * @method float getDiscountCanceled()
  114. * @method Mage_Sales_Model_Order setDiscountCanceled(float $value)
  115. * @method float getDiscountInvoiced()
  116. * @method Mage_Sales_Model_Order setDiscountInvoiced(float $value)
  117. * @method float getDiscountRefunded()
  118. * @method Mage_Sales_Model_Order setDiscountRefunded(float $value)
  119. * @method float getGrandTotal()
  120. * @method Mage_Sales_Model_Order setGrandTotal(float $value)
  121. * @method float getShippingAmount()
  122. * @method Mage_Sales_Model_Order setShippingAmount(float $value)
  123. * @method float getShippingCanceled()
  124. * @method Mage_Sales_Model_Order setShippingCanceled(float $value)
  125. * @method float getShippingInvoiced()
  126. * @method Mage_Sales_Model_Order setShippingInvoiced(float $value)
  127. * @method float getShippingRefunded()
  128. * @method Mage_Sales_Model_Order setShippingRefunded(float $value)
  129. * @method float getShippingTaxAmount()
  130. * @method Mage_Sales_Model_Order setShippingTaxAmount(float $value)
  131. * @method float getShippingTaxRefunded()
  132. * @method Mage_Sales_Model_Order setShippingTaxRefunded(float $value)
  133. * @method float getStoreToBaseRate()
  134. * @method Mage_Sales_Model_Order setStoreToBaseRate(float $value)
  135. * @method float getStoreToOrderRate()
  136. * @method Mage_Sales_Model_Order setStoreToOrderRate(float $value)
  137. * @method float getSubtotal()
  138. * @method Mage_Sales_Model_Order setSubtotal(float $value)
  139. * @method float getSubtotalCanceled()
  140. * @method Mage_Sales_Model_Order setSubtotalCanceled(float $value)
  141. * @method float getSubtotalInvoiced()
  142. * @method Mage_Sales_Model_Order setSubtotalInvoiced(float $value)
  143. * @method float getSubtotalRefunded()
  144. * @method Mage_Sales_Model_Order setSubtotalRefunded(float $value)
  145. * @method float getTaxAmount()
  146. * @method Mage_Sales_Model_Order setTaxAmount(float $value)
  147. * @method float getTaxCanceled()
  148. * @method Mage_Sales_Model_Order setTaxCanceled(float $value)
  149. * @method float getTaxInvoiced()
  150. * @method Mage_Sales_Model_Order setTaxInvoiced(float $value)
  151. * @method float getTaxRefunded()
  152. * @method Mage_Sales_Model_Order setTaxRefunded(float $value)
  153. * @method float getTotalCanceled()
  154. * @method Mage_Sales_Model_Order setTotalCanceled(float $value)
  155. * @method float getTotalInvoiced()
  156. * @method Mage_Sales_Model_Order setTotalInvoiced(float $value)
  157. * @method float getTotalOfflineRefunded()
  158. * @method Mage_Sales_Model_Order setTotalOfflineRefunded(float $value)
  159. * @method float getTotalOnlineRefunded()
  160. * @method Mage_Sales_Model_Order setTotalOnlineRefunded(float $value)
  161. * @method float getTotalPaid()
  162. * @method Mage_Sales_Model_Order setTotalPaid(float $value)
  163. * @method float getTotalQtyOrdered()
  164. * @method Mage_Sales_Model_Order setTotalQtyOrdered(float $value)
  165. * @method float getTotalRefunded()
  166. * @method Mage_Sales_Model_Order setTotalRefunded(float $value)
  167. * @method int getCanShipPartially()
  168. * @method Mage_Sales_Model_Order setCanShipPartially(int $value)
  169. * @method int getCanShipPartiallyItem()
  170. * @method Mage_Sales_Model_Order setCanShipPartiallyItem(int $value)
  171. * @method int getCustomerIsGuest()
  172. * @method Mage_Sales_Model_Order setCustomerIsGuest(int $value)
  173. * @method int getCustomerNoteNotify()
  174. * @method Mage_Sales_Model_Order setCustomerNoteNotify(int $value)
  175. * @method int getBillingAddressId()
  176. * @method Mage_Sales_Model_Order setBillingAddressId(int $value)
  177. * @method int getCustomerGroupId()
  178. * @method Mage_Sales_Model_Order setCustomerGroupId(int $value)
  179. * @method int getEditIncrement()
  180. * @method Mage_Sales_Model_Order setEditIncrement(int $value)
  181. * @method int getEmailSent()
  182. * @method Mage_Sales_Model_Order setEmailSent(int $value)
  183. * @method int getForcedDoShipmentWithInvoice()
  184. * @method Mage_Sales_Model_Order setForcedDoShipmentWithInvoice(int $value)
  185. * @method int getGiftMessageId()
  186. * @method Mage_Sales_Model_Order setGiftMessageId(int $value)
  187. * @method int getPaymentAuthorizationExpiration()
  188. * @method Mage_Sales_Model_Order setPaymentAuthorizationExpiration(int $value)
  189. * @method int getPaypalIpnCustomerNotified()
  190. * @method Mage_Sales_Model_Order setPaypalIpnCustomerNotified(int $value)
  191. * @method int getQuoteAddressId()
  192. * @method Mage_Sales_Model_Order setQuoteAddressId(int $value)
  193. * @method int getQuoteId()
  194. * @method Mage_Sales_Model_Order setQuoteId(int $value)
  195. * @method int getShippingAddressId()
  196. * @method Mage_Sales_Model_Order setShippingAddressId(int $value)
  197. * @method float getAdjustmentNegative()
  198. * @method Mage_Sales_Model_Order setAdjustmentNegative(float $value)
  199. * @method float getAdjustmentPositive()
  200. * @method Mage_Sales_Model_Order setAdjustmentPositive(float $value)
  201. * @method float getBaseAdjustmentNegative()
  202. * @method Mage_Sales_Model_Order setBaseAdjustmentNegative(float $value)
  203. * @method float getBaseAdjustmentPositive()
  204. * @method Mage_Sales_Model_Order setBaseAdjustmentPositive(float $value)
  205. * @method float getBaseShippingDiscountAmount()
  206. * @method Mage_Sales_Model_Order setBaseShippingDiscountAmount(float $value)
  207. * @method float getBaseSubtotalInclTax()
  208. * @method Mage_Sales_Model_Order setBaseSubtotalInclTax(float $value)
  209. * @method Mage_Sales_Model_Order setBaseTotalDue(float $value)
  210. * @method float getPaymentAuthorizationAmount()
  211. * @method Mage_Sales_Model_Order setPaymentAuthorizationAmount(float $value)
  212. * @method float getShippingDiscountAmount()
  213. * @method Mage_Sales_Model_Order setShippingDiscountAmount(float $value)
  214. * @method float getSubtotalInclTax()
  215. * @method Mage_Sales_Model_Order setSubtotalInclTax(float $value)
  216. * @method Mage_Sales_Model_Order setTotalDue(float $value)
  217. * @method float getWeight()
  218. * @method Mage_Sales_Model_Order setWeight(float $value)
  219. * @method string getCustomerDob()
  220. * @method Mage_Sales_Model_Order setCustomerDob(string $value)
  221. * @method string getIncrementId()
  222. * @method Mage_Sales_Model_Order setIncrementId(string $value)
  223. * @method string getAppliedRuleIds()
  224. * @method Mage_Sales_Model_Order setAppliedRuleIds(string $value)
  225. * @method string getBaseCurrencyCode()
  226. * @method Mage_Sales_Model_Order setBaseCurrencyCode(string $value)
  227. * @method string getCustomerEmail()
  228. * @method Mage_Sales_Model_Order setCustomerEmail(string $value)
  229. * @method string getCustomerFirstname()
  230. * @method Mage_Sales_Model_Order setCustomerFirstname(string $value)
  231. * @method string getCustomerLastname()
  232. * @method Mage_Sales_Model_Order setCustomerLastname(string $value)
  233. * @method string getCustomerMiddlename()
  234. * @method Mage_Sales_Model_Order setCustomerMiddlename(string $value)
  235. * @method string getCustomerPrefix()
  236. * @method Mage_Sales_Model_Order setCustomerPrefix(string $value)
  237. * @method string getCustomerSuffix()
  238. * @method Mage_Sales_Model_Order setCustomerSuffix(string $value)
  239. * @method string getCustomerTaxvat()
  240. * @method Mage_Sales_Model_Order setCustomerTaxvat(string $value)
  241. * @method string getDiscountDescription()
  242. * @method Mage_Sales_Model_Order setDiscountDescription(string $value)
  243. * @method string getExtCustomerId()
  244. * @method Mage_Sales_Model_Order setExtCustomerId(string $value)
  245. * @method string getExtOrderId()
  246. * @method Mage_Sales_Model_Order setExtOrderId(string $value)
  247. * @method string getGlobalCurrencyCode()
  248. * @method Mage_Sales_Model_Order setGlobalCurrencyCode(string $value)
  249. * @method string getHoldBeforeState()
  250. * @method Mage_Sales_Model_Order setHoldBeforeState(string $value)
  251. * @method string getHoldBeforeStatus()
  252. * @method Mage_Sales_Model_Order setHoldBeforeStatus(string $value)
  253. * @method string getOrderCurrencyCode()
  254. * @method Mage_Sales_Model_Order setOrderCurrencyCode(string $value)
  255. * @method string getOriginalIncrementId()
  256. * @method Mage_Sales_Model_Order setOriginalIncrementId(string $value)
  257. * @method string getRelationChildId()
  258. * @method Mage_Sales_Model_Order setRelationChildId(string $value)
  259. * @method string getRelationChildRealId()
  260. * @method Mage_Sales_Model_Order setRelationChildRealId(string $value)
  261. * @method string getRelationParentId()
  262. * @method Mage_Sales_Model_Order setRelationParentId(string $value)
  263. * @method string getRelationParentRealId()
  264. * @method Mage_Sales_Model_Order setRelationParentRealId(string $value)
  265. * @method string getRemoteIp()
  266. * @method Mage_Sales_Model_Order setRemoteIp(string $value)
  267. * @method Mage_Sales_Model_Order setShippingMethod(string $value)
  268. * @method string getStoreCurrencyCode()
  269. * @method Mage_Sales_Model_Order setStoreCurrencyCode(string $value)
  270. * @method string getStoreName()
  271. * @method Mage_Sales_Model_Order setStoreName(string $value)
  272. * @method string getXForwardedFor()
  273. * @method Mage_Sales_Model_Order setXForwardedFor(string $value)
  274. * @method string getCustomerNote()
  275. * @method Mage_Sales_Model_Order setCustomerNote(string $value)
  276. * @method string getCreatedAt()
  277. * @method Mage_Sales_Model_Order setCreatedAt(string $value)
  278. * @method string getUpdatedAt()
  279. * @method Mage_Sales_Model_Order setUpdatedAt(string $value)
  280. * @method int getTotalItemCount()
  281. * @method Mage_Sales_Model_Order setTotalItemCount(int $value)
  282. * @method int getCustomerGender()
  283. * @method Mage_Sales_Model_Order setCustomerGender(int $value)
  284. * @method float getHiddenTaxAmount()
  285. * @method Mage_Sales_Model_Order setHiddenTaxAmount(float $value)
  286. * @method float getBaseHiddenTaxAmount()
  287. * @method Mage_Sales_Model_Order setBaseHiddenTaxAmount(float $value)
  288. * @method float getShippingHiddenTaxAmount()
  289. * @method Mage_Sales_Model_Order setShippingHiddenTaxAmount(float $value)
  290. * @method float getBaseShippingHiddenTaxAmount()
  291. * @method Mage_Sales_Model_Order setBaseShippingHiddenTaxAmount(float $value)
  292. * @method float getHiddenTaxInvoiced()
  293. * @method Mage_Sales_Model_Order setHiddenTaxInvoiced(float $value)
  294. * @method float getBaseHiddenTaxInvoiced()
  295. * @method Mage_Sales_Model_Order setBaseHiddenTaxInvoiced(float $value)
  296. * @method float getHiddenTaxRefunded()
  297. * @method Mage_Sales_Model_Order setHiddenTaxRefunded(float $value)
  298. * @method float getBaseHiddenTaxRefunded()
  299. * @method Mage_Sales_Model_Order setBaseHiddenTaxRefunded(float $value)
  300. * @method float getShippingInclTax()
  301. * @method Mage_Sales_Model_Order setShippingInclTax(float $value)
  302. * @method float getBaseShippingInclTax()
  303. * @method Mage_Sales_Model_Order setBaseShippingInclTax(float $value)
  304. *
  305. * @category Mage
  306. * @package Mage_Sales
  307. * @author Magento Core Team <core@magentocommerce.com>
  308. */
  309. class Mage_Sales_Model_Order extends Mage_Sales_Model_Abstract
  310. {
  311. const ENTITY = 'order';
  312. /**
  313. * XML configuration paths
  314. */
  315. const XML_PATH_EMAIL_TEMPLATE = 'sales_email/order/template';
  316. const XML_PATH_EMAIL_GUEST_TEMPLATE = 'sales_email/order/guest_template';
  317. const XML_PATH_EMAIL_IDENTITY = 'sales_email/order/identity';
  318. const XML_PATH_EMAIL_COPY_TO = 'sales_email/order/copy_to';
  319. const XML_PATH_EMAIL_COPY_METHOD = 'sales_email/order/copy_method';
  320. const XML_PATH_EMAIL_ENABLED = 'sales_email/order/enabled';
  321. const XML_PATH_UPDATE_EMAIL_TEMPLATE = 'sales_email/order_comment/template';
  322. const XML_PATH_UPDATE_EMAIL_GUEST_TEMPLATE = 'sales_email/order_comment/guest_template';
  323. const XML_PATH_UPDATE_EMAIL_IDENTITY = 'sales_email/order_comment/identity';
  324. const XML_PATH_UPDATE_EMAIL_COPY_TO = 'sales_email/order_comment/copy_to';
  325. const XML_PATH_UPDATE_EMAIL_COPY_METHOD = 'sales_email/order_comment/copy_method';
  326. const XML_PATH_UPDATE_EMAIL_ENABLED = 'sales_email/order_comment/enabled';
  327. /**
  328. * Order states
  329. */
  330. const STATE_NEW = 'new';
  331. const STATE_PENDING_PAYMENT = 'pending_payment';
  332. const STATE_PROCESSING = 'processing';
  333. const STATE_COMPLETE = 'complete';
  334. const STATE_CLOSED = 'closed';
  335. const STATE_CANCELED = 'canceled';
  336. const STATE_HOLDED = 'holded';
  337. const STATE_PAYMENT_REVIEW = 'payment_review';
  338. /**
  339. * Order statuses
  340. */
  341. const STATUS_FRAUD = 'fraud';
  342. /**
  343. * Order flags
  344. */
  345. const ACTION_FLAG_CANCEL = 'cancel';
  346. const ACTION_FLAG_HOLD = 'hold';
  347. const ACTION_FLAG_UNHOLD = 'unhold';
  348. const ACTION_FLAG_EDIT = 'edit';
  349. const ACTION_FLAG_CREDITMEMO = 'creditmemo';
  350. const ACTION_FLAG_INVOICE = 'invoice';
  351. const ACTION_FLAG_REORDER = 'reorder';
  352. const ACTION_FLAG_SHIP = 'ship';
  353. const ACTION_FLAG_COMMENT = 'comment';
  354. const ACTION_FLAG_PRODUCTS_PERMISSION_DENIED= 'product_permission_denied';
  355. /**
  356. * Report date types
  357. */
  358. const REPORT_DATE_TYPE_CREATED = 'created';
  359. const REPORT_DATE_TYPE_UPDATED = 'updated';
  360. /*
  361. * Identifier for history item
  362. */
  363. const HISTORY_ENTITY_NAME = 'order';
  364. protected $_eventPrefix = 'sales_order';
  365. protected $_eventObject = 'order';
  366. protected $_addresses = null;
  367. protected $_items = null;
  368. protected $_payments = null;
  369. protected $_statusHistory = null;
  370. protected $_invoices;
  371. protected $_tracks;
  372. protected $_shipments;
  373. protected $_creditmemos;
  374. protected $_relatedObjects = array();
  375. protected $_orderCurrency = null;
  376. protected $_baseCurrency = null;
  377. /**
  378. * Array of action flags for canUnhold, canEdit, etc.
  379. *
  380. * @var array
  381. */
  382. protected $_actionFlag = array();
  383. /**
  384. * Flag: if after order placing we can send new email to the customer.
  385. *
  386. * @var bool
  387. */
  388. protected $_canSendNewEmailFlag = true;
  389. /*
  390. * Identifier for history item
  391. *
  392. * @var string
  393. */
  394. protected $_historyEntityName = self::HISTORY_ENTITY_NAME;
  395. /**
  396. * Initialize resource model
  397. */
  398. protected function _construct()
  399. {
  400. $this->_init('sales/order');
  401. }
  402. /**
  403. * Init mapping array of short fields to
  404. * its full names
  405. *
  406. * @return Varien_Object
  407. */
  408. protected function _initOldFieldsMap()
  409. {
  410. $this->_oldFieldsMap = Mage::helper('sales')->getOldFieldMap('order');
  411. return $this;
  412. }
  413. /**
  414. * Clear order object data
  415. *
  416. * @param string $key data key
  417. * @return Mage_Sales_Model_Order
  418. */
  419. public function unsetData($key=null)
  420. {
  421. parent::unsetData($key);
  422. if (is_null($key)) {
  423. $this->_items = null;
  424. }
  425. return $this;
  426. }
  427. /**
  428. * Retrieve can flag for action (edit, unhold, etc..)
  429. *
  430. * @param string $action
  431. * @return boolean|null
  432. */
  433. public function getActionFlag($action)
  434. {
  435. if (isset($this->_actionFlag[$action])) {
  436. return $this->_actionFlag[$action];
  437. }
  438. return null;
  439. }
  440. /**
  441. * Set can flag value for action (edit, unhold, etc...)
  442. *
  443. * @param string $action
  444. * @param boolean $flag
  445. * @return Mage_Sales_Model_Order
  446. */
  447. public function setActionFlag($action, $flag)
  448. {
  449. $this->_actionFlag[$action] = (boolean) $flag;
  450. return $this;
  451. }
  452. /**
  453. * Return flag for order if it can sends new email to customer.
  454. *
  455. * @return bool
  456. */
  457. public function getCanSendNewEmailFlag()
  458. {
  459. return $this->_canSendNewEmailFlag;
  460. }
  461. /**
  462. * Set flag for order if it can sends new email to customer.
  463. *
  464. * @param bool $flag
  465. * @return Mage_Sales_Model_Order
  466. */
  467. public function setCanSendNewEmailFlag($flag)
  468. {
  469. $this->_canSendNewEmailFlag = (boolean) $flag;
  470. return $this;
  471. }
  472. /**
  473. * Load order by system increment identifier
  474. *
  475. * @param string $incrementId
  476. * @return Mage_Sales_Model_Order
  477. */
  478. public function loadByIncrementId($incrementId)
  479. {
  480. return $this->loadByAttribute('increment_id', $incrementId);
  481. }
  482. /**
  483. * Load order by custom attribute value. Attribute value should be unique
  484. *
  485. * @param string $attribute
  486. * @param string $value
  487. * @return Mage_Sales_Model_Order
  488. */
  489. public function loadByAttribute($attribute, $value)
  490. {
  491. $this->load($value, $attribute);
  492. return $this;
  493. }
  494. /**
  495. * Retrieve store model instance
  496. *
  497. * @return Mage_Core_Model_Store
  498. */
  499. public function getStore()
  500. {
  501. $storeId = $this->getStoreId();
  502. if ($storeId) {
  503. return Mage::app()->getStore($storeId);
  504. }
  505. return Mage::app()->getStore();
  506. }
  507. /**
  508. * Retrieve order cancel availability
  509. *
  510. * @return bool
  511. */
  512. public function canCancel()
  513. {
  514. if (!$this->_canVoidOrder()) {
  515. return false;
  516. }
  517. if ($this->canUnhold()) { // $this->isPaymentReview()
  518. return false;
  519. }
  520. $allInvoiced = true;
  521. foreach ($this->getAllItems() as $item) {
  522. if ($item->getQtyToInvoice()) {
  523. $allInvoiced = false;
  524. break;
  525. }
  526. }
  527. if ($allInvoiced) {
  528. return false;
  529. }
  530. $state = $this->getState();
  531. if ($this->isCanceled() || $state === self::STATE_COMPLETE || $state === self::STATE_CLOSED) {
  532. return false;
  533. }
  534. if ($this->getActionFlag(self::ACTION_FLAG_CANCEL) === false) {
  535. return false;
  536. }
  537. /**
  538. * Use only state for availability detect
  539. */
  540. /*foreach ($this->getAllItems() as $item) {
  541. if ($item->getQtyToCancel()>0) {
  542. return true;
  543. }
  544. }
  545. return false;*/
  546. return true;
  547. }
  548. /**
  549. * Getter whether the payment can be voided
  550. *
  551. * @return bool
  552. */
  553. public function canVoidPayment()
  554. {
  555. return $this->_canVoidOrder() ? $this->getPayment()->canVoid($this->getPayment()) : false;
  556. }
  557. /**
  558. * Check whether order could be canceled by states and flags
  559. *
  560. * @return bool
  561. */
  562. protected function _canVoidOrder()
  563. {
  564. if ($this->canUnhold() || $this->isPaymentReview()) {
  565. return false;
  566. }
  567. return true;
  568. }
  569. /**
  570. * Retrieve order invoice availability
  571. *
  572. * @return bool
  573. */
  574. public function canInvoice()
  575. {
  576. if ($this->canUnhold() || $this->isPaymentReview()) {
  577. return false;
  578. }
  579. $state = $this->getState();
  580. if ($this->isCanceled() || $state === self::STATE_COMPLETE || $state === self::STATE_CLOSED) {
  581. return false;
  582. }
  583. if ($this->getActionFlag(self::ACTION_FLAG_INVOICE) === false) {
  584. return false;
  585. }
  586. foreach ($this->getAllItems() as $item) {
  587. if ($item->getQtyToInvoice()>0 && !$item->getLockedDoInvoice()) {
  588. return true;
  589. }
  590. }
  591. return false;
  592. }
  593. /**
  594. * Retrieve order credit memo (refund) availability
  595. *
  596. * @return bool
  597. */
  598. public function canCreditmemo()
  599. {
  600. if ($this->hasForcedCanCreditmemo()) {
  601. return $this->getForcedCanCreditmemo();
  602. }
  603. if ($this->canUnhold() || $this->isPaymentReview()) {
  604. return false;
  605. }
  606. if ($this->isCanceled() || $this->getState() === self::STATE_CLOSED) {
  607. return false;
  608. }
  609. /**
  610. * We can have problem with float in php (on some server $a=762.73;$b=762.73; $a-$b!=0)
  611. * for this we have additional diapason for 0
  612. * TotalPaid - contains amount, that were not rounded.
  613. */
  614. if (abs($this->getStore()->roundPrice($this->getTotalPaid()) - $this->getTotalRefunded()) < .0001) {
  615. return false;
  616. }
  617. if ($this->getActionFlag(self::ACTION_FLAG_EDIT) === false) {
  618. return false;
  619. }
  620. return true;
  621. }
  622. /**
  623. * Retrieve order hold availability
  624. *
  625. * @return bool
  626. */
  627. public function canHold()
  628. {
  629. $state = $this->getState();
  630. if ($this->isCanceled() || $this->isPaymentReview()
  631. || $state === self::STATE_COMPLETE || $state === self::STATE_CLOSED || $state === self::STATE_HOLDED) {
  632. return false;
  633. }
  634. if ($this->getActionFlag(self::ACTION_FLAG_HOLD) === false) {
  635. return false;
  636. }
  637. return true;
  638. }
  639. /**
  640. * Retrieve order unhold availability
  641. *
  642. * @return bool
  643. */
  644. public function canUnhold()
  645. {
  646. if ($this->getActionFlag(self::ACTION_FLAG_UNHOLD) === false || $this->isPaymentReview()) {
  647. return false;
  648. }
  649. return $this->getState() === self::STATE_HOLDED;
  650. }
  651. /**
  652. * Check if comment can be added to order history
  653. *
  654. * @return bool
  655. */
  656. public function canComment()
  657. {
  658. if ($this->getActionFlag(self::ACTION_FLAG_COMMENT) === false) {
  659. return false;
  660. }
  661. return true;
  662. }
  663. /**
  664. * Retrieve order shipment availability
  665. *
  666. * @return bool
  667. */
  668. public function canShip()
  669. {
  670. if ($this->canUnhold() || $this->isPaymentReview()) {
  671. return false;
  672. }
  673. if ($this->getIsVirtual() || $this->isCanceled()) {
  674. return false;
  675. }
  676. if ($this->getActionFlag(self::ACTION_FLAG_SHIP) === false) {
  677. return false;
  678. }
  679. foreach ($this->getAllItems() as $item) {
  680. if ($item->getQtyToShip()>0 && !$item->getIsVirtual()
  681. && !$item->getLockedDoShip())
  682. {
  683. return true;
  684. }
  685. }
  686. return false;
  687. }
  688. /**
  689. * Retrieve order edit availability
  690. *
  691. * @return bool
  692. */
  693. public function canEdit()
  694. {
  695. if ($this->canUnhold()) {
  696. return false;
  697. }
  698. $state = $this->getState();
  699. if ($this->isCanceled() || $this->isPaymentReview()
  700. || $state === self::STATE_COMPLETE || $state === self::STATE_CLOSED) {
  701. return false;
  702. }
  703. if (!$this->getPayment()->getMethodInstance()->canEdit()) {
  704. return false;
  705. }
  706. if ($this->getActionFlag(self::ACTION_FLAG_EDIT) === false) {
  707. return false;
  708. }
  709. return true;
  710. }
  711. /**
  712. * Retrieve order reorder availability
  713. *
  714. * @return bool
  715. */
  716. public function canReorder()
  717. {
  718. return $this->_canReorder(false);
  719. }
  720. /**
  721. * Check the ability to reorder ignoring the availability in stock or status of the ordered products
  722. *
  723. * @return bool
  724. */
  725. public function canReorderIgnoreSalable()
  726. {
  727. return $this->_canReorder(true);
  728. }
  729. /**
  730. * Retrieve order reorder availability
  731. *
  732. * @param bool $ignoreSalable
  733. * @return bool
  734. */
  735. protected function _canReorder($ignoreSalable = false)
  736. {
  737. if ($this->canUnhold() || $this->isPaymentReview() || !$this->getCustomerId()) {
  738. return false;
  739. }
  740. if ($this->getActionFlag(self::ACTION_FLAG_REORDER) === false) {
  741. return false;
  742. }
  743. $products = array();
  744. foreach ($this->getItemsCollection() as $item) {
  745. $products[] = $item->getProductId();
  746. }
  747. if (!empty($products)) {
  748. /*
  749. * @TODO ACPAOC: Use product collection here, but ensure that product
  750. * is loaded with order store id, otherwise there'll be problems with isSalable()
  751. * for configurables, bundles and other composites
  752. *
  753. */
  754. /*
  755. $productsCollection = Mage::getModel('catalog/product')->getCollection()
  756. ->setStoreId($this->getStoreId())
  757. ->addIdFilter($products)
  758. ->addAttributeToSelect('status')
  759. ->load();
  760. foreach ($productsCollection as $product) {
  761. if (!$product->isSalable()) {
  762. return false;
  763. }
  764. }
  765. */
  766. foreach ($products as $productId) {
  767. $product = Mage::getModel('catalog/product')
  768. ->setStoreId($this->getStoreId())
  769. ->load($productId);
  770. }
  771. if (!$product->getId() || (!$ignoreSalable && !$product->isSalable())) {
  772. return false;
  773. }
  774. }
  775. return true;
  776. }
  777. /**
  778. * Check whether the payment is in payment review state
  779. * In this state order cannot be normally processed. Possible actions can be:
  780. * - accept or deny payment
  781. * - fetch transaction information
  782. *
  783. * @return bool
  784. */
  785. public function isPaymentReview()
  786. {
  787. return $this->getState() === self::STATE_PAYMENT_REVIEW;
  788. }
  789. /**
  790. * Check whether payment can be accepted or denied
  791. *
  792. * @return bool
  793. */
  794. public function canReviewPayment()
  795. {
  796. return $this->isPaymentReview() && $this->getPayment()->canReviewPayment();
  797. }
  798. /**
  799. * Check whether there can be a transaction update fetched for payment in review state
  800. *
  801. * @return bool
  802. */
  803. public function canFetchPaymentReviewUpdate()
  804. {
  805. return $this->isPaymentReview() && $this->getPayment()->canFetchTransactionInfo();
  806. }
  807. /**
  808. * Retrieve order configuration model
  809. *
  810. * @return Mage_Sales_Model_Order_Config
  811. */
  812. public function getConfig()
  813. {
  814. return Mage::getSingleton('sales/order_config');
  815. }
  816. /**
  817. * Place order payments
  818. *
  819. * @return Mage_Sales_Model_Order
  820. */
  821. protected function _placePayment()
  822. {
  823. $this->getPayment()->place();
  824. return $this;
  825. }
  826. /**
  827. * Retrieve order payment model object
  828. *
  829. * @return Mage_Sales_Model_Order_Payment
  830. */
  831. public function getPayment()
  832. {
  833. foreach ($this->getPaymentsCollection() as $payment) {
  834. if (!$payment->isDeleted()) {
  835. return $payment;
  836. }
  837. }
  838. return false;
  839. }
  840. /**
  841. * Declare order billing address
  842. *
  843. * @param Mage_Sales_Model_Order_Address $address
  844. * @return Mage_Sales_Model_Order
  845. */
  846. public function setBillingAddress(Mage_Sales_Model_Order_Address $address)
  847. {
  848. $old = $this->getBillingAddress();
  849. if (!empty($old)) {
  850. $address->setId($old->getId());
  851. }
  852. $this->addAddress($address->setAddressType('billing'));
  853. return $this;
  854. }
  855. /**
  856. * Declare order shipping address
  857. *
  858. * @param Mage_Sales_Model_Order_Address $address
  859. * @return Mage_Sales_Model_Order
  860. */
  861. public function setShippingAddress(Mage_Sales_Model_Order_Address $address)
  862. {
  863. $old = $this->getShippingAddress();
  864. if (!empty($old)) {
  865. $address->setId($old->getId());
  866. }
  867. $this->addAddress($address->setAddressType('shipping'));
  868. return $this;
  869. }
  870. /**
  871. * Retrieve order billing address
  872. *
  873. * @return Mage_Sales_Model_Order_Address
  874. */
  875. public function getBillingAddress()
  876. {
  877. foreach ($this->getAddressesCollection() as $address) {
  878. if ($address->getAddressType()=='billing' && !$address->isDeleted()) {
  879. return $address;
  880. }
  881. }
  882. return false;
  883. }
  884. /**
  885. * Retrieve order shipping address
  886. *
  887. * @return Mage_Sales_Model_Order_Address
  888. */
  889. public function getShippingAddress()
  890. {
  891. foreach ($this->getAddressesCollection() as $address) {
  892. if ($address->getAddressType()=='shipping' && !$address->isDeleted()) {
  893. return $address;
  894. }
  895. }
  896. return false;
  897. }
  898. /**
  899. * Order state setter.
  900. * If status is specified, will add order status history with specified comment
  901. * the setData() cannot be overriden because of compatibility issues with resource model
  902. *
  903. * @param string $state
  904. * @param string|bool $status
  905. * @param string $comment
  906. * @param bool $isCustomerNotified
  907. * @return Mage_Sales_Model_Order
  908. */
  909. public function setState($state, $status = false, $comment = '', $isCustomerNotified = null)
  910. {
  911. return $this->_setState($state, $status, $comment, $isCustomerNotified, true);
  912. }
  913. /**
  914. * Order state protected setter.
  915. * By default allows to set any state. Can also update status to default or specified value
  916. * 小omplete and closed states are encapsulated intentionally, see the _checkState()
  917. *
  918. * @param string $state
  919. * @param string|bool $status
  920. * @param string $comment
  921. * @param bool $isCustomerNotified
  922. * @param $shouldProtectState
  923. * @return Mage_Sales_Model_Order
  924. */
  925. protected function _setState($state, $status = false, $comment = '',
  926. $isCustomerNotified = null, $shouldProtectState = false)
  927. {
  928. // attempt to set the specified state
  929. if ($shouldProtectState) {
  930. if ($this->isStateProtected($state)) {
  931. Mage::throwException(
  932. Mage::helper('sales')->__('The Order State "%s" must not be set manually.', $state)
  933. );
  934. }
  935. }
  936. $this->setData('state', $state);
  937. // add status history
  938. if ($status) {
  939. if ($status === true) {
  940. $status = $this->getConfig()->getStateDefaultStatus($state);
  941. }
  942. $this->setStatus($status);
  943. $history = $this->addStatusHistoryComment($comment, false); // no sense to set $status again
  944. $history->setIsCustomerNotified($isCustomerNotified); // for backwards compatibility
  945. }
  946. return $this;
  947. }
  948. /**
  949. * Whether specified state can be set from outside
  950. * @param $state
  951. * @return bool
  952. */
  953. public function isStateProtected($state)
  954. {
  955. if (empty($state)) {
  956. return false;
  957. }
  958. return self::STATE_COMPLETE == $state || self::STATE_CLOSED == $state;
  959. }
  960. /**
  961. * Retrieve label of order status
  962. *
  963. * @return string
  964. */
  965. public function getStatusLabel()
  966. {
  967. return $this->getConfig()->getStatusLabel($this->getStatus());
  968. }
  969. /**
  970. * Add status change information to history
  971. * @deprecated after 1.4.0.0-alpha3
  972. *
  973. * @param string $status
  974. * @param string $comment
  975. * @param bool $isCustomerNotified
  976. * @return Mage_Sales_Model_Order
  977. */
  978. public function addStatusToHistory($status, $comment = '', $isCustomerNotified = false)
  979. {
  980. $history = $this->addStatusHistoryComment($comment, $status)
  981. ->setIsCustomerNotified($isCustomerNotified);
  982. return $this;
  983. }
  984. /*
  985. * Add a comment to order
  986. * Different or default status may be specified
  987. *
  988. * @param string $comment
  989. * @param string $status
  990. * @return Mage_Sales_Model_Order_Status_History
  991. */
  992. public function addStatusHistoryComment($comment, $status = false)
  993. {
  994. if (false === $status) {
  995. $status = $this->getStatus();
  996. } elseif (true === $status) {
  997. $status = $this->getConfig()->getStateDefaultStatus($this->getState());
  998. } else {
  999. $this->setStatus($status);
  1000. }
  1001. $history = Mage::getModel('sales/order_status_history')
  1002. ->setStatus($status)
  1003. ->setComment($comment)
  1004. ->setEntityName($this->_historyEntityName);
  1005. $this->addStatusHistory($history);
  1006. return $history;
  1007. }
  1008. /**
  1009. * Overrides entity id, which will be saved to comments history status
  1010. *
  1011. * @param string $status
  1012. * @return Mage_Sales_Model_Order
  1013. */
  1014. public function setHistoryEntityName( $entityName )
  1015. {
  1016. $this->_historyEntityName = $entityName;
  1017. return $this;
  1018. }
  1019. /**
  1020. * Place order
  1021. *
  1022. * @return Mage_Sales_Model_Order
  1023. */
  1024. public function place()
  1025. {
  1026. Mage::dispatchEvent('sales_order_place_before', array('order'=>$this));
  1027. $this->_placePayment();
  1028. Mage::dispatchEvent('sales_order_place_after', array('order'=>$this));
  1029. return $this;
  1030. }
  1031. public function hold()
  1032. {
  1033. if (!$this->canHold()) {
  1034. Mage::throwException(Mage::helper('sales')->__('Hold action is not available.'));
  1035. }
  1036. $this->setHoldBeforeState($this->getState());
  1037. $this->setHoldBeforeStatus($this->getStatus());
  1038. $this->setState(self::STATE_HOLDED, true);
  1039. return $this;
  1040. }
  1041. /**
  1042. * Attempt to unhold the order
  1043. *
  1044. * @return Mage_Sales_Model_Order
  1045. * @throws Mage_Core_Exception
  1046. */
  1047. public function unhold()
  1048. {
  1049. if (!$this->canUnhold()) {
  1050. Mage::throwException(Mage::helper('sales')->__('Unhold action is not available.'));
  1051. }
  1052. $this->setState($this->getHoldBeforeState(), $this->getHoldBeforeStatus());
  1053. $this->setHoldBeforeState(null);
  1054. $this->setHoldBeforeStatus(null);
  1055. return $this;
  1056. }
  1057. /**
  1058. * Cancel order
  1059. *
  1060. * @return Mage_Sales_Model_Order
  1061. */
  1062. public function cancel()
  1063. {
  1064. if ($this->canCancel()) {
  1065. $this->getPayment()->cancel();
  1066. $this->registerCancellation();
  1067. Mage::dispatchEvent('order_cancel_after', array('order' => $this));
  1068. }
  1069. return $this;
  1070. }
  1071. /**
  1072. * Prepare order totals to cancellation
  1073. * @param string $comment
  1074. * @param bool $graceful
  1075. * @return Mage_Sales_Model_Order
  1076. * @throws Mage_Core_Exception
  1077. */
  1078. public function registerCancellation($comment = '', $graceful = true)
  1079. {
  1080. if ($this->canCancel() || $this->isPaymentReview()) {
  1081. $cancelState = self::STATE_CANCELED;
  1082. foreach ($this->getAllItems() as $item) {
  1083. if ($cancelState != self::STATE_PROCESSING && $item->getQtyToRefund()) {
  1084. if ($item->getQtyToShip() > $item->getQtyToCancel()) {
  1085. $cancelState = self::STATE_PROCESSING;
  1086. } else {
  1087. $cancelState = self::STATE_COMPLETE;
  1088. }
  1089. }
  1090. $item->cancel();
  1091. }
  1092. $this->setSubtotalCanceled($this->getSubtotal() - $this->getSubtotalInvoiced());
  1093. $this->setBaseSubtotalCanceled($this->getBaseSubtotal() - $this->getBaseSubtotalInvoiced());
  1094. $this->setTaxCanceled($this->getTaxAmount() - $this->getTaxInvoiced());
  1095. $this->setBaseTaxCanceled($this->getBaseTaxAmount() - $this->getBaseTaxInvoiced());
  1096. $this->setShippingCanceled($this->getShippingAmount() - $this->getShippingInvoiced());
  1097. $this->setBaseShippingCanceled($this->getBaseShippingAmount() - $this->getBaseShippingInvoiced());
  1098. $this->setDiscountCanceled(abs($this->getDiscountAmount()) - $this->getDiscountInvoiced());
  1099. $this->setBaseDiscountCanceled(abs($this->getBaseDiscountAmount()) - $this->getBaseDiscountInvoiced());
  1100. $this->setTotalCanceled($this->getGrandTotal() - $this->getTotalPaid());
  1101. $this->setBaseTotalCanceled($this->getBaseGrandTotal() - $this->getBaseTotalPaid());
  1102. $this->_setState($cancelState, true, $comment);
  1103. } elseif (!$graceful) {
  1104. Mage::throwException(Mage::helper('sales')->__('Order does not allow to be canceled.'));
  1105. }
  1106. return $this;
  1107. }
  1108. /**
  1109. * Retrieve tracking numbers
  1110. *
  1111. * @return array
  1112. */
  1113. public function getTrackingNumbers()
  1114. {
  1115. if ($this->getData('tracking_numbers')) {
  1116. return explode(',', $this->getData('tracking_numbers'));
  1117. }
  1118. return array();
  1119. }
  1120. /**
  1121. * Return model of shipping carrier
  1122. *
  1123. * @return bool|float|Mage_Shipping_Model_Carrier_Abstract
  1124. */
  1125. public function getShippingCarrier()
  1126. {
  1127. $carrierModel = $this->getData('shipping_carrier');
  1128. if (is_null($carrierModel)) {
  1129. $carrierModel = false;
  1130. /**
  1131. * $method - carrier_method
  1132. */
  1133. $method = $this->getShippingMethod(true);
  1134. if ($method instanceof Varien_Object) {
  1135. $className = Mage::getStoreConfig('carriers/' . $method->getCarrierCode() . '/model');
  1136. if ($className) {
  1137. $carrierModel = Mage::getModel($className);
  1138. }
  1139. }
  1140. $this->setData('shipping_carrier', $carrierModel);
  1141. }
  1142. return $carrierModel;
  1143. }
  1144. /**
  1145. * Retrieve shipping method
  1146. *
  1147. * @param bool $asObject return carrier code and shipping method data as object
  1148. * @return string|Varien_Object
  1149. */
  1150. public function getShippingMethod($asObject = false)
  1151. {
  1152. $shippingMethod = parent::getShippingMethod();
  1153. if (!$asObject) {
  1154. return $shippingMethod;
  1155. } else {
  1156. list($carrierCode, $method) = explode('_', $shippingMethod, 2);
  1157. return new Varien_Object(array(
  1158. 'carrier_code' => $carrierCode,
  1159. 'method' => $method
  1160. ));
  1161. }
  1162. }
  1163. /**
  1164. * Send email with order data
  1165. *
  1166. * @return Mage_Sales_Model_Order
  1167. * @throws Exception
  1168. */
  1169. public function sendNewOrderEmail()
  1170. {
  1171. $storeId = $this->getStore()->getId();
  1172. if (!Mage::helper('sales')->canSendNewOrderEmail($storeId)) {
  1173. return $this;
  1174. }
  1175. $emailSentAttributeValue = $this->hasEmailSent()
  1176. ? $this->getEmailSent()
  1177. : Mage::getModel('sales/order')->load($this->getId())->getData('email_sent');
  1178. $this->setEmailSent((bool)$emailSentAttributeValue);
  1179. if ($this->getEmailSent()) {
  1180. return $this;
  1181. }
  1182. // Get the destination email addresses to send copies to
  1183. $copyTo = $this->_getEmails(self::XML_PATH_EMAIL_COPY_TO);
  1184. $copyMethod = Mage::getStoreConfig(self::XML_PATH_EMAIL_COPY_METHOD, $storeId);
  1185. // Start store emulation process
  1186. $appEmulation = Mage::getSingleton('core/app_emulation');
  1187. $initialEnvironmentInfo = $appEmulation->startEnvironmentEmulation($storeId);
  1188. try {
  1189. // Retrieve specified view block from appropriate design package (depends on emulated store)
  1190. $paymentBlock = Mage::helper('payment')->getInfoBlock($this->getPayment())
  1191. ->setIsSecureMode(true);
  1192. $paymentBlock->getMethod()->setStore($storeId);
  1193. $paymentBlockHtml = $paymentBlock->toHtml();
  1194. } catch (Exception $exception) {
  1195. // Stop store emulation process
  1196. $appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);
  1197. throw $exception;
  1198. }
  1199. // Stop store emulation process
  1200. $appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);
  1201. // Retrieve corresponding email template id and customer name
  1202. if ($this->getCustomerIsGuest()) {
  1203. $templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_GUEST_TEMPLATE, $storeId);
  1204. $customerName = $this->getBillingAddress()->getName();
  1205. } else {
  1206. $templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_TEMPLATE, $storeId);
  1207. $customerName = $this->getCustomerName();
  1208. }
  1209. $mailer = Mage::getModel('core/email_template_mailer');
  1210. $emailInfo = Mage::getModel('core/email_info');
  1211. $emailInfo->addTo($this->getCustomerEmail(), $customerName);
  1212. if ($copyTo && $copyMethod == 'bcc') {
  1213. // Add bcc to customer email
  1214. foreach ($copyTo as $email) {
  1215. $emailInfo->addBcc($email);
  1216. }
  1217. }
  1218. $mailer->addEmailInfo($emailInfo);
  1219. // Email copies are sent as separated emails if their copy method is 'copy'
  1220. if ($copyTo && $copyMethod == 'copy') {
  1221. foreach ($copyTo as $email) {
  1222. $emailInfo = Mage::getModel('core/email_info');
  1223. $emailInfo->addTo($email);
  1224. $mailer->addEmailInfo($emailInfo);
  1225. }
  1226. }
  1227. // Set all required params and send emails
  1228. $mailer->setSender(Mage::getStoreConfig(self::XML_PATH_EMAIL_IDENTITY, $storeId));
  1229. $mailer->setStoreId($storeId);
  1230. $mailer->setTemplateId($templateId);
  1231. $mailer->setTemplateParams(array(
  1232. 'order' => $this,
  1233. 'billing' => $this->getBillingAddress(),
  1234. 'payment_html' => $paymentBlockHtml
  1235. )
  1236. );
  1237. $mailer->send();
  1238. $this->setEmailSent(true);
  1239. $this->_getResource()->saveAttribute($this, 'email_sent');
  1240. return $this;
  1241. }
  1242. /**
  1243. * Send email with order update information
  1244. *
  1245. * @param boolean $notifyCustomer
  1246. * @param string $comment
  1247. * @return Mage_Sales_Model_Order
  1248. */
  1249. public function sendOrderUpdateEmail($notifyCustomer = true, $comment = '')
  1250. {
  1251. $storeId = $this->getStore()->getId();
  1252. if (!Mage::helper('sales')->canSendOrderCommentEmail($storeId)) {
  1253. return $this;
  1254. }
  1255. // Get the destination email addresses to send copies to
  1256. $copyTo = $this->_getEmails(self::XML_PATH_UPDATE_EMAIL_COPY_TO);
  1257. $copyMethod = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_COPY_METHOD, $storeId);
  1258. // Check if at least one recepient is found
  1259. if (!$notifyCustomer && !$copyTo) {
  1260. return $this;
  1261. }
  1262. // Retrieve corresponding email template id and customer name
  1263. if ($this->getCustomerIsGuest()) {
  1264. $templateId = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_GUEST_TEMPLATE, $storeId);
  1265. $customerName = $this->getBillingAddress()->getName();
  1266. } else {
  1267. $templateId = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_TEMPLATE, $storeId);
  1268. $customerName = $this->getCustomerName();
  1269. }
  1270. $mailer = Mage::getModel('core/email_template_mailer');
  1271. if ($notifyCustomer) {
  1272. $emailInfo = Mage::getModel('core/email_info');
  1273. $emailInfo->addTo($this->getCustomerEmail(), $customerName);
  1274. if ($copyTo && $copyMethod == 'bcc') {
  1275. // Add bcc to customer email
  1276. foreach ($copyTo as $email) {
  1277. $emailInfo->addBcc($email);
  1278. }
  1279. }
  1280. $mailer->addEmailInfo($emailInfo);
  1281. }
  1282. // Email copies are sent as separated emails if their copy method is
  1283. // 'copy' or a customer should not be notified
  1284. if ($copyTo && ($copyMethod == 'copy' || !$notifyCustomer)) {
  1285. foreach ($copyTo as $email) {
  1286. $emailInfo = Mage::getModel('core/email_info');
  1287. $emailInfo->addTo($email);
  1288. $mailer->addEmailInfo($emailInfo);
  1289. }
  1290. }
  1291. // Set all required params and send emails
  1292. $mailer->setSender(Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_IDENTITY, $storeId));
  1293. $mailer->setStoreId($storeId);
  1294. $mailer->setTemplateId($templateId);
  1295. $mailer->setTemplateParams(array(
  1296. 'order' => $this,
  1297. 'comment' => $comment,
  1298. 'billing' => $this->getBillingAddress()
  1299. )
  1300. );
  1301. $mailer->send();
  1302. return $this;
  1303. }
  1304. protected function _getEmails($configPath)
  1305. {
  1306. $data = Mage::getStoreConfig($configPath, $this->getStoreId());
  1307. if (!empty($data)) {
  1308. return explode(',', $data);
  1309. }
  1310. return false;
  1311. }
  1312. /*********************** ADDRESSES ***************************/
  1313. public function getAddressesCollection()
  1314. {
  1315. if (is_null($this->_addresses)) {
  1316. $this->_addresses = Mage::getResourceModel('sales/order_address_collection')
  1317. ->setOrderFilter($this);
  1318. if ($this->getId()) {
  1319. foreach ($this->_addresses as $address) {
  1320. $address->setOrder($this);
  1321. }
  1322. }
  1323. }
  1324. return $this->_addresses;
  1325. }
  1326. public function getAddressById($addressId)
  1327. {
  1328. foreach ($this->getAddressesCollection() as $address) {
  1329. if ($address->getId()==$addressId) {
  1330. return $address;
  1331. }
  1332. }
  1333. return false;
  1334. }
  1335. public function addAddress(Mage_Sales_Model_Order_Address $address)
  1336. {
  1337. $address->setOrder($this)->setParentId($this->getId());
  1338. if (!$address->getId()) {
  1339. $this->getAddressesCollection()->addItem($address);
  1340. }
  1341. return $this;
  1342. }
  1343. public function getItemsCollection($filterByTypes = array(), $nonChildrenOnly = false)
  1344. {
  1345. if (is_null($this->_items)) {
  1346. $this->_items = Mage::getResourceModel('sales/order_item_collection')
  1347. ->setOrderFilter($this);
  1348. if ($filterByTypes) {
  1349. $this->_items->filterByTypes($filterByTypes);
  1350. }
  1351. if ($nonChildrenOnly) {
  1352. $this->_items->filterByParent();
  1353. }
  1354. if ($this->getId()) {
  1355. foreach ($this->_items as $item) {
  1356. $item->setOrder($this);
  1357. }
  1358. }
  1359. }
  1360. return $this->_items;
  1361. }
  1362. /**
  1363. * Get random items collection with related children
  1364. *
  1365. * @param int $limit
  1366. * @return Mage_Sales_Model_Mysql4_Order_Item_Collection
  1367. */
  1368. public function getItemsRandomCollection($limit = 1)
  1369. {
  1370. return $this->_getItemsRandomCollection($limit);
  1371. }
  1372. /**
  1373. * Get random items collection without related children
  1374. *
  1375. * @param int $limit
  1376. * @return Mage_Sales_Model_Mysql4_Order_Item_Collection
  1377. */
  1378. public function getParentItemsRandomCollection($limit = 1)
  1379. {
  1380. return $this->_getItemsRandomCollection($limit, true);
  1381. }
  1382. /**
  1383. * Get random items collection with or without related children
  1384. *
  1385. * @param int $limit
  1386. * @param bool $nonChildrenOnly
  1387. * @return Mage_Sales_Model_Mysql4_Order_Item_Collection
  1388. */
  1389. protected function _getItemsRandomCollection($limit, $nonChildrenOnly = false)
  1390. {
  1391. $collection = Mage::getModel('sales/order_item')->getCollection()
  1392. ->setOrderFilter($this)
  1393. ->setRandomOrder();
  1394. if ($nonChildrenOnly) {
  1395. $collection->filterByParent();
  1396. }
  1397. $products = array();
  1398. foreach ($collection as $item) {
  1399. $products[] = $item->getProductId();
  1400. }
  1401. $productsCollection = Mage::getModel('catalog/product')
  1402. ->getCollection()
  1403. ->addIdFilter($products)
  1404. ->setVisibility(Mage::getSingleton('catalog/product_visibility')->getVisibleInSiteIds())
  1405. /* Price data is added to consider item stock status using price index */
  1406. ->addPriceData()
  1407. ->setPageSize($limit)
  1408. ->load();
  1409. foreach ($collection as $item) {
  1410. $product = $productsCollection->getItemById($item->getProductId());
  1411. if ($product) {
  1412. $item->setProduct($product);
  1413. }
  1414. }
  1415. return $collection;
  1416. }
  1417. public function getAllItems()
  1418. {
  1419. $items = array();
  1420. foreach ($this->getItemsCollection() as $item) {
  1421. if (!$item->isDeleted()) {
  1422. $items[] = $item;
  1423. }
  1424. }
  1425. return $items;
  1426. }
  1427. public function getAllVisibleItems()
  1428. {
  1429. $items = array();
  1430. foreach ($this->getItemsCollection() as $item) {
  1431. if (!$item->isDeleted() && !$item->getParentItemId()) {
  1432. $items[] = $item;
  1433. }
  1434. }
  1435. return $items;
  1436. }
  1437. public function getItemById($itemId)
  1438. {
  1439. return $this->getItemsCollection()->getItemById($itemId);
  1440. }
  1441. public function getItemByQuoteItemId($quoteItemId)
  1442. {
  1443. foreach ($this->getItemsCollection() as $item) {
  1444. if ($item->getQuoteItemId()==$quoteItemId) {
  1445. return $item;
  1446. }
  1447. }
  1448. return null;
  1449. }
  1450. public function addItem(Mage_Sales_Model_Order_Item $item)
  1451. {
  1452. $item->setOrder($this);
  1453. if (!$item->getId()) {
  1454. $this->getItemsCollection()->addItem($item);
  1455. }
  1456. return $this;
  1457. }
  1458. /**
  1459. * Whether the order has nominal items only
  1460. *
  1461. * @return bool
  1462. */
  1463. public function isNominal()
  1464. {
  1465. foreach ($this->getAllVisibleItems() as $item) {
  1466. if ('0' == $item->getIsNominal()) {
  1467. return false;
  1468. }
  1469. }
  1470. return true;
  1471. }
  1472. /*********************** PAYMENTS ***************************/
  1473. public function getPaymentsCollection()
  1474. {
  1475. if (is_null($this->_payments)) {
  1476. $this->_payments = Mage::getResourceModel('sales/order_payment_collection')
  1477. ->setOrderFilter($this);
  1478. if ($this->getId()) {
  1479. foreach ($this->_payments as $payment) {
  1480. $payment->setOrder($this);
  1481. }
  1482. }
  1483. }
  1484. return $this->_payments;
  1485. }
  1486. public function getAllPayments()
  1487. {
  1488. $payments = array();
  1489. foreach ($this->getPaymentsCollection() as $payment) {
  1490. if (!$payment->isDeleted()) {
  1491. $payments[] = $payment;
  1492. }
  1493. }
  1494. return $payments;
  1495. }
  1496. public function getPaymentById($paymentId)
  1497. {
  1498. foreach ($this->getPaymentsCollection() as $payment) {
  1499. if ($payment->getId()==$paymentId) {
  1500. return $payment;
  1501. }
  1502. }
  1503. return false;
  1504. }
  1505. public function addPayment(Mage_Sales_Model_Order_Payment $payment)
  1506. {
  1507. $payment->setOrder($this)
  1508. ->setParentId($this->getId());
  1509. if (!$payment->getId()) {
  1510. $this->getPaymentsCollection()->addItem($payment);
  1511. }
  1512. return $this;
  1513. }
  1514. public function setPayment(Mage_Sales_Model_Order_Payment $payment)
  1515. {
  1516. if (!$this->getIsMultiPayment() && ($old = $this->getPayment())) {
  1517. $payment->setId($old->getId());
  1518. }
  1519. $this->addPayment($payment);
  1520. return $payment;
  1521. }
  1522. /*********************** STATUSES ***************************/
  1523. /**
  1524. * Enter description here...
  1525. *
  1526. * @return Mage_Sales_Model_Entity_Order_Status_History_Collection
  1527. */
  1528. public function getStatusHistoryCollection($reload=false)
  1529. {
  1530. if (is_null($this->_statusHistory) || $reload) {
  1531. $this->_statusHistory = Mage::getResourceModel('sales/order_status_history_collection')
  1532. ->setOrderFilter($this)
  1533. ->setOrder('created_at', 'desc')
  1534. ->setOrder('entity_id', 'desc');
  1535. if ($this->getId()) {
  1536. foreach ($this->_statusHistory as $status) {
  1537. $status->setOrder($this);
  1538. }
  1539. }
  1540. }
  1541. return $this->_statusHistory;
  1542. }
  1543. /**
  1544. * Return collection of order status history items.
  1545. *
  1546. * @return array
  1547. */
  1548. public function getAllStatusHistory()
  1549. {
  1550. $history = array();
  1551. foreach ($this->getStatusHistoryCollection() as $status) {
  1552. if (!$status->isDeleted()) {
  1553. $history[] = $status;
  1554. }
  1555. }
  1556. return $history;
  1557. }
  1558. /**
  1559. * Return collection of visible on frontend order status history items.
  1560. *
  1561. * @return array
  1562. */
  1563. public function getVisibleStatusHistory()
  1564. {
  1565. $history = array();
  1566. foreach ($this->getStatusHistoryCollection() as $status) {
  1567. if (!$status->isDeleted() && $status->getComment() && $status->getIsVisibleOnFront()) {
  1568. $history[] = $status;
  1569. }
  1570. }
  1571. return $history;
  1572. }
  1573. public function getStatusHistoryById($statusId)
  1574. {
  1575. foreach ($this->getStatusHistoryCollection() as $status) {
  1576. if ($status->getId()==$statusId) {
  1577. return $status;
  1578. }
  1579. }
  1580. return false;
  1581. }
  1582. /**
  1583. * Set the order status history object and the order object to each other
  1584. * Adds the object to the status history collection, which is automatically saved when the order is saved.
  1585. * See the entity_id attribute backend model.
  1586. * Or the history record can be saved standalone after this.
  1587. *
  1588. * @param Mage_Sales_Model_Order_Status_History $status
  1589. * @return Mage_Sales_Model_Order
  1590. */
  1591. public function addStatusHistory(Mage_Sales_Model_Order_Status_History $history)
  1592. {
  1593. $history->setOrder($this);
  1594. $this->setStatus($history->getStatus());
  1595. if (!$history->getId()) {
  1596. $this->getStatusHistoryCollection()->addItem($history);
  1597. }
  1598. return $this;
  1599. }
  1600. /**
  1601. * Enter description here...
  1602. *
  1603. * @return string
  1604. */
  1605. public function getRealOrderId()
  1606. {
  1607. $id = $this->getData('real_order_id');
  1608. if (is_null($id)) {
  1609. $id = $this->getIncrementId();
  1610. }
  1611. return $id;
  1612. }
  1613. /**
  1614. * Get currency model instance. Will be used currency with which order placed
  1615. *
  1616. * @return Mage_Directory_Model_Currency
  1617. */
  1618. public function getOrderCurrency()
  1619. {
  1620. if (is_null($this->_orderCurrency)) {
  1621. $this->_orderCurrency = Mage::getModel('directory/currency')->load($this->getOrderCurrencyCode());
  1622. }
  1623. return $this->_orderCurrency;
  1624. }
  1625. /**
  1626. * Get formated price value including order currency rate to order website currency
  1627. *
  1628. * @param float $price
  1629. * @param bool $addBrackets
  1630. * @return string
  1631. */
  1632. public function formatPrice($price, $addBrackets = false)
  1633. {
  1634. return $this->formatPricePrecision($price, 2, $addBrackets);
  1635. }
  1636. public function formatPricePrecision($price, $precision, $addBrackets = false)
  1637. {
  1638. return $this->getOrderCurrency()->formatPrecision($price, $precision, array(), true, $addBrackets);
  1639. }
  1640. /**
  1641. * Retrieve text formated price value includeing order rate
  1642. *
  1643. * @param float $price
  1644. * @return string
  1645. */
  1646. public function formatPriceTxt($price)
  1647. {
  1648. return $this->getOrderCurrency()->formatTxt($price);
  1649. }
  1650. /**
  1651. * Retrieve order website currency for working with base prices
  1652. *
  1653. * @return Mage_Directory_Model_Currency
  1654. */
  1655. public function getBaseCurrency()
  1656. {
  1657. if (is_null($this->_baseCurrency)) {
  1658. $this->_baseCurrency = Mage::getModel('directory/currency')->load($this->getBaseCurrencyCode());
  1659. }
  1660. return $this->_baseCurrency;
  1661. }
  1662. /**
  1663. * Retrieve order website currency for working with base prices
  1664. * @deprecated please use getBaseCurrency instead.
  1665. *
  1666. * @return Mage_Directory_Model_Currency
  1667. */
  1668. public function getStoreCurrency()
  1669. {
  1670. return $this->getData('store_currency');
  1671. }
  1672. public function formatBasePrice($price)
  1673. {
  1674. return $this->formatBasePricePrecision($price, 2);
  1675. }
  1676. public function formatBasePricePrecision($price, $precision)
  1677. {
  1678. return $this->getBaseCurrency()->formatPrecision($price, $precision);
  1679. }
  1680. public function isCurrencyDifferent()
  1681. {
  1682. return $this->getOrderCurrencyCode() != $this->getBaseCurrencyCode();
  1683. }
  1684. /**
  1685. * Retrieve order total due value
  1686. *
  1687. * @return float
  1688. */
  1689. public function getTotalDue()
  1690. {
  1691. $total = $this->getGrandTotal()-$this->getTotalPaid();
  1692. $total = Mage::app()->getStore($this->getStoreId())->roundPrice($total);
  1693. return max($total, 0);
  1694. }
  1695. /**
  1696. * Retrieve order total due value
  1697. *
  1698. * @return float
  1699. */
  1700. public function getBaseTotalDue()
  1701. {
  1702. $total = $this->getBaseGrandTotal()-$this->getBaseTotalPaid();
  1703. $total = Mage::app()->getStore($this->getStoreId())->roundPrice($total);
  1704. return max($total, 0);
  1705. }
  1706. public function getData($key='', $index=null)
  1707. {
  1708. if ($key == 'total_due') {
  1709. return $this->getTotalDue();
  1710. }
  1711. if ($key == 'base_total_due') {
  1712. return $this->getBaseTotalDue();
  1713. }
  1714. return parent::getData($key, $index);
  1715. }
  1716. /**
  1717. * Retrieve order invoices collection
  1718. *
  1719. * @return unknown
  1720. */
  1721. public function getInvoiceCollection()
  1722. {
  1723. if (is_null($this->_invoices)) {
  1724. $this->_invoices = Mage::getResourceModel('sales/order_invoice_collection')
  1725. ->setOrderFilter($this);
  1726. if ($this->getId()) {
  1727. foreach ($this->_invoices as $invoice) {
  1728. $invoice->setOrder($this);
  1729. }
  1730. }
  1731. }
  1732. return $this->_invoices;
  1733. }
  1734. /**
  1735. * Retrieve order shipments collection
  1736. *
  1737. * @return unknown
  1738. */
  1739. public function getShipmentsCollection()
  1740. {
  1741. if (empty($this->_shipments)) {
  1742. if ($this->getId()) {
  1743. $this->_shipments = Mage::getResourceModel('sales/order_shipment_collection')
  1744. ->setOrderFilter($this)
  1745. ->load();
  1746. } else {
  1747. return false;
  1748. }
  1749. }
  1750. return $this->_shipments;
  1751. }
  1752. /**
  1753. * Retrieve order creditmemos collection
  1754. *
  1755. * @return unknown
  1756. */
  1757. public function getCreditmemosCollection()
  1758. {
  1759. if (empty($this->_creditmemos)) {
  1760. if ($this->getId()) {
  1761. $this->_creditmemos = Mage::getResourceModel('sales/order_creditmemo_collection')
  1762. ->setOrderFilter($this)
  1763. ->load();
  1764. } else {
  1765. return false;
  1766. }
  1767. }
  1768. return $this->_creditmemos;
  1769. }
  1770. /**
  1771. * Retrieve order tracking numbers collection
  1772. *
  1773. * @return unknown
  1774. */
  1775. public function getTracksCollection()
  1776. {
  1777. if (empty($this->_tracks)) {
  1778. $this->_tracks = Mage::getResourceModel('sales/order_shipment_track_collection')
  1779. ->setOrderFilter($this);
  1780. if ($this->getId()) {
  1781. $this->_tracks->load();
  1782. }
  1783. }
  1784. return $this->_tracks;
  1785. }
  1786. /**
  1787. * Check order invoices availability
  1788. *
  1789. * @return bool
  1790. */
  1791. public function hasInvoices()
  1792. {
  1793. return $this->getInvoiceCollection()->count();
  1794. }
  1795. /**
  1796. * Check order shipments availability
  1797. *
  1798. * @return bool
  1799. */
  1800. public function hasShipments()
  1801. {
  1802. return $this->getShipmentsCollection()->count();
  1803. }
  1804. /**
  1805. * Check order creditmemos availability
  1806. *
  1807. * @return bool
  1808. */
  1809. public function hasCreditmemos()
  1810. {
  1811. return $this->getCreditmemosCollection()->count();
  1812. }
  1813. /**
  1814. * Retrieve array of related objects
  1815. *
  1816. * Used for order saving
  1817. *
  1818. * @return array
  1819. */
  1820. public function getRelatedObjects()
  1821. {
  1822. return $this->_relatedObjects;
  1823. }
  1824. public function getCustomerName()
  1825. {
  1826. if ($this->getCustomerFirstname()) {
  1827. $customerName = $this->getCustomerFirstname() . ' ' . $this->getCustomerLastname();
  1828. }
  1829. else {
  1830. $customerName = Mage::helper('sales')->__('Guest');
  1831. }
  1832. return $customerName;
  1833. }
  1834. /**
  1835. * Add New object to related array
  1836. *
  1837. * @param Mage_Core_Model_Abstract $object
  1838. * @return Mage_Sales_Model_Order
  1839. */
  1840. public function addRelatedObject(Mage_Core_Model_Abstract $object)
  1841. {
  1842. $this->_relatedObjects[] = $object;
  1843. return $this;
  1844. }
  1845. /**
  1846. * Get formated order created date in store timezone
  1847. *
  1848. * @param string $format date format type (short|medium|long|full)
  1849. * @return string
  1850. */
  1851. public function getCreatedAtFormated($format)
  1852. {
  1853. return Mage::helper('core')->formatDate($this->getCreatedAtStoreDate(), $format, true);
  1854. }
  1855. public function getEmailCustomerNote()
  1856. {
  1857. if ($this->getCustomerNoteNotify()) {
  1858. return $this->getCustomerNote();
  1859. }
  1860. return '';
  1861. }
  1862. /**
  1863. * Processing object before save data
  1864. *
  1865. * @return Mage_Core_Model_Abstract
  1866. */
  1867. protected function _beforeSave()
  1868. {
  1869. parent::_beforeSave();
  1870. $this->_checkState();
  1871. if (!$this->getId()) {
  1872. $store = $this->getStore();
  1873. $name = array($store->getWebsite()->getName(),$store->getGroup()->getName(),$store->getName());
  1874. $this->setStoreName(implode("\n", $name));
  1875. }
  1876. if (!$this->getIncrementId()) {
  1877. $incrementId = Mage::getSingleton('eav/config')
  1878. ->getEntityType('order')
  1879. ->fetchNewIncrementId($this->getStoreId());
  1880. $this->setIncrementId($incrementId);
  1881. }
  1882. /**
  1883. * Process items dependency for new order
  1884. */
  1885. if (!$this->getId()) {
  1886. $itemsCount = 0;
  1887. foreach ($this->getAllItems() as $item) {
  1888. $parent = $item->getQuoteParentItemId();
  1889. if ($parent && !$item->getParentItem()) {
  1890. $item->setParentItem($this->getItemByQuoteItemId($parent));
  1891. } elseif (!$parent) {
  1892. $itemsCount++;
  1893. }
  1894. }
  1895. // Set items count
  1896. $this->setTotalItemCount($itemsCount);
  1897. }
  1898. if ($this->getCustomer()) {
  1899. $this->setCustomerId($this->getCustomer()->getId());
  1900. }
  1901. if ($this->hasBillingAddressId() && $this->getBillingAddressId() === null) {
  1902. $this->unsBillingAddressId();
  1903. }
  1904. if ($this->hasShippingAddressId() && $this->getShippingAddressId() === null) {
  1905. $this->unsShippingAddressId();
  1906. }
  1907. $this->setData('protect_code', substr(md5(uniqid(mt_rand(), true) . ':' . microtime(true)), 5, 6));
  1908. return $this;
  1909. }
  1910. /**
  1911. * Check order state before saving
  1912. */
  1913. protected function _checkState()
  1914. {
  1915. if (!$this->getId()) {
  1916. return $this;
  1917. }
  1918. $userNotification = $this->hasCustomerNoteNotify() ? $this->getCustomerNoteNotify() : null;
  1919. if (!$this->isCanceled()
  1920. && !$this->canUnhold()
  1921. && !$this->canInvoice()
  1922. && !$this->canShip()) {
  1923. if (0 == $this->getBaseGrandTotal() || $this->canCreditmemo()) {
  1924. if ($this->getState() !== self::STATE_COMPLETE) {
  1925. $this->_setState(self::STATE_COMPLETE, true, '', $userNotification);
  1926. }
  1927. }
  1928. /**
  1929. * Order can be closed just in case when we have refunded amount.
  1930. * In case of "0" grand total order checking ForcedCanCreditmemo flag
  1931. */
  1932. elseif (floatval($this->getTotalRefunded()) || (!$this->getTotalRefunded()
  1933. && $this->hasForcedCanCreditmemo())
  1934. ) {
  1935. if ($this->getState() !== self::STATE_CLOSED) {
  1936. $this->_setState(self::STATE_CLOSED, true, '', $userNotification);
  1937. }
  1938. }
  1939. }
  1940. if ($this->getState() == self::STATE_NEW && $this->getIsInProcess()) {
  1941. $this->setState(self::STATE_PROCESSING, true, '', $userNotification);
  1942. }
  1943. return $this;
  1944. }
  1945. /**
  1946. * Save order related objects
  1947. *
  1948. * @return Mage_Sales_Model_Order
  1949. */
  1950. protected function _afterSave()
  1951. {
  1952. if (null !== $this->_addresses) {
  1953. $this->_addresses->save();
  1954. $billingAddress = $this->getBillingAddress();
  1955. $attributesForSave = array();
  1956. if ($billingAddress && $this->getBillingAddressId() != $billingAddress->getId()) {
  1957. $this->setBillingAddressId($billingAddress->getId());
  1958. $attributesForSave[] = 'billing_address_id';
  1959. }
  1960. $shippingAddress = $this->getShippingAddress();
  1961. if ($shippingAddress && $this->getShippigAddressId() != $shippingAddress->getId()) {
  1962. $this->setShippingAddressId($shippingAddress->getId());
  1963. $attributesForSave[] = 'shipping_address_id';
  1964. }
  1965. if (!empty($attributesForSave)) {
  1966. $this->_getResource()->saveAttribute($this, $attributesForSave);
  1967. }
  1968. }
  1969. if (null !== $this->_items) {
  1970. $this->_items->save();
  1971. }
  1972. if (null !== $this->_payments) {
  1973. $this->_payments->save();
  1974. }
  1975. if (null !== $this->_statusHistory) {
  1976. $this->_statusHistory->save();
  1977. }
  1978. foreach ($this->getRelatedObjects() as $object) {
  1979. $object->save();
  1980. }
  1981. return parent::_afterSave();
  1982. }
  1983. public function getStoreGroupName()
  1984. {
  1985. $storeId = $this->getStoreId();
  1986. if (is_null($storeId)) {
  1987. return $this->getStoreName(1); // 0 - website name, 1 - store group name, 2 - store name
  1988. }
  1989. return $this->getStore()->getGroup()->getName();
  1990. }
  1991. /**
  1992. * Resets all data in object
  1993. * so after another load it will be complete new object
  1994. *
  1995. * @return Mage_Sales_Model_Order
  1996. */
  1997. public function reset()
  1998. {
  1999. $this->unsetData();
  2000. $this->_actionFlag = array();
  2001. $this->_addresses = null;
  2002. $this->_items = null;
  2003. $this->_payments = null;
  2004. $this->_statusHistory = null;
  2005. $this->_invoices = null;
  2006. $this->_tracks = null;
  2007. $this->_shipments = null;
  2008. $this->_creditmemos = null;
  2009. $this->_relatedObjects = array();
  2010. $this->_orderCurrency = null;
  2011. $this->_baseCurrency = null;
  2012. return $this;
  2013. }
  2014. public function getIsNotVirtual()
  2015. {
  2016. return !$this->getIsVirtual();
  2017. }
  2018. public function getFullTaxInfo()
  2019. {
  2020. $rates = Mage::getModel('tax/sales_order_tax')->getCollection()->loadByOrder($this)->toArray();
  2021. return Mage::getSingleton('tax/calculation')->reproduceProcess($rates['items']);
  2022. }
  2023. /**
  2024. * Create new invoice with maximum qty for invoice for each item
  2025. *
  2026. * @return Mage_Sales_Model_Order_Invoice
  2027. */
  2028. public function prepareInvoice($qtys = array())
  2029. {
  2030. $invoice = Mage::getModel('sales/service_order', $this)->prepareInvoice($qtys);
  2031. return $invoice;
  2032. }
  2033. /**
  2034. * Create new shipment with maximum qty for shipping for each item
  2035. *
  2036. * @return Mage_Sales_Model_Order_Shipment
  2037. */
  2038. public function prepareShipment($qtys = array())
  2039. {
  2040. $shipment = Mage::getModel('sales/service_order', $this)->prepareShipment($qtys);
  2041. return $shipment;
  2042. }
  2043. /**
  2044. * Check whether order is canceled
  2045. *
  2046. * @return bool
  2047. */
  2048. public function isCanceled()
  2049. {
  2050. return ($this->getState() === self::STATE_CANCELED);
  2051. }
  2052. /**
  2053. * Protect order delete from not admin scope
  2054. * @return Mage_Sales_Model_Order
  2055. */
  2056. protected function _beforeDelete()
  2057. {
  2058. $this->_protectFromNonAdmin();
  2059. return parent::_beforeDelete();
  2060. }
  2061. }