PageRenderTime 81ms CodeModel.GetById 38ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://bitbucket.org/claudiu_marginean/magento-hg-mirror
PHP | 1729 lines | 1204 code | 173 blank | 352 comment | 204 complexity | 2c721e67039acfc3b2d027aa2d2c7cdc MD5 | raw file
Possible License(s): CC-BY-SA-3.0, LGPL-2.1, GPL-2.0, WTFPL

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

  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Mage
  22. * @package Mage_Adminhtml
  23. * @copyright Copyright (c) 2010 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Order create model
  28. *
  29. * @category Mage
  30. * @package Mage_Adminhtml
  31. * @author Magento Core Team <core@magentocommerce.com>
  32. */
  33. class Mage_Adminhtml_Model_Sales_Order_Create extends Varien_Object
  34. {
  35. /**
  36. * Quote session object
  37. *
  38. * @var Mage_Adminhtml_Model_Session_Quote
  39. */
  40. protected $_session;
  41. /**
  42. * Quote customer wishlist model object
  43. *
  44. * @var Mage_Wishlist_Model_Wishlist
  45. */
  46. protected $_wishlist;
  47. /**
  48. * Sales Quote instance
  49. *
  50. * @var Mage_Sales_Model_Quote
  51. */
  52. protected $_cart;
  53. /**
  54. * Catalog Compare List instance
  55. *
  56. * @var Mage_Catalog_Model_Product_Compare_List
  57. */
  58. protected $_compareList;
  59. /**
  60. * Re-collect quote flag
  61. *
  62. * @var boolean
  63. */
  64. protected $_needCollect;
  65. /**
  66. * Re-collect cart flag
  67. *
  68. * @var boolean
  69. */
  70. protected $_needCollectCart = false;
  71. /**
  72. * Collect (import) data and validate it flag
  73. *
  74. * @var boolean
  75. */
  76. protected $_isValidate = false;
  77. /**
  78. * Customer instance
  79. *
  80. * @var Mage_Customer_Model_Customer
  81. */
  82. protected $_customer;
  83. /**
  84. * Customer Address Form instance
  85. *
  86. * @var Mage_Customer_Model_Form
  87. */
  88. protected $_customerAddressForm;
  89. /**
  90. * Customer Form instance
  91. *
  92. * @var Mage_Customer_Model_Form
  93. */
  94. protected $_customerForm;
  95. /**
  96. * Array of validate errors
  97. *
  98. * @var array
  99. */
  100. protected $_errors = array();
  101. public function __construct()
  102. {
  103. $this->_session = Mage::getSingleton('adminhtml/session_quote');
  104. }
  105. /**
  106. * Set validate data in import data flag
  107. *
  108. * @param boolean $flag
  109. * @return Mage_Adminhtml_Model_Sales_Order_Create
  110. */
  111. public function setIsValidate($flag)
  112. {
  113. $this->_isValidate = (bool)$flag;
  114. return $this;
  115. }
  116. /**
  117. * Return is validate data in import flag
  118. *
  119. * @return boolean
  120. */
  121. public function getIsValidate()
  122. {
  123. return $this->_isValidate;
  124. }
  125. /**
  126. * Retrieve quote item
  127. *
  128. * @param int|Mage_Sales_Model_Quote_Item $item
  129. * @return Mage_Sales_Model_Quote_Item
  130. */
  131. protected function _getQuoteItem($item)
  132. {
  133. if ($item instanceof Mage_Sales_Model_Quote_Item) {
  134. return $item;
  135. } elseif (is_numeric($item)) {
  136. return $this->getSession()->getQuote()->getItemById($item);
  137. }
  138. return false;
  139. }
  140. /**
  141. * Initialize data for price rules
  142. *
  143. * @return Mage_Adminhtml_Model_Sales_Order_Create
  144. */
  145. public function initRuleData()
  146. {
  147. Mage::register('rule_data', new Varien_Object(array(
  148. 'store_id' => $this->_session->getStore()->getId(),
  149. 'website_id' => $this->_session->getStore()->getWebsiteId(),
  150. 'customer_group_id' => $this->getCustomerGroupId(),
  151. )));
  152. return $this;
  153. }
  154. /**
  155. * Set collect totals flag for quote
  156. *
  157. * @param bool $flag
  158. * @return Mage_Adminhtml_Model_Sales_Order_Create
  159. */
  160. public function setRecollect($flag)
  161. {
  162. $this->_needCollect = $flag;
  163. return $this;
  164. }
  165. /**
  166. * Recollect totals for customer cart.
  167. * Set recollect totals flag for quote
  168. *
  169. * @return Mage_Adminhtml_Model_Sales_Order_Create
  170. */
  171. public function recollectCart(){
  172. if ($this->_needCollectCart === true) {
  173. $this->getCustomerCart()
  174. ->collectTotals()
  175. ->save();
  176. }
  177. $this->setRecollect(true);
  178. return $this;
  179. }
  180. /**
  181. * Quote saving
  182. *
  183. * @return Mage_Adminhtml_Model_Sales_Order_Create
  184. */
  185. public function saveQuote()
  186. {
  187. if (!$this->getQuote()->getId()) {
  188. return $this;
  189. }
  190. if ($this->_needCollect) {
  191. $this->getQuote()->collectTotals();
  192. }
  193. $this->getQuote()->save();
  194. return $this;
  195. }
  196. /**
  197. * Retrieve session model object of quote
  198. *
  199. * @return Mage_Adminhtml_Model_Session_Quote
  200. */
  201. public function getSession()
  202. {
  203. return $this->_session;
  204. }
  205. /**
  206. * Retrieve quote object model
  207. *
  208. * @return Mage_Sales_Model_Quote
  209. */
  210. public function getQuote()
  211. {
  212. return $this->getSession()->getQuote();
  213. }
  214. /**
  215. * Initialize creation data from existing order
  216. *
  217. * @param Mage_Sales_Model_Order $order
  218. * @return unknown
  219. */
  220. public function initFromOrder(Mage_Sales_Model_Order $order)
  221. {
  222. if (!$order->getReordered()) {
  223. $this->getSession()->setOrderId($order->getId());
  224. } else {
  225. $this->getSession()->setReordered($order->getId());
  226. }
  227. /**
  228. * Check if we edit quest order
  229. */
  230. $this->getSession()->setCurrencyId($order->getOrderCurrencyCode());
  231. if ($order->getCustomerId()) {
  232. $this->getSession()->setCustomerId($order->getCustomerId());
  233. } else {
  234. $this->getSession()->setCustomerId(false);
  235. }
  236. $this->getSession()->setStoreId($order->getStoreId());
  237. /**
  238. * Initialize catalog rule data with new session values
  239. */
  240. $this->initRuleData();
  241. foreach ($order->getItemsCollection(
  242. array_keys(Mage::getConfig()->getNode('adminhtml/sales/order/create/available_product_types')->asArray()),
  243. true
  244. ) as $orderItem) {
  245. /* @var $orderItem Mage_Sales_Model_Order_Item */
  246. if (!$orderItem->getParentItem()) {
  247. if ($order->getReordered()) {
  248. $qty = $orderItem->getQtyOrdered();
  249. } else {
  250. $qty = $orderItem->getQtyOrdered() - $orderItem->getQtyShipped() - $orderItem->getQtyInvoiced();
  251. }
  252. if ($qty > 0) {
  253. $item = $this->initFromOrderItem($orderItem, $qty);
  254. if (is_string($item)) {
  255. Mage::throwException($item);
  256. }
  257. }
  258. }
  259. }
  260. $this->_initBillingAddressFromOrder($order);
  261. $this->_initShippingAddressFromOrder($order);
  262. $this->setShippingMethod($order->getShippingMethod());
  263. $this->getQuote()->getShippingAddress()->setShippingDescription($order->getShippingDescription());
  264. $this->getQuote()->getPayment()->addData($order->getPayment()->getData());
  265. $orderCouponCode = $order->getCouponCode();
  266. if ($orderCouponCode) {
  267. $this->getQuote()->setCouponCode($orderCouponCode);
  268. }
  269. if ($this->getQuote()->getCouponCode()) {
  270. $this->getQuote()->collectTotals();
  271. }
  272. Mage::helper('core')->copyFieldset(
  273. 'sales_copy_order',
  274. 'to_edit',
  275. $order,
  276. $this->getQuote()
  277. );
  278. Mage::dispatchEvent('sales_convert_order_to_quote', array(
  279. 'order' => $order,
  280. 'quote' => $this->getQuote()
  281. ));
  282. if (!$order->getCustomerId()) {
  283. $this->getQuote()->setCustomerIsGuest(true);
  284. }
  285. if ($this->getSession()->getUseOldShippingMethod(true)) {
  286. /*
  287. * if we are making reorder or editing old order
  288. * we need to show old shipping as preselected
  289. * so for this we need to collect shipping rates
  290. */
  291. $this->collectShippingRates();
  292. } else {
  293. /*
  294. * if we are creating new order then we don't need to collect
  295. * shipping rates before customer hit appropriate button
  296. */
  297. $this->collectRates();
  298. }
  299. // Make collect rates when user click "Get shipping methods and rates" in order creating
  300. // $this->getQuote()->getShippingAddress()->setCollectShippingRates(true);
  301. // $this->getQuote()->getShippingAddress()->collectShippingRates();
  302. $this->getQuote()->save();
  303. return $this;
  304. }
  305. protected function _initBillingAddressFromOrder(Mage_Sales_Model_Order $order)
  306. {
  307. $this->getQuote()->getBillingAddress()->setCustomerAddressId('');
  308. Mage::helper('core')->copyFieldset(
  309. 'sales_copy_order_billing_address',
  310. 'to_order',
  311. $order->getBillingAddress(),
  312. $this->getQuote()->getBillingAddress()
  313. );
  314. }
  315. protected function _initShippingAddressFromOrder(Mage_Sales_Model_Order $order)
  316. {
  317. $this->getQuote()->getShippingAddress()->setCustomerAddressId('');
  318. Mage::helper('core')->copyFieldset(
  319. 'sales_copy_order_shipping_address',
  320. 'to_order',
  321. $order->getShippingAddress(),
  322. $this->getQuote()->getShippingAddress()
  323. );
  324. }
  325. /**
  326. * Initialize creation data from existing order Item
  327. *
  328. * @param Mage_Sales_Model_Order_Item $orderItem
  329. * @param int $qty
  330. * @return Mage_Sales_Model_Quote_Item | string
  331. */
  332. public function initFromOrderItem(Mage_Sales_Model_Order_Item $orderItem, $qty = null)
  333. {
  334. if (!$orderItem->getId()) {
  335. return $this;
  336. }
  337. $product = Mage::getModel('catalog/product')
  338. ->setStoreId($this->getSession()->getStoreId())
  339. ->load($orderItem->getProductId());
  340. if ($product->getId()) {
  341. $product->setSkipCheckRequiredOption(true);
  342. $buyRequest = $orderItem->getBuyRequest();
  343. if (is_numeric($qty)) {
  344. $buyRequest->setQty($qty);
  345. }
  346. $item = $this->getQuote()->addProduct($product, $buyRequest);
  347. if (is_string($item)) {
  348. return $item;
  349. }
  350. if ($additionalOptions = $orderItem->getProductOptionByCode('additional_options')) {
  351. $item->addOption(new Varien_Object(
  352. array(
  353. 'product' => $item->getProduct(),
  354. 'code' => 'additional_options',
  355. 'value' => serialize($additionalOptions)
  356. )
  357. ));
  358. }
  359. Mage::dispatchEvent('sales_convert_order_item_to_quote_item', array(
  360. 'order_item' => $orderItem,
  361. 'quote_item' => $item
  362. ));
  363. return $item;
  364. }
  365. return $this;
  366. }
  367. /**
  368. * Retrieve customer wishlist model object
  369. *
  370. * @params bool $cacheReload pass cached wishlist object and get new one
  371. * @return Mage_Wishlist_Model_Wishlist
  372. */
  373. public function getCustomerWishlist($cacheReload = false)
  374. {
  375. if (!is_null($this->_wishlist) && !$cacheReload) {
  376. return $this->_wishlist;
  377. }
  378. if ($this->getSession()->getCustomer()->getId()) {
  379. $this->_wishlist = Mage::getModel('wishlist/wishlist')->loadByCustomer(
  380. $this->getSession()->getCustomer(), true
  381. );
  382. $this->_wishlist->setStore($this->getSession()->getStore())
  383. ->setSharedStoreIds($this->getSession()->getStore()->getWebsite()->getStoreIds());
  384. } else {
  385. $this->_wishlist = false;
  386. }
  387. return $this->_wishlist;
  388. }
  389. /**
  390. * Retrieve customer cart quote object model
  391. *
  392. * @return Mage_Sales_Model_Quote
  393. */
  394. public function getCustomerCart()
  395. {
  396. if (!is_null($this->_cart)) {
  397. return $this->_cart;
  398. }
  399. $this->_cart = Mage::getModel('sales/quote');
  400. if ($this->getSession()->getCustomer()->getId()) {
  401. $this->_cart->setStore($this->getSession()->getStore())
  402. ->loadByCustomer($this->getSession()->getCustomer()->getId());
  403. if (!$this->_cart->getId()) {
  404. $this->_cart->assignCustomer($this->getSession()->getCustomer());
  405. $this->_cart->save();
  406. }
  407. }
  408. return $this->_cart;
  409. }
  410. /**
  411. * Retrieve customer compare list model object
  412. *
  413. * @return Mage_Catalog_Model_Product_Compare_List
  414. */
  415. public function getCustomerCompareList()
  416. {
  417. if (!is_null($this->_compareList)) {
  418. return $this->_compareList;
  419. }
  420. if ($this->getSession()->getCustomer()->getId()) {
  421. $this->_compareList = Mage::getModel('catalog/product_compare_list');
  422. } else {
  423. $this->_compareList = false;
  424. }
  425. return $this->_compareList;
  426. }
  427. public function getCustomerGroupId()
  428. {
  429. $groupId = $this->getQuote()->getCustomerGroupId();
  430. if (!$groupId) {
  431. $groupId = $this->getSession()->getCustomerGroupId();
  432. }
  433. return $groupId;
  434. }
  435. /**
  436. * Move quote item to another items list
  437. *
  438. * @param int|Mage_Sales_Model_Quote_Item $item
  439. * @param string $moveTo
  440. * @param int $qty
  441. * @return Mage_Adminhtml_Model_Sales_Order_Create
  442. */
  443. public function moveQuoteItem($item, $moveTo, $qty)
  444. {
  445. $item = $this->_getQuoteItem($item);
  446. if ($item) {
  447. $removeItem = false;
  448. switch ($moveTo) {
  449. case 'order':
  450. $info = $item->getBuyRequest();
  451. $info->setOptions($this->_prepareOptionsForRequest($item))
  452. ->setQty($qty);
  453. $product = Mage::getModel('catalog/product')
  454. ->setStoreId($this->getQuote()->getStoreId())
  455. ->load($item->getProduct()->getId());
  456. $product->setSkipCheckRequiredOption(true);
  457. $newItem = $this->getQuote()->addProduct($product, $info);
  458. if (is_string($newItem)) {
  459. Mage::throwException($newItem);
  460. }
  461. $product->unsSkipCheckRequiredOption();
  462. $newItem->checkData();
  463. $this->_needCollectCart = true;
  464. break;
  465. case 'cart':
  466. $cart = $this->getCustomerCart();
  467. if ($cart && is_null($item->getOptionByCode('additional_options'))) {
  468. //options and info buy request
  469. $product = Mage::getModel('catalog/product')
  470. ->setStoreId($this->getQuote()->getStoreId())
  471. ->load($item->getProduct()->getId());
  472. $info = $item->getOptionByCode('info_buyRequest');
  473. if ($info) {
  474. $info = new Varien_Object(
  475. unserialize($info->getValue())
  476. );
  477. $info->setQty($qty);
  478. $info->setOptions($this->_prepareOptionsForRequest($item));
  479. } else {
  480. $info = new Varien_Object(array(
  481. 'product_id' => $product->getId(),
  482. 'qty' => $qty,
  483. 'options' => $this->_prepareOptionsForRequest($item)
  484. ));
  485. }
  486. $cartItem = $cart->addProduct($product, $info);
  487. if (is_string($cartItem)) {
  488. Mage::throwException($cartItem);
  489. }
  490. $cartItem->setPrice($item->getProduct()->getPrice());
  491. $this->_needCollectCart = true;
  492. $removeItem = true;
  493. }
  494. break;
  495. case 'wishlist':
  496. $wishlist = $this->getCustomerWishlist();
  497. if ($wishlist && $item->getProduct()->isVisibleInSiteVisibility()) {
  498. $info = $item->getBuyRequest();
  499. $info->setOptions($this->_prepareOptionsForRequest($item))
  500. ->setQty($qty)
  501. ->setStoreId($this->getSession()->getStoreId());
  502. $wishlist->addNewItem($item->getProduct(), $info);
  503. $removeItem = true;
  504. }
  505. break;
  506. case 'remove':
  507. $removeItem = true;
  508. break;
  509. default:
  510. break;
  511. }
  512. if ($removeItem) {
  513. $this->getQuote()->removeItem($item->getId());
  514. }
  515. $this->setRecollect(true);
  516. }
  517. return $this;
  518. }
  519. /**
  520. * Handle data sent from sidebar
  521. *
  522. * @param array $data
  523. * @return Mage_Adminhtml_Model_Sales_Order_Create
  524. */
  525. public function applySidebarData($data)
  526. {
  527. if (isset($data['add_order_item'])) {
  528. foreach ($data['add_order_item'] as $orderItemId => $value) {
  529. /* @var $orderItem Mage_Sales_Model_Order_Item */
  530. $orderItem = Mage::getModel('sales/order_item')->load($orderItemId);
  531. $item = $this->initFromOrderItem($orderItem);
  532. if (is_string($item)) {
  533. Mage::throwException($item);
  534. }
  535. }
  536. }
  537. if (isset($data['add_cart_item'])) {
  538. foreach ($data['add_cart_item'] as $itemId => $qty) {
  539. $item = $this->getCustomerCart()->getItemById($itemId);
  540. if ($item) {
  541. $this->moveQuoteItem($item, 'order', $qty);
  542. $this->removeItem($itemId, 'cart');
  543. }
  544. }
  545. }
  546. if (isset($data['add_wishlist_item'])) {
  547. foreach ($data['add_wishlist_item'] as $itemId => $qty) {
  548. $item = Mage::getModel('wishlist/item')
  549. ->loadWithOptions($itemId, 'info_buyRequest');
  550. if ($item->getId()) {
  551. $this->addProduct($item->getProduct(), $item->getBuyRequest()->toArray());
  552. }
  553. }
  554. }
  555. if (isset($data['add'])) {
  556. foreach ($data['add'] as $productId => $qty) {
  557. $this->addProduct($productId, array('qty' => $qty));
  558. }
  559. }
  560. if (isset($data['remove'])) {
  561. foreach ($data['remove'] as $itemId => $from) {
  562. $this->removeItem($itemId, $from);
  563. }
  564. }
  565. return $this;
  566. }
  567. /**
  568. * Remove item from some of customer items storage (shopping cart, wishlist etc.)
  569. *
  570. * @param int $itemId
  571. * @param string $from
  572. * @return Mage_Adminhtml_Model_Sales_Order_Create
  573. */
  574. public function removeItem($itemId, $from)
  575. {
  576. switch ($from) {
  577. case 'quote':
  578. $this->removeQuoteItem($itemId);
  579. break;
  580. case 'cart':
  581. if ($cart = $this->getCustomerCart()) {
  582. $cart->removeItem($itemId);
  583. $cart->collectTotals()
  584. ->save();
  585. }
  586. break;
  587. case 'wishlist':
  588. if ($wishlist = $this->getCustomerWishlist()) {
  589. $item = Mage::getModel('wishlist/item')->load($itemId);
  590. $item->delete();
  591. }
  592. break;
  593. case 'compared':
  594. $item = Mage::getModel('catalog/product_compare_item')
  595. ->load($itemId)
  596. ->delete();
  597. break;
  598. }
  599. return $this;
  600. }
  601. /**
  602. * Remove quote item
  603. *
  604. * @param int $item
  605. * @return Mage_Adminhtml_Model_Sales_Order_Create
  606. */
  607. public function removeQuoteItem($item)
  608. {
  609. $this->getQuote()->removeItem($item);
  610. $this->setRecollect(true);
  611. return $this;
  612. }
  613. /**
  614. * Add product to current order quote
  615. * $product can be either product id or product model
  616. * $config can be either buyRequest config, or just qty
  617. *
  618. * @param int|Mage_Catalog_Model_Product $product
  619. * @param float|array|Varien_Object $config
  620. * @return Mage_Adminhtml_Model_Sales_Order_Create
  621. */
  622. public function addProduct($product, $config = 1)
  623. {
  624. if (!is_array($config) && !($config instanceof Varien_Object)) {
  625. $config = array('qty' => $config);
  626. }
  627. $config = new Varien_Object($config);
  628. if (!($product instanceof Mage_Catalog_Model_Product)) {
  629. $productId = $product;
  630. $product = Mage::getModel('catalog/product')
  631. ->setStore($this->getSession()->getStore())
  632. ->setStoreId($this->getSession()->getStoreId())
  633. ->load($product);
  634. if (!$product->getId()) {
  635. Mage::throwException(
  636. Mage::helper('adminhtml')->__('Failed to add a product to cart by id "%s".', $productId)
  637. );
  638. }
  639. }
  640. $stockItem = $product->getStockItem();
  641. if ($stockItem && $stockItem->getIsQtyDecimal()) {
  642. $product->setIsQtyDecimal(1);
  643. }
  644. $product->setCartQty($config->getQty());
  645. $item = $this->getQuote()->addProductAdvanced(
  646. $product,
  647. $config,
  648. Mage_Catalog_Model_Product_Type_Abstract::PROCESS_MODE_FULL
  649. );
  650. if (is_string($item)) {
  651. if ($product->getTypeId() != Mage_Catalog_Model_Product_Type_Grouped::TYPE_CODE) {
  652. $item = $this->getQuote()->addProductAdvanced(
  653. $product,
  654. $config,
  655. Mage_Catalog_Model_Product_Type_Abstract::PROCESS_MODE_LITE
  656. );
  657. }
  658. if (is_string($item)) {
  659. Mage::throwException($item);
  660. }
  661. }
  662. $item->checkData();
  663. $this->setRecollect(true);
  664. return $this;
  665. }
  666. /**
  667. * Add multiple products to current order quote
  668. *
  669. * @param array $products
  670. * @return Mage_Adminhtml_Model_Sales_Order_Create|Exception
  671. */
  672. public function addProducts(array $products)
  673. {
  674. foreach ($products as $productId => $config) {
  675. $config['qty'] = isset($config['qty']) ? (float)$config['qty'] : 1;
  676. try {
  677. $this->addProduct($productId, $config);
  678. }
  679. catch (Mage_Core_Exception $e){
  680. $this->getSession()->addError($e->getMessage());
  681. }
  682. catch (Exception $e){
  683. return $e;
  684. }
  685. }
  686. return $this;
  687. }
  688. /**
  689. * Update quantity of order quote items
  690. *
  691. * @param array $data
  692. * @return Mage_Adminhtml_Model_Sales_Order_Create
  693. */
  694. public function updateQuoteItems($data)
  695. {
  696. if (is_array($data)) {
  697. try {
  698. foreach ($data as $itemId => $info) {
  699. if (!empty($info['configured'])) {
  700. $item = $this->getQuote()->updateItem($itemId, new Varien_Object($info));
  701. $itemQty = (float)$item->getQty();
  702. } else {
  703. $item = $this->getQuote()->getItemById($itemId);
  704. $itemQty = (float)$info['qty'];
  705. }
  706. if ($item) {
  707. if ($item->getProduct()->getStockItem()) {
  708. if (!$item->getProduct()->getStockItem()->getIsQtyDecimal()) {
  709. $itemQty = (int)$itemQty;
  710. } else {
  711. $item->setIsQtyDecimal(1);
  712. }
  713. }
  714. $itemQty = $itemQty > 0 ? $itemQty : 1;
  715. if (isset($info['custom_price'])) {
  716. $itemPrice = $this->_parseCustomPrice($info['custom_price']);
  717. } else {
  718. $itemPrice = null;
  719. }
  720. $noDiscount = !isset($info['use_discount']);
  721. if (empty($info['action']) || !empty($info['configured'])) {
  722. $item->setQty($itemQty);
  723. $item->setCustomPrice($itemPrice);
  724. $item->setOriginalCustomPrice($itemPrice);
  725. $item->setNoDiscount($noDiscount);
  726. $item->getProduct()->setIsSuperMode(true);
  727. $item->getProduct()->unsSkipCheckRequiredOption();
  728. $item->checkData();
  729. } else {
  730. $this->moveQuoteItem($item->getId(), $info['action'], $itemQty);
  731. }
  732. }
  733. }
  734. } catch (Mage_Core_Exception $e) {
  735. $this->recollectCart();
  736. throw $e;
  737. } catch (Exception $e) {
  738. Mage::logException($e);
  739. }
  740. $this->recollectCart();
  741. }
  742. return $this;
  743. }
  744. /**
  745. * Parse additional options and sync them with product options
  746. *
  747. * @param Mage_Sales_Model_Quote_Item $product
  748. * @param array $options
  749. */
  750. protected function _parseOptions(Mage_Sales_Model_Quote_Item $item, $additionalOptions)
  751. {
  752. $productOptions = Mage::getSingleton('catalog/product_option_type_default')
  753. ->setProduct($item->getProduct())
  754. ->getProductOptions();
  755. $newOptions = array();
  756. $newAdditionalOptions = array();
  757. foreach (explode("\n", $additionalOptions) as $_additionalOption) {
  758. if (strlen(trim($_additionalOption))) {
  759. try {
  760. if (strpos($_additionalOption, ':') === false) {
  761. Mage::throwException(
  762. Mage::helper('adminhtml')->__('There is an error in one of the option rows.')
  763. );
  764. }
  765. list($label,$value) = explode(':', $_additionalOption, 2);
  766. } catch (Exception $e) {
  767. Mage::throwException(Mage::helper('adminhtml')->__('There is an error in one of the option rows.'));
  768. }
  769. $label = trim($label);
  770. $value = trim($value);
  771. if (empty($value)) {
  772. continue;
  773. }
  774. if (array_key_exists($label, $productOptions)) {
  775. $optionId = $productOptions[$label]['option_id'];
  776. $option = $item->getProduct()->getOptionById($optionId);
  777. $group = Mage::getSingleton('catalog/product_option')->groupFactory($option->getType())
  778. ->setOption($option)
  779. ->setProduct($item->getProduct());
  780. $parsedValue = $group->parseOptionValue($value, $productOptions[$label]['values']);
  781. if ($parsedValue !== null) {
  782. $newOptions[$optionId] = $parsedValue;
  783. } else {
  784. $newAdditionalOptions[] = array(
  785. 'label' => $label,
  786. 'value' => $value
  787. );
  788. }
  789. } else {
  790. $newAdditionalOptions[] = array(
  791. 'label' => $label,
  792. 'value' => $value
  793. );
  794. }
  795. }
  796. }
  797. return array(
  798. 'options' => $newOptions,
  799. 'additional_options' => $newAdditionalOptions
  800. );
  801. }
  802. /**
  803. * Assign options to item
  804. *
  805. * @param Mage_Sales_Model_Quote_Item $item
  806. * @param array $options
  807. */
  808. protected function _assignOptionsToItem(Mage_Sales_Model_Quote_Item $item, $options)
  809. {
  810. if ($optionIds = $item->getOptionByCode('option_ids')) {
  811. foreach (explode(',', $optionIds->getValue()) as $optionId) {
  812. $item->removeOption('option_'.$optionId);
  813. }
  814. $item->removeOption('option_ids');
  815. }
  816. if ($item->getOptionByCode('additional_options')) {
  817. $item->removeOption('additional_options');
  818. }
  819. $item->save();
  820. if (!empty($options['options'])) {
  821. $item->addOption(new Varien_Object(
  822. array(
  823. 'product' => $item->getProduct(),
  824. 'code' => 'option_ids',
  825. 'value' => implode(',', array_keys($options['options']))
  826. )
  827. ));
  828. foreach ($options['options'] as $optionId => $optionValue) {
  829. $item->addOption(new Varien_Object(
  830. array(
  831. 'product' => $item->getProduct(),
  832. 'code' => 'option_'.$optionId,
  833. 'value' => $optionValue
  834. )
  835. ));
  836. }
  837. }
  838. if (!empty($options['additional_options'])) {
  839. $item->addOption(new Varien_Object(
  840. array(
  841. 'product' => $item->getProduct(),
  842. 'code' => 'additional_options',
  843. 'value' => serialize($options['additional_options'])
  844. )
  845. ));
  846. }
  847. return $this;
  848. }
  849. /**
  850. * Prepare options array for info buy request
  851. *
  852. * @param Mage_Sales_Model_Quote_Item $item
  853. * @return array
  854. */
  855. protected function _prepareOptionsForRequest($item)
  856. {
  857. $newInfoOptions = array();
  858. if ($optionIds = $item->getOptionByCode('option_ids')) {
  859. foreach (explode(',', $optionIds->getValue()) as $optionId) {
  860. $option = $item->getProduct()->getOptionById($optionId);
  861. $optionValue = $item->getOptionByCode('option_'.$optionId)->getValue();
  862. $group = Mage::getSingleton('catalog/product_option')->groupFactory($option->getType())
  863. ->setOption($option)
  864. ->setQuoteItem($item);
  865. $newInfoOptions[$optionId] = $group->prepareOptionValueForRequest($optionValue);
  866. }
  867. }
  868. return $newInfoOptions;
  869. }
  870. protected function _parseCustomPrice($price)
  871. {
  872. $price = Mage::app()->getLocale()->getNumber($price);
  873. $price = $price>0 ? $price : 0;
  874. return $price;
  875. }
  876. /**
  877. * Retrieve oreder quote shipping address
  878. *
  879. * @return Mage_Sales_Model_Quote_Address
  880. */
  881. public function getShippingAddress()
  882. {
  883. return $this->getQuote()->getShippingAddress();
  884. }
  885. /**
  886. * Return Customer (Checkout) Form instance
  887. *
  888. * @return Mage_Customer_Model_Form
  889. */
  890. protected function _getCustomerForm()
  891. {
  892. if (is_null($this->_customerForm)) {
  893. $this->_customerForm = Mage::getModel('customer/form')
  894. ->setFormCode('adminhtml_checkout')
  895. ->ignoreInvisible(false);
  896. }
  897. return $this->_customerForm;
  898. }
  899. /**
  900. * Return Customer Address Form instance
  901. *
  902. * @return Mage_Customer_Model_Form
  903. */
  904. protected function _getCustomerAddressForm()
  905. {
  906. if (is_null($this->_customerAddressForm)) {
  907. $this->_customerAddressForm = Mage::getModel('customer/form')
  908. ->setFormCode('adminhtml_customer_address')
  909. ->ignoreInvisible(false);
  910. }
  911. return $this->_customerAddressForm;
  912. }
  913. /**
  914. * Set and validate Quote address
  915. * All errors added to _errors
  916. *
  917. * @param Mage_Sales_Model_Quote_Address $address
  918. * @param array $data
  919. * @return Mage_Adminhtml_Model_Sales_Order_Create
  920. */
  921. protected function _setQuoteAddress(Mage_Sales_Model_Quote_Address $address, array $data)
  922. {
  923. $addressForm = $this->_getCustomerAddressForm()
  924. ->setEntity($address)
  925. ->setEntityType(Mage::getSingleton('eav/config')->getEntityType('customer_address'))
  926. ->setIsAjaxRequest(!$this->getIsValidate());
  927. // prepare request
  928. // save original request structure for files
  929. if ($address->getAddressType() == Mage_Sales_Model_Quote_Address::TYPE_SHIPPING) {
  930. $requestData = array('order' => array('shipping_address' => $data));
  931. $requestScope = 'order/shipping_address';
  932. } else {
  933. $requestData = array('order' => array('billing_address' => $data));
  934. $requestScope = 'order/billing_address';
  935. }
  936. $request = $addressForm->prepareRequest($requestData);
  937. $addressData = $addressForm->extractData($request, $requestScope);
  938. if ($this->getIsValidate()) {
  939. $errors = $addressForm->validateData($addressData);
  940. if ($errors !== true) {
  941. if ($address->getAddressType() == Mage_Sales_Model_Quote_Address::TYPE_SHIPPING) {
  942. $typeName = Mage::helper('adminhtml')->__('Shipping Address: ');
  943. } else {
  944. $typeName = Mage::helper('adminhtml')->__('Billing Address: ');
  945. }
  946. foreach ($errors as $error) {
  947. $this->_errors[] = $typeName . $error;
  948. }
  949. $addressForm->restoreData($addressData);
  950. } else {
  951. $addressForm->compactData($addressData);
  952. }
  953. } else {
  954. $addressForm->restoreData($addressData);
  955. }
  956. return $this;
  957. }
  958. public function setShippingAddress($address)
  959. {
  960. if (is_array($address)) {
  961. $address['save_in_address_book'] = isset($address['save_in_address_book'])
  962. && !empty($address['save_in_address_book']);
  963. $shippingAddress = Mage::getModel('sales/quote_address')
  964. ->setData($address)
  965. ->setAddressType(Mage_Sales_Model_Quote_Address::TYPE_SHIPPING);
  966. if (!$this->getQuote()->isVirtual()) {
  967. $this->_setQuoteAddress($shippingAddress, $address);
  968. }
  969. $shippingAddress->implodeStreetAddress();
  970. }
  971. if ($address instanceof Mage_Sales_Model_Quote_Address) {
  972. $shippingAddress = $address;
  973. }
  974. $this->setRecollect(true);
  975. $this->getQuote()->setShippingAddress($shippingAddress);
  976. return $this;
  977. }
  978. public function setShippingAsBilling($flag)
  979. {
  980. if ($flag) {
  981. $tmpAddress = clone $this->getBillingAddress();
  982. $tmpAddress->unsAddressId()
  983. ->unsAddressType();
  984. $this->getShippingAddress()->addData($tmpAddress->getData());
  985. }
  986. $this->getShippingAddress()->setSameAsBilling($flag);
  987. $this->setRecollect(true);
  988. return $this;
  989. }
  990. /**
  991. * Retrieve quote billing address
  992. *
  993. * @return Mage_Sales_Model_Quote_Address
  994. */
  995. public function getBillingAddress()
  996. {
  997. return $this->getQuote()->getBillingAddress();
  998. }
  999. public function setBillingAddress($address)
  1000. {
  1001. if (is_array($address)) {
  1002. $address['save_in_address_book'] = isset($address['save_in_address_book']) ? 1 : 0;
  1003. $billingAddress = Mage::getModel('sales/quote_address')
  1004. ->setData($address)
  1005. ->setAddressType(Mage_Sales_Model_Quote_Address::TYPE_BILLING);
  1006. $this->_setQuoteAddress($billingAddress, $address);
  1007. $billingAddress->implodeStreetAddress();
  1008. }
  1009. if ($this->getShippingAddress()->getSameAsBilling()) {
  1010. $shippingAddress = clone $billingAddress;
  1011. $shippingAddress->setSameAsBilling(true);
  1012. $shippingAddress->setSaveInAddressBook(false);
  1013. $address['save_in_address_book'] = 0;
  1014. $this->setShippingAddress($address);
  1015. }
  1016. $this->getQuote()->setBillingAddress($billingAddress);
  1017. return $this;
  1018. }
  1019. public function setShippingMethod($method)
  1020. {
  1021. $this->getShippingAddress()->setShippingMethod($method);
  1022. $this->setRecollect(true);
  1023. return $this;
  1024. }
  1025. public function resetShippingMethod()
  1026. {
  1027. $this->getShippingAddress()->setShippingMethod(false);
  1028. $this->getShippingAddress()->removeAllShippingRates();
  1029. return $this;
  1030. }
  1031. /**
  1032. * Collect shipping data for quote shipping address
  1033. */
  1034. public function collectShippingRates()
  1035. {
  1036. $this->getQuote()->getShippingAddress()->setCollectShippingRates(true);
  1037. $this->collectRates();
  1038. return $this;
  1039. }
  1040. public function collectRates()
  1041. {
  1042. $this->getQuote()->collectTotals();
  1043. }
  1044. public function setPaymentMethod($method)
  1045. {
  1046. $this->getQuote()->getPayment()->setMethod($method);
  1047. return $this;
  1048. }
  1049. public function setPaymentData($data)
  1050. {
  1051. if (!isset($data['method'])) {
  1052. $data['method'] = $this->getQuote()->getPayment()->getMethod();
  1053. }
  1054. $this->getQuote()->getPayment()->importData($data);
  1055. return $this;
  1056. }
  1057. public function applyCoupon($code)
  1058. {
  1059. $code = trim((string)$code);
  1060. $this->getQuote()->setCouponCode($code);
  1061. $this->setRecollect(true);
  1062. return $this;
  1063. }
  1064. public function setAccountData($accountData)
  1065. {
  1066. $customer = $this->getQuote()->getCustomer();
  1067. $form = $this->_getCustomerForm();
  1068. $form->setEntity($customer);
  1069. // emulate request
  1070. $request = $form->prepareRequest($accountData);
  1071. $data = $form->extractData($request);
  1072. $form->restoreData($data);
  1073. $data = array();
  1074. foreach ($form->getAttributes() as $attribute) {
  1075. $code = sprintf('customer_%s', $attribute->getAttributeCode());
  1076. $data[$code] = $customer->getData($attribute->getAttributeCode());
  1077. }
  1078. if (isset($data['customer_group_id'])) {
  1079. $groupModel = Mage::getModel('customer/group')->load($data['customer_group_id']);
  1080. $data['customer_tax_class_id'] = $groupModel->getTaxClassId();
  1081. $this->setRecollect(true);
  1082. }
  1083. $this->getQuote()->addData($data);
  1084. return $this;
  1085. }
  1086. /**
  1087. * Parse data retrieved from request
  1088. *
  1089. * @param array $data
  1090. * @return Mage_Adminhtml_Model_Sales_Order_Create
  1091. */
  1092. public function importPostData($data)
  1093. {
  1094. if (is_array($data)) {
  1095. $this->addData($data);
  1096. } else {
  1097. return $this;
  1098. }
  1099. if (isset($data['account'])) {
  1100. $this->setAccountData($data['account']);
  1101. }
  1102. if (isset($data['comment'])) {
  1103. $this->getQuote()->addData($data['comment']);
  1104. if (empty($data['comment']['customer_note_notify'])) {
  1105. $this->getQuote()->setCustomerNoteNotify(false);
  1106. } else {
  1107. $this->getQuote()->setCustomerNoteNotify(true);
  1108. }
  1109. }
  1110. if (isset($data['billing_address'])) {
  1111. $this->setBillingAddress($data['billing_address']);
  1112. }
  1113. if (isset($data['shipping_address'])) {
  1114. $this->setShippingAddress($data['shipping_address']);
  1115. }
  1116. if (isset($data['shipping_method'])) {
  1117. $this->setShippingMethod($data['shipping_method']);
  1118. }
  1119. if (isset($data['payment_method'])) {
  1120. $this->setPaymentMethod($data['payment_method']);
  1121. }
  1122. if (isset($data['coupon']['code'])) {
  1123. $this->applyCoupon($data['coupon']['code']);
  1124. }
  1125. return $this;
  1126. }
  1127. /**
  1128. * Check whether we need to create new customer (for another website) during order creation
  1129. *
  1130. * @param Mage_Core_Model_Store $store
  1131. * @return boolean
  1132. */
  1133. protected function _customerIsInStore($store)
  1134. {
  1135. $customer = $this->getSession()->getCustomer();
  1136. if ($customer->getWebsiteId() == $store->getWebsiteId()) {
  1137. return true;
  1138. }
  1139. return $customer->isInStore($store);
  1140. }
  1141. /**
  1142. * Set and validate Customer data
  1143. *
  1144. * @param Mage_Customer_Model_Customer $customer
  1145. * @return Mage_Adminhtml_Model_Sales_Order_Create
  1146. */
  1147. protected function _setCustomerData(Mage_Customer_Model_Customer $customer)
  1148. {
  1149. $form = $this->_getCustomerForm();
  1150. $form->setEntity($customer);
  1151. // emulate request
  1152. $request = $form->prepareRequest(array('order' => $this->getData()));
  1153. $data = $form->extractData($request, 'order/account');
  1154. if ($this->getIsValidate()) {
  1155. $errors = $form->validateData($data);
  1156. if ($errors !== true) {
  1157. foreach ($errors as $error) {
  1158. $this->_errors[] = $error;
  1159. }
  1160. $form->restoreData($data);
  1161. } else {
  1162. $form->compactData($data);
  1163. }
  1164. } else {
  1165. $form->restoreData($data);
  1166. }
  1167. return $this;
  1168. }
  1169. /**
  1170. * Prepare quote customer
  1171. */
  1172. public function _prepareCustomer()
  1173. {
  1174. $quote = $this->getQuote();
  1175. if ($quote->getCustomerIsGuest()) {
  1176. return $this;
  1177. }
  1178. $customer = $this->getSession()->getCustomer();
  1179. $store = $this->getSession()->getStore();
  1180. $customerIsInStore = $this->_customerIsInStore($store);
  1181. $billingAddress = null;
  1182. $shippingAddress = null;
  1183. if ($customer->getId()) {
  1184. if (!$customerIsInStore) {
  1185. $customer->setId(null)
  1186. ->setStore($store)
  1187. ->setDefaultBilling(null)
  1188. ->setDefaultShipping(null)
  1189. ->setPassword($customer->generatePassword());
  1190. $this->_setCustomerData($customer);
  1191. }
  1192. if ($this->getBillingAddress()->getSaveInAddressBook() || !$customerIsInStore) {
  1193. $billingAddress = $this->getBillingAddress()->exportCustomerAddress();
  1194. $customerAddressId = $this->getBillingAddress()->getCustomerAddressId();
  1195. if ($customerAddressId && $customer->getId()) {
  1196. $customer->getAddressItemById($customerAddressId)->addData($billingAddress->getData());
  1197. } else {
  1198. $customer->addAddress($billingAddress);
  1199. }
  1200. }
  1201. if (!$this->getQuote()->isVirtual() && ($this->getShippingAddress()->getSaveInAddressBook()
  1202. || !$customerIsInStore)
  1203. ) {
  1204. $shippingAddress = $this->getShippingAddress()->exportCustomerAddress();
  1205. $customerAddressId = $this->getShippingAddress()->getCustomerAddressId();
  1206. if ($customerAddressId && $customer->getId()) {
  1207. $customer->getAddressItemById($customerAddressId)->addData($shippingAddress->getData());
  1208. } elseif ($billingAddress !== null
  1209. && $this->getBillingAddress()->getCustomerAddressId() == $customerAddressId
  1210. ) {
  1211. $billingAddress->setIsDefaultShipping(true);
  1212. } else {
  1213. $customer->addAddress($shippingAddress);
  1214. }
  1215. }
  1216. if (is_null($customer->getDefaultBilling()) && $billingAddress) {
  1217. $billingAddress->setIsDefaultBilling(true);
  1218. }
  1219. if (is_null($customer->getDefaultShipping())) {
  1220. if ($this->getShippingAddress()->getSameAsBilling() && $billingAddress) {
  1221. $billingAddress->setIsDefaultShipping(true);
  1222. } elseif ($shippingAddress) {
  1223. $shippingAddress->setIsDefaultShipping(true);
  1224. }
  1225. }
  1226. } else {
  1227. $customer->addData($this->getBillingAddress()->exportCustomerAddress()->getData())
  1228. ->setPassword($customer->generatePassword())
  1229. ->setStore($store);
  1230. $customer->setEmail($this->_getNewCustomerEmail($customer));
  1231. $this->_setCustomerData($customer);
  1232. $customerBilling = $this->getBillingAddress()->exportCustomerAddress();
  1233. $customerBilling->setIsDefaultBilling(true);
  1234. $customer->addAddress($customerBilling);
  1235. $shipping = $this->getShippingAddress();
  1236. if (!$this->getQuote()->isVirtual() && !$shipping->getSameAsBilling()) {
  1237. $customerShipping = $shipping->exportCustomerAddress();
  1238. $customerShipping->setIsDefaultShipping(true);
  1239. $customer->addAddress($customerShipping);
  1240. } else {
  1241. $customerBilling->setIsDefaultShipping(true);
  1242. }
  1243. }
  1244. // set quote customer data to customer
  1245. $this->_setCustomerData($customer);
  1246. // set customer to quote and convert customer data to quote
  1247. $quote->setCustomer($customer);
  1248. // add user defined attributes to quote
  1249. $form = $this->_getCustomerForm()->setEntity($customer);
  1250. foreach ($form->getUserAttributes() as $attribute) {
  1251. $quoteCode = sprintf('customer_%s', $attribute->getAttributeCode());
  1252. $quote->setData($quoteCode, $customer->getData($attribute->getAttributeCode()));
  1253. }
  1254. if ($customer->getId()) {
  1255. // we should not change account data for existing customer, so restore it
  1256. $this->_getCustomerForm()
  1257. ->setEntity($customer)
  1258. ->resetEntityData();
  1259. } else {
  1260. $quote->setCustomerId(true);
  1261. }
  1262. return $this;
  1263. }
  1264. /**
  1265. * Prepare item otions
  1266. */
  1267. protected function _prepareQuoteItems()
  1268. {
  1269. foreach ($this->getQuote()->getAllItems() as $item) {
  1270. $options = array();
  1271. $productOptions = $item->getProduct()->getTypeInstance(true)->getOrderOptions($item->getProduct());
  1272. if ($productOptions) {
  1273. $productOptions['info_buyRequest']['options'] = $this->_prepareOptionsForRequest($item);
  1274. $options = $productOptions;
  1275. }
  1276. $addOptions = $item->getOptionByCode('additional_options');
  1277. if ($addOptions) {
  1278. $options['additional_options'] = unserialize($addOptions->getValue());
  1279. }
  1280. $item->setProductOrderOptions($options);
  1281. }
  1282. return $this;
  1283. }
  1284. /**
  1285. * Create new order
  1286. *
  1287. * @return Mage_Sales_Model_Order
  1288. */
  1289. public function createOrder()
  1290. {
  1291. $this->_prepareCustomer();
  1292. $this->_validate();
  1293. $quote = $this->getQuote();
  1294. $this->_prepareQuoteItems();
  1295. if (! $quote->getCustomer()->getId() || ! $quote->getCustomer()->isInStore($this->getSession()->getStore())) {
  1296. $quote->getCustomer()->sendNewAccountEmail('registered', '', $quote->getStoreId());
  1297. }
  1298. $service = Mage::getModel('sales/service_quote', $quote);
  1299. if ($this->getSession()->getOrder()->getId()) {
  1300. $oldOrder = $this->getSession()->getOrder();
  1301. $originalId = $oldOrder->getOriginalIncrementId();
  1302. if (!$originalId) {
  1303. $originalId = $oldOrder->getIncrementId();
  1304. }
  1305. $orderData = array(
  1306. 'original_increment_id' => $originalId,
  1307. 'relation_parent_id' => $oldOrder->getId(),
  1308. 'relation_parent_real_id' => $oldOrder->getIncrementId(),
  1309. 'edit_increment' => $oldOrder->getEditIncrement()+1,
  1310. 'increment_id' => $originalId.'-'.($oldOrder->getEditIncrement()+1)
  1311. );
  1312. $quote->setReservedOrderId($orderData['increment_id']);
  1313. $service->setOrderData($orderData);
  1314. }
  1315. $order = $service->submit();
  1316. if (!$quote->getCustomer()->getId() || !$quote->getCustomer()->isInStore($this->getSession()->getStore())) {
  1317. $quote->getCustomer()->setCreatedAt($order->getCreatedAt());
  1318. $quote->getCustomer()->save();
  1319. }
  1320. if ($this->getSession()->getOrder()->getId()) {
  1321. $oldOrder = $this->getSession()->getOrder();
  1322. $this->getSession()->getOrder()->setRelationChildId($order->getId());
  1323. $this->getSession()->getOrder()->setRelationChildRealId($order->getIncrementId());
  1324. $this->getSession()->getOrder()->cancel()
  1325. ->save();
  1326. $order->save();
  1327. }
  1328. if ($this->getSendConfirmation()) {
  1329. $order->sendNewOrderEmail();
  1330. }
  1331. Mage::dispatchEvent('checkout_submit_all_after', array('order' => $order, 'quote' => $quote));
  1332. return $order;

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