vendor/uvdesk/automation-bundle/EventListener/WorkflowListener.php line 109

Open in your IDE?
  1. <?php
  2. namespace Webkul\UVDesk\AutomationBundle\EventListener;
  3. use Doctrine\ORM\EntityManagerInterface;
  4. use Symfony\Component\DependencyInjection\ContainerInterface;
  5. use Webkul\UVDesk\AutomationBundle\Entity\Workflow;
  6. use Webkul\UVDesk\AutomationBundle\Workflow\Action;
  7. use Webkul\UVDesk\AutomationBundle\Workflow\Event;
  8. use Webkul\UVDesk\AutomationBundle\Workflow\Events as WorkflowEvents;
  9. use Webkul\UVDesk\AutomationBundle\Workflow\FunctionalGroup;
  10. use Webkul\UVDesk\CoreFrameworkBundle\Entity\Ticket;
  11. use Webkul\UVDesk\CoreFrameworkBundle\Services\TicketService;
  12. use Webkul\UVDesk\CoreFrameworkBundle\Services\UserService;
  13. use UVDesk\CommunityPackages\UVDesk as UVDeskCommunityPackages;
  14. use Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events as CoreWorkflowEvents;
  15. class WorkflowListener
  16. {
  17. private $container;
  18. private $entityManager;
  19. private $ticketService;
  20. private $userService;
  21. private $registeredWorkflowEvents = [];
  22. private $registeredWorkflowActions = [];
  23. public function __construct(ContainerInterface $container, EntityManagerInterface $entityManager, TicketService $ticketService, UserService $userService)
  24. {
  25. $this->container = $container;
  26. $this->entityManager = $entityManager;
  27. $this->ticketService = $ticketService;
  28. $this->userService = $userService;
  29. }
  30. public function registerWorkflowEvent(Event $serviceTag)
  31. {
  32. $this->registeredWorkflowEvents[] = $serviceTag;
  33. }
  34. public function registerWorkflowAction(Action $serviceTag)
  35. {
  36. $this->registeredWorkflowActions[] = $serviceTag;
  37. }
  38. public function getRegisteredWorkflowEvent($eventId)
  39. {
  40. foreach ($this->registeredWorkflowEvents as $workflowDefinition) {
  41. if ($workflowDefinition->getId() == $eventId) {
  42. /*
  43. @NOTICE: Events 'uvdesk.agent.forgot_password', 'uvdesk.customer.forgot_password' will be deprecated
  44. onwards uvdesk/automation-bundle:1.1.2 and uvdesk/core-framework:1.1.3 releases and will be
  45. completely removed with the next major release.
  46. Both the events have been mapped to return the 'uvdesk.user.forgot_password' id, so we need to
  47. return the correct definition.
  48. */
  49. if ('uvdesk.user.forgot_password' == $eventId) {
  50. if (
  51. $workflowDefinition instanceof \Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events\Agent\ForgotPassword
  52. || $workflowDefinition instanceof \Webkul\UVDesk\CoreFrameworkBundle\Workflow\Events\Customer\ForgotPassword
  53. ) {
  54. continue;
  55. }
  56. }
  57. return $workflowDefinition;
  58. }
  59. }
  60. return null;
  61. }
  62. public function getRegisteredWorkflowEvents()
  63. {
  64. return $this->registeredWorkflowEvents;
  65. }
  66. public function getRegisteredWorkflowActions()
  67. {
  68. return $this->registeredWorkflowActions;
  69. }
  70. public function executeReplyEvent(Event $event) {
  71. if ($this->userService->isFileExists('apps/uvdesk/report')) {
  72. $reportServiceClass = UVDeskCommunityPackages\Report\Services\ReportService::class;
  73. $reportService = new $reportServiceClass($this->entityManager, $this->container, $this->ticketService, $this->userService);
  74. if (($event) instanceof CoreWorkflowEvents\Ticket\Status) {
  75. $reportService->calculateResolveTime($event->getTicket());
  76. } else if (
  77. ($event) instanceof CoreWorkflowEvents\Ticket\AgentReply ||
  78. ($event) instanceof CoreWorkflowEvents\Ticket\CustomerReply ||
  79. ($event) instanceof CoreWorkflowEvents\Ticket\CollaboratorReply
  80. ) {
  81. $thread = $event->getThread();
  82. if (
  83. $thread
  84. && $thread->getThreadType() == 'reply'
  85. && ($thread->getCreatedBy() == 'agent'
  86. || $thread->getCreatedBy() == 'customer')
  87. ) {
  88. $reportService->calculateResponseTime($thread);
  89. }
  90. }
  91. }
  92. }
  93. public function executeWorkflow($event)
  94. {
  95. if (! ($event instanceof Event))
  96. return;
  97. $workflowCollection = $this->entityManager->getRepository(Workflow::class)->getEventWorkflows($event::getId());
  98. if (($event) instanceof CoreWorkflowEvents\Ticket\Create && $this->userService->isFileExists('apps/uvdesk/sla')) {
  99. $slaServiceClass = UVDeskCommunityPackages\SLA\Services\SlaService::class;
  100. $slaService = new $slaServiceClass($this->container, $this->entityManager );
  101. $slaService->refreshTicketPolicies($event->getTicket());
  102. }
  103. /*
  104. @NOTICE: Events 'uvdesk.agent.forgot_password', 'uvdesk.customer.forgot_password' will be deprecated
  105. onwards uvdesk/automation-bundle:1.1.2 and uvdesk/core-framework:1.1.3 releases and will be
  106. completely removed with the next major release.
  107. From uvdesk/core-framework:1.1.3 onwards, instead of the above mentioned events, the one being
  108. triggered will be 'uvdesk.user.forgot_password'. Since there still might be older workflows
  109. configured to work on either of the two deprecated events, we will need to make an educated guess
  110. which one to use (if any) if there's none found for the actual event.
  111. */
  112. if (empty($workflowCollection) && 'uvdesk.user.forgot_password' == $event::getId()) {
  113. $user = $event->getArgument('entity');
  114. if (!empty($user) && $user instanceof \Webkul\UVDesk\CoreFrameworkBundle\Entity\User) {
  115. $agentForgotPasswordWorkflows = $this->entityManager->getRepository(Workflow::class)->getEventWorkflows('uvdesk.agent.forgot_password');
  116. $customerForgotPasswordWorkflows = $this->entityManager->getRepository(Workflow::class)->getEventWorkflows('uvdesk.customer.forgot_password');
  117. if (!empty($agentForgotPasswordWorkflows) || !empty($customerForgotPasswordWorkflows)) {
  118. $agentInstance = $user->getAgentInstance();
  119. $customerInstance = $user->getCustomerInstance();
  120. if (!empty($customerForgotPasswordWorkflows) && !empty($customerInstance)) {
  121. // Resort to uvdesk.customer.forgot_password workflows
  122. $workflowCollection = $customerForgotPasswordWorkflows;
  123. } else if (!empty($agentForgotPasswordWorkflows) && !empty($agentInstance)) {
  124. // Resort to uvdesk.agent.forgot_password workflows
  125. $workflowCollection = $agentForgotPasswordWorkflows;
  126. }
  127. }
  128. }
  129. }
  130. if (! empty($workflowCollection)) {
  131. foreach ($workflowCollection as $workflow) {
  132. $totalConditions = 0;
  133. $totalEvaluatedConditions = 0;
  134. foreach ($this->evaluateWorkflowConditions($workflow) as $workflowCondition) {
  135. $totalEvaluatedConditions++;
  136. if (isset($workflowCondition['type']) && $this->checkCondition($workflowCondition, $event)) {
  137. $totalConditions++;
  138. }
  139. if (isset($workflowCondition['or'])) {
  140. foreach ($workflowCondition['or'] as $orCondition) {
  141. if ($this->checkCondition($orCondition, $event)) {
  142. $totalConditions++;
  143. }
  144. }
  145. }
  146. }
  147. if ($totalEvaluatedConditions == 0 || $totalConditions >= $totalEvaluatedConditions) {
  148. $this->applyWorkflowActions($workflow, $event);
  149. }
  150. }
  151. }
  152. }
  153. private function evaluateWorkflowConditions(Workflow $workflow)
  154. {
  155. $index = -1;
  156. $workflowConditions = [];
  157. if ($workflow->getConditions() == null) {
  158. return $workflowConditions;
  159. }
  160. foreach ($workflow->getConditions() as $condition) {
  161. if (! empty($condition['operation']) && $condition['operation'] != "&&") {
  162. if (!isset($finalConditions[$index]['or'])) {
  163. $finalConditions[$index]['or'] = [];
  164. }
  165. $workflowConditions[$index]['or'][] = $condition;
  166. } else {
  167. $index++;
  168. $workflowConditions[] = $condition;
  169. }
  170. }
  171. return $workflowConditions;
  172. }
  173. private function applyWorkflowActions(Workflow $workflow, Event $event)
  174. {
  175. foreach ($workflow->getActions() as $attributes) {
  176. if (empty($attributes['type'])) {
  177. continue;
  178. }
  179. foreach ($this->getRegisteredWorkflowActions() as $workflowAction) {
  180. if ($workflowAction->getId() == $attributes['type']) {
  181. $workflowAction->applyAction($this->container, $event, isset($attributes['value']) ? $attributes['value'] : '');
  182. }
  183. }
  184. }
  185. }
  186. public function checkCondition($condition, Event $event)
  187. {
  188. $entity = null;
  189. switch (true) {
  190. case $event instanceof WorkflowEvents\EmailActivity:
  191. $entity = $event->getResolvedEmailHeaders();
  192. break;
  193. case $event instanceof WorkflowEvents\TicketActivity:
  194. $entity = $event->getTicket();
  195. break;
  196. case $event instanceof WorkflowEvents\AgentActivity:
  197. case $event instanceof WorkflowEvents\CustomerActivity:
  198. case $event instanceof WorkflowEvents\UserActivity:
  199. $entity = $event->getUser();
  200. break;
  201. default:
  202. break;
  203. }
  204. if (empty($entity)) {
  205. return false;
  206. }
  207. switch ($condition['type']) {
  208. case 'from_mail':
  209. if (isset($condition['value'])) {
  210. if ($entity instanceof Ticket) {
  211. return $this->match($condition['match'], $entity->getCustomer()->getEmail(), $condition['value']);
  212. } else if (is_array($entity) && !empty($entity['from'])) {
  213. return $this->match($condition['match'], $entity['from'], $condition['value']);
  214. }
  215. }
  216. break;
  217. case 'to_mail':
  218. if (isset($condition['value']) && $entity instanceof Ticket && $entity->getMailboxEmail()) {
  219. return $this->match($condition['match'], $entity->getMailboxEmail(), $condition['value']);
  220. }
  221. break;
  222. case 'subject':
  223. if (isset($condition['value']) && ($entity instanceof Ticket || $entity instanceof Task)) {
  224. return $this->match($condition['match'], $entity->getSubject(), $condition['value']);
  225. }
  226. break;
  227. case 'description':
  228. if (isset($condition['value']) && $entity instanceof Ticket) {
  229. $reply = $entity->createdThread->getMessage();
  230. $reply = rtrim(strip_tags($reply), "\n" );
  231. return $this->match($condition['match'], rtrim($reply), $condition['value']);
  232. }
  233. break;
  234. case 'subject_or_description':
  235. if (isset($condition['value']) && $entity instanceof Ticket) {
  236. $flag = $this->match($condition['match'], $entity->getSubject(), $condition['value']);
  237. $createThread = $this->container->get('ticket.service')->getCreateReply($entity->getId(),false);
  238. if (! $flag) {
  239. $createThread = $this->container->get('ticket.service')->getCreateReply($entity->getId(),false);
  240. $createThread['reply'] = rtrim(strip_tags($createThread['reply']), "\n" );
  241. $flag = $this->match($condition['match'],$createThread['reply'],$condition['value']);
  242. }
  243. return $flag;
  244. }
  245. break;
  246. case 'TicketPriority':
  247. if (isset($condition['value']) && ($entity instanceof Ticket)) {
  248. return $this->match($condition['match'], $entity->getPriority()->getId(), $condition['value']);
  249. }
  250. break;
  251. case 'TicketType':
  252. if (isset($condition['value']) && $entity instanceof Ticket) {
  253. $typeId = $entity->getType() ? $entity->getType()->getId() : 0;
  254. return $this->match($condition['match'], $typeId, $condition['value']);
  255. }
  256. break;
  257. case 'TicketStatus':
  258. if (isset($condition['value']) && $entity instanceof Ticket) {
  259. return $this->match($condition['match'], $entity->getStatus()->getId(), $condition['value']);
  260. }
  261. break;
  262. case 'stage':
  263. if (isset($condition['value']) && $entity instanceof Task) {
  264. return $this->match($condition['match'], $entity->getStage()->getId(), $condition['value']);
  265. }
  266. break;
  267. case 'source':
  268. if (isset($condition['value']) && $entity instanceof Ticket) {
  269. return $this->match($condition['match'], $entity->getSource(), $condition['value']);
  270. }
  271. break;
  272. case 'created':
  273. if (isset($condition['value']) && ($entity instanceof Ticket || $entity instanceof Task)) {
  274. $date = date_format($entity->getCreatedAt(), "d-m-Y h:ia");
  275. return $this->match($condition['match'], $date, $condition['value']);
  276. }
  277. break;
  278. case 'agent':
  279. if (isset($condition['value']) && $entity instanceof Ticket && $entity->getAgent()) {
  280. 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']));
  281. }
  282. break;
  283. case 'group':
  284. if (isset($condition['value']) && $entity instanceof Ticket) {
  285. $groupId = $entity->getSupportGroup() ? $entity->getSupportGroup()->getId() : 0;
  286. return $this->match($condition['match'], $groupId, $condition['value']);
  287. }
  288. break;
  289. case 'team':
  290. if (isset($condition['value']) && $entity instanceof Ticket) {
  291. $subGroupId = $entity->getSupportTeam() ? $entity->getSupportTeam()->getId() : 0;
  292. return $this->match($condition['match'], $subGroupId, $condition['value']);
  293. }
  294. break;
  295. case 'customer_name':
  296. if (isset($condition['value']) && $entity instanceof Ticket) {
  297. $lastThread = $this->container->get('ticket.service')->getTicketLastThread($entity->getId());
  298. return $this->match($condition['match'], $entity->getCustomer()->getFullName(), $condition['value']);
  299. }
  300. break;
  301. case 'customer_email':
  302. if (isset($condition['value']) && $entity instanceof Ticket) {
  303. return $this->match($condition['match'], $entity->getCustomer()->getEmail(), $condition['value']);
  304. }
  305. break;
  306. case strpos($condition['type'], 'customFields[') == 0:
  307. $value = null;
  308. $ticketCfValues = $entity->getCustomFieldValues()->getValues();
  309. foreach ($ticketCfValues as $cfValue) {
  310. $mainCf = $cfValue->getTicketCustomFieldsValues();
  311. if ($condition['type'] == 'customFields[' . $mainCf->getId() . ']' ) {
  312. if (in_array($mainCf->getFieldType(), ['select', 'radio', 'checkbox'])) {
  313. $value = json_decode($cfValue->getValue(), true);
  314. } else {
  315. $value = trim($cfValue->getValue(), '"');
  316. }
  317. break;
  318. }
  319. }
  320. if (isset($condition['value']) && $entity instanceof Ticket) {
  321. return $this->match($condition['match'], !empty($value) ? $value : '', $condition['value']);
  322. }
  323. break;
  324. default:
  325. break;
  326. }
  327. return false;
  328. }
  329. public function match($condition, $haystack, $needle)
  330. {
  331. // Filter tags
  332. if ('string' == gettype($haystack)) {
  333. $haystack = strip_tags($haystack);
  334. }
  335. switch ($condition) {
  336. case 'is':
  337. return is_array($haystack) ? in_array($needle, $haystack) : $haystack == $needle;
  338. case 'isNot':
  339. return is_array($haystack) ? !in_array($needle, $haystack) : $haystack != $needle;
  340. case 'contains':
  341. return strripos($haystack,$needle) !== false ? true : false;
  342. case 'notContains':
  343. return strripos($haystack,$needle) === false ? true : false;
  344. case 'startWith':
  345. return $needle === "" || strripos($haystack, $needle, -strlen($haystack)) !== FALSE;
  346. case 'endWith':
  347. return $needle === "" || (($temp = strlen($haystack) - strlen($needle)) >= 0 && stripos($haystack, $needle, $temp) !== FALSE);
  348. case 'before':
  349. $createdTimeStamp = date('Y-m-d', strtotime($haystack));
  350. $conditionTimeStamp = date('Y-m-d', strtotime($needle . " 23:59:59"));
  351. return $createdTimeStamp < $conditionTimeStamp ? true : false;
  352. case 'beforeOn':
  353. $createdTimeStamp = date('Y-m-d', strtotime($haystack));
  354. $conditionTimeStamp = date('Y-m-d', strtotime($needle . " 23:59:59"));
  355. return ($createdTimeStamp < $conditionTimeStamp || $createdTimeStamp == $conditionTimeStamp) ? true : false;
  356. case 'after':
  357. $createdTimeStamp = date('Y-m-d', strtotime($haystack));
  358. $conditionTimeStamp = date('Y-m-d', strtotime($needle . " 23:59:59"));
  359. return $createdTimeStamp > $conditionTimeStamp ? true : false;
  360. case 'afterOn':
  361. $createdTimeStamp = date('Y-m-d', strtotime($haystack));
  362. $conditionTimeStamp = date('Y-m-d', strtotime($needle . " 23:59:59"));
  363. return $createdTimeStamp > $conditionTimeStamp || $createdTimeStamp == $conditionTimeStamp ? true : false;
  364. case 'beforeDateTime':
  365. $createdTimeStamp = date('Y-m-d h:i:s', strtotime($haystack));
  366. $conditionTimeStamp = date('Y-m-d h:i:s', strtotime($needle));
  367. return $createdTimeStamp < $conditionTimeStamp ? true : false;
  368. case 'beforeDateTimeOn':
  369. $createdTimeStamp = date('Y-m-d h:i:s', strtotime($haystack));
  370. $conditionTimeStamp = date('Y-m-d h:i:s', strtotime($needle));
  371. return ($createdTimeStamp < $conditionTimeStamp || $createdTimeStamp == $conditionTimeStamp) ? true : false;
  372. case 'afterDateTime':
  373. $createdTimeStamp = date('Y-m-d h:i:s', strtotime($haystack));
  374. $conditionTimeStamp = date('Y-m-d h:i:s', strtotime($needle));
  375. return $createdTimeStamp > $conditionTimeStamp ? true : false;
  376. case 'afterDateTimeOn':
  377. $createdTimeStamp = date('Y-m-d h:i:s', strtotime($haystack));
  378. $conditionTimeStamp = date('Y-m-d h:i:s', strtotime($needle));
  379. return $createdTimeStamp > $conditionTimeStamp || $createdTimeStamp == $conditionTimeStamp ? true : false;
  380. case 'beforeTime':
  381. $createdTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $haystack));
  382. $conditionTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $needle));
  383. return $createdTimeStamp < $conditionTimeStamp ? true : false;
  384. case 'beforeTimeOn':
  385. $createdTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $haystack));
  386. $conditionTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $needle));
  387. return ($createdTimeStamp < $conditionTimeStamp || $createdTimeStamp == $conditionTimeStamp) ? true : false;
  388. case 'afterTime':
  389. $createdTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $haystack));
  390. $conditionTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $needle));
  391. return $createdTimeStamp > $conditionTimeStamp ? true : false;
  392. case 'afterTimeOn':
  393. $createdTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $haystack));
  394. $conditionTimeStamp = date('Y-m-d H:i A', strtotime('2017-01-01' . $needle));
  395. return $createdTimeStamp > $conditionTimeStamp || $createdTimeStamp == $conditionTimeStamp ? true : false;
  396. case 'greaterThan':
  397. return !is_array($haystack) && $needle > $haystack;
  398. case 'lessThan':
  399. return !is_array($haystack) && $needle < $haystack;
  400. default:
  401. break;
  402. }
  403. return false;
  404. }
  405. }