PageRenderTime 47ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://bitbucket.org/claudiu_marginean/magento-hg-mirror
PHP | 560 lines | 368 code | 64 blank | 128 comment | 56 complexity | 7ec16d659de93aeee6a087a6d39ca042 MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL
  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. class Mage_Sales_Model_Order_Shipment extends Mage_Sales_Model_Abstract
  27. {
  28. const STATUS_NEW = 1;
  29. const XML_PATH_EMAIL_TEMPLATE = 'sales_email/shipment/template';
  30. const XML_PATH_EMAIL_GUEST_TEMPLATE = 'sales_email/shipment/guest_template';
  31. const XML_PATH_EMAIL_IDENTITY = 'sales_email/shipment/identity';
  32. const XML_PATH_EMAIL_COPY_TO = 'sales_email/shipment/copy_to';
  33. const XML_PATH_EMAIL_COPY_METHOD = 'sales_email/shipment/copy_method';
  34. const XML_PATH_EMAIL_ENABLED = 'sales_email/shipment/enabled';
  35. const XML_PATH_UPDATE_EMAIL_TEMPLATE = 'sales_email/shipment_comment/template';
  36. const XML_PATH_UPDATE_EMAIL_GUEST_TEMPLATE = 'sales_email/shipment_comment/guest_template';
  37. const XML_PATH_UPDATE_EMAIL_IDENTITY = 'sales_email/shipment_comment/identity';
  38. const XML_PATH_UPDATE_EMAIL_COPY_TO = 'sales_email/shipment_comment/copy_to';
  39. const XML_PATH_UPDATE_EMAIL_COPY_METHOD = 'sales_email/shipment_comment/copy_method';
  40. const XML_PATH_UPDATE_EMAIL_ENABLED = 'sales_email/shipment_comment/enabled';
  41. const REPORT_DATE_TYPE_ORDER_CREATED = 'order_created';
  42. const REPORT_DATE_TYPE_SHIPMENT_CREATED = 'shipment_created';
  43. protected $_items;
  44. protected $_tracks;
  45. protected $_order;
  46. protected $_comments;
  47. protected $_eventPrefix = 'sales_order_shipment';
  48. protected $_eventObject = 'shipment';
  49. /**
  50. * Initialize shipment resource model
  51. */
  52. protected function _construct()
  53. {
  54. $this->_init('sales/order_shipment');
  55. }
  56. /**
  57. * Load shipment by increment id
  58. *
  59. * @param string $incrementId
  60. * @return Mage_Sales_Model_Order_Shipment
  61. */
  62. public function loadByIncrementId($incrementId)
  63. {
  64. $ids = $this->getCollection()
  65. ->addAttributeToFilter('increment_id', $incrementId)
  66. ->getAllIds();
  67. if (!empty($ids)) {
  68. reset($ids);
  69. $this->load(current($ids));
  70. }
  71. return $this;
  72. }
  73. /**
  74. * Declare order for shipment
  75. *
  76. * @param Mage_Sales_Model_Order $order
  77. * @return Mage_Sales_Model_Order_Shipment
  78. */
  79. public function setOrder(Mage_Sales_Model_Order $order)
  80. {
  81. $this->_order = $order;
  82. $this->setOrderId($order->getId())
  83. ->setStoreId($order->getStoreId());
  84. return $this;
  85. }
  86. /**
  87. * Retrieve hash code of current order
  88. *
  89. * @return string
  90. */
  91. public function getProtectCode()
  92. {
  93. return (string)$this->getOrder()->getProtectCode();
  94. }
  95. /**
  96. * Retrieve the order the shipment for created for
  97. *
  98. * @return Mage_Sales_Model_Order
  99. */
  100. public function getOrder()
  101. {
  102. if (!$this->_order instanceof Mage_Sales_Model_Order) {
  103. $this->_order = Mage::getModel('sales/order')->load($this->getOrderId());
  104. }
  105. return $this->_order;
  106. }
  107. /**
  108. * Retrieve billing address
  109. *
  110. * @return Mage_Sales_Model_Order_Address
  111. */
  112. public function getBillingAddress()
  113. {
  114. return $this->getOrder()->getBillingAddress();
  115. }
  116. /**
  117. * Retrieve shipping address
  118. *
  119. * @return Mage_Sales_Model_Order_Address
  120. */
  121. public function getShippingAddress()
  122. {
  123. return $this->getOrder()->getShippingAddress();
  124. }
  125. /**
  126. * Register shipment
  127. *
  128. * Apply to order, order items etc.
  129. *
  130. * @return unknown
  131. */
  132. public function register()
  133. {
  134. if ($this->getId()) {
  135. Mage::throwException(
  136. Mage::helper('sales')->__('Cannot register existing shipment')
  137. );
  138. }
  139. $totalQty = 0;
  140. foreach ($this->getAllItems() as $item) {
  141. if ($item->getQty()>0) {
  142. $item->register();
  143. if (!$item->getOrderItem()->isDummy(true)) {
  144. $totalQty+= $item->getQty();
  145. }
  146. }
  147. else {
  148. $item->isDeleted(true);
  149. }
  150. }
  151. $this->setTotalQty($totalQty);
  152. return $this;
  153. }
  154. public function getItemsCollection()
  155. {
  156. if (empty($this->_items)) {
  157. $this->_items = Mage::getResourceModel('sales/order_shipment_item_collection')
  158. ->setShipmentFilter($this->getId());
  159. if ($this->getId()) {
  160. foreach ($this->_items as $item) {
  161. $item->setShipment($this);
  162. }
  163. }
  164. }
  165. return $this->_items;
  166. }
  167. public function getAllItems()
  168. {
  169. $items = array();
  170. foreach ($this->getItemsCollection() as $item) {
  171. if (!$item->isDeleted()) {
  172. $items[] = $item;
  173. }
  174. }
  175. return $items;
  176. }
  177. public function getItemById($itemId)
  178. {
  179. foreach ($this->getItemsCollection() as $item) {
  180. if ($item->getId()==$itemId) {
  181. return $item;
  182. }
  183. }
  184. return false;
  185. }
  186. public function addItem(Mage_Sales_Model_Order_Shipment_Item $item)
  187. {
  188. $item->setShipment($this)
  189. ->setParentId($this->getId())
  190. ->setStoreId($this->getStoreId());
  191. if (!$item->getId()) {
  192. $this->getItemsCollection()->addItem($item);
  193. }
  194. return $this;
  195. }
  196. public function getTracksCollection()
  197. {
  198. if (empty($this->_tracks)) {
  199. $this->_tracks = Mage::getResourceModel('sales/order_shipment_track_collection')
  200. ->setShipmentFilter($this->getId());
  201. if ($this->getId()) {
  202. foreach ($this->_tracks as $track) {
  203. $track->setShipment($this);
  204. }
  205. }
  206. }
  207. return $this->_tracks;
  208. }
  209. public function getAllTracks()
  210. {
  211. $tracks = array();
  212. foreach ($this->getTracksCollection() as $track) {
  213. if (!$track->isDeleted()) {
  214. $tracks[] = $track;
  215. }
  216. }
  217. return $tracks;
  218. }
  219. public function getTrackById($trackId)
  220. {
  221. foreach ($this->getTracksCollection() as $track) {
  222. if ($track->getId()==$trackId) {
  223. return $track;
  224. }
  225. }
  226. return false;
  227. }
  228. public function addTrack(Mage_Sales_Model_Order_Shipment_Track $track)
  229. {
  230. $track->setShipment($this)
  231. ->setParentId($this->getId())
  232. ->setOrderId($this->getOrderId())
  233. ->setStoreId($this->getStoreId());
  234. if (!$track->getId()) {
  235. $this->getTracksCollection()->addItem($track);
  236. }
  237. /**
  238. * Track saving is implemented in _afterSave()
  239. * This enforces Mage_Core_Model_Abstract::save() not to skip _afterSave()
  240. */
  241. $this->_hasDataChanges = true;
  242. return $this;
  243. }
  244. /**
  245. * Adds comment to shipment with additional possibility to send it to customer via email
  246. * and show it in customer account
  247. *
  248. * @param bool $notify
  249. * @param bool $visibleOnFront
  250. *
  251. * @return Mage_Sales_Model_Order_Shipment
  252. */
  253. public function addComment($comment, $notify=false, $visibleOnFront=false)
  254. {
  255. if (!($comment instanceof Mage_Sales_Model_Order_Shipment_Comment)) {
  256. $comment = Mage::getModel('sales/order_shipment_comment')
  257. ->setComment($comment)
  258. ->setIsCustomerNotified($notify)
  259. ->setIsVisibleOnFront($visibleOnFront);
  260. }
  261. $comment->setShipment($this)
  262. ->setParentId($this->getId())
  263. ->setStoreId($this->getStoreId());
  264. if (!$comment->getId()) {
  265. $this->getCommentsCollection()->addItem($comment);
  266. }
  267. $this->_hasDataChanges = true;
  268. return $this;
  269. }
  270. public function getCommentsCollection($reload=false)
  271. {
  272. if (is_null($this->_comments) || $reload) {
  273. $this->_comments = Mage::getResourceModel('sales/order_shipment_comment_collection')
  274. ->setShipmentFilter($this->getId())
  275. ->setCreatedAtOrder();
  276. /**
  277. * When shipment created with adding comment,
  278. * comments collection must be loaded before we added this comment.
  279. */
  280. $this->_comments->load();
  281. if ($this->getId()) {
  282. foreach ($this->_comments as $comment) {
  283. $comment->setShipment($this);
  284. }
  285. }
  286. }
  287. return $this->_comments;
  288. }
  289. /**
  290. * Send email with shipment data
  291. *
  292. * @param boolean $notifyCustomer
  293. * @param string $comment
  294. * @return Mage_Sales_Model_Order_Shipment
  295. */
  296. public function sendEmail($notifyCustomer = true, $comment = '')
  297. {
  298. $order = $this->getOrder();
  299. $storeId = $order->getStore()->getId();
  300. if (!Mage::helper('sales')->canSendNewShipmentEmail($storeId)) {
  301. return $this;
  302. }
  303. // Get the destination email addresses to send copies to
  304. $copyTo = $this->_getEmails(self::XML_PATH_EMAIL_COPY_TO);
  305. $copyMethod = Mage::getStoreConfig(self::XML_PATH_EMAIL_COPY_METHOD, $storeId);
  306. // Check if at least one recepient is found
  307. if (!$notifyCustomer && !$copyTo) {
  308. return $this;
  309. }
  310. // Start store emulation process
  311. $appEmulation = Mage::getSingleton('core/app_emulation');
  312. $initialEnvironmentInfo = $appEmulation->startEnvironmentEmulation($storeId);
  313. try {
  314. // Retrieve specified view block from appropriate design package (depends on emulated store)
  315. $paymentBlock = Mage::helper('payment')->getInfoBlock($order->getPayment())
  316. ->setIsSecureMode(true);
  317. $paymentBlock->getMethod()->setStore($storeId);
  318. $paymentBlockHtml = $paymentBlock->toHtml();
  319. } catch (Exception $exception) {
  320. // Stop store emulation process
  321. $appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);
  322. throw $exception;
  323. }
  324. // Stop store emulation process
  325. $appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo);
  326. // Retrieve corresponding email template id and customer name
  327. if ($order->getCustomerIsGuest()) {
  328. $templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_GUEST_TEMPLATE, $storeId);
  329. $customerName = $order->getBillingAddress()->getName();
  330. } else {
  331. $templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_TEMPLATE, $storeId);
  332. $customerName = $order->getCustomerName();
  333. }
  334. $mailer = Mage::getModel('core/email_template_mailer');
  335. if ($notifyCustomer) {
  336. $emailInfo = Mage::getModel('core/email_info');
  337. $emailInfo->addTo($order->getCustomerEmail(), $customerName);
  338. if ($copyTo && $copyMethod == 'bcc') {
  339. // Add bcc to customer email
  340. foreach ($copyTo as $email) {
  341. $emailInfo->addBcc($email);
  342. }
  343. }
  344. $mailer->addEmailInfo($emailInfo);
  345. }
  346. // Email copies are sent as separated emails if their copy method is 'copy' or a customer should not be notified
  347. if ($copyTo && ($copyMethod == 'copy' || !$notifyCustomer)) {
  348. foreach ($copyTo as $email) {
  349. $emailInfo = Mage::getModel('core/email_info');
  350. $emailInfo->addTo($email);
  351. $mailer->addEmailInfo($emailInfo);
  352. }
  353. }
  354. // Set all required params and send emails
  355. $mailer->setSender(Mage::getStoreConfig(self::XML_PATH_EMAIL_IDENTITY, $storeId));
  356. $mailer->setStoreId($storeId);
  357. $mailer->setTemplateId($templateId);
  358. $mailer->setTemplateParams(array(
  359. 'order' => $order,
  360. 'shipment' => $this,
  361. 'comment' => $comment,
  362. 'billing' => $order->getBillingAddress(),
  363. 'payment_html' => $paymentBlockHtml
  364. )
  365. );
  366. $mailer->send();
  367. return $this;
  368. }
  369. /**
  370. * Send email with shipment update information
  371. *
  372. * @param boolean $notifyCustomer
  373. * @param string $comment
  374. * @return Mage_Sales_Model_Order_Shipment
  375. */
  376. public function sendUpdateEmail($notifyCustomer = true, $comment = '')
  377. {
  378. $order = $this->getOrder();
  379. $storeId = $order->getStore()->getId();
  380. if (!Mage::helper('sales')->canSendShipmentCommentEmail($storeId)) {
  381. return $this;
  382. }
  383. // Get the destination email addresses to send copies to
  384. $copyTo = $this->_getEmails(self::XML_PATH_UPDATE_EMAIL_COPY_TO);
  385. $copyMethod = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_COPY_METHOD, $storeId);
  386. // Check if at least one recepient is found
  387. if (!$notifyCustomer && !$copyTo) {
  388. return $this;
  389. }
  390. // Retrieve corresponding email template id and customer name
  391. if ($order->getCustomerIsGuest()) {
  392. $templateId = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_GUEST_TEMPLATE, $storeId);
  393. $customerName = $order->getBillingAddress()->getName();
  394. } else {
  395. $templateId = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_TEMPLATE, $storeId);
  396. $customerName = $order->getCustomerName();
  397. }
  398. $mailer = Mage::getModel('core/email_template_mailer');
  399. if ($notifyCustomer) {
  400. $emailInfo = Mage::getModel('core/email_info');
  401. $emailInfo->addTo($order->getCustomerEmail(), $customerName);
  402. if ($copyTo && $copyMethod == 'bcc') {
  403. // Add bcc to customer email
  404. foreach ($copyTo as $email) {
  405. $emailInfo->addBcc($email);
  406. }
  407. }
  408. $mailer->addEmailInfo($emailInfo);
  409. }
  410. // Email copies are sent as separated emails if their copy method is 'copy' or a customer should not be notified
  411. if ($copyTo && ($copyMethod == 'copy' || !$notifyCustomer)) {
  412. foreach ($copyTo as $email) {
  413. $emailInfo = Mage::getModel('core/email_info');
  414. $emailInfo->addTo($email);
  415. $mailer->addEmailInfo($emailInfo);
  416. }
  417. }
  418. // Set all required params and send emails
  419. $mailer->setSender(Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_IDENTITY, $storeId));
  420. $mailer->setStoreId($storeId);
  421. $mailer->setTemplateId($templateId);
  422. $mailer->setTemplateParams(array(
  423. 'order' => $order,
  424. 'shipment' => $this,
  425. 'comment' => $comment,
  426. 'billing' => $order->getBillingAddress()
  427. )
  428. );
  429. $mailer->send();
  430. return $this;
  431. }
  432. protected function _getEmails($configPath)
  433. {
  434. $data = Mage::getStoreConfig($configPath, $this->getStoreId());
  435. if (!empty($data)) {
  436. return explode(',', $data);
  437. }
  438. return false;
  439. }
  440. /**
  441. * Before object save
  442. *
  443. * @return Mage_Sales_Model_Order_Shipment
  444. */
  445. protected function _beforeSave()
  446. {
  447. if ((!$this->getId() || null !== $this->_items) && !count($this->getAllItems())) {
  448. Mage::throwException(
  449. Mage::helper('sales')->__('Cannot create an empty shipment.')
  450. );
  451. }
  452. if (!$this->getOrderId() && $this->getOrder()) {
  453. $this->setOrderId($this->getOrder()->getId());
  454. $this->setShippingAddressId($this->getOrder()->getShippingAddress()->getId());
  455. }
  456. return parent::_beforeSave();
  457. }
  458. protected function _beforeDelete()
  459. {
  460. $this->_protectFromNonAdmin();
  461. return parent::_beforeDelete();
  462. }
  463. /**
  464. * After object save manipulations
  465. *
  466. * @return Mage_Sales_Model_Order_Shipment
  467. */
  468. protected function _afterSave()
  469. {
  470. if (null !== $this->_items) {
  471. foreach ($this->_items as $item) {
  472. $item->save();
  473. }
  474. }
  475. if (null !== $this->_tracks) {
  476. foreach($this->_tracks as $track) {
  477. $track->save();
  478. }
  479. }
  480. if (null !== $this->_comments) {
  481. foreach($this->_comments as $comment) {
  482. $comment->save();
  483. }
  484. }
  485. return parent::_afterSave();
  486. }
  487. /**
  488. * Retrieve store model instance
  489. *
  490. * @return Mage_Core_Model_Store
  491. */
  492. public function getStore()
  493. {
  494. return $this->getOrder()->getStore();
  495. }
  496. }