Your IP : 3.138.154.250


Current Path : /var/www/axolotl/data/www/axolotl.ru/www/bitrix/activities/bitrix/delayactivity/
Upload File :
Current File : /var/www/axolotl/data/www/axolotl.ru/www/bitrix/activities/bitrix/delayactivity/delayactivity.php

<?php

if (!defined('B_PROLOG_INCLUDED') || B_PROLOG_INCLUDED !== true)
{
	die();
}

class CBPDelayActivity extends CBPActivity implements
	IBPEventActivity,
	IBPActivityExternalEventListener,
	IBPActivityDebugEventListener,
	IBPEventDrivenActivity
{
	private $subscriptionId = 0;
	private $isInEventActivityMode = false;

	public function __construct($name)
	{
		parent::__construct($name);
		$this->arProperties = [
			'Title' => '',
			'TimeoutDuration' => null,
			'TimeoutDurationType' => 's',
			'TimeoutTime' => null,
			'TimeoutTimeIsLocal' => 'N',
			'WriteToLog' => 'N',
		];
	}

	public function Cancel()
	{
		if (!$this->isInEventActivityMode && $this->subscriptionId > 0)
		{
			$this->Unsubscribe($this);
		}

		return CBPActivityExecutionStatus::Closed;
	}

	public function Execute()
	{
		if ($this->isInEventActivityMode)
		{
			return CBPActivityExecutionStatus::Closed;
		}

		$result = $this->Subscribe($this);
		$this->isInEventActivityMode = false;

		return $result ? CBPActivityExecutionStatus::Executing : CBPActivityExecutionStatus::Closed;
	}

	public function Subscribe(IBPActivityExternalEventListener $eventHandler)
	{
		$this->isInEventActivityMode = true;

		$delayIntervalProperties = [
			'TimeoutDuration' => $this->getRawProperty('TimeoutDuration'),
			'TimeoutDurationType' => $this->getRawProperty('TimeoutDurationType'),
			'TimeoutTime' => $this->getRawProperty('TimeoutTime'),
			'TimeoutTimeIsLocal' => $this->getRawProperty('TimeoutTimeIsLocal'),
		];

		$timeoutDuration = $this->parseValue($delayIntervalProperties['TimeoutDuration']);
		$timeoutDurationValue = 0;
		$timeoutTime = $this->parseValue($delayIntervalProperties['TimeoutTime']);

		if (is_array($timeoutTime)) //if multiple value
		{
			$timeoutTime = reset($timeoutTime);
		}

		if ($timeoutDuration != null)
		{
			$timeoutDurationValue = $this->CalculateTimeoutDuration();
			$expiresAt = time() + $timeoutDurationValue;
		}
		elseif ($timeoutTime != null)
		{
			$timeoutTime = $this->timeoutTimeToTimestamp($timeoutTime, $delayIntervalProperties);
			$expiresAt = $timeoutTime;
		}
		else
		{
			$expiresAt = time();
		}

		$this->writeToTrackingService(
			$this->getDelayAutomationTrack($delayIntervalProperties),
			0,
			CBPTrackingType::DebugAutomation
		);

		if ($timeoutTime != null && $eventHandler === $this && $expiresAt <= time() + 1) //now + 1 second
		{
			$this->logMessage(GetMessage('BPDA_TRACK3'));

			return false;
		}

		$schedulerService = $this->workflow->GetService('SchedulerService');
		$this->subscriptionId =
			$schedulerService->SubscribeOnTime($this->workflow->GetInstanceId(), $this->name, $expiresAt)
		;

		if (!$this->subscriptionId)
		{
			throw new Exception(GetMessage('BPDA_SUBSCRIBE_ERROR'));
		}

		$this->workflow->AddEventHandler($this->name, $eventHandler);

		if ($timeoutDuration != null)
		{
			$timeoutDurationValue = max($timeoutDurationValue, CBPSchedulerService::getDelayMinLimit());
			$timestamp = time() + $timeoutDurationValue;

			$this->logMessage(
				GetMessage(
					'BPDA_TRACK4',
					[
						'#PERIOD1#' => trim(CBPHelper::FormatTimePeriod($timeoutDurationValue)),
						'#PERIOD2#' => sprintf(
							'%s (%s)',
							ConvertTimeStamp($timestamp, 'FULL'),
							date('P', $timestamp)
						),
					]
				)
			);
		}
		elseif ($timeoutTime != null)
		{
			$timestamp = max($timeoutTime, time() + CBPSchedulerService::getDelayMinLimit());
			$this->logMessage(
				GetMessage(
					'BPDA_TRACK1',
					[
						'#PERIOD#' => sprintf(
							'%s (%s)',
							ConvertTimeStamp($timestamp, 'FULL'),
							date('P', $timestamp)
						)
					]
				)
			);
		}
		else
		{
			$this->logMessage(GetMessage('BPDA_TRACK2'));
		}

		return true;
	}

	public function Unsubscribe(IBPActivityExternalEventListener $eventHandler)
	{
		$schedulerService = $this->workflow->GetService('SchedulerService');
		$schedulerService->UnSubscribeOnTime($this->subscriptionId);
		$this->workflow->RemoveEventHandler($this->name, $eventHandler);
		$this->subscriptionId = 0;
	}

	public function OnExternalEvent($arEventParameters = [])
	{
		if ($this->executionStatus != CBPActivityExecutionStatus::Closed)
		{
			if (!empty($arEventParameters['DebugEvent']))
			{
				$this->writeToTrackingService(
					\Bitrix\Main\Localization\Loc::getMessage('BPDA_DEBUG_EVENT'),
					0,
					CBPTrackingType::Debug
				);
			}

			$this->Unsubscribe($this);
			$this->workflow->CloseActivity($this);
		}
	}

	public function onDebugEvent(array $eventParameters = [])
	{
		$eventParameters['DebugEvent'] = true;
		$this->OnExternalEvent($eventParameters);
	}

	public static function ValidateProperties($arTestProperties = [], CBPWorkflowTemplateUser $user = null)
	{
		$errors = [];

		if (empty($arTestProperties['TimeoutDuration']) && empty($arTestProperties['TimeoutTime']))
		{
			$errors[] = [
				'code' => 'NotExist',
				'parameter' => 'TimeoutDuration',
				'message' => GetMessage('BPDA_EMPTY_PROP')
			];
		}

		return array_merge($errors, parent::ValidateProperties($arTestProperties, $user));
	}

	private function CalculateTimeoutDuration()
	{
		$timeoutDuration = ($this->IsPropertyExists('TimeoutDuration') ? $this->TimeoutDuration : 0);

		$timeoutDurationType = $this->TimeoutDurationType;
		$timeoutDurationType = mb_strtolower($timeoutDurationType);
		if (!in_array($timeoutDurationType, ['s', 'd', 'h', 'm']))
		{
			$timeoutDurationType = 's';
		}

		$timeoutDuration = intval($timeoutDuration);
		switch ($timeoutDurationType)
		{
			case 'd':
				$timeoutDuration *= 3600 * 24;
				break;
			case 'h':
				$timeoutDuration *= 3600;
				break;
			case 'm':
				$timeoutDuration *= 60;
				break;
			default:
				break;
		}

		return min($timeoutDuration, 3600 * 24 * 365 * 5);
	}

	private function logMessage(string $message): void
	{
		if (
			$this->WriteToLog === 'Y'
			|| $this->workflow->getService('TrackingService')->isForcedMode($this->getWorkflowInstanceId())
		)
		{
			$this->WriteToTrackingService($message);
		}
		else
		{
			$this->SetStatusTitle($message);
		}
	}

	public static function GetPropertiesDialog($documentType, $activityName, $arWorkflowTemplate, $arWorkflowParameters, $arWorkflowVariables, $arCurrentValues = null, $formName = '')
	{
		$runtime = CBPRuntime::GetRuntime();

		if (!is_array($arCurrentValues))
		{
			$arCurrentActivity = &CBPWorkflowTemplateLoader::FindActivityByName($arWorkflowTemplate, $activityName);

			if (is_array($arCurrentActivity['Properties']))
			{
				$arCurrentValues['delay_time'] = $arCurrentActivity['Properties']['TimeoutDuration'];
				$arCurrentValues['delay_type'] = $arCurrentActivity['Properties']['TimeoutDurationType'];
				$arCurrentValues['delay_date'] = $arCurrentActivity['Properties']['TimeoutTime'];
				if ($arCurrentValues['delay_date'] && !CBPActivity::isExpression($arCurrentValues['delay_date']))
				{
					$arCurrentValues['delay_date'] = ConvertTimeStamp($arCurrentValues['delay_date'], 'FULL');
				}
				$arCurrentValues['delay_date_is_local'] = $arCurrentActivity['Properties']['TimeoutTimeIsLocal'];
				$arCurrentValues['delay_write_to_log'] = $arCurrentActivity['Properties']['WriteToLog'];
			}

			if (
				is_array($arCurrentValues)
				&& array_key_exists('delay_time', $arCurrentValues)
				&& (intval($arCurrentValues['delay_time']) > 0)
				&& !array_key_exists('delay_type', $arCurrentValues)
			)
			{
				$arCurrentValues['delay_time'] = intval($arCurrentValues['delay_time']);

				$arCurrentValues['delay_type'] = 's';
				if ($arCurrentValues['delay_time'] % (3600 * 24) == 0)
				{
					$arCurrentValues['delay_time'] = $arCurrentValues['delay_time'] / (3600 * 24);
					$arCurrentValues['delay_type'] = 'd';
				}
				elseif ($arCurrentValues['delay_time'] % 3600 == 0)
				{
					$arCurrentValues['delay_time'] = $arCurrentValues['delay_time'] / 3600;
					$arCurrentValues['delay_type'] = 'h';
				}
				elseif ($arCurrentValues['delay_time'] % 60 == 0)
				{
					$arCurrentValues['delay_time'] = $arCurrentValues['delay_time'] / 60;
					$arCurrentValues['delay_type'] = 'm';
				}
			}
		}

		if (!is_array($arCurrentValues) || !array_key_exists('delay_type', $arCurrentValues))
		{
			$arCurrentValues['delay_type'] = 's';
		}
		if (
			!is_array($arCurrentValues)
			|| !array_key_exists('delay_time', $arCurrentValues)
			&& !array_key_exists('delay_date', $arCurrentValues)
		)
		{
			$arCurrentValues['delay_time'] = 1;
			$arCurrentValues['delay_type'] = 'h';
		}

		if (!is_array($arCurrentValues) || !array_key_exists('delay_date_is_local', $arCurrentValues))
		{
			$arCurrentValues['delay_date_is_local'] = 'N';
		}

		if (!is_array($arCurrentValues) || !array_key_exists('delay_write_to_log', $arCurrentValues))
		{
			$arCurrentValues['delay_write_to_log'] = 'N';
		}

		return $runtime->ExecuteResourceFile(
			__FILE__,
			'properties_dialog.php',
			[
				'arCurrentValues' => $arCurrentValues,
				'formName'        => $formName
			]
		);
	}

	public static function GetPropertiesDialogValues($documentType, $activityName, &$arWorkflowTemplate, &$arWorkflowParameters, &$arWorkflowVariables, $arCurrentValues, &$errors)
	{
		$errors = [];
		$properties = [];

		if ($arCurrentValues['time_type_selector'] == 'time')
		{
			if (CBPDocument::IsExpression($arCurrentValues['delay_date']))
			{
				$arCurrentValues['delay_date_x'] = $arCurrentValues['delay_date'];
				$arCurrentValues['delay_date'] = '';
			}

			if ($arCurrentValues['delay_date'] <> '' && $d = MakeTimeStamp($arCurrentValues['delay_date']))
			{
				$properties['TimeoutTime'] = $d;
			}
			elseif (
				$arCurrentValues['delay_date_x'] <> ''
				&& CBPActivity::isExpression($arCurrentValues['delay_date_x'])
			)
			{
				$properties['TimeoutTime'] = $arCurrentValues['delay_date_x'];
			}

			$properties['TimeoutTimeIsLocal'] = ($arCurrentValues['delay_date_is_local'] === 'Y') ? 'Y' : 'N';
		}
		else
		{
			$properties['TimeoutDuration'] = $arCurrentValues['delay_time'];
			$properties['TimeoutDurationType'] = $arCurrentValues['delay_type'];
		}

		$properties['WriteToLog'] = CBPHelper::getBool($arCurrentValues['delay_write_to_log']) ? 'Y' : 'N';

		$user = new CBPWorkflowTemplateUser(CBPWorkflowTemplateUser::CurrentUser);
		$errors = self::ValidateProperties($properties, $user);
		if (count($errors) > 0)
		{
			return false;
		}

		$currentActivity = &CBPWorkflowTemplateLoader::FindActivityByName($arWorkflowTemplate, $activityName);
		$currentActivity['Properties'] = $properties;

		return true;
	}

	private function getDelayAutomationTrack(array $delayIntervalProperties): array
	{
		$delayInterval = \Bitrix\Bizproc\Automation\Engine\DelayInterval::createFromActivityProperties($delayIntervalProperties);
		$parsed = static::parseExpression($delayInterval->getBasis());
		[$fieldProperty, $fieldValue] = $this->getRuntimeProperty($parsed['object'], $parsed['field'], $this);
		if ($parsed['object'] !== \Bitrix\Bizproc\Workflow\Template\SourceType::System)
		{
			$fieldName = $fieldProperty['Name'] ?? $parsed['field'];
		}
		else
		{
			$fieldName = null;
			$fieldValue = $this->parseValue($delayInterval->getBasis());
		}
		$fieldValue = $fieldValue ? $this->timeoutTimeToTimestamp($fieldValue, $delayIntervalProperties) : '';
		if ($fieldValue)
		{
			$fieldValue = sprintf(
				'%s (%s)',
				ConvertTimeStamp($fieldValue, 'FULL'),
				date('P', $fieldValue)
			);
		}

		return array_merge(
			$delayInterval->toArray(),
			[
				'fieldName' => $fieldName,
				'fieldValue' => $fieldValue,
			]
		);
	}

	private function timeoutTimeToTimestamp($timeoutTime, $delayIntervalProperties)
	{
		$isLocalTime = ($this->parseValue($delayIntervalProperties['TimeoutTimeIsLocal']) === 'Y');

		if ($timeoutTime instanceof \Bitrix\Bizproc\BaseType\Value\Date)
		{
			return $timeoutTime->getTimestamp();
		}
		else
		{
			if (!is_numeric($timeoutTime))
			{
				$timeoutTime = MakeTimeStamp((string) $timeoutTime);
			}

			if ($isLocalTime)
			{
				$timeoutTime -= \CTimeZone::GetOffset();
			}
		}

		return $timeoutTime;
	}
}