'Transaction ID is wrong' ); protected $_itemObj; /** * Return cart id * * @return int */ public function getCartId() { return $this->_getSessionCartId(); } /** * Return cart id for transaction * * @param int $id * @return int|bool */ public function getCartIdByTransaction($id) { return $this->_getTable()->searchBy(array('transactionId' => $id), 'id'); } /** * Return cart id from session * * @return int */ protected function _getSessionCartId() { $cartSession = $this->getSessionCartObject(); if (null === $cartSession->id || null !== $this->getTransactionId($cartSession->id)) { $auth = App_User_Auth::getInstance(); $options = array(); if ($auth->hasIdentity()) { $options['userId'] = $auth->getData('id'); } $cartSession->id = $this->create($options); } return $cartSession->id; } /** * Return cart object from session * * @return Qs_Session_Namespace */ public function getSessionCartObject() { return new Qs_Session_Namespace($this->_sessionNamespace); } public function getList($assocMode = false) { if (empty($this->_filter) && null !== Qs_Array::get(self::$_dataCache, 'list[' . intval($assocMode) . ']')) { return self::$_dataCache['list'][$assocMode]; } if (true === $assocMode) { $list = $this->_db->fetchAssoc($this->getListSelect()); } else { $list = $this->getListStatement()->fetchAll(); } $this->_prepareList($list); if (empty($this->_filter)) { self::$_dataCache['list'][$assocMode] = $list; } return $list; } protected function _clearSelect() { if (array_key_exists('list', self::$_dataCache)) { unset(self::$_dataCache['list']); } return parent::_clearSelect(); } public function updateNumbers($itemId, &$spec) { $itemId = (int) $itemId; $itemData = $this->_getTable('CartItem')->searchBy(array( 'cartId' => $this->getCartId(), 'id' => $itemId, )); if (false == $itemData) { return false; } $adapter = new Qs_File_Transfer_Adapter_Db(); if ($spec['removeFile'] !== 'y') { if ($itemData['numbersFile']) { $adapter->delete($itemData['numbersFile']); } if (isset($_FILES['numbersFile'])) { $itemData['numbersFile'] = $adapter->insertFile( $_FILES['numbersFile']['tmp_name'], $_FILES['numbersFile']['name'] ); //Enable reading for users chmod(urldecode(Qs_FileFs::get($itemData['numbersFile'])), 644); } } else { $adapter->delete($itemData['numbersFile']); $itemData['numbersFile'] = null; } $itemData['numbersText'] = $spec['numbersText']; $itemData['quantity'] = $spec['quantity']; return (bool) $this->_getTable('CartItem')->updateByKey($itemData, $itemId); } /** * Update item quantity * * @param int $itemId * @param int $qty * @param float $price * @param float $tax * @return bool * @throws Qs_Exception */ public function updateItemQty($itemId, $qty, $price = null, $tax = null, $numbersText = null, $numbersFile = null) { if (!filter_var($itemId, FILTER_VALIDATE_INT) || !filter_var($qty, FILTER_VALIDATE_INT)) { return false; } $itemData = $this->_getTable('CartItem')->searchBy(array('cartId' => $this->getPrimaryKey(), 'id' => $itemId)); if (false == $itemData) { return false; } if ($price === null || $tax === null) { $itemClass = 'App_' . $itemData['cartItemType'] . 'Obj'; if (class_exists($itemClass)) { /** @var App_ECommerce_Product_Obj $itemClassObj */ $itemClassObj = new $itemClass(); $itemClassObj->setPrimaryKey($itemData['productId']); if ($price === null) { $price = $itemClassObj->getData('price'); } if ($tax === null) { $tax = $itemClassObj->getData('tax'); } if ($numbersText === null) { $numbersText = $itemClassObj->getData('numbersText'); } if ($numbersFile === null) { $numbersFile = $itemClassObj->getData('numbersFile'); } } else { throw new Qs_Exception('Item class ' . $itemClass . ' not exist'); } } $data = array( 'quantity' => $qty, 'price' => $price, 'tax' => $tax, 'numbersText' => $numbersText, 'numbersFile' => $numbersFile ); return (bool) $this->_getTable('CartItem')->updateByKey($data, $itemId); } /** * Update transactionId field * * @param int $id * @return bool|Exception * @throws Qs_Exception */ public function updateTransactionId($id) { try { if (!empty($id)) { $this->_getTable()->updateByKey(array('transactionId' => $id), $this->getPrimaryKey()); } else { throw new Qs_Exception($this->_exceptionMap[self::EXCEPTION_TRANSACTION_ID_IS_WRONG]); } } catch (Exception $e) { return $e; } return true; } /** * Method will clean transactionId field * * @param int $id * @return bool|Exception * @throws Qs_Exception */ public function cancelTransaction($id) { try { if (!empty($id)) { $this->_getTable()->update(array('transactionId' => null), $this->_db->quoteInto('`transactionId` = ?', $id, Qs_Db::INT_TYPE) ); } else { throw new Qs_Exception($this->_exceptionMap[self::EXCEPTION_TRANSACTION_ID_IS_WRONG]); } } catch (Exception $e) { return $e; } return true; } public function setAccessCode($transactionId) { if (!empty($transactionId)) { $accessCode = App_ECommerce_Order_GuestView_Obj::generateAccessCode($transactionId); return $this->_getTable()->updateByKey(array('accessCode' => $accessCode), $this->getPrimaryKey()); } return false; } public function getRowPrice($itemId) { return Zend_Locale_Math::round($this->getRowData($itemId, 'price'), 2); } /** * Return total price for one cart item * * @param int $itemId * @return string */ public function getRowTotal($itemId) { return Zend_Locale_Math::round($this->getRowData($itemId, 'rowTotal'), 2); } public function getRowData($itemId, $field = null) { $select = clone $this->getListSelect(); $select->where('`CartItem`.`id` = ?', $itemId, Qs_Db::INT_TYPE); $list = $this->_db->fetchAll($select); if (!empty($list)) { $this->_prepareList($list); $row = reset($list); if (null !== $field) { return (array_key_exists($field, $row)) ? $row[$field] : null; } return $row; } return false; } /** * Return data object for item * * @param string $itemType * @return Qs_Db_Obj */ protected function _getItemObj($itemType) { if (false !== strpos($itemType, '\\')) { $objClass = 'App\\' . $itemType . 'Obj'; } else { $objClass = 'App_' . $itemType . 'Obj'; } if (class_exists($objClass)) { $this->_itemObj[$itemType] = new $objClass; } return (isset($this->_itemObj[$itemType]) ? $this->_itemObj[$itemType] : false); } protected function _prepareList(&$list) { parent::_prepareList($list); $taxPercent = (float) App_Settings_Obj::get('orderPriceTax'); $subtotal = $this->getSubtotal(); foreach ($list as &$row) { /** @var App_ECommerce_Product_Obj $itemObj */ $itemObj = $this->_getItemObj($row['cartItemType']); if (method_exists($itemObj, 'prepareCartItemData')) { $itemObj->prepareCartItemData($row); } //calculating tax if promo code assigned to one item if ($row['promoValue'] > 0 && $subtotal >= $row['promoMinOrderValue']) { require_once 'lib/Smarty/app_plugins/modifier.money.php'; $row['promoDescription'] = '-'; if ($row['promoType'] == App_ECommerce_Promo_Admin_View::PROMO_TYPE_PERCENT) { $promoPrice = Zend_Locale_Math::Mul($row['rowTotal'], $row['promoValue'], 4); $promoPrice = Zend_Locale_Math::Div($promoPrice, 100, 4); $row['promoDescription'] .= smarty_modifier_money($row['promoValue'], 2, true) . '% '; } else { $promoPrice = $row['promoValue']; $row['promoDescription'] .= '$' . smarty_modifier_money($row['promoValue']) . ' '; } $row['promoDescription'] .= 'Client Code Discount'; if (-1 != Zend_Locale_Math::Comp($promoPrice, $row['rowTotal'])) { $promoPrice = Zend_Locale_Math::Sub($row['rowTotal'], self::MIN_SUBTOTAL_VAL, 4); } if ($row['promoType'] != App_ECommerce_Promo_Admin_View::PROMO_TYPE_PERCENT) { $row['promoValue'] = Zend_Locale_Math::round($promoPrice, 2); } $row['promoValuePrice'] = Zend_Locale_Math::round($promoPrice, 2); $row['rowTotal'] = Zend_Locale_Math::Sub($row['rowTotal'], $promoPrice, 4); if ($row['tax'] > 0) { $row['rowTax'] = Zend_Locale_Math::Mul($row['rowTotal'], $taxPercent, 4); $row['rowTax'] = Zend_Locale_Math::Div($row['rowTax'], 100, 4); } } } return $this; } /** * Clear session cart object * * @return App_ECommerce_Cart_Obj */ public function clearSessionCartObject() { $this->getSessionCartObject()->unsetAll(); return $this; } /** * Merge cart for loged in and not loged in users * * @return App_ECommerce_Cart_Obj */ public function mergeCart() { /** @var Qs_Doc $doc */ $doc = Zend_Registry::get('doc'); $userId = $this->getData('userId'); $auth = $doc->getAuth(); if ($auth->hasIdentity()) { $userCartId = $this->_getTable()->searchBy( array('userId' => $auth->getData('id'), 'transactionId' => null), 'id' ); if ($userCartId) { $this->_mergeCartItems($userCartId); $this->getSessionCartObject()->id = $userCartId; } else if (empty($userId)) { $this->update(array('userId' => $auth->getData('id'))); } } return $this; } protected function _mergeCartItems($userCartId) { $currentItems = $this->getList(); $userItems = $this->setPrimaryKey($userCartId)->_clearSelect()->getList(); $preparedUserItems = array(); foreach($userItems as $userItem) { $preparedUserItems[$userItem['productId']] = $userItem; } foreach ($currentItems as $item) { if (array_key_exists($item['productId'], $preparedUserItems)) { $quantity = bcadd($item['quantity'], $preparedUserItems[$item['productId']]['quantity']); $this->updateItemQty($preparedUserItems[$item['productId']]['id'], $quantity); } else { $this->addItem($item); } $this->removeItem($item['id']); } return $this; } /** * Return tax price * * @param bool $onlyShippingItems * @return float|int */ public function getTax($onlyShippingItems = false) { $items = (array) $this->getList(); $tax = 0; if ($onlyShippingItems) { foreach ($items as $item) { if ($item['doNotApplyShipping'] == 'n') { $tax = Zend_Locale_Math::Add($tax, $item['rowTax'], 4); } } } else { foreach ($items as $item) { $tax = Zend_Locale_Math::Add($tax, $item['rowTax'], 4); } } return ((float) $tax > 0 ? $tax : 0); } /** * Validate cart items * * @return bool */ public function validateCartItems() { $list = $this->getList(); $result = true; foreach ($list as $row) { /** @var App_ECommerce_Product_Obj $itemObj */ $itemObj = $this->_getItemObj($row['cartItemType']); if ($itemObj) { if (method_exists($itemObj, 'validateCartItem')) { if (false === $itemObj->validateCartItem($row)) { $result = false; break; } } } else { $result = false; } } return $result; } protected function _getFromDbSelect($primaryKey) { $select = parent::_getFromDbSelect($primaryKey); $select->joinLeft( $this->_getPair('CartItemPromo'), '`CartItemPromo`.`cartId` = `' . $this->_tableAlias . '`.`id`', array( 'promoCodeProduct' => 'productId', 'promoCode' => 'code', 'promoCodeValue' => 'value', 'promoCodeType' => 'type', 'promoCodeMinOrderValue' => 'minOrderValue', 'promoId' ) ); $select->joinLeft( $this->_getPair('CartItemGiftCard'), '`CartItemGiftCard`.`cartId` = `' . $this->_tableAlias . '`.`id`', array('giftCardCode' => 'cardCode', 'giftCardValue' => 'cardValue') ); return $select; } /** * @param $code * @return bool|string return true on success or error code otherwise */ public function applyPromoCode($code) { if ($this->hasPromo()) { return App_ECommerce_Checkout_Abstract_View::ERROR_PROMO_HAS_OTHER; } $promoObj = new App_ECommerce_Promo_Admin_Obj(); $promo = $promoObj->getDataByCode($code); if (empty($promo)) { return App_ECommerce_Checkout_Abstract_View::ERROR_PROMO_INCORRECT; } $errorCode = null; $currentDate = strtotime(date('Y-m-d')); if (strtotime($promo['startDate']) > $currentDate) { $errorCode = App_ECommerce_Checkout_Abstract_View::ERROR_PROMO_INCORRECT; } else if ($promo['hasNoExpirationDate'] == 'n' && strtotime($promo['endDate']) < $currentDate) { $errorCode = App_ECommerce_Checkout_Abstract_View::ERROR_PROMO_INCORRECT; } else if (($total = $this->getSubtotal(true)) < $promo['minOrderValue']) { $errorCode = App_ECommerce_Checkout_Abstract_View::ERROR_PROMO_LOW_AMOUNT; } else if ( $promo['isRelated'] == 'y' && $promo['productCategoryIds'] && !$this->getItem(array('productCategoryId' => $promo['productCategoryIds'])) ) { $errorCode = App_ECommerce_Checkout_Abstract_View::ERROR_PROMO_NO_PRODUCT; } else if (!$this->_addPromo($promo)) { $errorCode = App_ECommerce_Checkout_Abstract_View::ERROR_OTHER; } return (null == $errorCode) ? true : $errorCode; } public function hasPromo() { return (bool) $this->getData('promoCode'); } protected function _addPromo($data) { $data['promoId'] = $data['id']; $data['cartId'] = $this->getPrimaryKey(); unset($data['added'], $data['changed'], $data['id']); if ($data['isRelated'] == 'y' && !$this->getItem(array('productCategoryId' => $data['productCategoryIds']))) { return false; } else if ($data['isRelated'] == 'n') { $data['productId'] = 0; } return (bool) $this->_getTable('CartItemPromo')->insert($data); } public function applyGiftCard($code) { $giftCardObj = new App_ECommerce_GiftCard_Admin_Obj(); $result = $giftCardObj->getDataByCode($code); if ($result) { if ($this->hasGiftCard() || strtotime($result['expirationDate'] < strtotime(date('Y-m-d'))) || $this->getData('userId') != $result['userId'] || $result['statusId'] == App_ECommerce_GiftCard_Admin_View::CARD_STATUS_REDEEMED) { $result = false; } else { $result = $this->_addGiftCard($result); } } return (bool)$result; } public function hasGiftCard() { return (bool) $this->getData('giftCardCode'); } protected function _addGiftCard($data) { $data['giftCardId'] = $data['id']; $data['cartId'] = $this->getPrimaryKey(); unset($data['added'], $data['changed'], $data['id']); return (bool) $this->_getTable('CartItemGiftCard')->insert($data); } /** * Return array with discounts values * @param string|null $type discount type (promo|giftCard) * @return array */ public function getDiscounts($type = null) { $discounts = array('promo' => 0, 'giftCard' => 0); if ($this->hasPromo() || $this->hasGiftCard()) { $subtotal = $this->getSubtotal(true); $cart = $this->getData(); if ($this->hasPromo() && !$this->getPromoRelatedCategories($cart['promoId']) && $subtotal >= $cart['promoCodeMinOrderValue'] ) { $discounts['promo'] = $this->_getPromoDiscount($cart, $subtotal); $subtotal = Zend_Locale_Math::Sub($subtotal, $discounts['promo'], 2); } if ($this->hasGiftCard()) { $discounts['giftCard'] = $this->_getGiftCardDiscount($cart, $subtotal); } } return (null !== $type) ? Qs_Array::get($discounts, $type) : $discounts; } /** * @param array $cart * @param float $subtotal * @return float */ protected function _getPromoDiscount(array $cart, $subtotal) { $discount = $cart['promoCodeValue']; if ($cart['promoCodeType'] == App_ECommerce_Promo_Admin_View::PROMO_TYPE_PERCENT) { $result = Zend_Locale_Math::Div(Zend_Locale_Math::Mul($this->getTotal(), $discount, 4), 100, 2); } else { $result = $discount; } if (-1 != Zend_Locale_Math::Comp($result, $subtotal)) { $result = Zend_Locale_Math::Sub($subtotal, App_ECommerce_Cart_Obj::MIN_SUBTOTAL_VAL, 2); } return $result; } /** * @param array $cart * @param float $subtotal * @return float */ protected function _getGiftCardDiscount(array $cart, $subtotal) { $giftCardObj = new App_ECommerce_GiftCard_Admin_Obj(); $cardData = $giftCardObj->getDataByCode($cart['giftCardCode']); if (!empty($cardData) && $cardData['statusId'] != App_ECommerce_GiftCard_Admin_View::CARD_STATUS_REDEEMED ) { $result = $cart['giftCardValue']; if (-1 != Zend_Locale_Math::Comp($result, $subtotal)) { $result = Zend_Locale_Math::Sub($subtotal, App_ECommerce_Cart_Obj::MIN_SUBTOTAL_VAL, 2); } } else { $result = 0; } return $result; } }