A New Magento 2 module for Helpdesk Ticket System
The ticket system requirement:
- Name used, Jeff/Helpdesk
- Data to be stored in table is called jeff_helpdesk_ticket
- Tickets entity will contain ticket_id, customer_id, title, severity, created_at and status attributes
- Two email templates: store_owner_to_customer_email_template and customer_to_store_owner_email_template are to be defined for pushing email updates ticket creation and status change
- Customers will be able to submit a ticket through their “MY ACCOUNT” section.
- Customers will be able to see all of their previously submitted tickets under their “My Account” section
- Customer will not be able to edit any existing tickets
- Once a customer submits a new ticket, transactional email will be sent to the store owner.
- Admin users will be able to access a list of all tickets under “Customers | Helpdesk Tickets”.
- Once Admin users change the ticket status, an email will be sent to the customer.
Create a new module by creating registration.php and module.xml
registration.php file:
module.xml file:
#app/code/Jeff/Helpdesk/etc/module.xml
Create Database setup script
InstallSchema.php file:
#app/code/Jeff/Helpdesk/Setup/InstallSchema.php startSetup(); $table = $installer->getConnection() ->newTable($installer->getTable('jeff_helpdesk_ticket')) ->addColumn( 'ticket_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], 'Ticket Id' ) ->addColumn( 'customer_id', \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, null, ['unsigned' => true], 'Customer Id' ) ->addColumn( 'title', \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, null, ['nullable' => false], 'Title' ) ->addColumn( 'severity', \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, null, ['nullable' => false], 'Severity' ) ->addColumn( 'created_at', \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, null, ['nullable' => false], 'Created At' ) ->addColumn( 'status', \Magento\Framework\DB\Ddl\Table::TYPE_SMALLINT, null, ['nullable' => false], 'Severity' ) ->addIndex( $installer->getIdxName('jeff_helpdesk_ticket', ['customer_id']), ['customer_id'] ) ->addForeignKey( $installer->getFkName('jeff_helpdesk_ticket', 'customer_id', 'customer_entity', 'entity_id'), 'customer_id', $installer->getTable('customer_entity'), 'entity_id', \Magento\Framework\DB\Ddl\Table::ACTION_SET_NULL ); $installer->getConnection()->createTable($table); $installer->endSetup(); } }
Create Model and Resource Model file for Database CRUD
Ticket.php file:Ticket.php resource model file:#app/code/Jeff/Helpdesk/Model/Ticket.php 'Opened', self::STATUS_CLOSED=>'Closed']; protected static $severitiesOptions = [self::SEVERITY_LOW=>'Low', self::SEVERITY_MEDIUM=>'Medium', self::SEVERITY_HIGH=>'High']; /** * Initialize resource model * @return void */ protected function _construct() { $this->_init('Jeff\Helpdesk\Model\ResourceModel\Ticket'); } public static function getSeveritiesOptionArray() { return self::$severitiesOptions; } public static function getStatusesOptionArray() { return self::$statusesOptions; } public function getStatusAsLabel() { return self::$statusesOptions[$this->getStatus()]; } public function getSeverityAsLabel() { return self::$severitiesOptions[$this->getSeverity()]; } }
model's collection file:#app/code/Jeff/Helpdesk/Model/ResourceModel/Ticket.php _init('jeff_helpdesk_ticket', 'ticket_id'); } }
#app/code/Jeff/Helpdesk/Model/ResourceModel/Ticket/Collection.php _init('Jeff\Helpdesk\Model\Ticket', 'Jeff\Helpdesk\Model\ResourceModel\Ticket'); } }
Module's backend config file to set up default email templates
config.xml file:#app/code/Jeff/Helpdesk/etc/config.xml jeff_helpdesk_email_template_customer jeff_helpdesk_email_template_store_owner
Register two email templates for our system
email_templates.xml file:
#app/code/Jeff/Helpdesk/etc/email_templates.xml *Note: The values of the "file" attribute point to the location of the following files: 1) app/code/Jeff/Helpdesk/view/frontend/email/store_owner_to_customer.html 2) app/code/Jeff/Helpdesk/view/frontend/email/customer_to_owner.html
Create two email templates
customer_to_store_owner.html file:
#app/code/Jeff/Helpdesk/view/frontend/email Ticket #{{var ticket.ticket_id}} created
- Id: {{var ticket.ticket_id}}
- Title: {{var ticket.title}}
- Created_at: {{var ticket.created_at}}
- Severity: {{var ticket.serverity}}
store_owner_to_customer.html file:
#app/code/Jeff/Helpdesk/view/frontend/email/store_owner_to_customer.html Ticket #{{var ticket.ticket_id}} updated
Hi {{var customer_name}}
Status of your ticket #{var ticket.ticket_id}} has been updated
- Title: {{var ticket.title}}
- Created at: {{var ticket.created_at}}
- Severity: {{var ticket.severity}}
Set up the frontend route
routes.xml file:
#app/code/Jeff/Helpdesk/etc/frontend/routes.xml
Create the frontend Block
Index.php block file:
#app/code/Jeff/Helpdesk/Block/Ticket/Index.php dateTime = $dateTime; $this->customerSession = $customerSession; $this->ticketFactory = $ticketFactory; parent::__construct($context, $data); } /** * @return \Jeff\Helpdesk\Model\ResourceModel\Ticket\Collection */ public function getTickets() { return $this->ticketFactory->create() ->getCollection() ->addFieldToFilter('customer_id', $this->customerSession->getcustomerId()) ->setOrder('ticket_id', 'DESC'); } public function getSeverities() { return \Jeff\Helpdesk\Model\Ticket::getSeveritiesOptionArray(); } }
Create frontend controller files
Ticket.php --abstract controller fileIndex Action file Index.php:#app/code/Jeff/Helpdesk/Controller/Ticket.php customerSession = $customerSession; parent::__construct($context); } public function dispatch(RequestInterface $request) { if(!$this->customerSession->authenticate()) { $this->_actionFlag->set('', 'no-dispatch', true); if(!$this->customerSession->getBeforeUrl()) { $this->customerSession->setBeforeUrl($this->_redirect->getRefererUrl()); } } return parent::dispatch($request); } } /* our controller loads the customer session object through its constructor. The customer session object is then used within the dispatch method to check if the customer is authenticated or not. */
Save action file: Save.php#app/code/Jeff/Helpdesk/Controller/Ticket/Index.php resultFactory->create(\Magento\Framework\Controller\ResultFactory::TYPE_PAGE); $resultPage->getConfig()->getTitle()->set(__('Help Tickets')); return $resultPage; } }
#app/code/Jeff/Helpdesk/Controller/Ticket/Save.php transportBuilder = $transportBuilder; $this->inlineTranslation = $inlineTranslation; $this->scopeConfig = $scopeConfig; $this->storeManager = $storeManager; $this->formKeyValidator = $formKeyValidator; $this->dateTime = $dateTime; $this->ticketFactory = $ticketFactory; $this->messageManager = $context->getMessageManager(); //get Message block parent::__construct($context, $customerSession); } public function execute() { $resultRedirect = $this->resultRedirectFactory->create(); //var_dump($this->getRequest()->getParam('title')); //var_dump($this->getRequest()->getParam('severity')); if(!$this->formKeyValidator->validate($this->getRequest())) { return $resultRedirect->setRefererUrl(); } $title = $this->getRequest()->getParam('title'); $severity = $this->getRequest()->getParam('severity'); try{ $ticket = $this->ticketFactory->create(); $ticket->setCustomerId($this->customerSession->getCustomerId()); $ticket->setTitle($title); $ticket->setSeverity($severity); $ticket->setCreatedAt($this->dateTime->formatDate(true)); $ticket->setStatus(\Jeff\Helpdesk\Model\Ticket::STATUS_OPENED); $ticket->save(); $customer = $this->customerSession->getCustomerData(); /* //Send email to store owner $storeScope = \Magento\Store\Model\ScopeInterface::SCOPE_STORE; $transport = $this->transportBuilder->setTemplateIdentifier($this->scopeConfig->getValue('jeff_helpdesk/email_template/store_owner', $storeScope)) ->setTemplateOptions( [ 'area' => \Magento\Framework\App\Area::AREA_FRONTEND, 'store' => $this->storeManager->getStore()->getId(), ] ) ->setTemplateVars(['ticket' => $ticket]) ->setFrom([ 'name' => $customer->getFirstName. ' ' . $customer->getLastname(), 'email' => $customer->getEmail() ]) ->addTo($this->scopeConfig->getValue('trans_email/ident_general/email', $storeScope)) ->getTransport(); $transport->sendMessage(); $this->inlineTranslation->resume(); */ $this->messageManager->addSuccess(__('Ticket successfully created.')); } catch(Exception $e) { $this->messageManager->addError(__('Error occurred during tickete creation.')); } return $resultRedirect->setRefererUrl(); } }
Two Layout files to add a link to the navigation of customer account panel
customer_account.xml file:#app/code/Jeff/Helpdesk/view/frontend/layout/customer_account.xml Helpdesk Tickets jeff_helpdesk/ticket Helpdesk Tickets
jeff_helpdesk_ticket_index.xml file:
#app/code/Jeff/Helpdesk/view/frontend/layout/jeff_helpdesk_ticket_index.html
Install and update our system
php bin/magento module:enable Jeff_Helpdesk php bin/magento setup:upgrade php bin/magento cache:clean php bin/magento cache:flush
If you go to your account in the frontend, you will notice there is a new link “Helpdesk Tickets” at the left sidebar as following:
Conclusion:
This “part 1” is the first part of Helpdesk Ticket system for Magento 2. In the tutorial, I presented how to create a new module for Magento 2 and add a link to the navigation of customer account panel. In the next part, I will present the steps to create backend for the Helpdesk Ticke system.
You could download the code from Github