00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 class Mage_Sales_Model_Order_Creditmemo extends Mage_Sales_Model_Abstract
00029 {
00030 const STATE_OPEN = 1;
00031 const STATE_REFUNDED = 2;
00032 const STATE_CANCELED = 3;
00033
00034 const XML_PATH_EMAIL_TEMPLATE = 'sales_email/creditmemo/template';
00035 const XML_PATH_EMAIL_GUEST_TEMPLATE = 'sales_email/creditmemo/guest_template';
00036 const XML_PATH_EMAIL_IDENTITY = 'sales_email/creditmemo/identity';
00037 const XML_PATH_EMAIL_COPY_TO = 'sales_email/creditmemo/copy_to';
00038 const XML_PATH_EMAIL_COPY_METHOD = 'sales_email/creditmemo/copy_method';
00039 const XML_PATH_EMAIL_ENABLED = 'sales_email/creditmemo/enabled';
00040
00041 const XML_PATH_UPDATE_EMAIL_TEMPLATE = 'sales_email/creditmemo_comment/template';
00042 const XML_PATH_UPDATE_EMAIL_GUEST_TEMPLATE = 'sales_email/creditmemo_comment/guest_template';
00043 const XML_PATH_UPDATE_EMAIL_IDENTITY = 'sales_email/creditmemo_comment/identity';
00044 const XML_PATH_UPDATE_EMAIL_COPY_TO = 'sales_email/creditmemo_comment/copy_to';
00045 const XML_PATH_UPDATE_EMAIL_COPY_METHOD = 'sales_email/creditmemo_comment/copy_method';
00046 const XML_PATH_UPDATE_EMAIL_ENABLED = 'sales_email/creditmemo_comment/enabled';
00047
00048 protected static $_states;
00049
00050 protected $_items;
00051 protected $_order;
00052
00053 protected $_eventPrefix = 'sales_order_creditmemo';
00054 protected $_eventObject = 'creditmemo';
00055
00056
00057
00058
00059 protected function _construct()
00060 {
00061 $this->_init('sales/order_creditmemo');
00062 }
00063
00064
00065
00066
00067
00068
00069 public function getConfig()
00070 {
00071 return Mage::getSingleton('sales/order_creditmemo_config');
00072 }
00073
00074
00075
00076
00077
00078
00079 public function getStore()
00080 {
00081 return $this->getOrder()->getStore();
00082 }
00083
00084
00085
00086
00087
00088
00089
00090 public function setOrder(Mage_Sales_Model_Order $order)
00091 {
00092 $this->_order = $order;
00093 $this->setOrderId($order->getId())
00094 ->setStoreId($order->getStoreId());
00095 return $this;
00096 }
00097
00098
00099
00100
00101
00102
00103 public function getOrder()
00104 {
00105 if (!$this->_order instanceof Mage_Sales_Model_Order) {
00106 $this->_order = Mage::getModel('sales/order')->load($this->getOrderId());
00107 }
00108 return $this->_order;
00109 }
00110
00111
00112
00113
00114
00115
00116 public function getBillingAddress()
00117 {
00118 return $this->getOrder()->getBillingAddress();
00119 }
00120
00121
00122
00123
00124
00125
00126 public function getShippingAddress()
00127 {
00128 return $this->getOrder()->getShippingAddress();
00129 }
00130
00131 public function getItemsCollection()
00132 {
00133 if (empty($this->_items)) {
00134 $this->_items = Mage::getResourceModel('sales/order_creditmemo_item_collection')
00135 ->addAttributeToSelect('*')
00136 ->setCreditmemoFilter($this->getId());
00137
00138 if ($this->getId()) {
00139 foreach ($this->_items as $item) {
00140 $item->setCreditmemo($this);
00141 }
00142 }
00143 }
00144 return $this->_items;
00145 }
00146
00147 public function getAllItems()
00148 {
00149 $items = array();
00150 foreach ($this->getItemsCollection() as $item) {
00151 if (!$item->isDeleted()) {
00152 $items[] = $item;
00153 }
00154 }
00155 return $items;
00156 }
00157
00158 public function getItemById($itemId)
00159 {
00160 foreach ($this->getItemsCollection() as $item) {
00161 if ($item->getId()==$itemId) {
00162 return $item;
00163 }
00164 }
00165 return false;
00166 }
00167
00168 public function addItem(Mage_Sales_Model_Order_Creditmemo_Item $item)
00169 {
00170 $item->setCreditmemo($this)
00171 ->setParentId($this->getId())
00172 ->setStoreId($this->getStoreId());
00173 if (!$item->getId()) {
00174 $this->getItemsCollection()->addItem($item);
00175 }
00176 return $this;
00177 }
00178
00179
00180
00181
00182
00183
00184 public function collectTotals()
00185 {
00186 foreach ($this->getConfig()->getTotalModels() as $model) {
00187 $model->collect($this);
00188 }
00189 return $this;
00190 }
00191
00192 public function canRefund()
00193 {
00194 if ($this->getState() != self::STATE_CANCELED
00195 && $this->getState() != self::STATE_REFUNDED
00196 && $this->getOrder()->getPayment()->canRefund()
00197 ) {
00198 return true;
00199 }
00200 return false;
00201 }
00202
00203
00204
00205
00206
00207
00208 public function canCancel()
00209 {
00210 return $this->getState() == self::STATE_OPEN;
00211 }
00212
00213
00214
00215
00216
00217
00218 public function canVoid()
00219 {
00220 $canVoid = false;
00221 return false;
00222 if ($this->getState() == self::STATE_REFUNDED) {
00223 $canVoid = $this->getCanVoidFlag();
00224
00225
00226
00227 if (is_null($canVoid)) {
00228 $canVoid = $this->getOrder()->getPayment()->canVoid($this);
00229 if ($canVoid === false) {
00230 $this->setCanVoidFlag(false);
00231 $this->_saveBeforeDestruct = true;
00232 }
00233 }
00234 else {
00235 $canVoid = (bool) $canVoid;
00236 }
00237 }
00238 return $canVoid;
00239 }
00240
00241
00242 public function refund()
00243 {
00244 $this->setState(self::STATE_REFUNDED);
00245 $orderRefund = Mage::app()->getStore()->roundPrice($this->getOrder()->getTotalRefunded()+$this->getGrandTotal());
00246 $baseOrderRefund = Mage::app()->getStore()->roundPrice($this->getOrder()->getBaseTotalRefunded()+$this->getBaseGrandTotal());
00247
00248 if ($baseOrderRefund > Mage::app()->getStore()->roundPrice($this->getOrder()->getBaseTotalPaid())) {
00249
00250 $baseAvailableRefund = $this->getOrder()->getBaseTotalPaid()
00251 - $this->getOrder()->getBaseTotalRefunded();
00252
00253 Mage::throwException(
00254 Mage::helper('sales')->__('Maximum amount available to refund is %s',
00255 $this->getOrder()->formatBasePrice($baseAvailableRefund)
00256 )
00257 );
00258 }
00259
00260 $this->getOrder()->setBaseTotalRefunded($baseOrderRefund);
00261 $this->getOrder()->setTotalRefunded($orderRefund);
00262
00263 $this->getOrder()->setBaseSubtotalRefunded(
00264 $this->getOrder()->getBaseSubtotalRefunded()+$this->getBaseSubtotal()
00265 );
00266 $this->getOrder()->setSubtotalRefunded(
00267 $this->getOrder()->getSubtotalRefunded()+$this->getSubtotal()
00268 );
00269
00270 $this->getOrder()->setBaseTaxRefunded(
00271 $this->getOrder()->getBaseTaxRefunded()+$this->getBaseTaxAmount()
00272 );
00273 $this->getOrder()->setTaxRefunded(
00274 $this->getOrder()->getTaxRefunded()+$this->getTaxAmount()
00275 );
00276
00277 $this->getOrder()->setBaseShippingRefunded(
00278 $this->getOrder()->getBaseShippingRefunded()+$this->getBaseShippingAmount()
00279 );
00280 $this->getOrder()->setShippingRefunded(
00281 $this->getOrder()->getShippingRefunded()+$this->getShippingAmount()
00282 );
00283
00284 $this->getOrder()->setBaseShippingTaxRefunded(
00285 $this->getOrder()->getBaseShippingTaxRefunded()+$this->getBaseShippingTaxAmount()
00286 );
00287 $this->getOrder()->setShippingTaxRefunded(
00288 $this->getOrder()->getShippingTaxRefunded()+$this->getShippingTaxAmount()
00289 );
00290
00291 $this->getOrder()->setAdjustmentPositive(
00292 $this->getOrder()->getAdjustmentPositive()+$this->getAdjustmentPositive()
00293 );
00294 $this->getOrder()->setBaseAdjustmentPositive(
00295 $this->getOrder()->getBaseAdjustmentPositive()+$this->getBaseAdjustmentPositive()
00296 );
00297
00298 $this->getOrder()->setAdjustmentNegative(
00299 $this->getOrder()->getAdjustmentNegative()+$this->getAdjustmentNegative()
00300 );
00301 $this->getOrder()->setBaseAdjustmentNegative(
00302 $this->getOrder()->getBaseAdjustmentNegative()+$this->getBaseAdjustmentNegative()
00303 );
00304
00305 $this->getOrder()->setDiscountRefunded(
00306 $this->getOrder()->getDiscountRefunded()+$this->getDiscountAmount()
00307 );
00308 $this->getOrder()->setBaseDiscountRefunded(
00309 $this->getOrder()->getBaseDiscountRefunded()+$this->getBaseDiscountAmount()
00310 );
00311
00312 if ($this->getInvoice()) {
00313 $this->getInvoice()->setIsUsedForRefund(true);
00314 $this->setInvoiceId($this->getInvoice()->getId());
00315 }
00316
00317 if (!$this->getPaymentRefundDisallowed()) {
00318 $this->getOrder()->getPayment()->refund($this);
00319 }
00320
00321 Mage::dispatchEvent('sales_order_creditmemo_refund', array($this->_eventObject=>$this));
00322 return $this;
00323 }
00324
00325
00326
00327
00328
00329
00330 public function cancel()
00331 {
00332 $this->setState(self::STATE_CANCELED);
00333 foreach ($this->getAllItems() as $item) {
00334 $item->cancel();
00335 }
00336 $this->getOrder()->getPayment()->cancelCreditmemo($this);
00337
00338 if ($this->getTransactionId()) {
00339 $this->getOrder()->setTotalOnlineRefunded(
00340 $this->getOrder()->getTotalOnlineRefunded()-$this->getGrandTotal()
00341 );
00342 $this->getOrder()->setBaseTotalOnlineRefunded(
00343 $this->getOrder()->getBaseTotalOnlineRefunded()-$this->getBaseGrandTotal()
00344 );
00345 }
00346 else {
00347 $this->getOrder()->setTotalOfflineRefunded(
00348 $this->getOrder()->getTotalOfflineRefunded()-$this->getGrandTotal()
00349 );
00350 $this->getOrder()->setBaseTotalOfflineRefunded(
00351 $this->getOrder()->getBaseTotalOfflineRefunded()-$this->getBaseGrandTotal()
00352 );
00353 }
00354
00355 $this->getOrder()->setBaseSubtotalRefunded($this->getOrder()->getBaseSubtotalRefunded()-$this->getBaseSubtotal());
00356 $this->getOrder()->setSubtotalRefunded($this->getOrder()->getSubtotalRefunded()-$this->getSubtotal());
00357
00358 $this->getOrder()->setBaseTaxRefunded($this->getOrder()->getBaseTaxRefunded()-$this->getBaseTaxAmount());
00359 $this->getOrder()->setTaxRefunded($this->getOrder()->getTaxRefunded()-$this->getTaxAmount());
00360
00361 $this->getOrder()->setBaseShippingRefunded($this->getOrder()->getBaseShippingRefunded()-$this->getBaseShippingAmount());
00362 $this->getOrder()->setShippingRefunded($this->getOrder()->getShippingRefunded()-$this->getShippingAmount());
00363
00364 Mage::dispatchEvent('sales_order_creditmemo_cancel', array($this->_eventObject=>$this));
00365 return $this;
00366 }
00367
00368
00369
00370
00371
00372
00373
00374
00375 public function register()
00376 {
00377 if ($this->getId()) {
00378 Mage::throwException(
00379 Mage::helper('sales')->__('Can not register existing creditmemo')
00380 );
00381 }
00382
00383 foreach ($this->getAllItems() as $item) {
00384 if ($item->getQty()>0) {
00385 $item->register();
00386 }
00387 else {
00388 $item->isDeleted(true);
00389 }
00390 }
00391
00392 $this->setDoTransaction(true);
00393 if ($this->getOfflineRequested()) {
00394 $this->getDoTransaction(false);
00395 }
00396 $this->refund();
00397
00398 if ($this->getDoTransaction()) {
00399 $this->getOrder()->setTotalOnlineRefunded(
00400 $this->getOrder()->getTotalOnlineRefunded()+$this->getGrandTotal()
00401 );
00402 $this->getOrder()->setBaseTotalOnlineRefunded(
00403 $this->getOrder()->getBaseTotalOnlineRefunded()+$this->getBaseGrandTotal()
00404 );
00405 }
00406 else {
00407 $this->getOrder()->setTotalOfflineRefunded(
00408 $this->getOrder()->getTotalOfflineRefunded()+$this->getGrandTotal()
00409 );
00410 $this->getOrder()->setBaseTotalOfflineRefunded(
00411 $this->getOrder()->getBaseTotalOfflineRefunded()+$this->getBaseGrandTotal()
00412 );
00413 }
00414
00415 $state = $this->getState();
00416 if (is_null($state)) {
00417 $this->setState(self::STATE_OPEN);
00418 }
00419 return $this;
00420 }
00421
00422
00423
00424
00425
00426
00427 public static function getStates()
00428 {
00429 if (is_null(self::$_states)) {
00430 self::$_states = array(
00431 self::STATE_OPEN => Mage::helper('sales')->__('Pending'),
00432 self::STATE_REFUNDED => Mage::helper('sales')->__('Refunded'),
00433 self::STATE_CANCELED => Mage::helper('sales')->__('Canceled'),
00434 );
00435 }
00436 return self::$_states;
00437 }
00438
00439
00440
00441
00442
00443
00444
00445 public function getStateName($stateId = null)
00446 {
00447 if (is_null($stateId)) {
00448 $stateId = $this->getState();
00449 }
00450
00451 if (is_null(self::$_states)) {
00452 self::getStates();
00453 }
00454 if (isset(self::$_states[$stateId])) {
00455 return self::$_states[$stateId];
00456 }
00457 return Mage::helper('sales')->__('Unknown State');
00458 }
00459
00460 public function setShippingAmount($amount)
00461 {
00462 $amount = $this->getStore()->roundPrice($amount);
00463 $this->setData('base_shipping_amount', $amount);
00464
00465 $amount = $this->getStore()->roundPrice(
00466 $amount*$this->getOrder()->getStoreToOrderRate()
00467 );
00468 $this->setData('shipping_amount', $amount);
00469 return $this;
00470 }
00471
00472
00473 public function setAdjustmentPositive($amount)
00474 {
00475 $amount = $this->getStore()->roundPrice($amount);
00476 $this->setData('base_adjustment_positive', $amount);
00477
00478 $amount = $this->getStore()->roundPrice(
00479 $amount*$this->getOrder()->getStoreToOrderRate()
00480 );
00481 $this->setData('adjustment_positive', $amount);
00482 return $this;
00483 }
00484
00485 public function setAdjustmentNegative($amount)
00486 {
00487 $amount = $this->getStore()->roundPrice($amount);
00488 $this->setData('base_adjustment_negative', $amount);
00489
00490 $amount = $this->getStore()->roundPrice(
00491 $amount*$this->getOrder()->getStoreToOrderRate()
00492 );
00493 $this->setData('adjustment_negative', $amount);
00494 return $this;
00495 }
00496
00497 public function addComment($comment, $notify=false)
00498 {
00499 if (!($comment instanceof Mage_Sales_Model_Order_Creditmemo_Comment)) {
00500 $comment = Mage::getModel('sales/order_creditmemo_comment')
00501 ->setComment($comment)
00502 ->setIsCustomerNotified($notify);
00503 }
00504 $comment->setCreditmemo($this)
00505 ->setParentId($this->getId())
00506 ->setStoreId($this->getStoreId());
00507 if (!$comment->getId()) {
00508 $this->getCommentsCollection()->addItem($comment);
00509 }
00510 return $this;
00511 }
00512
00513 public function getCommentsCollection($reload=false)
00514 {
00515 if (is_null($this->_comments) || $reload) {
00516 $this->_comments = Mage::getResourceModel('sales/order_creditmemo_comment_collection')
00517 ->addAttributeToSelect('*')
00518 ->setCreditmemoFilter($this->getId())
00519 ->setCreatedAtOrder();
00520 if ($this->getId()) {
00521 foreach ($this->_comments as $comment) {
00522 $comment->setCreditmemo($this);
00523 }
00524 }
00525 }
00526 return $this->_comments;
00527 }
00528
00529
00530
00531
00532
00533
00534
00535 public function sendEmail($notifyCustomer=true, $comment='')
00536 {
00537 if (!Mage::helper('sales')->canSendNewCreditmemoEmail($this->getOrder()->getStore()->getId())) {
00538 return $this;
00539 }
00540
00541 $currentDesign = Mage::getDesign()->setAllGetOld(array(
00542 'package' => Mage::getStoreConfig('design/package/name', $this->getStoreId()),
00543 'store' => $this->getStoreId()
00544 ));
00545
00546 $translate = Mage::getSingleton('core/translate');
00547
00548 $translate->setTranslateInline(false);
00549
00550 $order = $this->getOrder();
00551
00552 $copyTo = $this->_getEmails(self::XML_PATH_EMAIL_COPY_TO);
00553 $copyMethod = Mage::getStoreConfig(self::XML_PATH_EMAIL_COPY_METHOD, $this->getStoreId());
00554
00555 if (!$notifyCustomer && !$copyTo) {
00556 return $this;
00557 }
00558 $paymentBlock = Mage::helper('payment')->getInfoBlock($order->getPayment())
00559 ->setIsSecureMode(true);
00560
00561 $mailTemplate = Mage::getModel('core/email_template');
00562
00563 if ($order->getCustomerIsGuest()) {
00564 $template = Mage::getStoreConfig(self::XML_PATH_EMAIL_GUEST_TEMPLATE, $order->getStoreId());
00565 $customerName = $order->getBillingAddress()->getName();
00566 } else {
00567 $template = Mage::getStoreConfig(self::XML_PATH_EMAIL_TEMPLATE, $order->getStoreId());
00568 $customerName = $order->getCustomerName();
00569 }
00570
00571 if ($notifyCustomer) {
00572 $sendTo[] = array(
00573 'name' => $customerName,
00574 'email' => $order->getCustomerEmail()
00575 );
00576 if ($copyTo && $copyMethod == 'bcc') {
00577 foreach ($copyTo as $email) {
00578 $mailTemplate->addBcc($email);
00579 }
00580 }
00581
00582 }
00583
00584 if ($copyTo && ($copyMethod == 'copy' || !$notifyCustomer)) {
00585 foreach ($copyTo as $email) {
00586 $sendTo[] = array(
00587 'name' => null,
00588 'email' => $email
00589 );
00590 }
00591 }
00592
00593 foreach ($sendTo as $recipient) {
00594 $mailTemplate->setDesignConfig(array('area'=>'frontend', 'store'=>$order->getStoreId()))
00595 ->sendTransactional(
00596 $template,
00597 Mage::getStoreConfig(self::XML_PATH_EMAIL_IDENTITY, $order->getStoreId()),
00598 $recipient['email'],
00599 $recipient['name'],
00600 array(
00601 'order' => $order,
00602 'creditmemo' => $this,
00603 'comment' => $comment,
00604 'billing' => $order->getBillingAddress(),
00605 'payment_html'=> $paymentBlock->toHtml(),
00606 )
00607 );
00608 }
00609
00610 $translate->setTranslateInline(true);
00611
00612 Mage::getDesign()->setAllGetOld($currentDesign);
00613
00614 return $this;
00615 }
00616
00617
00618
00619
00620
00621
00622 public function sendUpdateEmail($notifyCustomer=true, $comment='')
00623 {
00624 if (!Mage::helper('sales')->canSendCreditmemoCommentEmail($this->getOrder()->getStore()->getId())) {
00625 return $this;
00626 }
00627
00628 $currentDesign = Mage::getDesign()->setAllGetOld(array(
00629 'package' => Mage::getStoreConfig('design/package/name', $this->getStoreId()),
00630 ));
00631
00632 $translate = Mage::getSingleton('core/translate');
00633
00634 $translate->setTranslateInline(false);
00635
00636 $order = $this->getOrder();
00637
00638 $copyTo = $this->_getEmails(self::XML_PATH_UPDATE_EMAIL_COPY_TO);
00639 $copyMethod = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_COPY_METHOD, $this->getStoreId());
00640
00641 if (!$notifyCustomer && !$copyTo) {
00642 return $this;
00643 }
00644
00645 $mailTemplate = Mage::getModel('core/email_template');
00646
00647 if ($order->getCustomerIsGuest()) {
00648 $template = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_GUEST_TEMPLATE, $order->getStoreId());
00649 $customerName = $order->getBillingAddress()->getName();
00650 } else {
00651 $template = Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_TEMPLATE, $order->getStoreId());
00652 $customerName = $order->getCustomerName();
00653 }
00654
00655 if ($notifyCustomer) {
00656 $sendTo[] = array(
00657 'name' => $customerName,
00658 'email' => $order->getCustomerEmail()
00659 );
00660 if ($copyTo && $copyMethod == 'bcc') {
00661 foreach ($copyTo as $email) {
00662 $mailTemplate->addBcc($email);
00663 }
00664 }
00665
00666 }
00667
00668 if ($copyTo && ($copyMethod == 'copy' || !$notifyCustomer)) {
00669 foreach ($copyTo as $email) {
00670 $sendTo[] = array(
00671 'name' => null,
00672 'email' => $email
00673 );
00674 }
00675 }
00676
00677 foreach ($sendTo as $recipient) {
00678 $mailTemplate->setDesignConfig(array('area'=>'frontend', 'store'=>$order->getStoreId()))
00679 ->sendTransactional(
00680 $template,
00681 Mage::getStoreConfig(self::XML_PATH_UPDATE_EMAIL_IDENTITY, $order->getStoreId()),
00682 $recipient['email'],
00683 $recipient['name'],
00684 array(
00685 'order' => $order,
00686 'billing'=> $order->getBillingAddress(),
00687 'creditmemo'=> $this,
00688 'comment'=> $comment
00689 )
00690 );
00691 }
00692
00693 $translate->setTranslateInline(true);
00694
00695 Mage::getDesign()->setAllGetOld($currentDesign);
00696
00697 return $this;
00698 }
00699
00700 protected function _getEmails($configPath)
00701 {
00702 $data = Mage::getStoreConfig($configPath, $this->getStoreId());
00703 if (!empty($data)) {
00704 return explode(',', $data);
00705 }
00706 return false;
00707 }
00708
00709 protected function _beforeDelete()
00710 {
00711 $this->_protectFromNonAdmin();
00712 return parent::_beforeDelete();
00713 }
00714 }