<?php
namespace Webkul\UVDesk\AutomationBundle\EventListener;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Webkul\UVDesk\AutomationBundle\Entity\Workflow;
use Webkul\UVDesk\AutomationBundle\Workflow\Action;
use Webkul\UVDesk\AutomationBundle\Workflow\Event;
use Webkul\UVDesk\AutomationBundle\Workflow\Events as WorkflowEvents;
use Webkul\UVDesk\CoreFrameworkBundle\Entity\Ticket;
use Webkul\UVDesk\CoreFrameworkBundle\Services\TicketService;
use Webkul\UVDesk\CoreFrameworkBundle\Services\UserService;
use UVDesk\CommunityPackages\UVDesk as UVDeskCommunityPackages;
use Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events as CoreWorkflowEvents;
class WorkflowListener
{
private $container;
private $entityManager;
private $ticketService;
private $userService;
private $registeredWorkflowEvents = [];
private $registeredWorkflowActions = [];
public function __construct(ContainerInterface $container, EntityManagerInterface $entityManager, TicketService $ticketService, UserService $userService)
{
$this->container = $container;
$this->entityManager = $entityManager;
$this->ticketService = $ticketService;
$this->userService = $userService;
}
public function registerWorkflowEvent(Event $serviceTag)
{
$this->registeredWorkflowEvents[] = $serviceTag;
}
public function registerWorkflowAction(Action $serviceTag)
{
$this->registeredWorkflowActions[] = $serviceTag;
}
public function getRegisteredWorkflowEvent($eventId)
{
foreach ($this->registeredWorkflowEvents as $workflowDefinition) {
if ($workflowDefinition->getId() == $eventId) {
return $workflowDefinition;
}
}
return null;
}
public function getRegisteredWorkflowEvents()
{
return $this->registeredWorkflowEvents;
}
public function getRegisteredWorkflowActions()
{
return $this->registeredWorkflowActions;
}
public function executeReplyEvent(Event $event) {
if ($this->userService->isFileExists('apps/uvdesk/report')) {
$reportServiceClass = UVDeskCommunityPackages\Report\Services\ReportService::class;
$reportService = new $reportServiceClass($this->entityManager, $this->container, $this->ticketService, $this->userService);
if (($event) instanceof CoreWorkflowEvents\Ticket\Status) {
$reportService->calculateResolveTime($event->getTicket());
} else if (
($event) instanceof CoreWorkflowEvents\Ticket\AgentReply ||
($event) instanceof CoreWorkflowEvents\Ticket\CustomerReply ||
($event) instanceof CoreWorkflowEvents\Ticket\CollaboratorReply
) {
$thread = $event->getThread();
if (
$thread
&& $thread->getThreadType() == 'reply'
&& ($thread->getCreatedBy() == 'agent'
|| $thread->getCreatedBy() == 'customer')
) {
$reportService->calculateResponseTime($thread);
}
}
}
}
public function executeWorkflow($event)
{
if (! ($event instanceof Event))
return;
$workflowCollection = $this->entityManager->getRepository(Workflow::class)->getEventWorkflows($event::getId());
if ((
$event instanceof CoreWorkflowEvents\Ticket\Create
|| $event instanceof CoreWorkflowEvents\Ticket\Priority
)
&& $this->userService->isFileExists('apps/uvdesk/sla')
) {
$slaServiceClass = UVDeskCommunityPackages\SLA\Services\SlaService::class;
$slaService = new $slaServiceClass($this->container, $this->entityManager );
$slaService->refreshTicketPolicies($event->getTicket());
}
if (($event) instanceof CoreWorkflowEvents\Ticket\Status) {
$this->executeReplyEvent($event);
}
if (empty($workflowCollection) && 'uvdesk.user.forgot_password' == $event::getId()) {
$user = $event->getArgument('entity');
if (
! empty($user)
&& $user instanceof \Webkul\UVDesk\CoreFrameworkBundle\Entity\User
) {
$agentForgotPasswordWorkflows = $this->entityManager->getRepository(Workflow::class)->getEventWorkflows('uvdesk.agent.forgot_password');
$customerForgotPasswordWorkflows = $this->entityManager->getRepository(Workflow::class)->getEventWorkflows('uvdesk.customer.forgot_password');
if (!empty($agentForgotPasswordWorkflows) || !empty($customerForgotPasswordWorkflows)) {
$agentInstance = $user->getAgentInstance();
$customerInstance = $user->getCustomerInstance();
if (
! empty($customerForgotPasswordWorkflows)
&& !empty($customerInstance)
) {
// Resort to uvdesk.customer.forgot_password workflows
$workflowCollection = $customerForgotPasswordWorkflows;
} else if (
! empty($agentForgotPasswordWorkflows)
&& !empty($agentInstance)
) {
// Resort to uvdesk.agent.forgot_password workflows
$workflowCollection = $agentForgotPasswordWorkflows;
}
}
}
}
if (! empty($workflowCollection)) {
foreach ($workflowCollection as $workflow) {
$totalConditions = 0;
$totalEvaluatedConditions = 0;
foreach ($this->evaluateWorkflowConditions($workflow) as $workflowCondition) {
$totalEvaluatedConditions++;
if (isset($workflowCondition['type']) && $this->checkCondition($workflowCondition, $event)) {
$totalConditions++;
}
if (isset($workflowCondition['or'])) {
foreach ($workflowCondition['or'] as $orCondition) {
if ($this->checkCondition($orCondition, $event)) {
$totalConditions++;
}
}
}
}
if ($totalEvaluatedConditions == 0 || $totalConditions >= $totalEvaluatedConditions) {
$this->applyWorkflowActions($workflow, $event);
}
}
}
}
private function evaluateWorkflowConditions(Workflow $workflow)
{
$index = -1;
$workflowConditions = [];
if ($workflow->getConditions() == null) {
return $workflowConditions;
}
foreach ($workflow->getConditions() as $condition) {
if (
! empty($condition['operation'])
&& $condition['operation'] != "&&"
) {
if (!isset($finalConditions[$index]['or'])) {
$finalConditions[$index]['or'] = [];
}
$workflowConditions[$index]['or'][] = $condition;
} else {
$index++;
$workflowConditions[] = $condition;
}
}
return $workflowConditions;
}
private function applyWorkflowActions(Workflow $workflow, Event $event)
{
foreach ($workflow->getActions() as $attributes) {
if (empty($attributes['type'])) {
continue;
}
foreach ($this->getRegisteredWorkflowActions() as $workflowAction) {
if ($workflowAction->getId() == $attributes['type']) {
$workflowAction->applyAction($this->container, $event, isset($attributes['value']) ? $attributes['value'] : '');
}
}
}
}
public function checkCondition($condition, Event $event)
{
$entity = null;
switch (true) {
case $event instanceof WorkflowEvents\EmailActivity:
$entity = $event->getResolvedEmailHeaders();
break;
case $event instanceof WorkflowEvents\TicketActivity:
$entity = $event->getTicket();
break;
case $event instanceof WorkflowEvents\AgentActivity:
case $event instanceof WorkflowEvents\CustomerActivity:
case $event instanceof WorkflowEvents\UserActivity:
$entity = $event->getUser();
break;
default:
break;
}
if (empty($entity)) {
return false;
}
switch ($condition['type']) {
case 'from_mail':
if (isset($condition['value'])) {
if ($entity instanceof Ticket) {
return $this->match($condition['match'], $entity->getCustomer()->getEmail(), $condition['value']);
} else if (
is_array($entity)
&& ! empty($entity['from'])
) {
return $this->match($condition['match'], $entity['from'], $condition['value']);
}
}
break;
case 'to_mail':
if (
isset($condition['value'])
&& $entity instanceof Ticket
&& $entity->getMailboxEmail()
) {
return $this->match($condition['match'], $entity->getMailboxEmail(), $condition['value']);
}
break;
case 'subject':
if (
isset($condition['value'])
&& ($entity instanceof Ticket || $entity instanceof Task)
) {
return $this->match($condition['match'], $entity->getSubject(), $condition['value']);
}
break;
case 'description':
if (
isset($condition['value'])
&& $entity instanceof Ticket
) {
$reply = $entity->createdThread->getMessage();
$reply = rtrim(strip_tags($reply), "\n" );
return $this->match($condition['match'], rtrim($reply), $condition['value']);
}
break;
case 'subject_or_description':
if (
isset($condition['value'])
&& $entity instanceof Ticket
) {
$flag = $this->match($condition['match'], $entity->getSubject(), $condition['value']);
$createThread = $this->container->get('ticket.service')->getCreateReply($entity->getId(),false);
if (! $flag) {
$createThread = $this->container->get('ticket.service')->getCreateReply($entity->getId(),false);
$createThread['reply'] = rtrim(strip_tags($createThread['reply']), "\n" );
$flag = $this->match($condition['match'],$createThread['reply'],$condition['value']);
}
return $flag;
}
break;
case 'TicketPriority':
if (
isset($condition['value'])
&& ($entity instanceof Ticket)
) {
return $this->match($condition['match'], $entity->getPriority()->getId(), $condition['value']);
}
break;
case 'TicketType':
if (
isset($condition['value'])
&& $entity instanceof Ticket
) {
$typeId = $entity->getType() ? $entity->getType()->getId() : 0;
return $this->match($condition['match'], $typeId, $condition['value']);
}
break;
case 'TicketStatus':
if (
isset($condition['value'])
&& $entity instanceof Ticket
) {
return $this->match($condition['match'], $entity->getStatus()->getId(), $condition['value']);
}
break;
case 'stage':
if (
isset($condition['value'])
&& $entity instanceof Task
) {
return $this->match($condition['match'], $entity->getStage()->getId(), $condition['value']);
}
break;
case 'source':
if (
isset($condition['value'])
&& $entity instanceof Ticket
) {
return $this->match($condition['match'], $entity->getSource(), $condition['value']);
}
break;
case 'created':
if (
isset($condition['value'])
&& ($entity instanceof Ticket || $entity instanceof Task)
) {
$date = date_format($entity->getCreatedAt(), "d-m-Y h:ia");
return $this->match($condition['match'], $date, $condition['value']);
}
break;
case 'agent':
if (
isset($condition['value'])
&& $entity instanceof Ticket
&& $entity->getAgent()
) {
return $this->match($condition['match'], $entity->getAgent()->getId(), (($condition['value'] == 'actionPerformingAgent') ? ($this->container->get('user.service')->getCurrentUser() ? $this->container->get('user.service')->getCurrentUser()->getId() : 0) : $condition['value']));
}
break;
case 'group':
if (
isset($condition['value'])
&& $entity instanceof Ticket
) {
$groupId = $entity->getSupportGroup() ? $entity->getSupportGroup()->getId() : 0;
return $this->match($condition['match'], $groupId, $condition['value']);
}
break;
case 'team':
if (
isset($condition['value'])
&& $entity instanceof Ticket
) {
$subGroupId = $entity->getSupportTeam() ? $entity->getSupportTeam()->getId() : 0;
return $this->match($condition['match'], $subGroupId, $condition['value']);
}
break;
case 'customer_name':
if (
isset($condition['value'])
&& $entity instanceof Ticket
) {
return $this->match($condition['match'], $entity->getCustomer()->getFullName(), $condition['value']);
}
break;
case 'customer_email':
if (
isset($condition['value'])
&& $entity instanceof Ticket
) {
return $this->match($condition['match'], $entity->getCustomer()->getEmail(), $condition['value']);
}
break;
case strpos($condition['type'], 'customFields') == 0:
$value = null;
$ticketCfValues = $entity->getCustomFieldValues()->getValues();
foreach ($ticketCfValues as $cfValue) {
$mainCf = $cfValue->getTicketCustomFieldsValues();
if ($condition['type'] == 'customFields[' . $mainCf->getId() . ']' ) {
if (in_array($mainCf->getFieldType(), ['select', 'radio', 'checkbox'])) {
$value = json_decode($cfValue->getValue(), true);
} else {
$value = trim($cfValue->getValue(), '"');
}
break;
}
}
if (
isset($condition['value'])
&& $entity instanceof Ticket
) {
return $this->match($condition['match'], !empty($value) ? $value : '', $condition['value']);
}
break;
default:
break;
}
return false;
}
public function match($condition, $haystack, $needle)
{
// Filter tags
if ('string' == gettype($haystack)) {
$haystack = strip_tags($haystack);
}
switch ($condition) {
case 'is':
return is_array($haystack) ? in_array($needle, $haystack) : $haystack == $needle;
case 'isNot':
return is_array($haystack) ? !in_array($needle, $haystack) : $haystack != $needle;
case 'contains':
return strripos($haystack,$needle) !== false ? true : false;
case 'notContains':
return strripos($haystack,$needle) === false ? true : false;
case 'startWith':
return $needle === "" || strripos($haystack, $needle, -strlen($haystack)) !== FALSE;
case 'endWith':
return $needle === "" || (($temp = strlen($haystack) - strlen($needle)) >= 0 && stripos($haystack, $needle, $temp) !== FALSE);
case 'before':
$createdTimeStamp = date('Y-m-d', strtotime($haystack));
$conditionTimeStamp = date('Y-m-d', strtotime($needle . " 23:59:59"));
return $createdTimeStamp < $conditionTimeStamp ? true : false;
case 'beforeOn':
$createdTimeStamp = date('Y-m-d', strtotime($haystack));
$conditionTimeStamp = date('Y-m-d', strtotime($needle . " 23:59:59"));
return ($createdTimeStamp < $conditionTimeStamp || $createdTimeStamp == $conditionTimeStamp) ? true : false;
case 'after':
$createdTimeStamp = date('Y-m-d', strtotime($haystack));
$conditionTimeStamp = date('Y-m-d', strtotime($needle . " 23:59:59"));
return $createdTimeStamp > $conditionTimeStamp ? true : false;
case 'afterOn':
$createdTimeStamp = date('Y-m-d', strtotime($haystack));
$conditionTimeStamp = date('Y-m-d', strtotime($needle . " 23:59:59"));
return $createdTimeStamp > $conditionTimeStamp || $createdTimeStamp == $conditionTimeStamp ? true : false;
case 'beforeDateTime':
$createdTimeStamp = date('Y-m-d h:i:s', strtotime($haystack));
$conditionTimeStamp = date('Y-m-d h:i:s', strtotime($needle));
return $createdTimeStamp < $conditionTimeStamp ? true : false;
case 'beforeDateTimeOn':
$createdTimeStamp = date('Y-m-d h:i:s', strtotime($haystack));
$conditionTimeStamp = date('Y-m-d h:i:s', strtotime($needle));
return ($createdTimeStamp < $conditionTimeStamp || $createdTimeStamp == $conditionTimeStamp) ? true : false;
case 'afterDateTime':
$createdTimeStamp = date('Y-m-d h:i:s', strtotime($haystack));
$conditionTimeStamp = date('Y-m-d h:i:s', strtotime($needle));
return $createdTimeStamp > $conditionTimeStamp ? true : false;
case 'afterDateTimeOn':
$createdTimeStamp = date('Y-m-d h:i:s', strtotime($haystack));
$conditionTimeStamp = date('Y-m-d h:i:s', strtotime($needle));
return $createdTimeStamp > $conditionTimeStamp || $createdTimeStamp == $conditionTimeStamp ? true : false;
case 'beforeTime':
$createdTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $haystack));
$conditionTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $needle));
return $createdTimeStamp < $conditionTimeStamp ? true : false;
case 'beforeTimeOn':
$createdTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $haystack));
$conditionTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $needle));
return ($createdTimeStamp < $conditionTimeStamp || $createdTimeStamp == $conditionTimeStamp) ? true : false;
case 'afterTime':
$createdTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $haystack));
$conditionTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $needle));
return $createdTimeStamp > $conditionTimeStamp ? true : false;
case 'afterTimeOn':
$createdTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $haystack));
$conditionTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $needle));
return $createdTimeStamp > $conditionTimeStamp || $createdTimeStamp == $conditionTimeStamp ? true : false;
case 'greaterThan':
return !is_array($haystack) && $needle > $haystack;
case 'lessThan':
return !is_array($haystack) && $needle < $haystack;
default:
break;
}
return false;
}
}