*/ class Mage_Sales_Model_Order_Shipment extends Mage_Sales_Model_Abstract { const STATUS_NEW = 1; const XML_PATH_EMAIL_TEMPLATE = 'sales_email/shipment/template'; const XML_PATH_EMAIL_GUEST_TEMPLATE = 'sales_email/shipment/guest_template'; const XML_PATH_EMAIL_IDENTITY = 'sales_email/shipment/identity'; const XML_PATH_EMAIL_COPY_TO = 'sales_email/shipment/copy_to'; const XML_PATH_EMAIL_COPY_METHOD = 'sales_email/shipment/copy_method'; const XML_PATH_EMAIL_ENABLED = 'sales_email/shipment/enabled'; const XML_PATH_UPDATE_EMAIL_TEMPLATE = 'sales_email/shipment_comment/template'; const XML_PATH_UPDATE_EMAIL_GUEST_TEMPLATE = 'sales_email/shipment_comment/guest_template'; const XML_PATH_UPDATE_EMAIL_IDENTITY = 'sales_email/shipment_comment/identity'; const XML_PATH_UPDATE_EMAIL_COPY_TO = 'sales_email/shipment_comment/copy_to'; const XML_PATH_UPDATE_EMAIL_COPY_METHOD = 'sales_email/shipment_comment/copy_method'; const XML_PATH_UPDATE_EMAIL_ENABLED = 'sales_email/shipment_comment/enabled'; const REPORT_DATE_TYPE_ORDER_CREATED = 'order_created'; const REPORT_DATE_TYPE_SHIPMENT_CREATED = 'shipment_created'; /* * Identifier for order history item */ const HISTORY_ENTITY_NAME = 'shipment'; protected $_items; protected $_tracks; protected $_order; protected $_comments; protected $_eventPrefix = 'sales_order_shipment'; protected $_eventObject = 'shipment'; /** * Initialize shipment resource model */ protected function _construct() { $this->_init('sales/order_shipment'); } /** * Init mapping array of short fields to its full names * * @return Mage_Sales_Model_Order_Shipment */ protected function _initOldFieldsMap() { $this->_oldFieldsMap = Mage::helper('sales')->getOldFieldMap('order_shipment'); return $this; } /** * Load shipment by increment id * * @param string $incrementId * @return Mage_Sales_Model_Order_Shipment */ public function loadByIncrementId($incrementId) { $ids = $this->getCollection() ->addAttributeToFilter('increment_id', $incrementId) ->getAllIds(); if (!empty($ids)) { reset($ids); $this->load(current($ids)); } return $this; } /** * Declare order for shipment * * @param Mage_Sales_Model_Order $order * @return Mage_Sales_Model_Order_Shipment */ public function setOrder(Mage_Sales_Model_Order $order) { $this->_order = $order; $this->setOrderId($order->getId()) ->setStoreId($order->getStoreId()); return $this; } /** * Retrieve hash code of current order * * @return string */ public function getProtectCode() { return (string)$this->getOrder()->getProtectCode(); } /** * Retrieve the order the shipment for created for * * @return Mage_Sales_Model_Order */ public function getOrder() { if (!$this->_order instanceof Mage_Sales_Model_Order) { $this->_order = Mage::getModel('sales/order')->load($this->getOrderId()); } return $this->_order->setHistoryEntityName(self::HISTORY_ENTITY_NAME); } /** * Retrieve billing address * * @return Mage_Sales_Model_Order_Address */ public function getBillingAddress() { return $this->getOrder()->getBillingAddress(); } /** * Retrieve shipping address * * @return Mage_Sales_Model_Order_Address */ public function getShippingAddress() { return $this->getOrder()->getShippingAddress(); } /** * Register shipment * * Apply to order, order items etc. * * @return unknown */ public function register() { if ($this->getId()) { Mage::throwException( Mage::helper('sales')->__('Cannot register existing shipment') ); } $totalQty = 0; foreach ($this->getAllItems() as $item) { if ($item->getQty()>0) { $item->register(); if (!$item->getOrderItem()->isDummy(true)) { $totalQty+= $item->getQty(); } } else { $item->isDeleted(true); } } $this->setTotalQty($totalQty); return $this; } public function getItemsCollection() { if (empty($this->_items)) { $this->_items = Mage::getResourceModel('sales/order_shipment_item_collection') ->setShipmentFilter($this->getId()); if ($this->getId()) { foreach ($this->_items as $item) { $item->setShipment($this); } } } return $this->_items; } public function getAllItems() { $items = array(); foreach ($this->getItemsCollection() as $item) { if (!$item->isDeleted()) { $items[] = $item; } } return $items; } public function getItemById($itemId) { foreach ($this->getItemsCollection() as $item) { if ($item->getId()==$itemId) { return $item; } } return false; } public function addItem(Mage_Sales_Model_Order_Shipment_Item $item) { $item->setShipment($this) ->setParentId($this->getId()) ->setStoreId($this->getStoreId()); if (!$item->getId()) { $this->getItemsCollection()->addItem($item); } return $this; } public function getTracksCollection() { if (empty($this->_tracks)) { $this->_tracks = Mage::getResourceModel('sales/order_shipment_track_collection') ->setShipmentFilter($this->getId()); if ($this->getId()) { foreach ($this->_tracks as $track) { $track->setShipment($this); } } } return $this->_tracks; } public function getAllTracks() { $tracks = array(); foreach ($this->getTracksCollection() as $track) { if (!$track->isDeleted()) { $tracks[] = $track; } } return $tracks; } public function getTrackById($trackId) { foreach ($this->getTracksCollection() as $track) { if ($track->getId()==$trackId) { return $track; } } return false; } public function addTrack(Mage_Sales_Model_Order_Shipment_Track $track) { $track->setShipment($this) ->setParentId($this->getId()) ->setOrderId($this->getOrderId()) ->setStoreId($this->getStoreId()); if (!$track->getId()) { $this->getTracksCollection()->addItem($track); } /** * Track saving is implemented in _afterSave() * This enforces Mage_Core_Model_Abstract::save() not to skip _afterSave() */ $this->_hasDataChanges = true; return $this; } /** * Adds comment to shipment with additional possibility to send it to customer via email * and show it in customer account * * @param bool $notify * @param bool $visibleOnFront * * @return Mage_Sales_Model_Order_Shipment */ public function addComment($comment, $notify=false, $visibleOnFront=false) { if (!($comment instanceof Mage_Sales_Model_Order_Shipment_Comment)) { $comment = Mage::getModel('sales/order_shipment_comment') ->setComment($comment) ->setIsCustomerNotified($notify) ->setIsVisibleOnFront($visibleOnFront); } $comment->setShipment($this) ->setParentId($this->getId()) ->setStoreId($this->getStoreId()); if (!$comment->getId()) { $this->getCommentsCollection()->addItem($comment); } $this->_hasDataChanges = true; return $this; } public function getCommentsCollection($reload=false) { if (is_null($this->_comments) || $reload) { $this->_comments = Mage::getResourceModel('sales/order_shipment_comment_collection') ->setShipmentFilter($this->getId()) ->setCreatedAtOrder(); /** * When shipment created with adding comment, * comments collection must be loaded before we added this comment. */ $this->_comments->load(); if ($this->getId()) { foreach ($this->_comments as $comment) { $comment->setShipment($this); } } } return $this->_comments; } /** * Send email with shipment data * * @param boolean $notifyCustomer * @param string $comment * @return Mage_Sales_Model_Order_Shipment */ public function sendEmail($notifyCustomer = true, $comment = '') { $order = $this->getOrder(); $storeId = $order->getStore()->getId(); if (!Mage::helper('sales')->canSendNewShipmentEmail($storeId)) { return $this; } // Get the destination email addresses to send copies to $copyTo = $this->_getEmails(self::XML_PATH_EMAIL_COPY_TO); $copyMethod = Mage::getStoreConfig(self::XML_PATH_EMAIL_COPY_METHOD, $storeId); // Check if at least one recepient is found if (!$notifyCustomer && !$copyTo) { return $this; } // Start store emulation process $appEmulation = Mage::getSingleton('core/app_emulation'); $initialEnvironmentInfo = $appEmulation->startEnvironmentEmulation($storeId); try { // Retrieve specified view block from appropriate design package (depends on emulated store) $paymentBlock = Mage::helper('payment')->getInfoBlock($order->getPayment()) ->setIsSecureMode(true); $paymentBlock->getMethod()->setStore($storeId); $paymentBlockHtml = $paymentBlock->toHtml(); } catch (Exception $exception) { // Stop store emulation process $appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo); throw $exception; } // Stop store emulation process $appEmulation->stopEnvironmentEmulation($initialEnvironmentInfo); // Retrieve corresponding email template id and customer name if ($order->getCustomerIsGuest()) { $templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_GUEST_TEMPLATE, $storeId); $customerName = $order->getBillingAddress()->getName(); } else { $templateId = Mage::getStoreConfig(self::XML_PATH_EMAIL_TEMPLATE, $storeId); $customerName = $order->getCustomerName(); } $mailer = Mage::getModel('core/email_template_mailer'); if ($notifyCustomer) { $emailInfo = Mage::getModel('core/email_info'); $emailInfo->addTo($order->getCustomerEmail(), $customerName); if ($copyTo && $copyMethod == 'bcc') { // Add bcc to customer email foreach ($copyTo as $email) { $emailInfo->addBcc($email); } } $mailer->addEmailInfo($emailInfo); } // Email copies are sent as separated emails if their copy method is 'copy' or a customer should not be notified if ($copyTo && ($copyMethod == 'copy' || !$notifyCustomer)) { foreach ($copyTo as $email) { $emailInfo = Mage::getModel('core/email_info'); $emailInfo->addTo($email); $mailer->addEmailInfo($emailInfo); } } // Set all required params and send emails $mailer->setSender(Mage::getStoreConfig(self::XML_PATH_EMAIL_IDENTITY, $storeId)); $mailer->setStoreId($storeId); $mailer->setTemplateId($templateId); $mailer->setTemplateParams(array( 'order' => $order, 'shipment' => $this, 'comment' => $comment, 'billing' => $order->getBillingAddress(), 'payment_html' => $paymentBlockHtml ) ); $mailer->send(); return $this; } /** * Send email with shipment update information * * @param boolean $notifyCustomer * @param string $comment * @return Mage_Sales_Model_Order_Shipment */ public function sendUpdateEmail($notifyCustomer = true, $comment = '') { $order = $this->getOrder(); $storeId = $order->getStore()->getId(); if (!Mage::helper('sales')->canSendShipmentCommentEmail($storeId)) { return $this; } // Get the destination email addresses to send copies to $copyTo = $this->_getEmails(self::XML_PATH_UPDATE_EMAIL_COPY_TO); $copyMethod = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_COPY_METHOD, $storeId); // Check if at least one recepient is found if (!$notifyCustomer && !$copyTo) { return $this; } // Retrieve corresponding email template id and customer name if ($order->getCustomerIsGuest()) { $templateId = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_GUEST_TEMPLATE, $storeId); $customerName = $order->getBillingAddress()->getName(); } else { $templateId = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_TEMPLATE, $storeId); $customerName = $order->getCustomerName(); } $mailer = Mage::getModel('core/email_template_mailer'); if ($notifyCustomer) { $emailInfo = Mage::getModel('core/email_info'); $emailInfo->addTo($order->getCustomerEmail(), $customerName); if ($copyTo && $copyMethod == 'bcc') { // Add bcc to customer email foreach ($copyTo as $email) { $emailInfo->addBcc($email); } } $mailer->addEmailInfo($emailInfo); } // Email copies are sent as separated emails if their copy method is 'copy' or a customer should not be notified if ($copyTo && ($copyMethod == 'copy' || !$notifyCustomer)) { foreach ($copyTo as $email) { $emailInfo = Mage::getModel('core/email_info'); $emailInfo->addTo($email); $mailer->addEmailInfo($emailInfo); } } // Set all required params and send emails $mailer->setSender(Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_IDENTITY, $storeId)); $mailer->setStoreId($storeId); $mailer->setTemplateId($templateId); $mailer->setTemplateParams(array( 'order' => $order, 'shipment' => $this, 'comment' => $comment, 'billing' => $order->getBillingAddress() ) ); $mailer->send(); return $this; } protected function _getEmails($configPath) { $data = Mage::getStoreConfig($configPath, $this->getStoreId()); if (!empty($data)) { return explode(',', $data); } return false; } /** * Before object save * * @return Mage_Sales_Model_Order_Shipment */ protected function _beforeSave() { if ((!$this->getId() || null !== $this->_items) && !count($this->getAllItems())) { Mage::throwException( Mage::helper('sales')->__('Cannot create an empty shipment.') ); } if (!$this->getOrderId() && $this->getOrder()) { $this->setOrderId($this->getOrder()->getId()); $this->setShippingAddressId($this->getOrder()->getShippingAddress()->getId()); } if ($this->getPackages() && !is_scalar($this->getPackages())) { $this->setPackages(serialize($this->getPackages())); } return parent::_beforeSave(); } protected function _beforeDelete() { $this->_protectFromNonAdmin(); return parent::_beforeDelete(); } /** * After object save manipulations * * @return Mage_Sales_Model_Order_Shipment */ protected function _afterSave() { if (null !== $this->_items) { foreach ($this->_items as $item) { $item->save(); } } if (null !== $this->_tracks) { foreach($this->_tracks as $track) { $track->save(); } } if (null !== $this->_comments) { foreach($this->_comments as $comment) { $comment->save(); } } return parent::_afterSave(); } /** * Retrieve store model instance * * @return Mage_Core_Model_Store */ public function getStore() { return $this->getOrder()->getStore(); } /** * Set shipping label * * @param string $label label representation (image or pdf file) * @return Mage_Sales_Model_Order_Shipment */ public function setShippingLabel($label) { $this->setData('shipping_label', $label); return $this; } /** * Get shipping label and decode by db adapter * * @return void */ public function getShippingLabel() { $label = $this->getData('shipping_label'); if ($label) { return $this->getResource()->getReadConnection()->decodeVarbinary($label); } return $label; } }