diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Config/Buttons/Sync.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Config/Buttons/Sync.php new file mode 100644 index 00000000..6372802d --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Config/Buttons/Sync.php @@ -0,0 +1,56 @@ +getTemplate()) { + $this->setTemplate('zendesk/config/button-sync.phtml'); + } + return $this; + } + + public function render(Varien_Data_Form_Element_Abstract $element) + { + $element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue(); + return parent::render($element); + } + + protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element) + { + $originalData = $element->getOriginalData(); + $this->addData(array( + 'button_label' => Mage::helper('zendesk')->__($originalData['button_label']), + 'html_id' => $element->getHtmlId(), + 'url' => Mage::getSingleton('adminhtml/url')->getUrl('adminhtml/zendesk/sync') + )); + + return $this->_toHtml(); + } + + public function getTestUrl() + { + return Mage::getSingleton('adminhtml/url')->getUrl('adminhtml/zendesk/sync'); + } + + public function getAuthHeader() + { + return 'Token token="' . Mage::helper('zendesk')->getApiToken(false) . '"'; + } +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Customer.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Customer.php new file mode 100644 index 00000000..886bf58f --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Customer.php @@ -0,0 +1,47 @@ +setId('zendesk_create_customer_search'); + } + + public function getHeaderText() + { + return Mage::helper('zendesk')->__('Please Select User to Add'); + } + + public function getButtonsHtml() + { + $addButtonData = array( + 'label' => Mage::helper('zendesk')->__('Select User'), + 'onclick' => 'showUsers()', + 'id' => 'show-users' + ); + return $this->getLayout()->createBlock('adminhtml/widget_button')->setData($addButtonData)->toHtml(); + } + + public function getHeaderCssClass() + { + return 'head-catalog-customer'; + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Customer/Grid.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Customer/Grid.php new file mode 100644 index 00000000..4fc956b5 --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Customer/Grid.php @@ -0,0 +1,103 @@ +setId('zendesk_create_customer_search_grid'); + $this->setDefaultSort('entity_id'); + $this->setUseAjax(true); + if ($this->getRequest()->getParam('collapse')) { + $this->setIsCollapsed(true); + } + } + + /** + * Retrieve quote store object + * @return Mage_Core_Model_Store + */ + public function getStore() + { + return Mage::getSingleton('adminhtml/session_quote')->getStore(); + } + + /** + * Prepare collection to be displayed in the grid + * + * @return Mage_Adminhtml_Block_Sales_Order_Create_Search_Grid + */ + protected function _prepareCollection() + { + $collection = Mage::getModel('customer/customer')->getCollection() + ->addAttributeToSelect('firstname') + ->addAttributeToSelect('lastname') + ->addAttributeToSelect('email'); + + + $this->setCollection($collection); + return parent::_prepareCollection(); + } + + /** + * Prepare columns + * + * @return Mage_Adminhtml_Block_Sales_Order_Create_Search_Grid + */ + protected function _prepareColumns() + { + $this->addColumn('entity_id', array( + 'header' => Mage::helper('zendesk')->__('ID'), + 'sortable' => true, + 'width' => '60', + 'index' => 'entity_id' + )); + $this->addColumn('firstname', array( + 'header' => Mage::helper('zendesk')->__('Firstname'), + 'index' => 'firstname' + )); + $this->addColumn('lastname', array( + 'header' => Mage::helper('zendesk')->__('Lastname'), + 'index' => 'lastname' + )); + $this->addColumn('email', array( + 'header' => Mage::helper('zendesk')->__('Email'), + 'index' => 'email' + )); + $this->addColumn('action', array( + 'header' => Mage::helper('zendesk')->__('Action'), + 'renderer' => 'zendesk/adminhtml_create_customer_grid_renderer_action', + 'filter' => false, + 'sortable' => false + )); + + return parent::_prepareColumns(); + } + + public function getGridUrl() + { + return $this->getUrl('adminhtml/zendesk/loadBlock', array('block'=>'customer_grid', '_current' => true, 'collapse' => null)); + } + + public function getRowUrl($row) + { + return ""; + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Customer/Grid/Renderer/Action.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Customer/Grid/Renderer/Action.php new file mode 100644 index 00000000..c04ce721 --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Customer/Grid/Renderer/Action.php @@ -0,0 +1,27 @@ +getId()) { + return ""; + } + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Edit.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Edit.php index 9635985f..fc8b77b2 100644 --- a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Edit.php +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Edit.php @@ -19,8 +19,7 @@ class Zendesk_Zendesk_Block_Adminhtml_Create_Edit extends Mage_Adminhtml_Block_W { protected function _construct() { - parent::_construct(); - $this->_controller = FALSE; + parent::_construct(); } protected function _preparelayout() diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Edit/Form.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Edit/Form.php index 52186a5c..1d81be93 100644 --- a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Edit/Form.php +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Edit/Form.php @@ -105,8 +105,8 @@ protected function _prepareForm() $fieldset->addField('order', 'text', array( 'name' => 'order', - 'label' => Mage::helper('zendesk')->__('Order number'), - 'title' => Mage::helper('zendesk')->__('Order number'), + 'label' => Mage::helper('zendesk')->__('Order Number'), + 'title' => Mage::helper('zendesk')->__('Order Number'), 'required' => false )); diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Order.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Order.php new file mode 100644 index 00000000..73dcba3f --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Order.php @@ -0,0 +1,47 @@ +setId('zendesk_create_order_search'); + } + + public function getHeaderText() + { + return Mage::helper('zendesk')->__('Please Select Order to Add'); + } + + public function getButtonsHtml() + { + $addButtonData = array( + 'label' => Mage::helper('zendesk')->__('Select Order'), + 'onclick' => 'showOrders()', + 'id' => 'show-orders' + ); + return $this->getLayout()->createBlock('adminhtml/widget_button')->setData($addButtonData)->toHtml(); + } + + public function getHeaderCssClass() + { + return 'head-catalog-order'; + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Order/Grid.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Order/Grid.php new file mode 100644 index 00000000..f37c9b11 --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Order/Grid.php @@ -0,0 +1,141 @@ +setId('zendesk_create_order_search_grid'); + $this->setDefaultSort('entity_id'); + $this->setUseAjax(true); + if ($this->getRequest()->getParam('collapse')) { + $this->setIsCollapsed(true); + } + } + + /** + * Retrieve quote store object + * @return Mage_Core_Model_Store + */ + public function getStore() + { + return Mage::getSingleton('adminhtml/session_quote')->getStore(); + } + + /** + * Retrieve collection class + * + * @return string + */ + protected function _getCollectionClass() + { + return 'sales/order_grid_collection'; + } + + protected function _prepareCollection() + { + $collection = Mage::getResourceModel($this->_getCollectionClass()); + $this->setCollection($collection); + return parent::_prepareCollection(); + } + + /** + * Prepare columns + * + * @return Mage_Adminhtml_Block_Sales_Order_Create_Search_Grid + */ + protected function _prepareColumns() + { + $this->addColumn('real_order_id', array( + 'header'=> Mage::helper('sales')->__('Order #'), + 'width' => '80px', + 'type' => 'text', + 'index' => 'increment_id', + )); + + if (!Mage::app()->isSingleStoreMode()) { + $this->addColumn('store_id', array( + 'header' => Mage::helper('sales')->__('Purchased From (Store)'), + 'index' => 'store_id', + 'type' => 'store', + 'store_view'=> true, + 'display_deleted' => true, + )); + } + + $this->addColumn('created_at', array( + 'header' => Mage::helper('sales')->__('Purchased On'), + 'index' => 'created_at', + 'type' => 'datetime', + 'width' => '100px', + )); + + $this->addColumn('billing_name', array( + 'header' => Mage::helper('sales')->__('Bill to Name'), + 'index' => 'billing_name', + )); + + $this->addColumn('shipping_name', array( + 'header' => Mage::helper('sales')->__('Ship to Name'), + 'index' => 'shipping_name', + )); + + $this->addColumn('base_grand_total', array( + 'header' => Mage::helper('sales')->__('G.T. (Base)'), + 'index' => 'base_grand_total', + 'type' => 'currency', + 'currency' => 'base_currency_code', + )); + + $this->addColumn('grand_total', array( + 'header' => Mage::helper('sales')->__('G.T. (Purchased)'), + 'index' => 'grand_total', + 'type' => 'currency', + 'currency' => 'order_currency_code', + )); + + $this->addColumn('status', array( + 'header' => Mage::helper('sales')->__('Status'), + 'index' => 'status', + 'type' => 'options', + 'width' => '70px', + 'options' => Mage::getSingleton('sales/order_config')->getStatuses(), + )); + + $this->addColumn('action', array( + 'header' => Mage::helper('zendesk')->__('Action'), + 'renderer' => 'zendesk/adminhtml_create_order_grid_renderer_action', + 'filter' => false, + 'sortable' => false + )); + + return parent::_prepareColumns(); + } + + public function getGridUrl() + { + return $this->getUrl('adminhtml/zendesk/loadBlock', array('block'=>'order_grid', '_current' => true, 'collapse' => null)); + } + + public function getRowUrl($row) + { + return ""; + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Order/Grid/Renderer/Action.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Order/Grid/Renderer/Action.php new file mode 100644 index 00000000..a7a860ca --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Create/Order/Grid/Renderer/Action.php @@ -0,0 +1,27 @@ +getId()) { + return ""; + } + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard.php index f25c8909..06f5d4da 100644 --- a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard.php +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard.php @@ -1,4 +1,5 @@ setTemplate('zendesk/dashboard/index.phtml'); } - public function getIsZendeskDashboard() - { - $controller = Mage::app()->getFrontController()->getRequest()->getControllerName(); + public function getIsZendeskDashboard() { + return Mage::app()->getFrontController()->getRequest()->getControllerName() === 'zendesk'; + } + + public function getAuthHeader() { + return 'Token token="' . Mage::helper('zendesk')->getApiToken(false) . '"'; + } + + public function isConnected() { + $connection = Mage::helper('zendesk')->getConnectionStatus(); + return $connection['success']; + } - if($controller == 'zendesk') { - return true; - } else { - return false; - } + public function getTotals() { + return Mage::helper("zendesk")->getTicketTotals(); } } diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Grids.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Grids.php index f33d786d..de34aebe 100644 --- a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Grids.php +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Grids.php @@ -1,4 +1,5 @@ setId('tickets_grid_tab'); $this->setDestElementId('tickets_grid_tab_content'); $this->setTemplate('widget/tabshoriz.phtml'); } - - protected function _prepareLayout() - { + + protected function _prepareLayout() { // Check if we are on the main admin dashboard and, if so, whether we should be showing the grid // Note: an additional check in the template is needed, but this will prevent unnecessary API calls to Zendesk - if(!$this->getIsZendeskDashboard() && !Mage::getStoreConfig('zendesk/features/show_on_dashboard')) { + if ( !$this->getIsZendeskDashboard() && !Mage::getStoreConfig('zendesk/backend_features/show_on_dashboard') ) + { return parent::_prepareLayout(); } - $views = null; - $first = true; + //check if module is setted up + $configured = (bool) Mage::getStoreConfig('zendesk/general/domain'); + $viewsIds = Mage::getStoreConfig('zendesk/backend_features/show_views') ? Mage::helper('zendesk')->getChosenViews() : array(); - if(Mage::getStoreConfig('zendesk/features/show_views')) { - $list = trim(trim(Mage::getStoreConfig('zendesk/features/show_views')), ','); - $views = explode(',', $list); + if( Mage::getStoreConfig('zendesk/backend_features/show_all') AND $configured) { + $all = array( + 'class' => 'ajax', + 'url' => $this->getUrl('zendesk/adminhtml_zendesk/ticketsAll'), + ); + $label = $this->__("All tickets"); + + $all_count = Mage::registry('zendesk_tickets_all'); + if (!$all_count) { + $this->getLayout()->createBlock('zendesk/adminhtml_dashboard_tab_tickets_grid_all')->toHtml(); + $all_count = Mage::registry('zendesk_tickets_all'); + } + + $label .= " (" . $all_count . ")"; + + $all['label'] = $label; + $this->addTab('all-tickets', $all); } - if($views && count($views)) { - foreach($views as $viewId) { - try { - $view = Mage::getModel('zendesk/api_views')->get($viewId); - - $tab = array( - 'label' => $this->__($view['title']), - 'content' => $this->getLayout()->createBlock('zendesk/adminhtml_dashboard_tab_view')->setView($view)->toHtml(), - ); + if(count($viewsIds) AND $configured) { + try { + $allTicketView = Mage::getModel('zendesk/api_views')->active(); + $ticketsCounts = Mage::getModel('zendesk/api_views')->countByIds($viewsIds); - if($first) { - $tab['active'] = true; - $first = false; - } - - $this->addTab($viewId, $tab); + } catch (Exception $ex) { + $allTicketView = array(); + } + + foreach($viewsIds as $viewId) { + $view = array_shift(array_filter($allTicketView, function($view) use($viewId) { + return $view['id'] === (int) $viewId; + })); + + $count = array_shift(array_filter($ticketsCounts['view_counts'], function($view) use($viewId) { + return $view['view_id'] === (int) $viewId; + })); + + if($count['value']) { + $label = $view['title'] . ' (' . $count['value'] . ')'; + $this->addTab($viewId, array( + 'label' => $label, + 'class' => 'ajax', + 'url' => $this->getUrl('zendesk/adminhtml_zendesk/ticketsView', array('viewid' => $viewId)), + )); + } else { + Mage::unregister('zendesk_tickets_view'); + Mage::register('zendesk_tickets_view', $viewId); - } catch(Exception $e) { - // Just don't add the tab + $this->addTab($viewId, array( + 'content' => $this->getLayout()->createBlock('zendesk/adminhtml_dashboard_tab_tickets_grid_view')->toHtml(), + 'label' => $view['title'] . ' (' . Mage::registry('zendesk_tickets_view_'.$viewId) . ')' + )); } } } else { - if($this->getIsZendeskDashboard()) { + if ($this->getIsZendeskDashboard() AND !Mage::getStoreConfig('zendesk/backend_features/show_all')) { $block = $this->getLayout()->createBlock('core/template', 'zendesk_dashboard_empty')->setTemplate('zendesk/dashboard/empty.phtml'); $this->getLayout()->getBlock('zendesk_dashboard')->append($block); } @@ -71,15 +101,8 @@ protected function _prepareLayout() return parent::_prepareLayout(); } - - public function getIsZendeskDashboard() - { - $controller = Mage::app()->getFrontController()->getRequest()->getControllerName(); - - if($controller == 'zendesk') { - return true; - } else { - return false; - } + + public function getIsZendeskDashboard() { + return Mage::app()->getFrontController()->getRequest()->getControllerName() === 'zendesk'; } } diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Abstract.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Abstract.php new file mode 100644 index 00000000..80d379cd --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Abstract.php @@ -0,0 +1,240 @@ +_viewId = (is_null($id) ? uniqid() : $id); + } + + public function __construct($attributes = array()) { + parent::__construct($attributes); + + $this->_defaultSort = Mage::getStoreConfig('zendesk/backend_features/default_sort'); + $this->_defaultDir = Mage::getStoreConfig('zendesk/backend_features/default_sort_dir'); + + $this->setTemplate('zendesk/widget/grid.phtml'); + + $this->_emptyText = Mage::helper('zendesk')->__('No tickets found'); + } + + protected function _construct() { + parent::_construct(); + + $this->setMassactionBlockName('zendesk/adminhtml_dashboard_tab_tickets_grid_massaction'); + $this->setId('zendesk_tab_tickets_grid_' . $this->_viewId); + $this->setSaveParametersInSession(true); + $this->setUseAjax(true); + + if ($this->getRequest()->getParam('collapse')) { + $this->setIsCollapsed(true); + } + + $this->_page = (int) $this->getParam( $this->getVarNamePage(), $this->_defaultPage); + $this->_limit = (int) $this->getParam( $this->getVarNameLimit(), $this->_defaultLimit); + } + + protected function _preparePage() { + parent::_preparePage(); + + $this->_page = (int) $this->getParam($this->getVarNamePage(), $this->_defaultPage); + $this->_limit = (int) $this->getParam($this->getVarNameLimit(), $this->_defaultLimit); + } + + protected function _prepareCollection() { + if( ! $this->getCollection() ) { + $collection = $this->_getCollectionModel(); + $filter = $this->getParam('filter'); + $filterData = Mage::helper('adminhtml')->prepareFilterString($filter); + + foreach($filterData as $fieldName => $value) { + $collection->addFieldToFilter($fieldName, $value); + } + + $this->setDefaultLimit( $this->getParam('limit', $this->_defaultLimit) ); + $this->setCollection( $this->_getCollection($collection) ); + } + + return parent::_prepareCollection(); + } + + protected function _prepareMassaction() { + parent::_prepareMassaction(); + + $this->setMassactionIdField('id'); + $this->getMassactionBlock()->setFormFieldName('id'); + + $formKey = Mage::getSingleton('core/session')->getFormKey(); + + $this->getMassactionBlock()->addItem('delete', array( + 'label' => Mage::helper('zendesk')->__('Delete'), + 'url' => $this->getUrl('*/adminhtml_zendesk/bulkDelete', array('form_key' => $formKey, '_current' => true)), + 'confirm' => Mage::helper('zendesk')->__('Are you sure you want to delete selected tickets?') + )); + + $this->getMassactionBlock()->addItem('change_status', array( + 'label' => Mage::helper('zendesk')->__('Change Status'), + 'url' => $this->getUrl('*/adminhtml_zendesk/bulkChangeStatus', array('form_key' => $formKey, '_current' => true)), + 'confirm' => Mage::helper('zendesk')->__('Are you sure you want to change status of selected tickets?'), + 'additional' => array( + 'visibility' => array( + 'name' => 'status', + 'type' => 'select', + 'class' => 'required-entry', + 'label' => Mage::helper('zendesk')->__('Status'), + 'values' => Mage::helper('zendesk')->getStatusMap() + ) + ) + )); + + $this->getMassactionBlock()->addItem('change_priority', array( + 'label' => Mage::helper('zendesk')->__('Change Priority'), + 'url' => $this->getUrl('*/adminhtml_zendesk/bulkChangePriority', array('form_key' => $formKey, '_current' => true)), + 'confirm' => Mage::helper('zendesk')->__('Are you sure you want to change priority of selected tickets?'), + 'additional' => array( + 'visibility' => array( + 'name' => 'priority', + 'type' => 'select', + 'class' => 'required-entry', + 'label' => Mage::helper('zendesk')->__('Priority'), + 'values' => Mage::helper('zendesk')->getPriorityMap() + ) + ) + )); + + $this->getMassactionBlock()->addItem('change_type', array( + 'label' => Mage::helper('zendesk')->__('Change Type'), + 'url' => $this->getUrl('*/adminhtml_zendesk/bulkChangeType', array('form_key' => $formKey, '_current' => true)), + 'confirm' => Mage::helper('zendesk')->__('Are you sure you want to change type of selected tickets?'), + 'additional' => array( + 'visibility' => array( + 'name' => 'type', + 'type' => 'select', + 'class' => 'required-entry', + 'label' => Mage::helper('zendesk')->__('Type'), + 'values' => Mage::helper('zendesk')->getTypeMap() + ) + ) + )); + + $this->getMassactionBlock()->addItem('mark_as_spam', array( + 'label' => Mage::helper('zendesk')->__('Mark as Spam'), + 'url' => $this->getUrl('*/adminhtml_zendesk/bulkMarkSpam', array('form_key' => $formKey, '_current' => true)), + 'confirm' => Mage::helper('zendesk')->__('Are you sure you want to mark as spam selected tickets?'), + )); + + return $this; + } + + protected function getNoFilterMassactionColumn(){ + return true; + } + + protected function addColumnBasedOnType($index, $title, $filter = false, $sortable = true) { + $column = array( + 'header' => Mage::helper('zendesk')->__($title), + 'sortable' => $sortable, + 'filter' => $filter, + 'index' => $index, + 'type' => $this->getColumnType($index), + ); + + $renderer = $this->getColumnRenderer($index); + + if($renderer !== null) { + $column['renderer'] = $renderer; + } + + $this->addColumn($index, $column); + } + + protected function getColumnType($index) { + switch($index) { + case 'created_at': + case 'created': + case 'requested': + case 'updated_at': + case 'updated': + return 'datetime'; + default: + return 'text'; + } + } + + protected function getColumnRenderer($index) { + switch($index) { + case 'requester': + case 'assignee': + return 'zendesk/adminhtml_dashboard_tab_tickets_grid_renderer_user'; + case 'subject': + return 'zendesk/adminhtml_dashboard_tab_tickets_grid_renderer_action'; + case 'group': + return 'zendesk/adminhtml_dashboard_tab_tickets_grid_renderer_group'; + default: + return null; + } + } + + protected function getGridParams() { + return array( + 'page' => $this->_page, + 'per_page' => $this->_limit, + 'sort_order' => $this->getParam( $this->getVarNameDir(), $this->_defaultDir), + 'sort_by' => $this->getParam( $this->getVarNameSort(), $this->_defaultSort), + ); + } + + public function getGridJavascript() + { + $js = $this->getJsObjectName()."= new varienGrid('".$this->getId()."', '".$this->getGridUrl()."', '".$this->getVarNamePage()."', '".$this->getVarNameSort()."', '".$this->getVarNameDir()."', '".$this->getVarNameFilter()."');"; + $js .= $this->getJsObjectName() .".useAjax = '".$this->getUseAjax()."';"; + + if($this->getRowClickCallback()) + $js .= $this->getJsObjectName() .".rowClickCallback = ".$this->getRowClickCallback().";"; + + if($this->getCheckboxCheckCallback()) + $js .= $this->getJsObjectName().".checkboxCheckCallback = ".$this->getCheckboxCheckCallback().";"; + + if($this->getRowInitCallback()) { + $js .= $this->getJsObjectName().".initRowCallback = ".$this->getRowInitCallback().";"; + $js .= $this->getJsObjectName().".initGridRows();"; + } + + if($this->getMassactionBlock()->isAvailable()) + $js .= $this->getMassactionBlock()->getJavaScript(); + + $js .= $this->getAdditionalJavaScript(); + + return $js; + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/All.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/All.php new file mode 100644 index 00000000..d2a4b95a --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/All.php @@ -0,0 +1,106 @@ +setViewId('all'); + + parent::__construct($attributes); + } + + protected function _getCollection($collection) { + return $collection->getCollection($this->getGridParams()); + } + + public function getGridUrl() { + return $this->getUrl('*/*/ticketsAll', array('_current' => true)); + } + + protected function _prepareColumns() { + $this->addColumn('id', array( + 'header' => Mage::helper('zendesk')->__('Ticket ID'), + 'sortable' => false, + 'align' => 'right', + 'width' => '30px', + 'index' => 'id', + )); + + $this->addColumn('subject', array( + 'header' => Mage::helper('zendesk')->__('Subject'), + 'sortable' => false, + 'index' => 'description', + 'type' => 'text', + 'renderer' => 'zendesk/adminhtml_dashboard_tab_tickets_grid_renderer_action', + )); + + $this->addColumn('requester_id', array( + 'header' => Mage::helper('zendesk')->__('Email'), + 'width' => '60', + 'renderer' => 'zendesk/adminhtml_dashboard_tab_tickets_grid_renderer_email', + 'index' => 'requester_id', + 'sortable' => false, + )); + + $this->addColumn('type', array( + 'header' => Mage::helper('zendesk')->__('Type'), + 'width' => '100', + 'type' => 'options', + 'options' => Mage::helper('zendesk')->getTypeMap(), + 'index' => 'type', + 'sortable' => false, + )); + + $this->addColumn('status', array( + 'header' => Mage::helper('zendesk')->__('Status'), + 'sortable' => true, + 'width' => '100px', + 'index' => 'status', + 'type' => 'options', + 'options' => Mage::helper('zendesk')->getStatusMap(), + )); + + $this->addColumn('priority', array( + 'header' => Mage::helper('zendesk')->__('Priority'), + 'sortable' => true, + 'width' => '100px', + 'index' => 'priority', + 'type' => 'options', + 'options' => Mage::helper('zendesk')->getPriorityMap(), + )); + + $this->addColumn('created_at', array( + 'header' => Mage::helper('zendesk')->__('Requested'), + 'sortable' => true, + 'width' => '160px', + 'index' => 'created_at', + 'type' => 'datetime', + )); + + $this->addColumn('updated_at', array( + 'header' => Mage::helper('zendesk')->__('Updated'), + 'sortable' => true, + 'width' => '160px', + 'index' => 'updated_at', + 'type' => 'datetime', + )); + + return parent::_prepareColumns(); + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Massaction.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Massaction.php new file mode 100644 index 00000000..e9e39026 --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Massaction.php @@ -0,0 +1,32 @@ +getJsObjectName()} = new varienGridMassaction('{$this->getHtmlId()}', " + . "{$this->getGridJsObjectName()}, '{$this->getSelectedJson()}'" + . ", '{$this->getFormFieldNameInternal()}', '{$this->getFormFieldName()}');" + . "{$this->getJsObjectName()}.setItems({$this->getItemsJson()}); " + . "{$this->getJsObjectName()}.setGridIds('{$this->getGridIdsJson()}');" + . ($this->getUseAjax() ? "{$this->getJsObjectName()}.setUseAjax(true);" : '') + . ($this->getUseSelectAll() ? "{$this->getJsObjectName()}.setUseSelectAll(true);" : '') + . "{$this->getJsObjectName()}.errorText = '{$this->getErrorText()}';"; + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Renderer/Action.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Renderer/Action.php new file mode 100644 index 00000000..6d32df7d --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Renderer/Action.php @@ -0,0 +1,25 @@ +getTicketUrl($row->getData()); + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Renderer/Email.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Renderer/Email.php new file mode 100644 index 00000000..3f9178a3 --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Renderer/Email.php @@ -0,0 +1,38 @@ +getData($this->getColumn()->getIndex()); + + $found = array_filter($users, function($user) use($value) { + return (int) $user['id'] === $value; + }); + + if( count($found) ) { + $user = array_shift($found); + + return $user['email']; + } + + return ''; + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Renderer/Group.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Renderer/Group.php new file mode 100644 index 00000000..1100d534 --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Renderer/Group.php @@ -0,0 +1,38 @@ +getData($this->getColumn()->getIndex()); + + $found = array_filter($groups, function($group) use($value) { + return (int) $group['id'] === $value; + }); + + if( count($found) ) { + $group = array_shift($found); + + return $group['name']; + } + + return ''; + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Renderer/Type.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Renderer/Type.php new file mode 100644 index 00000000..111a7905 --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/Renderer/Type.php @@ -0,0 +1,25 @@ +getData($this->getColumn()->getIndex()); + + $found = array_filter($users, function($user) use($value) { + return (int) $user['id'] === $value; + }); + + if( count($found) ) { + $user = array_shift($found); + + return $user['name']; + } + + return ''; + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/View.php b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/View.php new file mode 100644 index 00000000..1ad70a7b --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/Tickets/Grid/View.php @@ -0,0 +1,65 @@ +setViewId($viewId); + + parent::__construct($attributes); + } + + protected function _getCollection($collection) { + return $collection->getCollectionFromView($this->_viewId, $this->getGridParams()); + } + + public function getGridUrl() { + return $this->getUrl('*/*/ticketsView', array('_current' => true)); + } + + protected function _prepareGrid() { + parent::_prepareGrid(); + $this->_prepareDynamicColumns(); + $this->_prepareCollection(); + + return $this; + } + + protected function _prepareColumns() { + $this->addColumn('id', array( + 'header' => Mage::helper('zendesk')->__('Ticket ID'), + 'sortable' => true, + 'filter' => false, + 'align' => 'right', + 'width' => '30px', + 'index' => 'id', + )); + + return parent::_prepareColumns(); + } + + protected function _prepareDynamicColumns() { + $viewColumns = $this->getCollection()->getColumnsForView(); + + foreach($viewColumns as $column) { + $this->addColumnBasedOnType($column['id'], $column['title']); + } + } + +} \ No newline at end of file diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Customer/Tickets.php b/src/app/code/community/Zendesk/Zendesk/Block/Customer/Tickets.php index 49110c1f..51500882 100644 --- a/src/app/code/community/Zendesk/Zendesk/Block/Customer/Tickets.php +++ b/src/app/code/community/Zendesk/Zendesk/Block/Customer/Tickets.php @@ -22,4 +22,9 @@ public function __construct() parent::__construct(); $this->setTemplate('zendesk/customer/tickets.phtml'); } -} \ No newline at end of file + + public function getSubmitAction() { + $url = Mage::helper('adminhtml')->getUrl('*/sso/login', array("return_url" => Mage::helper('core')->urlEncode("http://".Mage::getStoreConfig('zendesk/general/domain')."/requests/new"))); + return $url; + } +} diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Customer/Tickets/List.php b/src/app/code/community/Zendesk/Zendesk/Block/Customer/Tickets/List.php index 32a87b58..3bb17c06 100644 --- a/src/app/code/community/Zendesk/Zendesk/Block/Customer/Tickets/List.php +++ b/src/app/code/community/Zendesk/Zendesk/Block/Customer/Tickets/List.php @@ -61,7 +61,7 @@ public function getList() $customer = $this->getCustomer(); $tickets = null; - if($customer) { + if($customer && $customer->getEmail()) { $tickets = Mage::getModel('zendesk/api_tickets')->forRequester($customer->getEmail()); } diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Supporttab.php b/src/app/code/community/Zendesk/Zendesk/Block/Supporttab.php index c7f80fdf..20d93972 100644 --- a/src/app/code/community/Zendesk/Zendesk/Block/Supporttab.php +++ b/src/app/code/community/Zendesk/Zendesk/Block/Supporttab.php @@ -19,10 +19,10 @@ class Zendesk_Zendesk_Block_Supporttab extends Mage_Core_Block_Template { protected function _toHtml() { - if(!Mage::getStoreConfig('zendesk/features/feedback_tab_code_active')) { + if(!Mage::getStoreConfig('zendesk/frontend_features/feedback_tab_code_active')) { return ''; } - return Mage::getStoreConfig('zendesk/features/feedback_tab_code'); + return Mage::getStoreConfig('zendesk/frontend_features/feedback_tab_code'); } -} \ No newline at end of file +} diff --git a/src/app/code/community/Zendesk/Zendesk/Helper/Data.php b/src/app/code/community/Zendesk/Zendesk/Helper/Data.php index e7f7e662..051c574e 100644 --- a/src/app/code/community/Zendesk/Zendesk/Helper/Data.php +++ b/src/app/code/community/Zendesk/Zendesk/Helper/Data.php @@ -25,7 +25,7 @@ public function getUrl($object = '', $id = null, $format = 'old') $root = ($format === 'old') ? '' : '/agent/#'; $base = $protocol . $domain . $root; - + switch($object) { case '': return $base; @@ -45,6 +45,86 @@ public function getUrl($object = '', $id = null, $format = 'old') } } + /** + * Returns configured Zendesk Domain + * format: company.zendesk.com + * + * @return mixed Zendesk Account Domain + */ + public function getZendeskDomain() + { + return Mage::getStoreConfig('zendesk/general/domain'); + } + + + /** + * Returns if SSO is enabled for EndUsers + * @return integer + */ + public function isSSOEndUsersEnabled() + { + return Mage::getStoreConfig('zendesk/sso_frontend/enabled'); + } + + /** + * Returns if SSO is enabled for Admin/Agent Users + * @return integer + */ + public function isSSOAdminUsersEnabled() + { + return Mage::getStoreConfig('zendesk/sso/enabled'); + } + + /** + * Returns frontend URL where authentication process starts for EndUsers + * + * @return string SSO Url to auth EndUsers + */ + public function getSSOAuthUrlEndUsers() + { + return Mage::getUrl('zendesk/sso/login'); + } + + /** + * Returns backend URL where authentication process starts for Admin/Agents + * + * @return string SSO Url to auth Admin/Agents + */ + public function getSSOAuthUrlAdminUsers() + { + return Mage::helper('adminhtml')->getUrl('*/zendesk/login'); + } + + /** + * Returns Zendesk Account Login URL for normal access + * format: https:/// + * + * @return string Zendesk Account login url + */ + public function getZendeskAuthNormalUrl() + { + $protocol = 'https://'; + $domain = $this->getZendeskDomain(); + $route = '/access/normal'; + + return $protocol . $domain . $route; + } + + /** + * Returns Zendesk Login Form unauthenticated URL + * format: https:/// + * + * @return string Zendesk Account login unauthenticated form url + */ + public function getZendeskUnauthUrl() + { + $protocol = 'https://'; + $domain = $this->getZendeskDomain(); + $route = '/access/unauthenticated'; + + return $protocol . $domain . $route; + } + public function getApiToken($generate = true) { // Grab any existing token from the admin scope @@ -188,4 +268,104 @@ public function isExternalIdEnabled() { return Mage::getStoreConfig('zendesk/general/use_external_id'); } + + public function getTicketUrl($row, $link = false) + { + $path = Mage::getSingleton('admin/session')->getUser() ? 'adminhtml/zendesk/login' : '*/sso/login'; + $url = Mage::helper('adminhtml')->getUrl($path, array("return_url" => Mage::helper('core')->urlEncode(Mage::helper('zendesk')->getUrl('ticket', $row['id'])))); + + if ($link) + return $url; + + $subject = $row['subject'] ? $row['subject'] : $this->__('No Subject'); + + return '' . $subject. ''; + } + + public function getStatusMap() + { + return array( + 'new' => 'New', + 'open' => 'Open', + 'pending' => 'Pending', + 'solved' => 'Solved', + 'closed' => 'Closed', + 'hold' => 'Hold' + ); + } + + public function getPriorityMap() + { + return array( + 'low' => 'Low', + 'normal' => 'Normal', + 'high' => 'High', + 'urgent' => 'Urgent' + ); + } + + public function getTypeMap() + { + return array( + 'problem' => 'Problem', + 'incident' => 'Incident', + 'question' => 'Question', + 'task' => 'Task' + ); + } + + public function getChosenViews() { + $list = trim(trim(Mage::getStoreConfig('zendesk/backend_features/show_views')), ','); + return explode(',', $list); + } + + public function getFormatedDataForAPI($dateToFormat) { + $myDateTime = DateTime::createFromFormat('d/m/Y', $dateToFormat); + return $myDateTime->format('Y-m-d'); + } + + public function isValidDate($date) { + if(is_string($date)) { + $d = DateTime::createFromFormat('d/m/Y', $date); + return $d && $d->format('d/m/Y') == $date; + } + + return false; + } + + public function getFormatedDateTime($dateToFormat) { + return Mage::helper('core')->formatDate($dateToFormat, 'medium', true); + } + + public function getConnectionStatus() { + try { + $user = Mage::getModel('zendesk/api_users')->me(); + + if($user['id']) { + return array( + 'success' => true, + 'msg' => Mage::helper('zendesk')->__('Connection to Zendesk API successful'), + ); + } + + $error = Mage::helper('zendesk')->__('Connection to Zendesk API failed') . + '
' . Mage::helper('zendesk')->__('Troubleshooting tips can be found at %s', 'https://support.zendesk.com/entries/26579987', 'https://support.zendesk.com/entries/26579987'); + + return array( + 'success' => false, + 'msg' => $error, + ); + + } catch (Exception $ex) { + $error = Mage::helper('zendesk')->__('Connection to Zendesk API failed') . + '
' . $ex->getCode() . ': ' . $ex->getMessage() . + '
' . Mage::helper('zendesk')->__('Troubleshooting tips can be found at %s', 'https://support.zendesk.com/entries/26579987', 'https://support.zendesk.com/entries/26579987'); + + return array( + 'success' => false, + 'msg' => $error, + ); + } + } + } diff --git a/src/app/code/community/Zendesk/Zendesk/Model/Api/Abstract.php b/src/app/code/community/Zendesk/Zendesk/Model/Api/Abstract.php index 8861c039..9a9698c3 100644 --- a/src/app/code/community/Zendesk/Zendesk/Model/Api/Abstract.php +++ b/src/app/code/community/Zendesk/Zendesk/Model/Api/Abstract.php @@ -24,16 +24,8 @@ protected function _getUrl($path) return $base_url . '/' . $path; } - protected function _call( - $endpoint, - $params = null, - $method = 'GET', - $data = null, - $headers = null - ) + protected function _call($endpoint, $params = null, $method = 'GET', $data = null, $silent = false, $global = false) { - $usingRawData = false; - if($params && is_array($params) && count($params) > 0) { $args = array(); foreach($params as $arg => $val) { @@ -41,37 +33,27 @@ protected function _call( } $endpoint .= '?' . implode('&', $args); } - - if (empty($headers)) { - $headers = array( - 'Accept' => 'application/json', - 'Content-Type' => 'application/json', - ); - } - + $url = $this->_getUrl($endpoint); $method = strtoupper($method); $client = new Zend_Http_Client($url); $client->setMethod($method); - $client->setHeaders($headers); + $client->setHeaders( + array( + 'Accept' => 'application/json', + 'Content-Type' => 'application/json' + ) + ); $client->setAuth( - Mage::getStoreConfig('zendesk/general/email') . '/token', + Mage::getStoreConfig('zendesk/general/email'). '/token', Mage::getStoreConfig('zendesk/general/password') ); - if($method == 'POST' || $method == 'PUT') { - $contentType = $client->getHeader('Content-Type'); - - if ($contentType == 'application/json' && !preg_match('/^[\{\[]/', $contentType)) { - $data = json_encode($data); - } - - $client->setRawData($data, $client->getHeader('Content-Type')); - - $usingRawData = true; + if($method == 'POST' || $method == "PUT") { + $client->setRawData(json_encode($data), 'application/json'); } Mage::log( @@ -79,15 +61,20 @@ protected function _call( array( 'url' => $url, 'method' => $method, - 'data' => $usingRawData ? '' : json_encode($data), + 'data' => json_encode($data), ), true ), null, 'zendesk.log' ); - - $response = $client->request(); + + try { + $response = $client->request(); + } catch ( Exception $ex ) { + return array(); + } + $body = json_decode($response->getBody(), true); Mage::log(var_export($body, true), null, 'zendesk.log'); @@ -95,12 +82,27 @@ protected function _call( if($response->isError()) { if(is_array($body) && isset($body['error'])) { if(is_array($body['error']) && isset($body['error']['title'])) { - throw new Exception($body['error']['title'], $response->getStatus()); + if (!$silent) { + Mage::getSingleton('adminhtml/session')->addError(Mage::helper('zendesk')->__($body['error']['title'],$response->getStatus())); + return; + } else { + return $body; + } } else { - throw new Exception($body['error'], $response->getStatus()); + if (!$silent) { + Mage::getSingleton('adminhtml/session')->addError(Mage::helper('zendesk')->__($body['error'],$response->getStatus())); + return; + } else { + return $body; + } } } else { - throw new Exception($body, $response->getStatus()); + if (!$silent) { + Mage::getSingleton('adminhtml/session')->addError(Mage::helper('zendesk')->__($body, $response->getStatus())); + return; + } else { + return $body; + } } } diff --git a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/View.php b/src/app/code/community/Zendesk/Zendesk/Model/Api/Groups.php similarity index 55% rename from src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/View.php rename to src/app/code/community/Zendesk/Zendesk/Model/Api/Groups.php index 37e0df57..d70c239d 100644 --- a/src/app/code/community/Zendesk/Zendesk/Block/Adminhtml/Dashboard/Tab/View.php +++ b/src/app/code/community/Zendesk/Zendesk/Model/Api/Groups.php @@ -1,4 +1,5 @@ _view = $view; - $this->setId('view-' . $view['id']); + public function all() { + $page = 1; + $groups = array(); - return $this; - } + while ($page) { + $response = $this->_call('groups.json?page=' . $page); + $groups = array_merge($groups, $response['groups']); + $page = is_null($response['next_page']) ? 0 : $page + 1; + } - public function getView() - { - return $this->_view; + return $groups; } - public function __construct() - { - parent::__construct(); - $this->setTemplate('zendesk/dashboard/tabs/view.phtml'); - } } diff --git a/src/app/code/community/Zendesk/Zendesk/Model/Api/Tickets.php b/src/app/code/community/Zendesk/Zendesk/Model/Api/Tickets.php index 90238cd2..1392a689 100644 --- a/src/app/code/community/Zendesk/Zendesk/Model/Api/Tickets.php +++ b/src/app/code/community/Zendesk/Zendesk/Model/Api/Tickets.php @@ -87,6 +87,17 @@ public function recent() return $response['tickets']; } + public function all() + { + $response = $this->_call('tickets.json'); + return $response['tickets']; + } + + public function search($data) + { + return $this->_call('search.json', $data); + } + public function forOrder($orderIncrementId) { if(!$orderIncrementId) { @@ -103,7 +114,7 @@ public function forOrder($orderIncrementId) // Now check through the tickets to make sure the appropriate field has been filled out with the order number $tickets = array(); - $fieldId = Mage::getStoreConfig('zendesk/features/order_field_id'); + $fieldId = Mage::getStoreConfig('zendesk/frontend_features/order_field_id'); if(!$fieldId) { return false; @@ -132,25 +143,51 @@ public function forOrder($orderIncrementId) public function forRequester($customerEmail) { - if(!$customerEmail || strlen(trim($customerEmail)) === 0) { - throw new InvalidArgumentException('Customer email address not valid'); + $user = Mage::getModel('zendesk/api_users')->find($customerEmail); + if(isset($user['id'])) { + $response = $this->_call('users/' . $user['id'] . '/requests.json', null, 'GET', null, false); + return $response['requests']; + } else { + return array(); } - - $response = $this->_call('search.json', - array( - 'query' => 'requester:' . $customerEmail . ' type:ticket', - 'sort_order' => 'desc', - 'sort_by' => 'updated_at', - ) - ); - - return $response['results']; } - + + public function bulkDelete($data) + { + if (is_array($data)) { + $params['ids'] = implode(",",$data); + return $this->_call('tickets/destroy_many.json', $params, 'DELETE'); + } + } + + public function updateMany($ids, $data) { + if(is_array($ids)) { + $params['ids'] = implode(",", $ids); + $ticket['ticket'] = $data; + + return $this->_call('tickets/update_many.json', $params, 'PUT', $ticket); + } + } + + public function getJobStatus($url) + { + $parts = explode("/", $url); + $link = 'job_statuses/'.end($parts); + return $this->_call($link); + } + + public function bulkMarkAsSpam($data) + { + if (is_array($data)) { + $params['ids'] = implode(",",$data); + return $this->_call('tickets/mark_many_as_spam.json', $params, 'PUT'); + } + } + public function create($data) { $response = $this->_call('tickets.json', null, 'POST', $data); - + return $response['ticket']; } diff --git a/src/app/code/community/Zendesk/Zendesk/Model/Api/Users.php b/src/app/code/community/Zendesk/Zendesk/Model/Api/Users.php index 9e944fd7..6aa3f4a7 100644 --- a/src/app/code/community/Zendesk/Zendesk/Model/Api/Users.php +++ b/src/app/code/community/Zendesk/Zendesk/Model/Api/Users.php @@ -33,6 +33,13 @@ public function find($email) } } + public function me() + { + $response = $this->_call('users/me.json'); + + return $response['user']; + } + public function get($id) { if(!Zend_Validate::is($id, 'NotEmpty')) { @@ -46,7 +53,62 @@ public function get($id) public function all() { - $response = $this->_call('users.json'); - return $response['users']; + $page = 1; + $users = array(); + + while($page) { + $response = $this->_call('users.json?page=' . $page); + $users = array_merge($users, $response['users']); + $page = is_null($response['next_page']) ? 0 : $page + 1; + } + + return $users; + } + + public function end($id) + { + if(!Zend_Validate::is($id, 'NotEmpty')) { + throw new InvalidArgumentException('No ID value provided'); + } + + $response = $this->_call('end_users/'. $id .'.json'); + + return $response['user']; + } + + public function getIdentities($id) + { + $response = $this->_call('users/' . $id . '/identities.json'); + return $response['identities']; + } + + public function setPrimaryIdentity($user_id, $identity_id) + { + $response = $this->_call('users/' . $user_id . '/identities/'.$identity_id.'/make_primary.json', null, 'PUT', null, true); + return $response['identities']; + } + + public function addIdentity($user_id, $data) + { + $response = $this->_call('users/' . $user_id . '/identities.json', null, 'POST', $data, true); + return $response['identity']; + } + + public function update($user_id, $user) + { + $response = $this->_call('users/' . $user_id . '.json', null, 'PUT', $user, true); + return $response['user']; + } + + public function create($user) + { + $response = $this->_call('users.json', null, 'POST', $user, true); + return $response['user']; + } + + public function createUserField($field) + { + $response = $this->_call('user_fields.json', null, 'POST', $field, true); + return $response['user_field']; } } \ No newline at end of file diff --git a/src/app/code/community/Zendesk/Zendesk/Model/Api/Views.php b/src/app/code/community/Zendesk/Zendesk/Model/Api/Views.php index cf5e657d..df0c7c9f 100644 --- a/src/app/code/community/Zendesk/Zendesk/Model/Api/Views.php +++ b/src/app/code/community/Zendesk/Zendesk/Model/Api/Views.php @@ -33,13 +33,25 @@ public function get($id) return $response['view']; } - public function execute($id) + public function execute($id, array $params = array()) { if(!Zend_Validate::is($id, 'NotEmpty')) { throw new InvalidArgumentException('View ID not provided'); } - $response = $this->_call('views/' . $id . '/execute.json'); + $paramsString = count($params) ? '?' . http_build_query($params) : ''; + + $response = $this->_call('views/' . $id . '/execute.json' . $paramsString); + return $response; + } + + public function countByIds(array $ids) { + if(empty($ids)) { + throw new InvalidArgumentException('View ID not provided'); +} + + $response = $this->_call('views/count_many.json?ids=' . implode(',', $ids)); + return $response; } -} \ No newline at end of file +} diff --git a/src/app/code/community/Zendesk/Zendesk/Model/Observer.php b/src/app/code/community/Zendesk/Zendesk/Model/Observer.php index cef79f49..dd02e2b4 100644 --- a/src/app/code/community/Zendesk/Zendesk/Model/Observer.php +++ b/src/app/code/community/Zendesk/Zendesk/Model/Observer.php @@ -1,4 +1,5 @@ getId(); } - $enableEmail = Mage::getStoreConfig('zendesk/features/contact_us', $storeCode); + $enableEmail = Mage::getStoreConfig('zendesk/frontend_features/contact_us', $storeCode); $currentEmail = Mage::getStoreConfig('contacts/email/recipient_email', $storeCode); $oldEmail = Mage::getStoreConfig('zendesk/hidden/contact_email_old', $storeCode); $zendeskEmail = Mage::helper('zendesk')->getSupportEmail($storeCode); @@ -101,7 +102,7 @@ public function saveConfig(Varien_Event_Observer $observer) public function addTicketButton(Varien_Event_Observer $event) { $block = $event->getBlock(); - if ($block instanceof Mage_Adminhtml_Block_Sales_Order_View && Mage::getStoreConfig('zendesk/features/show_on_order')) { + if ($block instanceof Mage_Adminhtml_Block_Sales_Order_View && Mage::getStoreConfig('zendesk/backend_features/show_on_order')) { $block->addButton('ticket_new', array( 'label' => Mage::helper('zendesk')->__('Create Ticket'), 'onclick' => 'setLocation(\'' . $block->getUrl('adminhtml/zendesk/create') . '\')', @@ -109,4 +110,101 @@ public function addTicketButton(Varien_Event_Observer $event) )); } } + + public function changeIdentity(Varien_Event_Observer $event) + { + if(!Mage::getStoreConfig('zendesk/general/customer_sync')) + return; + + $user = null; + $customer = $event->getCustomer(); + $email = $customer->getEmail(); + $orig_email = $customer->getOrigData(); + $orig_email = $orig_email['email']; + + //Get Customer Group + $group_id = $customer->getGroupId(); + $group = Mage::getModel('customer/group')->load($group_id); + + //Get Customer Last Login Date + $log_customer = Mage::getModel('log/customer')->loadByCustomer($customer); + if ($log_customer->getLoginAt()) + $logged_in = date("Y-m-d\TH:i:s\Z",strtotime($log_customer->getLoginAt())); + else + $logged_in = ""; + + //Get Customer Sales Statistics + $order_totals = Mage::getResourceModel('sales/order_collection'); + $lifetime_sale = 0; + $average_sale = 0; + + if (is_object($order_totals)) { + $order_totals + ->addFieldToSelect('*') + ->addFieldToFilter('customer_id', $customer->getId()) + ->addFieldToFilter('status', Mage_Sales_Model_Order::STATE_COMPLETE) + ->addAttributeToSelect('grand_total') + ->getColumnValues('grand_total'); + + $sum = 0; + foreach ($order_totals as $total) { + if (isset($total['grand_total'])) + $sum += (float)$total['grand_total']; + } + + $lifetime_sale = Mage::helper('core')->currency($sum, true, false); + $average_sale = Mage::helper('core')->currency($sum / count($order_totals), true, false); + } + + $info['user'] = array( + "name" => $customer->getFirstname() . " " . $customer->getLastname(), + "email" => $email, + "user_fields" => array( + "group" => $group->getCode(), + "name" => $customer->getFirstname() . " " . $customer->getLastname(), + "id" => $customer->getId(), + "logged_in" => $logged_in, + "average_sale" => $average_sale, + "lifetime_sale" => $lifetime_sale + ) + ); + + if($orig_email && $orig_email !== $email) { + $user = Mage::getModel('zendesk/api_users')->find($orig_email); + + if(isset($user['id'])) { + $data['identity'] = array( + 'type' => 'email', + 'value' => $email, + 'verified' => true + ); + $identity = Mage::getModel('zendesk/api_users')->addIdentity($user['id'],$data); + if(isset($identity['id'])) { + Mage::getModel('zendesk/api_users')->setPrimaryIdentity($user['id'], $identity['id']); + } + } + } + + if(!$user) { + $user = Mage::getModel('zendesk/api_users')->find($email); + } + + if(isset($user['id'])) { + $this->syncData($user['id'], $info); + } else { + $info['user']['verified'] = true; + $this->createAccount($info); + } + } + + public function syncData($user_id, $data) + { + Mage::getModel('zendesk/api_users')->update($user_id, $data); + } + + public function createAccount($data) + { + Mage::getModel('zendesk/api_users')->create($data); + } + } diff --git a/src/app/code/community/Zendesk/Zendesk/Model/Resource/Tickets.php b/src/app/code/community/Zendesk/Zendesk/Model/Resource/Tickets.php new file mode 100644 index 00000000..0c737d49 --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Model/Resource/Tickets.php @@ -0,0 +1,25 @@ +_init('zendesk/tickets', 'id'); + } +} diff --git a/src/app/code/community/Zendesk/Zendesk/Model/Resource/Tickets/Collection.php b/src/app/code/community/Zendesk/Zendesk/Model/Resource/Tickets/Collection.php new file mode 100644 index 00000000..babe9adb --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Model/Resource/Tickets/Collection.php @@ -0,0 +1,186 @@ +_search = new Zendesk_Zendesk_Model_Search( Zendesk_Zendesk_Model_Search::TYPE_TICKET ); + } + + public function addFieldToFilter($fieldName, $condition = null) { + if(is_string($condition) OR is_array($condition)) { + + $searchFields = array(); + + switch($fieldName) { + case 'subject': + $searchFields[] = array( + 'field' => 'subject', + 'value' => '"'.$condition.'"' + ); + break; + case 'requester': + case 'requester_id': + $value = is_numeric($condition) ? $condition : '*' . $condition . '*'; + $searchFields[] = array( + 'field' => 'requester', + 'value' => $value + ); + break; + case 'tags': + case 'status': + case 'priority': + case 'status': + case 'group': + case 'assignee': + $searchFields[] = array( + 'field' => $fieldName, + 'value' => $condition + ); + break; + case 'type': + $searchFields[] = array( + 'field' => 'ticket_type', + 'value' => $condition + ); + break; + case 'id': + $searchFields[] = array( + 'field' => '', + 'value' => $condition, + 'operator' => '' + ); + break; + case 'created_at': + case 'updated_at': + $fieldName = substr($fieldName, 0, -3); + + if( isset($condition['from']) AND Mage::helper('zendesk')->isValidDate($condition['from']) ) { + $value = Mage::helper('zendesk')->getFormatedDataForAPI( $condition['from'] ); + $searchFields[] = array( + 'field' => $fieldName, + 'value' => $value, + 'operator' => '>' + ); + } + + if( isset($condition['to']) AND Mage::helper('zendesk')->isValidDate($condition['to']) ) { + $value = Mage::helper('zendesk')->getFormatedDataForAPI( $condition['to'] ); + $searchFields[] = array( + 'field' => $fieldName, + 'value' => $value, + 'operator' => '<' + ); + } + break; + } + foreach ($searchFields as $field) { + $operator = isset($field['operator']) ? $field['operator'] : ":"; + $value = isset($field['value']) ? $field['value'] : "none"; + $this->_search->addField( new Zendesk_Zendesk_Model_Search_Field($field['field'], $value, $operator)); + } + } + + return $this; + } + + public function getCollection(array $params = array()) { + $searchQuery = array( + 'query' => $this->_search->getString(), + ); + + $params = array_merge($searchQuery, $params); + + $all = Mage::getModel('zendesk/api_tickets')->search($params); + + foreach ($all['results'] as $ticket) { + $obj = new Varien_Object(); + $obj->setData($ticket); + $this->addItem($obj); + } + + $this->setPageSize($params['per_page']); + $this->setCurPage($params['page']); + $this->setOrder($params['sort_by'], $params['sort_order']); + $this->_count = $all['count']; + + Mage::unregister('zendesk_tickets_all'); + Mage::register('zendesk_tickets_all', $all['count']); + + return $this; + } + + public function getCollectionFromView($viewId, array $params = array()) { + $view = Mage::getModel('zendesk/api_views')->execute($viewId, $params); + + foreach ($view['rows'] as $row) { + $ticket = array_merge($row, $row['ticket']); + + $this->appendParamsWithoutIdPostfix($ticket, array('requester', 'assignee', 'group')); + + $obj = new Varien_Object(); + $obj->setData($ticket); + $this->addItem($obj); + } + + $this->_viewColumns = $view['columns']; + + $this->setPageSize($params['per_page']); + $this->setCurPage($params['page']); + $this->setOrder($params['sort_by'], $params['sort_order']); + $this->_count = $view['count']; + + Mage::unregister('zendesk_tickets_view_'.$viewId); + Mage::register('zendesk_tickets_view_'.$viewId, $view['count']); + + return $this; + } + + protected function appendParamsWithoutIdPostfix(& $item, array $params = array()) { + foreach($params as $param) { + $name = $param . '_id'; + + if(isset($item[$name])) { + $item[$param] = $item[$name]; + } + } + } + + public function getColumnsForView() { + $excludedColumns = static::$_excludedColumns; + + return array_filter($this->_viewColumns, function($column) use($excludedColumns) { + return ! in_array($column['id'], $excludedColumns); + }); + } + + /** + * Retrieve collection all items count + * + * @return int + */ + public function getSize() { + return (int) $this->_count; + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Model/Search.php b/src/app/code/community/Zendesk/Zendesk/Model/Search.php new file mode 100644 index 00000000..94052a81 --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Model/Search.php @@ -0,0 +1,50 @@ +setType($type); + } + + public function setType($type) { + $this->type = $type; + } + + public function addField(Zendesk_Zendesk_Model_Search_Field $field) { + $this->fields[] = $field; + } + + public function addFields(array $fields) { + foreach($fields as $field) { + if($field instanceof Zendesk_Zendesk_Model_Search_Field) { + $this->addField($field); + } + } + } + + public function getString() { + return 'type:' . $this->type . $this->separator . implode($this->separator, $this->fields); + } +} diff --git a/src/app/code/community/Zendesk/Zendesk/Model/Search/Field.php b/src/app/code/community/Zendesk/Zendesk/Model/Search/Field.php new file mode 100644 index 00000000..ec1caf73 --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Model/Search/Field.php @@ -0,0 +1,50 @@ +setName($name); + $this->setValue($value); + $this->setOperator($operator); + } + + public function setName($name) { + $this->name = $name; + } + + public function setValue($value) { + $this->value = $value; + } + + public function setOperator($operator) { + $this->operator = $operator; + } + + public function getString() { + return $this->name . $this->operator . $this->value; + } + + public function __toString() { + return $this->getString(); + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/Model/Source/Sortdir.php b/src/app/code/community/Zendesk/Zendesk/Model/Source/Sortdir.php new file mode 100644 index 00000000..cd74f71b --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Model/Source/Sortdir.php @@ -0,0 +1,37 @@ +_options[] = array( + 'label' => Mage::helper('zendesk')->__('Descending'), + 'value' => 'desc' + ); + + $this->_options[] = array( + 'label' => Mage::helper('zendesk')->__('Ascending'), + 'value' => 'asc' + ); + + + return $this->_options; + } +} diff --git a/src/app/code/community/Zendesk/Zendesk/Model/Source/Sortorder.php b/src/app/code/community/Zendesk/Zendesk/Model/Source/Sortorder.php new file mode 100644 index 00000000..8a79b011 --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Model/Source/Sortorder.php @@ -0,0 +1,37 @@ +_options[] = array( + 'label' => Mage::helper('zendesk')->__('Requested Date'), + 'value' => 'created_at' + ); + + $this->_options[] = array( + 'label' => Mage::helper('zendesk')->__('Updated Date'), + 'value' => 'updated_at' + ); + + + return $this->_options; + } +} diff --git a/src/app/code/community/Zendesk/Zendesk/Model/Tickets.php b/src/app/code/community/Zendesk/Zendesk/Model/Tickets.php new file mode 100644 index 00000000..6fa10b4d --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/Model/Tickets.php @@ -0,0 +1,26 @@ +_init('zendesk/tickets'); + } + +} diff --git a/src/app/code/community/Zendesk/Zendesk/controllers/Adminhtml/ZendeskController.php b/src/app/code/community/Zendesk/Zendesk/controllers/Adminhtml/ZendeskController.php index 574b0a68..cc09dcd4 100644 --- a/src/app/code/community/Zendesk/Zendesk/controllers/Adminhtml/ZendeskController.php +++ b/src/app/code/community/Zendesk/Zendesk/controllers/Adminhtml/ZendeskController.php @@ -23,6 +23,21 @@ class Zendesk_Zendesk_Adminhtml_ZendeskController extends Mage_Adminhtml_Control public function indexAction() { + if (!$this->_domainConfigured()) { + return; + } + + $connection = Mage::helper('zendesk')->getConnectionStatus(); + + if(!$connection['success']) { + $this->setFlag('', 'no-dispatch', true); + Mage::getSingleton('adminhtml/session')->addError( $connection['msg'] ); + $this->_redirect('adminhtml/dashboard'); + return; + } + + $this->storeDependenciesInCachedRegistry(); + $this->_title($this->__('Zendesk Dashboard')); $this->loadLayout(); $this->_setActiveMenu('zendesk/zendesk_dashboard'); @@ -66,6 +81,7 @@ public function authenticateAction() $domain = Mage::getStoreConfig('zendesk/general/domain'); $token = Mage::getStoreConfig('zendesk/sso/token'); + $return_url = Mage::helper('core')->urlDecode($this->getRequest()->getParam('return_url', "")); if(!Zend_Validate::is($domain, 'NotEmpty')) { Mage::getSingleton('adminhtml/session')->addError(Mage::helper('zendesk')->__('Zendesk domain not set. Please add this to the settings page.')); @@ -101,19 +117,26 @@ public function authenticateAction() Mage::log('Admin JWT: ' . var_export($payload, true), null, 'zendesk.log'); $jwt = JWT::encode($payload, $token); - - $url = "http://".$domain."/access/jwt?jwt=" . $jwt; + $return = $return_url ? "&return_to=".$return_url : ""; + + $url = "http://".$domain."/access/jwt?jwt=" . $jwt . $return; Mage::log('Admin URL: ' . $url, null, 'zendesk.log'); $this->_redirectUrl($url); } - + /** * Wrapper for the existing authenticate action. Mirrors the login/logout actions available for customers. */ public function loginAction() { + if(!Mage::getStoreConfig('zendesk/sso/enabled')) { + Mage::getSingleton('adminhtml/session')->addError(Mage::helper('zendesk')->__('Single sign-on disabled.')); + $url = Mage::helper('core')->urlDecode($this->getRequest()->getParam('return_url', "")); + $this->_redirectUrl($url); + return; + } $this->authenticateAction(); } @@ -129,11 +152,15 @@ public function logoutAction() $adminSession->getCookie()->delete($adminSession->getSessionName()); $adminSession->addSuccess(Mage::helper('adminhtml')->__('You have logged out.')); - $this->_redirect('*'); + $this->_redirect('adminhtml/zendesk/*'); } public function createAction() { + if (!$this->_domainConfigured()) { + return; + } + // Check if we have been passed an order ID, in which case we can preload some of the form details if($orderId = $this->getRequest()->getParam('order_id')) { $order = Mage::getModel('sales/order')->load($orderId); @@ -162,11 +189,27 @@ public function createAction() $this->getLayout()->getBlock('js')->append($block); $this->renderLayout(); + } public function launchAction() { - $this->_redirectUrl(Mage::helper('zendesk')->getUrl()); + $domain = $this->_domainConfigured(); + if (!$domain) { + return; + } + + $sso = Mage::getStoreConfig('zendesk/sso/enabled'); + + if (!$sso) { + $url = "http://".$domain; + } elseif(Mage::helper('zendesk')->isSSOAdminUsersEnabled()) { + $url = Mage::helper('zendesk')->getSSOAuthUrlAdminUsers(); + } else { + $url = Mage::helper('zendesk')->getZendeskUnauthUrl(); + } + + $this->_redirectUrl($url); } public function saveAction() @@ -255,7 +298,7 @@ public function saveAction() $ticket['ticket']['type'] = $data['type']; } - if( ($fieldId = Mage::getStoreConfig('zendesk/features/order_field_id')) && isset($data['order']) && strlen(trim($data['order'])) > 0) { + if( ($fieldId = Mage::getStoreConfig('zendesk/frontend_features/order_field_id')) && isset($data['order']) && strlen(trim($data['order'])) > 0) { $ticket['ticket']['fields'] = array( 'id' => $fieldId, 'value' => $data['order'] @@ -265,7 +308,7 @@ public function saveAction() $response = Mage::getModel('zendesk/api_tickets')->create($ticket); $text = Mage::helper('zendesk')->__('Ticket #%s Created', $response['id']); - $text .= ' '; + $text .= ' '; $text .= Mage::helper('zendesk')->__('View ticket in Zendesk'); $text .= ''; @@ -319,7 +362,7 @@ public function autocompleteAction() public function logAction() { $path = Mage::helper('zendesk/log')->getLogPath(); - + if(!file_exists($path)) { Mage::getSingleton('adminhtml/session')->addError(Mage::helper('zendesk')->__('The Zendesk log file has not been created. Check to see if logging has been enabled.')); } @@ -346,18 +389,329 @@ public function clearLogAction() } public function checkOutboundAction() + { + $connection = Mage::helper('zendesk')->getConnectionStatus(); + + $this->getResponse()->clearHeaders()->setHeader('Content-type','application/json', true); + $this->getResponse()->setBody(json_encode($connection)); + } + + /** + * Loading page block + */ + public function loadBlockAction() { - try { - // Try to retrieve a user with ID 1, which should always exist as a user account is needed to set up - // the API credentials in the first place. + $request = $this->getRequest(); + + $block = $request->getParam('block'); + $update = $this->getLayout()->getUpdate(); + + + $update->addHandle('adminhtml_zendesk_create_load_block_'.$block); + + $this->loadLayoutUpdates()->generateLayoutXml()->generateLayoutBlocks(); + $result = $this->getLayout()->getBlock('content')->toHtml(); + if ($request->getParam('as_js_varname')) { + Mage::getSingleton('adminhtml/session')->setUpdateResult($result); + $this->_redirect('*/*/showUpdateResult'); + } else { + $this->getResponse()->setBody($result); + } + } + + public function getUserAction() + { + $request = $this->getRequest(); + $id = $request->getParam('id'); + + $user = Mage::getModel('customer/customer')->load($id); + + $this->getResponse()->clearHeaders()->setHeader('Content-type','application/json',true); + + if($user->getId()) { + $this->getResponse()->setBody(json_encode(array('success'=>true, 'usr'=> array( + 'firstname' => $user->getFirstname(), + 'lastname' => $user->getLastname(), + 'email' => $user->getEmail() + )))); + } else { + $this->getResponse()->setBody(json_encode(array('success'=>false, 'msg'=>Mage::helper('zendesk')->__('User does not exist')))); + } + } + + public function getOrderAction() + { + $request = $this->getRequest(); + $id= $request->getParam('id'); + + $order = Mage::getModel('sales/order')->load($id); + + $this->getResponse()->clearHeaders()->setHeader('Content-type','application/json',true); + if($order->getId()) { + $this->getResponse()->setBody(json_encode(array('success'=>true, 'order'=> array( + 'number' => $order->getIncrementId(), + )))); + } else { + $this->getResponse()->setBody(json_encode(array('success'=>false, 'msg'=>Mage::helper('zendesk')->__('Order does not exist')))); + } + } + + public function syncAction() + { + $this->getResponse()->clearHeaders()->setHeader('Content-type','application/json',true); + Mage::log('Synchronization started', null, 'zendesk.log'); + try { $user = Mage::getModel('zendesk/api_users')->all(); - Mage::getSingleton('adminhtml/session')->addSuccess(Mage::helper('zendesk')->__('Connection to Zendesk API successful')); - } catch(Exception $e) { - Mage::getSingleton('adminhtml/session')->addError(Mage::helper('zendesk')->__('Connection to Zendesk API failed') . - '
' . $e->getCode() . ': ' . $e->getMessage() . - '
' . Mage::helper('zendesk')->__('Troubleshooting tips can be found at %s', 'https://support.zendesk.com/entries/26579987', 'https://support.zendesk.com/entries/26579987')); + if (is_null($user)) + throw new Exception("Connection Failed"); + + $data = array(); + $data[] = array( + 'user_field' => array( + 'type' => 'integer', + 'title' => 'ID', + 'description' => 'Magento Customer Id', + 'position' => 0, + 'active' => true, + 'key' => 'id' + ) + ); + $data[] = array( + 'user_field' => array( + 'type' => 'text', + 'title' => 'Name', + 'description' => 'Magento Customer Name', + 'position' => 1, + 'active' => true, + 'key' => 'name' + ) + ); + $data[] = array( + 'user_field' => array( + 'type' => 'text', + 'title' => 'Group', + 'description' => 'Magento Customer Group', + 'position' => 2, + 'active' => true, + 'key' => 'group' + ) + ); + $data[] = array( + 'user_field' => array( + 'type' => 'text', + 'title' => 'Lifetime Sale', + 'description' => 'Magento Customer Lifetime Sale', + 'position' => 3, + 'active' => true, + 'key' => 'lifetime_sale' + ) + ); + $data[] = array( + 'user_field' => array( + 'type' => 'text', + 'title' => 'Average Sale', + 'description' => 'Magento Customer Average Sale', + 'position' => 4, + 'active' => true, + 'key' => 'average_sale' + ) + ); + $data[] = array( + 'user_field' => array( + 'type' => 'date', + 'title' => 'Last Logged In', + 'description' => 'Last Logged In', + 'position' => 5, + 'active' => true, + 'key' => 'logged_in' + ) + ); + + foreach($data as $field) { + $response = Mage::getModel('zendesk/api_users')->createUserField($field); + if (!isset($response['active']) || $response['active'] === false) + Mage::log('Unable to create User Field with key '.$field['user_field']['key'], null, 'zendesk.log'); + } + + $customers = Mage::getModel('customer/customer')->getCollection(); + $customers->addAttributeToSelect(array('firstname', 'lastname', 'email')); + foreach($customers as $customer) { + Mage::log('Synchronizing customer with id '.$customer->getId(), null, 'zendesk.log'); + Mage::dispatchEvent('customer_save_commit_after', array('customer' => $customer)); + } + + } catch (Exception $ex) { + Mage::log('Synchronization failed: '.$ex->getMessage(), null, 'zendesk.log'); + $this->getResponse()->setBody(json_encode(array('success'=>false, 'msg'=>Mage::helper('zendesk')->__('Synchronization failed: ').$ex->getMessage()))); + return; } + Mage::log('Synchronization completed successfully', null, 'zendesk.log'); + $this->getResponse()->setBody(json_encode(array('success'=>true, 'msg'=>Mage::helper('zendesk')->__('Customers synchronization finished successfuly')))); + } - $this->_redirect('adminhtml/system_config/edit/section/zendesk'); + public function bulkDeleteAction() + { + $ids = $this->getRequest()->getParam('id'); + try { + $response = Mage::getModel('zendesk/api_tickets')->bulkDelete($ids); + $message = '%d out of %d ticket(s) were deleted.'; + $this->getMassActionResponse($response, $ids, $message); + } catch (Exception $e) { + Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); + } + $this->_redirectReferer(); + } + + public function bulkChangeStatusAction() + { + $ids = $this->getRequest()->getParam('id'); + $status = $this->getRequest()->getParam('status'); + + try { + $response = Mage::getModel('zendesk/api_tickets')->updateMany($ids, compact('status')); + $this->getMassActionResponse($response, $ids); + } catch (Exception $e) { + Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); + } + $this->_redirect('adminhtml/zendesk/'); + } + + public function bulkChangePriorityAction() + { + $ids = $this->getRequest()->getParam('id'); + $priority = $this->getRequest()->getParam('priority'); + + try { + $response = Mage::getModel('zendesk/api_tickets')->updateMany($ids, compact('priority')); + $this->getMassActionResponse($response, $ids); + } catch (Exception $e) { + Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); + } + $this->_redirect('adminhtml/zendesk/'); + } + + public function bulkChangeTypeAction() + { + $ids = $this->getRequest()->getParam('id'); + $type = $this->getRequest()->getParam('type'); + + try { + $response = Mage::getModel('zendesk/api_tickets')->updateMany($ids, compact('type')); + $this->getMassActionResponse($response, $ids); + } catch (Exception $e) { + Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); + } + $this->_redirect('adminhtml/zendesk/'); + } + + public function bulkMarkSpamAction() + { + $ids = $this->getRequest()->getParam('id'); + + try { + $response = Mage::getModel('zendesk/api_tickets')->bulkMarkAsSpam($ids); + $message = '%d out of %d ticket(s) were marked as spam.'; + $this->getMassActionResponse($response, $ids, $message); + } catch (Exception $e) { + Mage::getSingleton('adminhtml/session')->addError($e->getMessage()); + } + $this->_redirectReferer(); + } + + public function ticketsAllAction() { + $isAjax = Mage::app()->getRequest()->isAjax(); + + if ($isAjax) { + $this->storeDependenciesInCachedRegistry(); + $this->getResponse()->setBody($this->getLayout()->createBlock('zendesk/adminhtml_dashboard_tab_tickets_grid_all')->toHtml()); + } + } + + public function ticketsViewAction() { + $isAjax = Mage::app()->getRequest()->isAjax(); + + if ($isAjax) { + $this->storeDependenciesInCachedRegistry(); + $viewId = (int) $this->getRequest()->getParam('viewid'); + Mage::register('zendesk_tickets_view', $viewId); + + $this->getResponse()->setBody($this->getLayout()->createBlock('zendesk/adminhtml_dashboard_tab_tickets_grid_view')->toHtml()); + } } + + protected function storeDependenciesInCachedRegistry() { + $cache = Mage::app()->getCache(); + + if( $cache->load('zendesk_users') === false) { + $users = serialize( Mage::getModel('zendesk/api_users')->all() ); + $cache->save($users, 'zendesk_users', array('zendesk', 'zendesk_users'), 300); + } + + if( $cache->load('zendesk_groups') === false) { + $groups = serialize( Mage::getModel('zendesk/api_groups')->all() ); + $cache->save($groups, 'zendesk_groups', array('zendesk', 'zendesk_groups'), 1200); + } + + $users = unserialize( $cache->load('zendesk_users') ); + $groups = unserialize( $cache->load('zendesk_groups') ); + + Mage::register('zendesk_users', $users); + Mage::register('zendesk_groups', $groups); + } + + protected function getMassActionResponse($response, $ids, $message = '%d out of %d ticket(s) were updated.') + { + if (isset($response['job_status']) && isset($response['job_status']['url'])) { + $job_status = Mage::getModel('zendesk/api_tickets')->getJobStatus($response['job_status']['url']); + + $parsed = array(); + $parsed['errors'] = array(); + $parsed['success'] = 0; + + if (isset($job_status['job_status']['results'])) { + foreach ($job_status['job_status']['results'] as $result) { + if ($result['success']) { + $parsed['success'] ++; + continue; + } + + if ($result['errors']) + $parsed['errors'][] = $result['errors']." (ID:".$result['id'].")"; + } + } + + Mage::getSingleton('adminhtml/session')->addSuccess( + Mage::helper('zendesk')->__( + $message, + $parsed['success'], + count($ids) + ) + ); + + foreach ($parsed['errors'] as $error) { + Mage::getSingleton('adminhtml/session')->addError( + Mage::helper('zendesk')->__($error) + ); + } + } else { + Mage::getSingleton('adminhtml/session')->addError( + Mage::helper('zendesk')->__( + 'Request failed for %d ticket(s).', count($ids) + ) + ); + } + } + + private function _domainConfigured() + { + $domain = Mage::getStoreConfig('zendesk/general/domain'); + if(!$domain) { + Mage::getSingleton('adminhtml/session')->addError(Mage::helper('zendesk')->__('Please set up Zendesk connection.')); + $this->_redirect('adminhtml/dashboard'); + return false; + } else { + return $domain; + } + } + } diff --git a/src/app/code/community/Zendesk/Zendesk/controllers/ApiController.php b/src/app/code/community/Zendesk/Zendesk/controllers/ApiController.php index c3cd7ae2..12e7d91e 100644 --- a/src/app/code/community/Zendesk/Zendesk/controllers/ApiController.php +++ b/src/app/code/community/Zendesk/Zendesk/controllers/ApiController.php @@ -32,6 +32,10 @@ public function _authorise() if(!$tokenString && isset($_SERVER['HTTP_AUTHORIZATION'])) { $tokenString = $_SERVER['HTTP_AUTHORIZATION']; } + + if (!$tokenString && isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) { + $tokenString = $_SERVER['REDIRECT_HTTP_AUTHORIZATION']; + } if (!$tokenString) { // Certain server configurations fail to extract headers from the request, see PR #24. @@ -308,7 +312,7 @@ public function finaliseAction() if(!isset($data['order_field_id'])) { $missingFields[] = 'order_field_id'; } else { - $configUpdates['zendesk/features/order_field_id'] = $data['order_field_id']; + $configUpdates['zendesk/frontend_features/order_field_id'] = $data['order_field_id']; } // Check that the required fields were provided and send back an error if not @@ -339,15 +343,15 @@ public function finaliseAction() } if(isset($data['magento_footer_link'])) { - $configUpdates['zendesk/features/footer_link_enabled'] = ($data['magento_footer_link'] == 'true'); + $configUpdates['zendesk/frontend_features/footer_link_enabled'] = ($data['magento_footer_link'] == 'true'); } if(isset($data['email_forwarding'])) { - $configUpdates['zendesk/features/contact_us'] = ($data['email_forwarding'] == 'true'); + $configUpdates['zendesk/frontend_features/contact_us'] = ($data['email_forwarding'] == 'true'); // Process this now, since it otherwise won't be triggered until the config page is saved // Unlike in the observer, we only need to deal with the case where the setting is enabled - if($configUpdates['zendesk/features/contact_us']) { + if($configUpdates['zendesk/frontend_features/contact_us']) { $currentEmail = Mage::getStoreConfig('contacts/email/recipient_email'); $zendeskEmail = 'support@' . $configUpdates['zendesk/general/domain']; @@ -364,11 +368,11 @@ public function finaliseAction() } if(isset($data['feedback_tab'])) { - $configUpdates['zendesk/features/feedback_tab_code_active'] = ($data['feedback_tab'] === 'true'); + $configUpdates['zendesk/frontend_features/feedback_tab_code_active'] = ($data['feedback_tab'] === 'true'); } if(isset($data['feedback_tab_html'])) { - $configUpdates['zendesk/features/feedback_tab_code'] = $data['feedback_tab_html']; + $configUpdates['zendesk/frontend_features/feedback_tab_code'] = $data['feedback_tab_html']; } diff --git a/src/app/code/community/Zendesk/Zendesk/controllers/IndexController.php b/src/app/code/community/Zendesk/Zendesk/controllers/IndexController.php index 63610cd8..a38f8784 100644 --- a/src/app/code/community/Zendesk/Zendesk/controllers/IndexController.php +++ b/src/app/code/community/Zendesk/Zendesk/controllers/IndexController.php @@ -22,7 +22,12 @@ class Zendesk_Zendesk_IndexController extends Mage_Core_Controller_Front_Action */ public function indexAction() { - $url = Mage::helper('zendesk')->getUrl(); + if(Mage::helper('zendesk')->isSSOEndUsersEnabled()) { + $url = Mage::helper('zendesk')->getSSOAuthUrlEndUsers(); + } else { + $url = Mage::helper('zendesk')->getUrl(); + } $this->_redirectUrl($url); } -} \ No newline at end of file + +} diff --git a/src/app/code/community/Zendesk/Zendesk/controllers/SsoController.php b/src/app/code/community/Zendesk/Zendesk/controllers/SsoController.php index e7431c3a..15619634 100644 --- a/src/app/code/community/Zendesk/Zendesk/controllers/SsoController.php +++ b/src/app/code/community/Zendesk/Zendesk/controllers/SsoController.php @@ -32,7 +32,8 @@ public function loginAction() $domain = Mage::getStoreConfig('zendesk/general/domain'); $token = Mage::getStoreConfig('zendesk/sso_frontend/token'); - + $return_url = Mage::helper('core')->urlDecode($this->getRequest()->getParam('return_url', "")); + if(!Zend_Validate::is($domain, 'NotEmpty')) { Mage::log(Mage::helper('zendesk')->__('Zendesk domain not set. Please add this to the settings page.'), null, 'zendesk.log'); $this->_redirect('/'); @@ -77,8 +78,9 @@ public function loginAction() Mage::log('End-user JWT: ' . var_export($payload, true), null, 'zendesk.log'); $jwt = JWT::encode($payload, $token); - - $url = "http://".$domain."/access/jwt?jwt=" . $jwt; + $return_url = $return_url ? "&return_to=".$return_url : ""; + + $url = "http://".$domain."/access/jwt?jwt=" . $jwt.$return_url; Mage::log('End-user URL: ' . $url, null, 'zendesk.log'); diff --git a/src/app/code/community/Zendesk/Zendesk/data/zendesk_setup/data-upgrade-1.3.0-1.4.0.php b/src/app/code/community/Zendesk/Zendesk/data/zendesk_setup/data-upgrade-1.3.0-1.4.0.php new file mode 100644 index 00000000..3142c621 --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/data/zendesk_setup/data-upgrade-1.3.0-1.4.0.php @@ -0,0 +1,36 @@ + $value ) +{ + $config->saveConfig($key, $value, 'default', 0); +} diff --git a/src/app/code/community/Zendesk/Zendesk/data/zendesk_setup/data-upgrade-1.3.1-1.4.0.php b/src/app/code/community/Zendesk/Zendesk/data/zendesk_setup/data-upgrade-1.3.1-1.4.0.php new file mode 100644 index 00000000..3142c621 --- /dev/null +++ b/src/app/code/community/Zendesk/Zendesk/data/zendesk_setup/data-upgrade-1.3.1-1.4.0.php @@ -0,0 +1,36 @@ + $value ) +{ + $config->saveConfig($key, $value, 'default', 0); +} diff --git a/src/app/code/community/Zendesk/Zendesk/etc/config.xml b/src/app/code/community/Zendesk/Zendesk/etc/config.xml index ecc42109..6501fb91 100644 --- a/src/app/code/community/Zendesk/Zendesk/etc/config.xml +++ b/src/app/code/community/Zendesk/Zendesk/etc/config.xml @@ -19,7 +19,7 @@ - 1.3.1 + 1.4.0 @@ -79,6 +79,24 @@ + + + + + zendesk/observer + changeIdentity + + + + + + + zendesk/observer + changeIdentity + + + + @@ -109,6 +127,7 @@ + @@ -141,6 +160,15 @@ + + + + zendesk/observer + changeIdentity + + + + @@ -162,11 +190,11 @@ adminhtml/zendesk/launch 3 - - Settings + + Configuration adminhtml/system_config/edit/section/zendesk 4 - + Log Viewer adminhtml/zendesk/log @@ -218,13 +246,21 @@ - - 1 - 1 - 1 + + 0 + + 0 0 - + + + 0 + 1 + 1 + 1 + created_at + desc + diff --git a/src/app/code/community/Zendesk/Zendesk/etc/system.xml b/src/app/code/community/Zendesk/Zendesk/etc/system.xml index 7cf8d965..b4976a6e 100644 --- a/src/app/code/community/Zendesk/Zendesk/etc/system.xml +++ b/src/app/code/community/Zendesk/Zendesk/etc/system.xml @@ -35,7 +35,7 @@ 1 1 - + 1 General settings that are required to connect Zendesk and Magento. @@ -44,7 +44,7 @@ 1 1 1 - + text @@ -80,7 +80,7 @@ 1 1 - + select adminhtml/system_config_source_yesno @@ -90,6 +90,26 @@ 1 + + + select + adminhtml/system_config_source_yesno + 6 + 1 + 1 + 1 + + + + + Sync All Customers And Create User Fields + zendesk/adminhtml_config_buttons_sync + 7 + 1 + 1 + 1 + + @@ -150,53 +170,16 @@ - + 1 - + Decide which features you would like turned on in your Magento store. text 30 1 1 1 - - - - select - adminhtml/system_config_source_yesno - 1 - 1 - 1 - 0 - - - - multiselect - zendesk/source_views - 2 - 1 - 1 - 0 - 1 - - - - select - adminhtml/system_config_source_yesno - 3 - 1 - 1 - 0 - - - - select - adminhtml/system_config_source_yesno - 4 - 1 - 1 - 0 - + select @@ -247,6 +230,16 @@ 1 1 + + + select + adminhtml/system_config_source_yesno + 20 + 1 + 1 + 1 + + text @@ -256,18 +249,84 @@ 1 - - + + + + 1 + + Decide which features you would like turned on in your admin panel. + text + 35 + 1 + 1 + 1 + + + select adminhtml/system_config_source_yesno - 20 + 7 1 1 - 1 - - + 0 + + + + select + adminhtml/system_config_source_yesno + 5 + 1 + 1 + 0 + + + + select + adminhtml/system_config_source_yesno + 1 + 1 + 1 + 0 + + + + select + zendesk/source_sortorder + 2 + 1 + 1 + 0 + + + + select + zendesk/source_sortdir + 3 + 1 + 1 + 0 + + + + multiselect + zendesk/source_views + 4 + 1 + 1 + 0 + 1 + + + + select + adminhtml/system_config_source_yesno + 6 + 1 + 1 + 0 + - + Required for Magento App inside Zendesk to work. @@ -296,7 +355,7 @@ - Generate new token + Generate New Token zendesk/adminhtml_config_buttons_generate 3 1 @@ -417,7 +476,7 @@ - Setup guide + Setup Guide zendesk/adminhtml_config_buttons_signup 1 1 diff --git a/src/app/design/adminhtml/default/default/layout/zendesk.xml b/src/app/design/adminhtml/default/default/layout/zendesk.xml index a0ae8259..3ef3f26a 100644 --- a/src/app/design/adminhtml/default/default/layout/zendesk.xml +++ b/src/app/design/adminhtml/default/default/layout/zendesk.xml @@ -1,37 +1,49 @@ +* Copyright 2012 Zendesk. +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +--> - - - zendesk/zendesk.css - - + + + + zendesk/zendesk.css + + + - zendesk/zendesk.css + + zendesk/zendesk.css + + + + + zendesk/zendesk.css + + + + @@ -39,26 +51,69 @@ + + + zendesk/zendesk.css + + - dashboard + + dashboard + - + + + + + + + + + + + + + + + + + + + + + + + + + + + zendesk/zendesk.css + + - create + + create + + + + + + + diff --git a/src/app/design/adminhtml/default/default/template/zendesk/config/button-sync.phtml b/src/app/design/adminhtml/default/default/template/zendesk/config/button-sync.phtml new file mode 100644 index 00000000..4be8dc3b --- /dev/null +++ b/src/app/design/adminhtml/default/default/template/zendesk/config/button-sync.phtml @@ -0,0 +1,43 @@ + + + +
+ diff --git a/src/app/design/adminhtml/default/default/template/zendesk/config/button-test-magento.phtml b/src/app/design/adminhtml/default/default/template/zendesk/config/button-test-magento.phtml index 1747fb45..a0a9483e 100644 --- a/src/app/design/adminhtml/default/default/template/zendesk/config/button-test-magento.phtml +++ b/src/app/design/adminhtml/default/default/template/zendesk/config/button-test-magento.phtml @@ -41,4 +41,4 @@ -
\ No newline at end of file +
diff --git a/src/app/design/adminhtml/default/default/template/zendesk/config/button-test-zendesk.phtml b/src/app/design/adminhtml/default/default/template/zendesk/config/button-test-zendesk.phtml index 1e4c2816..54e2f7a0 100644 --- a/src/app/design/adminhtml/default/default/template/zendesk/config/button-test-zendesk.phtml +++ b/src/app/design/adminhtml/default/default/template/zendesk/config/button-test-zendesk.phtml @@ -15,6 +15,28 @@ * limitations under the License. */ ?> - \ No newline at end of file + + +
+ diff --git a/src/app/design/adminhtml/default/default/template/zendesk/create/customer.phtml b/src/app/design/adminhtml/default/default/template/zendesk/create/customer.phtml new file mode 100644 index 00000000..4b2ff71a --- /dev/null +++ b/src/app/design/adminhtml/default/default/template/zendesk/create/customer.phtml @@ -0,0 +1,46 @@ + +
+
+
getButtonsHtml() ?>
+

getHeaderText() ?>

+
+
+ getChildHtml('', true, true) ?> +
+
+ diff --git a/src/app/design/adminhtml/default/default/template/zendesk/create/order.phtml b/src/app/design/adminhtml/default/default/template/zendesk/create/order.phtml new file mode 100644 index 00000000..bc1c8986 --- /dev/null +++ b/src/app/design/adminhtml/default/default/template/zendesk/create/order.phtml @@ -0,0 +1,45 @@ + +
+
+
getButtonsHtml() ?>
+

getHeaderText() ?>

+
+
+ getChildHtml('', true, true) ?> +
+
+ diff --git a/src/app/design/adminhtml/default/default/template/zendesk/customer/tickets.phtml b/src/app/design/adminhtml/default/default/template/zendesk/customer/tickets.phtml index 7d3252c0..be70c518 100644 --- a/src/app/design/adminhtml/default/default/template/zendesk/customer/tickets.phtml +++ b/src/app/design/adminhtml/default/default/template/zendesk/customer/tickets.phtml @@ -17,7 +17,7 @@ ?> - get($ticket['id'], true); ?> - - - - formatDate($ticket['created_at'], Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM, true); ?> - formatDate($ticket['updated_at'], Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM, true); ?> - - - - + get($ticket['id'], true); ?> + + + getTicketUrl($ticket); ?> + formatDate($ticket['created_at'], Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM, true); ?> + formatDate($ticket['updated_at'], Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM, true); ?> + + + + @@ -71,4 +71,4 @@ if($customer = Mage::registry('current_customer')) {
- \ No newline at end of file + diff --git a/src/app/design/adminhtml/default/default/template/zendesk/dashboard/index.phtml b/src/app/design/adminhtml/default/default/template/zendesk/dashboard/index.phtml index 5bb3d3af..e21e6df8 100644 --- a/src/app/design/adminhtml/default/default/template/zendesk/dashboard/index.phtml +++ b/src/app/design/adminhtml/default/default/template/zendesk/dashboard/index.phtml @@ -15,30 +15,31 @@ * limitations under the License. */ ?> -getIsZendeskDashboard() || Mage::getStoreConfig('zendesk/features/show_on_dashboard')): ?> - getIsZendeskDashboard()): ?> -
- - - - -

__('Dashboard') ?>

-
- -
- getChildHtml('zendesk_dashboard_grids') ?> -
- - getIsZendeskDashboard()): ?> -
- - +isConnected() ): ?> + getIsZendeskDashboard() || Mage::getStoreConfig('zendesk/backend_features/show_on_dashboard')): ?> + getIsZendeskDashboard()): ?> +
+ + + + +

