'Transaction ID is wrong' ); protected $_itemObj; /** * Return cart id * * @return int */ public function getCartId() { return $this->_getSessionCartId(); } public function setSponsorFlag($flag = true) { if ($flag) { $this->initSponsorshipFlagDb(); } return $this; } /** * 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(); } /** * 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) { 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'); } } else { throw new Qs_Exception('Item class ' . $itemClass . ' not exist'); } } $data = array( 'quantity' => $qty, 'price' => $price, 'tax' => $tax, ); 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 getRowPrice($itemId) { return Zend_Locale_Math::round($this->getRowData($itemId, 'price'), 2); } public function getRowData($itemId, $field = null) { $select = $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); $this->_addAttendees($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); } if (\App_ECommerce_Cart_View::ITEM_TYPE_EVENT == $row['cartItemType']) { $row['cartItemTypeTitle'] = 'Event'; } else { $row['cartItemTypeTitle'] = 'Sponsorship'; } //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['rowPrice'], $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'] .= 'Promo Code Discount'; if (-1 != Zend_Locale_Math::Comp($promoPrice, $row['rowPrice'])) { $promoPrice = Zend_Locale_Math::Sub($row['rowPrice'], 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['rowPrice'] = Zend_Locale_Math::Sub($row['rowPrice'], $promoPrice, 4); if ($row['tax'] > 0) { $row['tax'] = Zend_Locale_Math::Mul($row['rowPrice'], $taxPercent, 4); $row['tax'] = Zend_Locale_Math::Div($row['tax'], 100, 4); } } } return $this; } protected function _addAttendees(&$list) { if (empty($list)) { return $this; } $parentAttendeeIds = array(); foreach ($list as $item) { if (\App_ECommerce_Cart_View::ITEM_TYPE_EVENT == $item['cartItemType']) { $parentAttendeeIds[] = $item['productId']; } } $attendees = $this->_getEventAttendeesByParentAttendeesId($parentAttendeeIds); if (!$attendees) { return $this; } foreach ($list as &$item) { if (CartView::ITEM_TYPE_EVENT == $item['cartItemType'] && isset($attendees[$item['productId']])) { $item['attendees'] = $attendees[$item['productId']]; } } unset($item); return $this; } /** * return attendees, grouped by parentAttendeeId * * @param $ids * @return array */ protected function _getEventAttendeesByParentAttendeesId($ids) { if (empty($ids)) { return array(); } $select = $this->_db->select(); $select->from( $this->_getPair('EventAttendee'), array('parentAttendeeId', 'firstName', 'lastName', 'userId', 'email', 'amount', 'eventId') ); $select->where('parentAttendeeId IN (?)', $ids, Qs_Db::INT_TYPE) ->order('id'); //вивід в тому ж порядку, що й додавалося в карту return $this->_db->fetchAll($select, array(), \Qs_Db::FETCH_GROUP); } /** * 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 * * @return float|int */ public function getTax() { $items = (array) $this->getList(); $tax = 0; foreach ($items as $item) { $tax = Zend_Locale_Math::Add($tax, $item['tax'], 4); } return ((float) $tax > 0 ? $tax : 0); } /** * Validate cart items * @throws Exception * @return array|bool */ public function validateCartItems() { $result = array(); $list = $this->getList(); foreach ($list as $row) { /** @var \App\Event\Obj $itemObj */ $itemObj = $this->_getItemObj($row['cartItemType']); if ($itemObj) { if (method_exists($itemObj, 'validateCartItem')) { if (true !== ($errors = $itemObj->validateCartItem($row))) { $result = array_merge($result, $errors); break; } } } else { throw new Exception('Unknown cart item type "' . $row['cartItemType'] . '"'); } } return ($result) ? $result : true; } 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', ) ); $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()) < $promo['minOrderValue']) { $errorCode = App_ECommerce_Checkout_Abstract_View::ERROR_PROMO_LOW_AMOUNT; } else if ( $promo['isRelated'] == 'y' && $promo['productId'] && !$this->getItem(array('productId' => $promo['productId'])) ) { $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('productId' => $data['productId']))) { 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(); $cart = $this->getData(); if ($this->hasPromo() && !$cart['promoCodeProduct'] && $this->getSubtotal() >= $cart['promoCodeMinOrderValue'] ) { $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); } $discounts['promo'] = $result; $subtotal = Zend_Locale_Math::Sub($subtotal, $result, 2); } if ($this->hasGiftCard()) { $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; } $discounts['giftCard'] = $result; } } if (null !== $type) { return (array_key_exists($type, $discounts)) ? $discounts[$type] : null; } return $discounts; } }