__('Dashboard') ?>

-
- getChildHtml('zendesk_dashboard_empty'); ?> - \ No newline at end of file +
+ getChildHtml('zendesk_dashboard_grids') ?> +
+ getIsZendeskDashboard()): ?> +
+ + +
+ +
+ getChildHtml('zendesk_dashboard_empty'); ?> + + diff --git a/src/app/design/adminhtml/default/default/template/zendesk/dashboard/tabs/view.phtml b/src/app/design/adminhtml/default/default/template/zendesk/dashboard/tabs/view.phtml deleted file mode 100644 index 28d114c7..00000000 --- a/src/app/design/adminhtml/default/default/template/zendesk/dashboard/tabs/view.phtml +++ /dev/null @@ -1,140 +0,0 @@ - -getView(); - -if($view) { - try { - $execute = Mage::getModel('zendesk/api_views')->execute($view['id']); - - $columns = $execute['columns']; - $rows = $execute['rows']; - - $isScoped = Mage::getModel('customer/customer')->getSharingConfig()->isWebsiteScope(); - - $users = array(); - $magentoUsers = array(); - - if(isset($execute['users'])) { - foreach($execute['users'] as $user) { - $users[$user['id']] = $user['name']; - - // TODO: Re-enable once the results can be cached, to reduce the significant performance impact -// if(!$isScoped && !isset($magentoUsers[$user['id']])) { -// $info = Mage::getModel('zendesk/api_users')->get($user['id']); -// $customer = Mage::getModel('customer/customer')->loadByEmail($info['email']); -// -// if($customer && $customer->getId()) { -// $magentoUsers[$user['id']] = $customer->getId(); -// } else { -// $magentoUsers[$user['id']] = false; -// } -// } - } - } - - if(isset($execute['groups'])) { - $groups = array(); - foreach($execute['groups'] as $group) { - $groups[$group['id']] = $group['name']; - } - } - } catch(Exception $e) { - // Most likely the Zendesk domain has not been configured, so just don't show anything here. - $view = null; - } -} -?> - -
- - - - - - - - - - - - - - - - getUrl('ticket', $row['ticket']['id']); - $value = '' . $value . ''; - } - break; - - case 'requester': - case 'assignee': - $name = $value; - - if(isset($users[$value])) { - $name = $users[$value]; - } - - if(isset($magentoUsers[$value]) && $magentoUsers[$value] !== false) { - $url = $this->getUrl('adminhtml/customer/edit', array('id' => $magentoUsers[$value])); - $value = '' . $name . ''; - } else { - $value = $name; - } - break; - - case 'created': - case 'updated': - $value = Mage::helper('core')->formatDate($value, Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM, true); - break; - - case 'group': - if(isset($groups[$value])) { - $value = $groups[$value]; - } - break; - } - ?> - - - - - - - - - - -
__($col['title']); ?>
__('No tickets found'); ?>
-
-
- \ No newline at end of file diff --git a/src/app/design/adminhtml/default/default/template/zendesk/left-menu.phtml b/src/app/design/adminhtml/default/default/template/zendesk/left-menu.phtml index 152b235d..9b0570fa 100644 --- a/src/app/design/adminhtml/default/default/template/zendesk/left-menu.phtml +++ b/src/app/design/adminhtml/default/default/template/zendesk/left-menu.phtml @@ -33,7 +33,7 @@ isAllowed('launch')) { ?>
  • - + __('Launch Zendesk'); ?>
  • @@ -41,8 +41,9 @@ isAllowed('settings')) { ?>
  • - __('Settings'); ?> + __('Configuration'); ?>
  • + diff --git a/src/app/design/adminhtml/default/default/template/zendesk/order/tickets.phtml b/src/app/design/adminhtml/default/default/template/zendesk/order/tickets.phtml index 531f54fd..4ded847b 100644 --- a/src/app/design/adminhtml/default/default/template/zendesk/order/tickets.phtml +++ b/src/app/design/adminhtml/default/default/template/zendesk/order/tickets.phtml @@ -17,7 +17,7 @@ ?> +forRequester($customer->getEmail()); + } catch(Exception $e) { + // Don't do anything, just don't show the tickets + } +} +?> + +
    +
    +
    +
    + +
    +
    +
    + + + + + + + + + + + + + + + get($ticket['id'], true); ?> + + + + + + + + + + + +
    __('Priority') ?>__('Subject') ?>__('Requested') ?>__('Updated') ?>__('Status') ?>__('Group') ?>__('Assignee') ?>
    formatDate($ticket['created_at'], Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM, true); ?>formatDate($ticket['updated_at'], Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM, true); ?>
    +
    +
    +
    +
    + diff --git a/src/app/design/adminhtml/default/default/template/zendesk/widget/grid.phtml b/src/app/design/adminhtml/default/default/template/zendesk/widget/grid.phtml new file mode 100644 index 00000000..ef7fb9e1 --- /dev/null +++ b/src/app/design/adminhtml/default/default/template/zendesk/widget/grid.phtml @@ -0,0 +1,214 @@ + +getColumns()); +?> +getCollection()): ?> + canDisplayContainer()): ?> + getGridHeader()): ?> +
    + + + + +

    getGridHeader(); ?>

    +
    + + +
    + + getMessagesBlock()->getGroupedHtml() ?> + +getPagerVisibility() || $this->getExportTypes() || $this->getFilterVisibility()): ?> + + + getPagerVisibility()): ?> + + + getExportTypes()): ?> + + + + +
    + __('Page') ?> + + getCollection()->getCurPage() ?> + getCollection()->getLastPageNumber() ?> + 1): ?> + Go to Previous page + + Go to Previous page + + + + + + Go to Next page + + Go to Previous page + + + __('of %s pages', $this->getCollection()->getLastPageNumber()) ?> + | + __('View') ?> + + __('per page') ?>| + __('Total %d records found', $this->getCollection()->getSize()) ?> + getCollection()->getSize() ?> + getRssLists()): ?> + getRssLists() as $_rss): ?> + |getLabel() ?> + + + +   __('Export to:') ?> + + getExportButtonHtml() ?> + + getMainButtonsHtml() ?> +
    + +getMassactionBlock()->isAvailable()){ + echo $this->getMassactionBlockHtml(); +} +?> +
    +
    + + getColumns() as $_column): ?> + getHtmlProperty() ?> /> + + getHeadersVisibility() || $this->getFilterVisibility()): ?> + + getHeadersVisibility()): ?> + + getColumns() as $_column): ?> + getHeaderHtmlProperty() ?>>getHeaderHtml() ?> + + + + getFilterVisibility()): ?> + + getColumns() as $_column): ?> + getHeaderHtmlProperty() ?>>getFilterHtml() ?> + + + + + + getCountTotals()): ?> + + + getColumns() as $_column): ?> + + + + + + + + getCollection()->getSize()>0) && (!$this->getIsCollapsed())): ?> + getCollection() as $_index=>$_item): ?> + + getColumns() as $_column): ?> + + shouldRenderCell($_item, $_column)):?> + getRowspan($_item, $_column);?> + + shouldRenderEmptyCell($_item, $_column)):?> + + + + + + + getMultipleRows($_item)):?> + + + getMultipleRowColumns($_i) as $_column): ?> + + + + + + + shouldRenderSubTotal($_item)): ?> + + getSubTotalColumns() as $_column): ?> + + + + + + getEmptyText()): ?> + + + + + + +
    hasTotalsLabel()) ? $_column->getTotalsLabel() : $_column->getRowField($_column->getGrid()->getTotals()) ?> 
    class="getCssProperty() ?> "> + getRowField($_item)) != '' ? $_html : ' ') ?> + getEmptyCellLabel()?>
    + getRowField($_i)) != '' ? $_html : ' ') ?> +
    + hasSubtotalsLabel() ? $_column->getSubtotalsLabel() : + $_column->getRowField($this->getSubTotalItem($_item)) + ); + ?> +
    getEmptyText() ?>
    +
    +
    +canDisplayContainer()): ?> +
    + + + diff --git a/src/app/design/frontend/base/default/layout/zendesk.xml b/src/app/design/frontend/base/default/layout/zendesk.xml index 3e7d7c98..2718945a 100644 --- a/src/app/design/frontend/base/default/layout/zendesk.xml +++ b/src/app/design/frontend/base/default/layout/zendesk.xml @@ -19,7 +19,7 @@ - + zendesk Support @@ -33,7 +33,7 @@ - + customertickets zendesk/customer_tickets/index @@ -49,5 +49,6 @@ - - \ No newline at end of file + + + diff --git a/src/app/design/frontend/base/default/template/zendesk/customer/tickets.phtml b/src/app/design/frontend/base/default/template/zendesk/customer/tickets.phtml index fbc0b04a..d804ff6d 100644 --- a/src/app/design/frontend/base/default/template/zendesk/customer/tickets.phtml +++ b/src/app/design/frontend/base/default/template/zendesk/customer/tickets.phtml @@ -17,7 +17,7 @@ ?> @@ -28,4 +28,8 @@
    getChildHtml(); ?>
    - \ No newline at end of file + + diff --git a/src/app/design/frontend/base/default/template/zendesk/customer/tickets/list.phtml b/src/app/design/frontend/base/default/template/zendesk/customer/tickets/list.phtml index e16f497a..6b89baf0 100644 --- a/src/app/design/frontend/base/default/template/zendesk/customer/tickets/list.phtml +++ b/src/app/design/frontend/base/default/template/zendesk/customer/tickets/list.phtml @@ -38,7 +38,7 @@ get($ticket['id'], true); ?> - + getTicketUrl($ticket); ?> formatDate($ticket['created_at'], Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM, true); ?> formatDate($ticket['updated_at'], Mage_Core_Model_Locale::FORMAT_TYPE_MEDIUM, true); ?> diff --git a/src/app/locale/da_DA/Zendesk_Zendesk.csv b/src/app/locale/da_DA/Zendesk_Zendesk.csv index a6764ce5..06a46a07 100644 --- a/src/app/locale/da_DA/Zendesk_Zendesk.csv +++ b/src/app/locale/da_DA/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normal" "On-hold","I bero" "Open","Åben" -"Order number","Ordrenummer" +"Order Number","Ordrenummer" "Pending","Venter" "Priority","Prioritet" "Problem","Problem" diff --git a/src/app/locale/de_DE/Zendesk_Zendesk.csv b/src/app/locale/de_DE/Zendesk_Zendesk.csv index e39b8209..0152675c 100644 --- a/src/app/locale/de_DE/Zendesk_Zendesk.csv +++ b/src/app/locale/de_DE/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normal" "On-hold","Angehalten" "Open","Offen" -"Order number","Bestellnummer" +"Order Number","Bestellnummer" "Pending","Wartend" "Priority","Priorität" "Problem","Problem" diff --git a/src/app/locale/en_CA/Zendesk_Zendesk.csv b/src/app/locale/en_CA/Zendesk_Zendesk.csv index fe2823a3..3d8e534d 100644 --- a/src/app/locale/en_CA/Zendesk_Zendesk.csv +++ b/src/app/locale/en_CA/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normal" "On-hold","On-hold" "Open","Open" -"Order number","Order number" +"Order Number","Order Number" "Pending","Pending" "Priority","Priority" "Problem","Problem" diff --git a/src/app/locale/en_GB/Zendesk_Zendesk.csv b/src/app/locale/en_GB/Zendesk_Zendesk.csv index fe5d40ee..f271955b 100644 --- a/src/app/locale/en_GB/Zendesk_Zendesk.csv +++ b/src/app/locale/en_GB/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normal" "On-hold","On-hold" "Open","Open" -"Order number","Order number" +"Order Number","Order Number" "Pending","Pending" "Priority","Priority" "Problem","Problem" diff --git a/src/app/locale/en_US/Zendesk_Zendesk.csv b/src/app/locale/en_US/Zendesk_Zendesk.csv index b4ae4f85..64f012db 100644 --- a/src/app/locale/en_US/Zendesk_Zendesk.csv +++ b/src/app/locale/en_US/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normal" "On-hold","On-hold" "Open","Open" -"Order number","Order number" +"Order Number","Order Number" "Pending","Pending" "Priority","Priority" "Problem","Problem" @@ -96,3 +96,16 @@ "Zendesk SSO token not been set. Please add this to the settings page.","Zendesk SSO token not been set. Please add this to the settings page." "Zendesk allows your customers to contact you using the methods they prefer. Use the links below to configure the channels you would like to use.","Zendesk allows your customers to contact you using the methods they prefer. Use the links below to configure the channels you would like to use." "Zendesk domain not set. Please add this to the settings page.","Zendesk domain not set. Please add this to the settings page." +"Use External ID","Use External ID" +"Depending on your Zendesk configuration under "Settings / Security / JSON Web Token / Update of external IDs?","Depending on your Zendesk configuration under "Settings / Security / JSON Web Token / Update of external IDs?" +"Synchronize Customers","Synchronize Customers" +"Synchronize magento customer accounts with zendesk end-users?","Synchronize magento customer accounts with zendesk end-users?" +"Sync All Customers And Create User Fields","Sync All Customers And Create User Fields" +"Only if customers synchronization is enabled ","Only if customers synchronization is enabled " +"Customer Frontend","Customer Frontend" +"Show Tickets in Customer Accounts","Show Tickets in Customer Accounts" +"Display Customer's tickets in My Account","Display Customer's tickets in My Account" +"Admin Backend","Admin Backend" +"Decide which features you would like turned on in your admin panel.","Decide which features you would like turned on in your admin panel." +"Show "All" tab on dashboard","Show "All" tab on dashboard" +"Generate New Token","Generate New Token" diff --git a/src/app/locale/en_US/Zendesk_Zendesk.yml b/src/app/locale/en_US/Zendesk_Zendesk.yml index 55f177c2..8c699629 100644 --- a/src/app/locale/en_US/Zendesk_Zendesk.yml +++ b/src/app/locale/en_US/Zendesk_Zendesk.yml @@ -333,7 +333,7 @@ parts: - translation: key: "txt.integrations.magento.tickets.order_number" title: "Label for order number field" - value: "Order number" + value: "Order Number" - translation: key: "txt.integrations.magento.tickets.description" title: "Label for the description of a ticket" diff --git a/src/app/locale/es_419/Zendesk_Zendesk.csv b/src/app/locale/es_419/Zendesk_Zendesk.csv index 9bdf9a5e..5d201724 100644 --- a/src/app/locale/es_419/Zendesk_Zendesk.csv +++ b/src/app/locale/es_419/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normal" "On-hold","En espera" "Open","Abierto" -"Order number","Número de pedido" +"Order Number","Número de pedido" "Pending","Pendiente" "Priority","Prioridad" "Problem","Problema" diff --git a/src/app/locale/es_ES/Zendesk_Zendesk.csv b/src/app/locale/es_ES/Zendesk_Zendesk.csv index 1869375e..ac4546f0 100644 --- a/src/app/locale/es_ES/Zendesk_Zendesk.csv +++ b/src/app/locale/es_ES/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normal" "On-hold","En espera" "Open","Abierto" -"Order number","Número de pedido" +"Order Number","Número de pedido" "Pending","Pendiente" "Priority","Prioridad" "Problem","Problema" diff --git a/src/app/locale/fr_CA/Zendesk_Zendesk.csv b/src/app/locale/fr_CA/Zendesk_Zendesk.csv index fc92f6ee..61e5257c 100644 --- a/src/app/locale/fr_CA/Zendesk_Zendesk.csv +++ b/src/app/locale/fr_CA/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normale" "On-hold","En pause" "Open","Ouvert" -"Order number","Numéro de commande" +"Order Number","Numéro de commande" "Pending","En attente" "Priority","Priorité" "Problem","Problème" diff --git a/src/app/locale/fr_FR/Zendesk_Zendesk.csv b/src/app/locale/fr_FR/Zendesk_Zendesk.csv index e5f281b5..f8aed62d 100644 --- a/src/app/locale/fr_FR/Zendesk_Zendesk.csv +++ b/src/app/locale/fr_FR/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normale" "On-hold","En pause" "Open","Ouvert" -"Order number","Numéro de commande" +"Order Number","Numéro de commande" "Pending","En attente" "Priority","Priorité" "Problem","Problème" diff --git a/src/app/locale/it_IT/Zendesk_Zendesk.csv b/src/app/locale/it_IT/Zendesk_Zendesk.csv index 16075c13..c0f428d6 100644 --- a/src/app/locale/it_IT/Zendesk_Zendesk.csv +++ b/src/app/locale/it_IT/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normale" "On-hold","In sospeso" "Open","Aperto" -"Order number","Numero ordine" +"Order Number","Numero ordine" "Pending","In attesa" "Priority","Priorità" "Problem","Problema" diff --git a/src/app/locale/ja_JA/Zendesk_Zendesk.csv b/src/app/locale/ja_JA/Zendesk_Zendesk.csv index 01191d0d..a2820b15 100644 --- a/src/app/locale/ja_JA/Zendesk_Zendesk.csv +++ b/src/app/locale/ja_JA/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","普通" "On-hold","待機中" "Open","オープン" -"Order number","注文番号" +"Order Number","注文番号" "Pending","保留中" "Priority","優先度" "Problem","問題" diff --git a/src/app/locale/ja_JP/Zendesk_Zendesk.csv b/src/app/locale/ja_JP/Zendesk_Zendesk.csv index ac3783f6..7b25563c 100644 --- a/src/app/locale/ja_JP/Zendesk_Zendesk.csv +++ b/src/app/locale/ja_JP/Zendesk_Zendesk.csv @@ -51,7 +51,7 @@ "Group","グループ" "New Support Ticket","新規サポートチケット" "No tickets found","該当するチケットがありません" -"Order number","注文番号" +"Order Number","注文番号" "Priority","優先度" "High","高" "Low","低" diff --git a/src/app/locale/ko_KO/Zendesk_Zendesk.csv b/src/app/locale/ko_KO/Zendesk_Zendesk.csv index 9047e6e6..d2dcfd9d 100644 --- a/src/app/locale/ko_KO/Zendesk_Zendesk.csv +++ b/src/app/locale/ko_KO/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","보통" "On-hold","대기" "Open","등록" -"Order number","주문 번호" +"Order Number","주문 번호" "Pending","보류" "Priority","우선 순위" "Problem","문제" diff --git a/src/app/locale/ko_KR/Zendesk_Zendesk.csv b/src/app/locale/ko_KR/Zendesk_Zendesk.csv index 10cb78e1..cef14986 100644 --- a/src/app/locale/ko_KR/Zendesk_Zendesk.csv +++ b/src/app/locale/ko_KR/Zendesk_Zendesk.csv @@ -51,7 +51,7 @@ "Group","그룹" "New Support Ticket","새 지원 티켓" "No tickets found","티켓을 찾을 수 없습니다" -"Order number","주문 번호" +"Order Number","주문 번호" "Priority","우선 순위" "High","높음" "Low","낮음" diff --git a/src/app/locale/nl_NL/Zendesk_Zendesk.csv b/src/app/locale/nl_NL/Zendesk_Zendesk.csv index dddadb4a..e0a65293 100644 --- a/src/app/locale/nl_NL/Zendesk_Zendesk.csv +++ b/src/app/locale/nl_NL/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normaal" "On-hold","Geparkeerd" "Open","Open" -"Order number","Ordernummer" +"Order Number","Ordernummer" "Pending","In afwachting" "Priority","Prioriteit" "Problem","Probleem" diff --git a/src/app/locale/no_NO/Zendesk_Zendesk.csv b/src/app/locale/no_NO/Zendesk_Zendesk.csv index 5b9089f1..358ca84f 100644 --- a/src/app/locale/no_NO/Zendesk_Zendesk.csv +++ b/src/app/locale/no_NO/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normal" "On-hold","On-hold" "Open","Open" -"Order number","Order number" +"Order Number","Order Number" "Pending","Pending" "Priority","Priority" "Problem","Problem" diff --git a/src/app/locale/pt_BR/Zendesk_Zendesk.csv b/src/app/locale/pt_BR/Zendesk_Zendesk.csv index 034cc4bb..4d3130ea 100644 --- a/src/app/locale/pt_BR/Zendesk_Zendesk.csv +++ b/src/app/locale/pt_BR/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normal" "On-hold","Em espera" "Open","Aberto" -"Order number","Número do pedido" +"Order Number","Número do pedido" "Pending","Pendente" "Priority","Prioridade" "Problem","Problema" diff --git a/src/app/locale/pt_PT/Zendesk_Zendesk.csv b/src/app/locale/pt_PT/Zendesk_Zendesk.csv index 3cf39d5b..407c8381 100644 --- a/src/app/locale/pt_PT/Zendesk_Zendesk.csv +++ b/src/app/locale/pt_PT/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normal" "On-hold","Em espera" "Open","Aberto" -"Order number","Número do pedido" +"Order Number","Número do pedido" "Pending","Pendente" "Priority","Prioridade" "Problem","Problema" diff --git a/src/app/locale/ru_RU/Zendesk_Zendesk.csv b/src/app/locale/ru_RU/Zendesk_Zendesk.csv index bad3831f..065398b1 100644 --- a/src/app/locale/ru_RU/Zendesk_Zendesk.csv +++ b/src/app/locale/ru_RU/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Нормальный" "On-hold","На удержании" "Open","Открыт" -"Order number","Номер заказа" +"Order Number","Номер заказа" "Pending","В ожидании" "Priority","Приоритет" "Problem","Проблема" diff --git a/src/app/locale/sv_SV/Zendesk_Zendesk.csv b/src/app/locale/sv_SV/Zendesk_Zendesk.csv index 9ef85812..2527e0f2 100644 --- a/src/app/locale/sv_SV/Zendesk_Zendesk.csv +++ b/src/app/locale/sv_SV/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normal" "On-hold","On-hold" "Open","Open" -"Order number","Order number" +"Order Number","Order Number" "Pending","Pending" "Priority","Priority" "Problem","Problem" diff --git a/src/app/locale/tr_TR/Zendesk_Zendesk.csv b/src/app/locale/tr_TR/Zendesk_Zendesk.csv index 3f1cdcf9..7090d2f4 100644 --- a/src/app/locale/tr_TR/Zendesk_Zendesk.csv +++ b/src/app/locale/tr_TR/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normal" "On-hold","On-hold" "Open","Open" -"Order number","Order number" +"Order Number","Order Number" "Pending","Pending" "Priority","Priority" "Problem","Problem" diff --git a/src/app/locale/uk_UK/Zendesk_Zendesk.csv b/src/app/locale/uk_UK/Zendesk_Zendesk.csv index 74e8d50e..86935a10 100644 --- a/src/app/locale/uk_UK/Zendesk_Zendesk.csv +++ b/src/app/locale/uk_UK/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","Normal" "On-hold","On-hold" "Open","Open" -"Order number","Order number" +"Order Number","Order Number" "Pending","Pending" "Priority","Priority" "Problem","Problem" diff --git a/src/app/locale/zh_TW/Zendesk_Zendesk.csv b/src/app/locale/zh_TW/Zendesk_Zendesk.csv index edafe221..13962ba5 100644 --- a/src/app/locale/zh_TW/Zendesk_Zendesk.csv +++ b/src/app/locale/zh_TW/Zendesk_Zendesk.csv @@ -41,7 +41,7 @@ "Normal","正常" "On-hold","暫停" "Open","已開啟" -"Order number","訂單號碼" +"Order Number","訂單號碼" "Pending","未決" "Priority","優先等級" "Problem","事故" diff --git a/src/skin/adminhtml/default/default/zendesk/zendesk.css b/src/skin/adminhtml/default/default/zendesk/zendesk.css index d3c10fd9..53f33e87 100644 --- a/src/skin/adminhtml/default/default/zendesk/zendesk.css +++ b/src/skin/adminhtml/default/default/zendesk/zendesk.css @@ -45,4 +45,43 @@ h3.zendesk-header { button.zendesk span { background-image: url("button.png"); padding-left: 16px; -} \ No newline at end of file +} +.grid tr.headings th.col-1 { + width: 100%; +} +.grid tr.headings th.col-2 { + width: 50%; +} +.grid tr.headings th.col-3 { + width: 33.33%; +} +.grid tr.headings th.col-4 { + width: 25%; +} +.grid tr.headings th.col-5 { + width: 20%; +} +.grid tr.headings th.col-6 { + width: 16.66%; +} +.grid tr.headings th.col-7 { + width: 14.28%; +} +.grid tr.headings th.col-8 { + width: 12.5%; +} +.grid tr.filter .range input { + min-width: 61px !important; +} +div.entry-edit-head .fright { + float: right; +} +#tickets_grid_tab_content tbody .zendesk-grid-tr:hover, +#zendesk_create_customer_search_grid_table tbody tr:hover, +#zendesk_create_order_search_grid_table tbody tr:hover, +#zendesk_tab_tickets_grid_all_table .zendesk-grid-tr:hover { + background: #fcf5dd; +} +#zendesk_create_order_search_grid_table tr.filter .range .range-line { + min-width: 124px; +}