Update
This commit is contained in:
@@ -39,7 +39,6 @@ final class TempFile extends EO_TempFile
|
||||
$chunk->setFile($newFile);
|
||||
}
|
||||
|
||||
$tempFile = null;
|
||||
if ($chunk->isOnlyOne())
|
||||
{
|
||||
// Cloud and local files are processed by CFile::SaveFile.
|
||||
|
||||
@@ -29,7 +29,7 @@ class TempFileAgent
|
||||
$agentName = '\\' . __METHOD__ . '();';
|
||||
$agents = \CAgent::getList(['ID' => 'DESC'], [
|
||||
'MODULE_ID' => 'ui',
|
||||
'NAME' => $agentName,
|
||||
'=NAME' => $agentName,
|
||||
]);
|
||||
|
||||
if ($agent = $agents->fetch())
|
||||
|
||||
@@ -9,6 +9,7 @@ use Bitrix\Main\ORM\Fields;
|
||||
use Bitrix\Main\ORM\Fields\Relations\Reference;
|
||||
use Bitrix\Main\ORM\Query\Join;
|
||||
use Bitrix\Main\Type\DateTime;
|
||||
use Bitrix\Main\UuidGenerator;
|
||||
|
||||
/**
|
||||
* Class TempFileTable
|
||||
@@ -50,13 +51,7 @@ class TempFileTable extends Data\DataManager
|
||||
->configureUnique(true)
|
||||
->configureNullable(false)
|
||||
->configureDefaultValue(static function () {
|
||||
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0xffff),
|
||||
mt_rand(0, 0x0fff) | 0x4000,
|
||||
mt_rand(0, 0x3fff) | 0x8000,
|
||||
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
|
||||
);
|
||||
return UuidGenerator::generateV4();
|
||||
})
|
||||
->configureSize(36)
|
||||
,
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\UI\Infrastructure\Agent;
|
||||
|
||||
class AgentBase
|
||||
{
|
||||
public static function run()
|
||||
{
|
||||
return static::doRun() ? get_called_class() . '::run();' : '';
|
||||
}
|
||||
|
||||
public static function doRun(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function setExecutionPeriod(int $period): void
|
||||
{
|
||||
global $pPERIOD;
|
||||
|
||||
$pPERIOD = $period; // some magic to run the agent next time in $periodInSeconds seconds
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\UI\Infrastructure\Agent\EntityEditorConfig;
|
||||
|
||||
use Bitrix\Main\ORM\Fields\Relations\Reference;
|
||||
use Bitrix\Main\ORM\Query\Join;
|
||||
use Bitrix\Main\ORM\Query\Query;
|
||||
use Bitrix\Ui\EntityForm\EntityFormConfigAcTable;
|
||||
use Bitrix\Ui\EntityForm\EntityFormConfigTable;
|
||||
use Bitrix\UI\Infrastructure\Agent\AgentBase;
|
||||
use Bitrix\UI\Integration\HumanResources\DepartmentQueries;
|
||||
use Bitrix\UI\Integration\HumanResources\HumanResources;
|
||||
use COption;
|
||||
|
||||
class CrmAccessCodesConverterAgent extends AgentBase
|
||||
{
|
||||
public const AGENT_DONE_STOP_IT = false;
|
||||
public const PERIODICAL_AGENT_RUN_LATER = true;
|
||||
public const LIMIT = 100;
|
||||
private const MODULE_NAME = 'ui';
|
||||
|
||||
public static function doRun(): bool
|
||||
{
|
||||
$instance = new self();
|
||||
|
||||
if (!HumanResources::getInstance()->isUsed())
|
||||
{
|
||||
$instance->setExecutionPeriod(86400);
|
||||
|
||||
return self::PERIODICAL_AGENT_RUN_LATER;
|
||||
}
|
||||
|
||||
$instance->setIsConvertingOption();
|
||||
|
||||
if ($instance->hasUnconvertedAccessCodes())
|
||||
{
|
||||
$isInProgress = $instance->execute();
|
||||
if ($isInProgress)
|
||||
{
|
||||
return self::PERIODICAL_AGENT_RUN_LATER;
|
||||
}
|
||||
}
|
||||
|
||||
$instance->cleanUp();
|
||||
|
||||
return self::AGENT_DONE_STOP_IT;
|
||||
}
|
||||
|
||||
private function setIsConvertingOption(): void
|
||||
{
|
||||
COption::SetOptionString(self::MODULE_NAME, HumanResources::IS_CONVERTED_OPTION_NAME, 'N');
|
||||
}
|
||||
|
||||
private function cleanUp(): void
|
||||
{
|
||||
COption::RemoveOption(self::MODULE_NAME, HumanResources::IS_CONVERTED_OPTION_NAME);
|
||||
}
|
||||
|
||||
private function hasUnconvertedAccessCodes(): bool
|
||||
{
|
||||
$result = $this->getQuery()
|
||||
->setSelect(['ID'])
|
||||
->setLimit(1)
|
||||
->fetch()
|
||||
;
|
||||
|
||||
return (bool)$result['ID'];
|
||||
}
|
||||
|
||||
private function execute(): bool
|
||||
{
|
||||
$items = $this->getItems();
|
||||
|
||||
$accessCodes = array_map(
|
||||
static fn(string $code) => str_replace('DR', 'D', $code),
|
||||
array_unique(array_column($items, 'ACCESS_CODE')),
|
||||
);
|
||||
|
||||
if (empty($accessCodes))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$departmentsQueries = DepartmentQueries::getInstance();
|
||||
$humanResources = HumanResources::getInstance();
|
||||
foreach ($items as $item)
|
||||
{
|
||||
$department = $departmentsQueries->getDepartmentByAccessCode($item['ACCESS_CODE']);
|
||||
if (!$department)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
EntityFormConfigAcTable::update($item['ID'], [
|
||||
'ACCESS_CODE' => $humanResources->buildAccessCode('SNDR', $department->id),
|
||||
]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function getItems(): array
|
||||
{
|
||||
return $this->getQuery()
|
||||
->setSelect(['*'])
|
||||
->setLimit(self::LIMIT)
|
||||
->fetchAll()
|
||||
;
|
||||
}
|
||||
|
||||
private function getQuery(): Query
|
||||
{
|
||||
return EntityFormConfigAcTable::query()
|
||||
->registerRuntimeField(
|
||||
new Reference(
|
||||
'CONFIG_CATEGORY',
|
||||
EntityFormConfigTable::class,
|
||||
Join::on('this.CONFIG_ID', 'ref.ID')
|
||||
->where('ref.CATEGORY', 'crm')
|
||||
->where('ref.OPTION_CATEGORY', 'crm.entity.editor'),
|
||||
['join_type' => Join::TYPE_LEFT],
|
||||
),
|
||||
)
|
||||
->whereLike('ACCESS_CODE', 'DR%')
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\UI\Integration\HumanResources;
|
||||
|
||||
use Bitrix\HumanResources;
|
||||
use Bitrix\Main\Loader;
|
||||
|
||||
Loader::requireModule('humanresources');
|
||||
|
||||
class DepartmentQueries
|
||||
{
|
||||
private HumanResources\Service\Container $hrServiceLocator;
|
||||
|
||||
public static function getInstance(): self
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
$this->hrServiceLocator = HumanResources\Service\Container::instance();
|
||||
}
|
||||
|
||||
public function getDepartmentByAccessCode(string $accessCode): ?HumanResources\Item\Node
|
||||
{
|
||||
return $this->hrServiceLocator::getNodeRepository()->getByAccessCode($accessCode);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\UI\Integration\HumanResources;
|
||||
|
||||
use Bitrix\HumanResources\Config\Storage;
|
||||
use Bitrix\HumanResources\Type\AccessCodeType;
|
||||
use Bitrix\Main\Loader;
|
||||
use COption;
|
||||
|
||||
final class HumanResources
|
||||
{
|
||||
public const IS_CONVERTED_OPTION_NAME = 'entity_editor_config_access_codes_is_converted';
|
||||
|
||||
public static function getInstance(): self
|
||||
{
|
||||
return new self();
|
||||
}
|
||||
|
||||
private function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function buildAccessCode(string $value, int $nodeId): ?string
|
||||
{
|
||||
if ($this->isUsed())
|
||||
{
|
||||
return AccessCodeType::tryFrom($value)?->buildAccessCode($nodeId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function isUsed(): bool
|
||||
{
|
||||
return Loader::includeModule('humanresources') && Storage::instance()->isCompanyStructureConverted(false);
|
||||
}
|
||||
|
||||
private function isEntityEditorConfigAccessCodesConverted(): bool
|
||||
{
|
||||
return COption::GetOptionString('ui', self::IS_CONVERTED_OPTION_NAME, 'Y') === 'Y';
|
||||
}
|
||||
|
||||
public function isAccessCodesCanBeUsed(): bool
|
||||
{
|
||||
return $this->isUsed() && $this->isEntityEditorConfigAccessCodesConverted();
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\UI\NotificationManager\Helpers;
|
||||
|
||||
final class Uuid
|
||||
{
|
||||
public static function getV4(): string
|
||||
{
|
||||
return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
random_int(0, 0xffff),
|
||||
random_int(0, 0xffff),
|
||||
random_int(0, 0xffff),
|
||||
random_int(0, 0x0fff) | 0x4000,
|
||||
random_int(0, 0x3fff) | 0x8000,
|
||||
random_int(0, 0xffff),
|
||||
random_int(0, 0xffff),
|
||||
random_int(0, 0xffff)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ use Bitrix\Main\Text\Encoding;
|
||||
*
|
||||
* Maximum length of BankName is increased up to 120, standard states it should not be more than 45.
|
||||
*/
|
||||
final class FinancialTransactionsRu
|
||||
class FinancialTransactionsRu
|
||||
{
|
||||
public const FORMAT_IDENTIFIER = 'ST';
|
||||
public const FORMAT_VERSION = '0001';
|
||||
@@ -237,6 +237,7 @@ final class FinancialTransactionsRu
|
||||
self::FIELD_BANK_NAME => 120,
|
||||
self::FIELD_BIC => 9,
|
||||
self::FIELD_CORRESPONDENT_ACCOUNT => 20,
|
||||
self::FIELD_PURPOSE => 210,
|
||||
];
|
||||
|
||||
return $maximumFieldLengths[$fieldName] ?? null;
|
||||
|
||||
@@ -35,6 +35,8 @@ class BaseButton implements Contract\Renderable
|
||||
protected $link;
|
||||
/** @var integer|string */
|
||||
protected $counter;
|
||||
/** @var CounterStyle */
|
||||
protected $counterStyle;
|
||||
/** @var array */
|
||||
protected $events = [];
|
||||
/** @var ButtonAttributes */
|
||||
@@ -114,6 +116,11 @@ class BaseButton implements Contract\Renderable
|
||||
$this->setCounter($params['counter']);
|
||||
}
|
||||
|
||||
if (!empty($params['counterStyle']))
|
||||
{
|
||||
$this->setCounterStyle($params['counterStyle']);
|
||||
}
|
||||
|
||||
if (!empty($params['id']))
|
||||
{
|
||||
$this->setId($params['id']);
|
||||
@@ -258,9 +265,10 @@ class BaseButton implements Contract\Renderable
|
||||
|
||||
if ($counter !== null)
|
||||
{
|
||||
$counterStyle = $this->getCounterStyle() ?? CounterStyle::FILLED_ALERT;
|
||||
$counter = new Counter(
|
||||
useAirDesign: true,
|
||||
style: CounterStyle::FILLED_ALERT,
|
||||
style: $counterStyle,
|
||||
value: (int)$counter,
|
||||
);
|
||||
|
||||
@@ -642,4 +650,33 @@ class BaseButton implements Contract\Renderable
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return $this
|
||||
*/
|
||||
public function setCounterStyle(CounterStyle | string $style): self
|
||||
{
|
||||
if ($style instanceof CounterStyle)
|
||||
{
|
||||
$this->counterStyle = $style;
|
||||
return $this;
|
||||
}
|
||||
|
||||
$styleFromEnum = CounterStyle::tryFrom($style);
|
||||
|
||||
if (!is_null($styleFromEnum))
|
||||
{
|
||||
$this->counterStyle = $styleFromEnum;
|
||||
return $this;
|
||||
}
|
||||
|
||||
$this->counterStyle = CounterStyle::FILLED_ALERT;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCounterStyle(): ?CounterStyle
|
||||
{
|
||||
return $this->counterStyle;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,6 +120,7 @@ trait ProviderWithUserFieldsTrait
|
||||
'MULTIPLE' => $userFieldInfo['MULTIPLE'],
|
||||
'MANDATORY' => $userFieldInfo['MANDATORY'],
|
||||
'SETTINGS' => $userFieldInfo['SETTINGS'] ?? null,
|
||||
'HELP_MESSAGE' => $userFieldInfo['HELP_MESSAGE'] ?? null,
|
||||
];
|
||||
|
||||
// required for the enum fields to work on mobile
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Ui\EntityForm\Dto;
|
||||
|
||||
use Bitrix\Ui\EntityForm\EO_EntityFormConfig;
|
||||
use Bitrix\UI\Form\EntityEditorConfigScope;
|
||||
|
||||
final class EntityEditorConfigDto
|
||||
{
|
||||
public function __construct(
|
||||
private readonly string $categoryName,
|
||||
private readonly string $entityTypeId,
|
||||
private readonly string $configScopeType,
|
||||
private readonly ?int $userScopeId,
|
||||
private ?int $userId = null,
|
||||
private readonly bool $onAdd = false,
|
||||
private readonly bool $onUpdate = false,
|
||||
) {
|
||||
}
|
||||
|
||||
public static function fromEntityFormConfig(EO_EntityFormConfig $config): self
|
||||
{
|
||||
return new self(
|
||||
$config->getOptionCategory(),
|
||||
$config->getEntityTypeId(),
|
||||
EntityEditorConfigScope::CUSTOM,
|
||||
$config->getId(),
|
||||
null,
|
||||
$config->getOnAdd(),
|
||||
$config->getOnUpdate(),
|
||||
);
|
||||
}
|
||||
|
||||
public function setUserId(int $int): self
|
||||
{
|
||||
$this->userId = $int;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getConfigScopeType(): string
|
||||
{
|
||||
return $this->configScopeType;
|
||||
}
|
||||
|
||||
public function getCategoryName(): string
|
||||
{
|
||||
return $this->categoryName;
|
||||
}
|
||||
|
||||
public function getEntityTypeId(): string
|
||||
{
|
||||
return $this->entityTypeId;
|
||||
}
|
||||
|
||||
public function getUserScopeId(): ?int
|
||||
{
|
||||
return $this->userScopeId;
|
||||
}
|
||||
|
||||
public function getUserId(): ?int
|
||||
{
|
||||
return $this->userId;
|
||||
}
|
||||
|
||||
public function getOptionValue(): array
|
||||
{
|
||||
return [
|
||||
'scope' => $this->configScopeType,
|
||||
'userScopeId' => $this->userScopeId,
|
||||
'onAdd' => $this->onAdd,
|
||||
'onUpdate' => $this->onUpdate,
|
||||
];
|
||||
}
|
||||
|
||||
public function hasOnAdd(): bool
|
||||
{
|
||||
return $this->onAdd;
|
||||
}
|
||||
|
||||
public function hasOnUpdate(): bool
|
||||
{
|
||||
return $this->onUpdate;
|
||||
}
|
||||
|
||||
public function getModuleIdFromCategory(): ?string
|
||||
{
|
||||
if (preg_match('/^([a-zA-Z0-9_]+)\.entity\.editor$/', $this->getCategoryName(), $matches))
|
||||
{
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -34,22 +34,22 @@ class EntityFormConfigTable extends Entity\DataManager
|
||||
return [
|
||||
new Entity\IntegerField('ID', [
|
||||
'autocomplete' => true,
|
||||
'primary' => true
|
||||
'primary' => true,
|
||||
]),
|
||||
new Entity\StringField('CATEGORY', [
|
||||
'required' => true,
|
||||
'size' => 20
|
||||
'size' => 20,
|
||||
]),
|
||||
new Entity\StringField('ENTITY_TYPE_ID', [
|
||||
'required' => true,
|
||||
'size' => 60
|
||||
'size' => 60,
|
||||
]),
|
||||
new Entity\StringField('NAME', [
|
||||
'required' => true,
|
||||
'size' => 100
|
||||
'size' => 100,
|
||||
]),
|
||||
(new ArrayField('CONFIG'))
|
||||
->configureSerializeCallback(function ($value){
|
||||
->configureSerializeCallback(function ($value) {
|
||||
return EntityFormConfigTable::serialize($value);
|
||||
})
|
||||
->configureUnserializeCallback(function ($value) {
|
||||
@@ -58,17 +58,27 @@ class EntityFormConfigTable extends Entity\DataManager
|
||||
new Entity\BooleanField('COMMON', [
|
||||
'values' => ['N', 'Y'],
|
||||
'required' => true,
|
||||
'default_value' => 'N'
|
||||
'default_value' => 'N',
|
||||
]),
|
||||
new Entity\BooleanField('AUTO_APPLY_SCOPE', [
|
||||
'values' => ['N', 'Y'],
|
||||
'required' => true,
|
||||
'default_value' => 'N'
|
||||
'default_value' => 'N',
|
||||
]),
|
||||
new Entity\StringField('OPTION_CATEGORY', [
|
||||
'required' => true,
|
||||
'size' => 50
|
||||
])
|
||||
'size' => 50,
|
||||
]),
|
||||
new Entity\BooleanField('ON_ADD', [
|
||||
'values' => ['N', 'Y'],
|
||||
'required' => true,
|
||||
'default_value' => 'Y',
|
||||
]),
|
||||
new Entity\BooleanField('ON_UPDATE', [
|
||||
'values' => ['N', 'Y'],
|
||||
'required' => true,
|
||||
'default_value' => 'Y',
|
||||
]),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -90,7 +100,7 @@ class EntityFormConfigTable extends Entity\DataManager
|
||||
{
|
||||
$value = Emoji::decode($value);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
elseif (is_string($unserialized))
|
||||
@@ -110,9 +120,9 @@ class EntityFormConfigTable extends Entity\DataManager
|
||||
{
|
||||
$value = Emoji::encode($value);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return serialize($fieldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
215
core/bitrix/modules/ui/lib/entityform/formconfigdata.php
Normal file
215
core/bitrix/modules/ui/lib/entityform/formconfigdata.php
Normal file
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Ui\EntityForm;
|
||||
|
||||
use Bitrix\Main\Config\Configuration;
|
||||
use Bitrix\Main\Grid\Options;
|
||||
use Bitrix\Main\Grid\Panel\Snippet;
|
||||
use Bitrix\Main\Loader;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\UI\PageNavigation;
|
||||
use Bitrix\Main\Web\Json;
|
||||
use Bitrix\UI\Integration\HumanResources\HumanResources;
|
||||
|
||||
class FormConfigData
|
||||
{
|
||||
private const SETTINGS_ENTITY_FORM_SCOPE_KEY = 'entityFormScope';
|
||||
private const SETTINGS_FORM_CONFIG_DATA_CLASS_KEY = 'formConfigData';
|
||||
|
||||
public function __construct(
|
||||
protected readonly string $navParamName,
|
||||
protected readonly string $moduleId,
|
||||
protected readonly string|int $entityTypeId,
|
||||
) {
|
||||
}
|
||||
|
||||
public static function getInstance(string $navParamName, string $moduleId, string|int $entityTypeId): static
|
||||
{
|
||||
$configuration = Configuration::getInstance($moduleId);
|
||||
|
||||
$value = $configuration->get(static::SETTINGS_ENTITY_FORM_SCOPE_KEY);
|
||||
if (
|
||||
is_array($value)
|
||||
&& isset($value[static::SETTINGS_FORM_CONFIG_DATA_CLASS_KEY])
|
||||
&& Loader::includeModule($moduleId)
|
||||
&& is_a($value[static::SETTINGS_FORM_CONFIG_DATA_CLASS_KEY], self::class, true)
|
||||
) {
|
||||
return new $value[static::SETTINGS_FORM_CONFIG_DATA_CLASS_KEY]($navParamName, $moduleId, $entityTypeId);
|
||||
}
|
||||
|
||||
return new self($navParamName, $moduleId, $entityTypeId);
|
||||
}
|
||||
|
||||
public function prepare(): array
|
||||
{
|
||||
$gridId = $this->getGridId();
|
||||
$grid['GRID_ID'] = $gridId;
|
||||
$grid['COLUMNS'] = $this->getColumns();
|
||||
|
||||
$gridOptions = new Options($gridId);
|
||||
$navParams = $gridOptions->getNavParams(['nPageSize' => 10]);
|
||||
$pageSize = (int)$navParams['nPageSize'];
|
||||
|
||||
$pageNavigation = new PageNavigation($this->navParamName);
|
||||
$pageNavigation->allowAllRecords(false)->setPageSize($pageSize)->initFromUri();
|
||||
|
||||
$entityTypeId = $this->entityTypeId ?? null;
|
||||
|
||||
if ($entityTypeId)
|
||||
{
|
||||
$moduleId = $this->moduleId ?? null;
|
||||
$list = Scope::getInstance()->getAllUserScopes($entityTypeId, $moduleId);
|
||||
}
|
||||
else
|
||||
{
|
||||
$list = [];
|
||||
}
|
||||
|
||||
$grid['ROWS'] = [];
|
||||
|
||||
if (!empty($list))
|
||||
{
|
||||
foreach ($list as $scopeId => $scope)
|
||||
{
|
||||
$grid['ROWS'][] = [
|
||||
'data' => $this->prepareRowData($scopeId, $scope, $entityTypeId),
|
||||
'actions' => $this->getContextActions($scopeId, $scope),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$grid['NAV_PARAM_NAME'] = $this->navParamName;
|
||||
$grid['CURRENT_PAGE'] = $pageNavigation->getCurrentPage();
|
||||
$grid['NAV_OBJECT'] = $pageNavigation;
|
||||
$grid['AJAX_MODE'] = 'Y';
|
||||
$grid['ALLOW_ROWS_SORT'] = false;
|
||||
$grid['AJAX_OPTION_JUMP'] = 'N';
|
||||
$grid['AJAX_OPTION_STYLE'] = 'N';
|
||||
$grid['AJAX_OPTION_HISTORY'] = 'N';
|
||||
$grid['AJAX_ID'] = \CAjax::GetComponentID(
|
||||
'bitrix:main.ui.grid', '', '',
|
||||
);
|
||||
$grid['SHOW_PAGESIZE'] = true;
|
||||
$grid['PAGE_SIZES'] = [
|
||||
['NAME' => '10', 'VALUE' => '10'], ['NAME' => '20', 'VALUE' => '20'], ['NAME' => '50', 'VALUE' => '50'],
|
||||
];
|
||||
$grid['DEFAULT_PAGE_SIZE'] = 20;
|
||||
$grid['SHOW_ROW_CHECKBOXES'] = true;
|
||||
$grid['SHOW_CHECK_ALL_CHECKBOXES'] = false;
|
||||
$grid['SHOW_ACTION_PANEL'] = true;
|
||||
|
||||
$snippet = new Snippet();
|
||||
$grid['ACTION_PANEL'] = [
|
||||
'GROUPS' => [
|
||||
'TYPE' => [
|
||||
'ITEMS' => [
|
||||
$snippet->getRemoveButton(),
|
||||
$snippet->getEditButton(),
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
$grid['FILTER'] = $this->getFilter();
|
||||
|
||||
return [
|
||||
'grid' => $grid,
|
||||
];
|
||||
}
|
||||
|
||||
protected function getGridId(): string
|
||||
{
|
||||
return 'editor_scopes';
|
||||
}
|
||||
|
||||
protected function getColumns(): array
|
||||
{
|
||||
$columns = [
|
||||
[
|
||||
'id' => 'ID',
|
||||
'name' => 'ID',
|
||||
'default' => true,
|
||||
],
|
||||
[
|
||||
'id' => 'NAME',
|
||||
'name' => Loc::getMessage('UI_FORM_CONFIG_SCOPE'),
|
||||
'default' => true,
|
||||
'editable' => true,
|
||||
],
|
||||
[
|
||||
'id' => 'USERS',
|
||||
'name' => Loc::getMessage('UI_FORM_CONFIG_MEMBERS'),
|
||||
'default' => true,
|
||||
'width' => 200,
|
||||
],
|
||||
[
|
||||
'id' => 'AUTO_APPLY_SCOPE',
|
||||
'name' => Loc::getMessage('UI_FORM_CONFIG_AUTO_APPLY_SCOPE'),
|
||||
'type' => \Bitrix\Main\Grid\Types::GRID_CHECKBOX,
|
||||
'default' => true,
|
||||
'editable' => true,
|
||||
],
|
||||
|
||||
];
|
||||
|
||||
if (ScopeAccess::getInstance($this->moduleId)->canUseOnAddOnUpdateSegregation())
|
||||
{
|
||||
$columns[] = [
|
||||
'id' => 'ON_ADD',
|
||||
'name' => Loc::getMessage('UI_FORM_CONFIG_ON_ADD'),
|
||||
'type' => \Bitrix\Main\Grid\Types::GRID_CHECKBOX,
|
||||
'default' => true,
|
||||
'editable' => true,
|
||||
];
|
||||
$columns[] = [
|
||||
'id' => 'ON_UPDATE',
|
||||
'name' => Loc::getMessage('UI_FORM_CONFIG_ON_UPDATE'),
|
||||
'type' => \Bitrix\Main\Grid\Types::GRID_CHECKBOX,
|
||||
'default' => true,
|
||||
'editable' => true,
|
||||
];
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
protected function getContextActions(int $scopeId, array $scope): array
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
protected function getFilter(): ?array
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function prepareRowData(int|string $scopeId, array $scope, string $entityTypeId): array
|
||||
{
|
||||
return [
|
||||
'ID' => $scopeId,
|
||||
'NAME' => $scope['NAME'],
|
||||
'USERS' => $this->getUserField($scopeId, $scope, $entityTypeId),
|
||||
'AUTO_APPLY_SCOPE' => $scope['AUTO_APPLY_SCOPE'],
|
||||
'ON_ADD' => $scope['ON_ADD'],
|
||||
'ON_UPDATE' => $scope['ON_UPDATE'],
|
||||
];
|
||||
}
|
||||
|
||||
protected function getUserField(int|string $scopeId, array $scope, $entityTypeId): string
|
||||
{
|
||||
$params = Json::encode([
|
||||
'scopeId' => $scopeId,
|
||||
'members' => $scope['MEMBERS'],
|
||||
'moduleId' => $this->moduleId,
|
||||
'entityTypeId' => $entityTypeId,
|
||||
'useHumanResourcesModule' => HumanResources::getInstance()->isAccessCodesCanBeUsed(),
|
||||
]);
|
||||
|
||||
return <<<HTML
|
||||
<div class="ui-editor-config" id="ui-editor-config-$scopeId"></div>
|
||||
<script>
|
||||
BX.ready(() => { new BX.Ui.Form.ConfigItem({$params}) });
|
||||
</script>
|
||||
HTML;
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ use Bitrix\Main\Error;
|
||||
use Bitrix\Main\Event;
|
||||
use Bitrix\Main\Loader;
|
||||
use Bitrix\Main\Localization\Loc;
|
||||
use Bitrix\Main\ObjectNotFoundException;
|
||||
use Bitrix\Main\ORM\Data\DeleteResult;
|
||||
use Bitrix\Main\ORM\Data\UpdateResult;
|
||||
use Bitrix\Main\ORM\Query\Query;
|
||||
@@ -18,6 +19,7 @@ use Bitrix\Main\Result;
|
||||
use Bitrix\Main\Text\HtmlFilter;
|
||||
use Bitrix\Main\UI\AccessRights\DataProvider;
|
||||
use Bitrix\Socialnetwork\UserToGroupTable;
|
||||
use Bitrix\Ui\EntityForm\Dto\EntityEditorConfigDto;
|
||||
use Bitrix\UI\Form\EntityEditorConfigScope;
|
||||
use CAccess;
|
||||
use CUserOptions;
|
||||
@@ -31,10 +33,12 @@ class Scope
|
||||
protected const CODE_USER = 'U';
|
||||
protected const CODE_PROJECT = 'SG';
|
||||
protected const CODE_DEPARTMENT = 'DR';
|
||||
protected const CODE_STRUCTURE_DEPARTMENT = 'SNDR';
|
||||
|
||||
protected const TYPE_USER = 'user';
|
||||
protected const TYPE_PROJECT = 'project';
|
||||
protected const TYPE_DEPARTMENT = 'department';
|
||||
protected const TYPE_STRUCTURE_NODE = 'structure-node';
|
||||
|
||||
protected static array $instances = [];
|
||||
private static array $userScopeIdsCache = [];
|
||||
@@ -89,32 +93,21 @@ class Scope
|
||||
if (!isset($results[$key]))
|
||||
{
|
||||
$result = [];
|
||||
$isAdminForEntity = $moduleId
|
||||
&& (
|
||||
($scopeAccess = ScopeAccess::getInstance($moduleId, $this->userId))
|
||||
&& $scopeAccess->isAdminForEntityTypeId($entityTypeId)
|
||||
);
|
||||
$isAdminForEntity = $this->isAdminForEntity($entityTypeId, $moduleId);
|
||||
|
||||
if (!$isAdminForEntity)
|
||||
{
|
||||
$filter['@ID'] = $this->getScopesIdByUser();
|
||||
}
|
||||
|
||||
$filter['@ENTITY_TYPE_ID'] = ($this->getEntityTypeIdMap()[$entityTypeId] ?? [$entityTypeId]);
|
||||
|
||||
if ($excludeEmptyAccessCode)
|
||||
{
|
||||
$filter['!=ACCESS_CODE'] = '';
|
||||
}
|
||||
$filter = ScopeListFilter::getInstance($moduleId)->prepareFilter($entityTypeId, $isAdminForEntity, $excludeEmptyAccessCode, $this);
|
||||
|
||||
if ($isAdminForEntity || !empty($filter['@ID']))
|
||||
{
|
||||
$scopes = EntityFormConfigTable::getList([
|
||||
'select' => [
|
||||
'ID',
|
||||
'ENTITY_TYPE_ID',
|
||||
'NAME',
|
||||
'AUTO_APPLY_SCOPE',
|
||||
'ACCESS_CODE' => '\Bitrix\Ui\EntityForm\EntityFormConfigAcTable:CONFIG.ACCESS_CODE',
|
||||
'ON_ADD',
|
||||
'ON_UPDATE',
|
||||
],
|
||||
'filter' => $filter,
|
||||
]);
|
||||
@@ -123,6 +116,9 @@ class Scope
|
||||
{
|
||||
$result[$scope['ID']]['NAME'] = HtmlFilter::encode($scope['NAME']);
|
||||
$result[$scope['ID']]['AUTO_APPLY_SCOPE'] = $scope['AUTO_APPLY_SCOPE'];
|
||||
$result[$scope['ID']]['ON_ADD'] = $scope['ON_ADD'];
|
||||
$result[$scope['ID']]['ON_UPDATE'] = $scope['ON_UPDATE'];
|
||||
$result[$scope['ID']]['ENTITY_TYPE_ID'] = $scope['ENTITY_TYPE_ID'];
|
||||
if (
|
||||
$loadMetadata
|
||||
&& !isset($result[$scope['ID']]['ACCESS_CODES'][$scope['ACCESS_CODE']])
|
||||
@@ -132,7 +128,7 @@ class Scope
|
||||
$accessCode = new AccessCode($scope['ACCESS_CODE']);
|
||||
$member = (new DataProvider())->getEntity(
|
||||
$accessCode->getEntityType(),
|
||||
$accessCode->getEntityId()
|
||||
$accessCode->getEntityId(),
|
||||
);
|
||||
$result[$scope['ID']]['ACCESS_CODES'][$scope['ACCESS_CODE']] = $scope['ACCESS_CODE'];
|
||||
$result[$scope['ID']]['MEMBERS'][$scope['ACCESS_CODE']] = $member->getMetaData();
|
||||
@@ -149,7 +145,7 @@ class Scope
|
||||
/**
|
||||
* This method must return entityTypeId values that correspond to a single CRM entity only.
|
||||
*/
|
||||
protected function getEntityTypeIdMap(): array
|
||||
public function getEntityTypeIdMap(): array
|
||||
{
|
||||
return [
|
||||
'lead_details' => ['lead_details', 'returning_lead_details'],
|
||||
@@ -171,7 +167,7 @@ class Scope
|
||||
return $this->userId;
|
||||
}
|
||||
|
||||
private function getScopesIdByUser(): array
|
||||
public function getScopesIdByUser(): array
|
||||
{
|
||||
if (isset(self::$userScopeIdsCache[$this->getUserId()]))
|
||||
{
|
||||
@@ -217,8 +213,9 @@ class Scope
|
||||
{
|
||||
if ($row = EntityFormConfigTable::getRowById($scopeId))
|
||||
{
|
||||
return (is_array($row['CONFIG']) ? $row['CONFIG'] : null);
|
||||
return is_array($row['CONFIG']) ? $row['CONFIG'] : null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -249,7 +246,18 @@ class Scope
|
||||
*/
|
||||
private function removeById(int $id): DeleteResult
|
||||
{
|
||||
$scopeObject = EntityFormConfigTable::getById($id)->fetchObject();
|
||||
if (!$scopeObject)
|
||||
{
|
||||
return (new DeleteResult())->addError(new Error('Configuration not found'));
|
||||
}
|
||||
|
||||
$this->removeScopeMembers($id);
|
||||
|
||||
$scopeName = $this->getScopeName(EntityEditorConfigDto::fromEntityFormConfig($scopeObject));
|
||||
|
||||
$this->removeUsersScopeOptions($id, $scopeObject->getOptionCategory(), $scopeName);
|
||||
|
||||
return EntityFormConfigTable::delete($id);
|
||||
}
|
||||
|
||||
@@ -257,23 +265,65 @@ class Scope
|
||||
* Set user option with config scope type and scopeId if selected custom scope
|
||||
* @param string $categoryName
|
||||
* @param string $guid
|
||||
* @param string $scope
|
||||
* @param string $configScopeType
|
||||
* @param int $userScopeId
|
||||
*/
|
||||
public function setScope(string $categoryName, string $guid, string $scope, int $userScopeId = 0, ?int $userId = null): void
|
||||
public function setScope(string $categoryName, string $guid, string $configScopeType, int $userScopeId = 0, ?int $userId = null): void
|
||||
{
|
||||
$this->setScopeToUser($categoryName, $guid, $scope, $userScopeId, $userId);
|
||||
$this->setScopeWithName($categoryName, $guid, $configScopeType, $userScopeId, $userId);
|
||||
}
|
||||
|
||||
public function setCreateScope(string $moduleId, string $categoryName, string $guid, string $configScopeType, int $userScopeId = 0): void
|
||||
{
|
||||
$scopeName = self::getScopeNameOnAdd($moduleId, $guid);
|
||||
|
||||
$this->setScopeWithName($categoryName, $guid, $configScopeType, $userScopeId, null, $scopeName);
|
||||
}
|
||||
|
||||
public function setEditScope(string $moduleId, string $categoryName, string $guid, string $configScopeType, int $userScopeId = 0): void
|
||||
{
|
||||
$scopeName = self::getScopeNameOnUpdate($moduleId, $guid);
|
||||
|
||||
$this->setScopeWithName($categoryName, $guid, $configScopeType, $userScopeId, null, $scopeName);
|
||||
}
|
||||
|
||||
private function setScopeWithName(
|
||||
string $categoryName,
|
||||
string $guid,
|
||||
string $configScopeType,
|
||||
int $userScopeId = 0,
|
||||
?int $userId = null,
|
||||
?string $scopeName = null,
|
||||
): void
|
||||
{
|
||||
$scopeObject = EntityFormConfigTable::getById($userScopeId)->fetchObject();
|
||||
if (!$scopeObject && $configScopeType === EntityEditorConfigScope::CUSTOM)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$this->setScopeToUser(
|
||||
new EntityEditorConfigDto(
|
||||
$categoryName,
|
||||
$guid,
|
||||
$configScopeType,
|
||||
$userScopeId,
|
||||
$userId,
|
||||
(bool)$scopeObject?->getOnAdd(),
|
||||
(bool)$scopeObject?->getOnUpdate(),
|
||||
),
|
||||
$scopeName,
|
||||
);
|
||||
}
|
||||
|
||||
public function setScopeConfig(
|
||||
string $category,
|
||||
string $moduleId,
|
||||
string $entityTypeId,
|
||||
string $name,
|
||||
array $accessCodes,
|
||||
array $config,
|
||||
array $params = []
|
||||
)
|
||||
{
|
||||
array $params = [],
|
||||
) {
|
||||
if (empty($name))
|
||||
{
|
||||
$errors['name'] = new Error(Loc::getMessage('FIELD_REQUIRED'));
|
||||
@@ -293,14 +343,22 @@ class Scope
|
||||
|
||||
$this->formatAccessCodes($accessCodes);
|
||||
|
||||
$canUseOnAddOunUpdateSegregation = ScopeAccess::getInstance($moduleId)->canUseOnAddOnUpdateSegregation();
|
||||
|
||||
$forceSetToUsers = ($params['forceSetToUsers'] ?? 'N') === 'Y';
|
||||
$availableOnAdd = (!$canUseOnAddOunUpdateSegregation || ($params['availableOnAdd'] ?? 'N') === 'Y');
|
||||
$availableOnUpdate = (!$canUseOnAddOunUpdateSegregation || ($params['availableOnUpdate'] ?? 'N') === 'Y');
|
||||
|
||||
$result = EntityFormConfigTable::add([
|
||||
'CATEGORY' => $category,
|
||||
'CATEGORY' => $moduleId,
|
||||
'ENTITY_TYPE_ID' => $entityTypeId,
|
||||
'NAME' => $name,
|
||||
'CONFIG' => $config,
|
||||
'COMMON' => ($params['common'] ?? 'Y'),
|
||||
'AUTO_APPLY_SCOPE' => ($params['forceSetToUsers'] ?? 'N'),
|
||||
'OPTION_CATEGORY' => $params['categoryName']
|
||||
'AUTO_APPLY_SCOPE' => $forceSetToUsers,
|
||||
'OPTION_CATEGORY' => $params['categoryName'],
|
||||
'ON_ADD' => $availableOnAdd,
|
||||
'ON_UPDATE' => $availableOnUpdate,
|
||||
]);
|
||||
|
||||
if ($result->isSuccess())
|
||||
@@ -314,19 +372,20 @@ class Scope
|
||||
]);
|
||||
}
|
||||
|
||||
$forceSetToUsers = ($params['forceSetToUsers'] ?? false);
|
||||
if (mb_strtoupper($forceSetToUsers) === 'FALSE')
|
||||
{
|
||||
$forceSetToUsers = false;
|
||||
}
|
||||
|
||||
Application::getInstance()->addBackgroundJob(
|
||||
static fn() => Scope::getInstance()->forceSetScopeToUsers($accessCodes, [
|
||||
'forceSetToUsers' => $forceSetToUsers,
|
||||
'categoryName' => ($params['categoryName'] ?? ''),
|
||||
'entityTypeId' => $entityTypeId,
|
||||
'configId' => $configId,
|
||||
])
|
||||
static fn() => Scope::getInstance()->forceSetScopeToUsers(
|
||||
new EntityEditorConfigDto(
|
||||
$params['categoryName'] ?? '',
|
||||
$entityTypeId,
|
||||
EntityEditorConfigScope::CUSTOM,
|
||||
$result->getId(),
|
||||
null,
|
||||
$availableOnAdd,
|
||||
$availableOnUpdate,
|
||||
),
|
||||
$forceSetToUsers,
|
||||
$accessCodes,
|
||||
),
|
||||
);
|
||||
|
||||
return $configId;
|
||||
@@ -344,78 +403,81 @@ class Scope
|
||||
{
|
||||
if ($item['entityId'] === self::TYPE_USER)
|
||||
{
|
||||
$accessCodes[$key]['id'] = self::CODE_USER . (int)$accessCodes[$key]['id'];
|
||||
$accessCodes[$key]['id'] = self::CODE_USER . (int)$item['id'];
|
||||
}
|
||||
elseif ($item['entityId'] === self::TYPE_DEPARTMENT)
|
||||
{
|
||||
$accessCodes[$key]['id'] = self::CODE_DEPARTMENT . (int)$accessCodes[$key]['id'];
|
||||
$accessCodes[$key]['id'] = self::CODE_DEPARTMENT . (int)$item['id'];
|
||||
}
|
||||
elseif ($item['entityId'] === self::TYPE_PROJECT)
|
||||
{
|
||||
$accessCodes[$key]['id'] = self::CODE_PROJECT . (int)$accessCodes[$key]['id'];
|
||||
$accessCodes[$key]['id'] = self::CODE_PROJECT . (int)$item['id'];
|
||||
}
|
||||
else{
|
||||
elseif ($item['entityId'] === self::TYPE_STRUCTURE_NODE)
|
||||
{
|
||||
$accessCodes[$key]['id'] = self::CODE_STRUCTURE_DEPARTMENT . (int)$item['id'];
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($accessCodes[$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $accessCodes
|
||||
* @param array $params
|
||||
*/
|
||||
protected function forceSetScopeToUsers(array $accessCodes = [], array $params = []): void
|
||||
protected function forceSetScopeToUsers(EntityEditorConfigDto $config, bool $forceSetToUsers, array $accessCodes = []): void
|
||||
{
|
||||
if ($params['forceSetToUsers'] && $params['categoryName'])
|
||||
if ($forceSetToUsers && $config->getCategoryName())
|
||||
{
|
||||
$codes = [];
|
||||
foreach ($accessCodes as $ac)
|
||||
{
|
||||
$codes[] = $ac['id'];
|
||||
}
|
||||
$this->setScopeByAccessCodes(
|
||||
$params['categoryName'],
|
||||
$params['entityTypeId'],
|
||||
EntityEditorConfigScope::CUSTOM,
|
||||
(int)$params['configId'],
|
||||
$codes
|
||||
);
|
||||
$this->setScopeByAccessCodes($config, $codes);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $categoryName
|
||||
* @param string $guid
|
||||
* @param string $scope
|
||||
* @param int $userScopeId
|
||||
* @param int|null $userId
|
||||
*/
|
||||
protected function setScopeToUser(
|
||||
string $categoryName,
|
||||
string $guid,
|
||||
string $scope,
|
||||
int $userScopeId,
|
||||
?int $userId = null
|
||||
): void
|
||||
protected function setScopeToUser(EntityEditorConfigDto $config, ?string $scopeName = null): void
|
||||
{
|
||||
$scope = (isset($scope) ? strtoupper($scope) : EntityEditorConfigScope::UNDEFINED);
|
||||
$scope = $config->getConfigScopeType() !== null ? strtoupper($config->getConfigScopeType()) : EntityEditorConfigScope::UNDEFINED;
|
||||
|
||||
if (EntityEditorConfigScope::isDefined($scope))
|
||||
if (!EntityEditorConfigScope::isDefined($scope))
|
||||
{
|
||||
if ($scope === EntityEditorConfigScope::CUSTOM && $userScopeId)
|
||||
{
|
||||
$value = [
|
||||
'scope' => $scope,
|
||||
'userScopeId' => $userScopeId,
|
||||
];
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = $scope;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$userId = ($userId ?? false);
|
||||
CUserOptions::SetOption($categoryName, "{$guid}_scope", $value, false, $userId);
|
||||
if ($scope === EntityEditorConfigScope::CUSTOM && $config->getUserScopeId())
|
||||
{
|
||||
$value = $config->getOptionValue();
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = $scope;
|
||||
}
|
||||
|
||||
$scopeNamesToApply = [];
|
||||
if ($scopeName)
|
||||
{
|
||||
$scopeNamesToApply[] = $scopeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($config->hasOnAdd())
|
||||
{
|
||||
$scopeNamesToApply[] = self::getScopeNameOnAdd($config->getModuleIdFromCategory(), $config->getEntityTypeId());
|
||||
}
|
||||
if ($config->hasOnUpdate())
|
||||
{
|
||||
$scopeNamesToApply[] = self::getScopeNameOnUpdate($config->getModuleIdFromCategory(), $config->getEntityTypeId());
|
||||
}
|
||||
}
|
||||
$scopeNamesToApply = array_unique($scopeNamesToApply);
|
||||
|
||||
$userId = !is_null($config->getUserId()) ? $config->getUserId() : false;
|
||||
|
||||
foreach ($scopeNamesToApply as $scopeNameToApply)
|
||||
{
|
||||
CUserOptions::SetOption($config->getCategoryName(), $scopeNameToApply, $value, false, $userId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,24 +488,80 @@ class Scope
|
||||
]);
|
||||
}
|
||||
|
||||
public function updateScopeName(int $id, string $name): UpdateResult
|
||||
public function updateScope(int $scopeId, array $fields): UpdateResult
|
||||
{
|
||||
return EntityFormConfigTable::update($id, [
|
||||
'NAME' => $name,
|
||||
]);
|
||||
$scopeObject = EntityFormConfigTable::getById($scopeId)->fetchObject();
|
||||
if (!$scopeObject)
|
||||
{
|
||||
return (new UpdateResult())->addError(new Error('Configuration not found'));
|
||||
}
|
||||
|
||||
$oldScopeName = $this->getScopeName(EntityEditorConfigDto::fromEntityFormConfig($scopeObject));
|
||||
|
||||
$canUseOnAddOunUpdateSegregation = ScopeAccess::getInstance($scopeObject->getCategory())->canUseOnAddOnUpdateSegregation();
|
||||
if (isset($fields['ON_ADD']) && !$canUseOnAddOunUpdateSegregation)
|
||||
{
|
||||
$fields['ON_ADD'] = 'Y';
|
||||
}
|
||||
if (isset($fields['ON_UPDATE']) && !$canUseOnAddOunUpdateSegregation)
|
||||
{
|
||||
$fields['ON_UPDATE'] = 'Y';
|
||||
}
|
||||
|
||||
$result = EntityFormConfigTable::update($scopeId, $fields);
|
||||
|
||||
$optionCategory = $scopeObject->getOptionCategory();
|
||||
|
||||
$newScopeName = $this->getScopeName(
|
||||
new EntityEditorConfigDto(
|
||||
$optionCategory,
|
||||
$scopeObject->getEntityTypeId(),
|
||||
EntityEditorConfigScope::CUSTOM,
|
||||
$scopeObject->getId(),
|
||||
null,
|
||||
$fields['ON_ADD'] === 'Y',
|
||||
$fields['ON_UPDATE'] === 'Y',
|
||||
),
|
||||
);
|
||||
|
||||
if ($fields['AUTO_APPLY_SCOPE'] === 'Y')
|
||||
{
|
||||
Application::getInstance()->addBackgroundJob(static function() use ($scopeId, $optionCategory, $oldScopeName, $newScopeName) {
|
||||
if ($oldScopeName !== $newScopeName)
|
||||
{
|
||||
Scope::getInstance()->removeUsersScopeOptions($scopeId, $optionCategory, $oldScopeName);
|
||||
}
|
||||
Scope::getInstance()->setScopeForEligibleUsers($scopeId);
|
||||
});
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $configId
|
||||
* @param array $accessCodes
|
||||
* @return array
|
||||
*/
|
||||
public function updateScopeAccessCodes(int $configId, array $accessCodes = []): array
|
||||
{
|
||||
$scopeObject = EntityFormConfigTable::getById($configId)->fetchObject();
|
||||
|
||||
if (!$scopeObject)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
$this->removeScopeMembers($configId);
|
||||
$this->addAccessCodes($configId, $accessCodes);
|
||||
|
||||
return $this->getScopeMembers($configId);
|
||||
$scopeMembers = $this->getScopeMembers($configId);
|
||||
if ($scopeObject->getAutoApplyScope())
|
||||
{
|
||||
Application::getInstance()->addBackgroundJob(
|
||||
static fn() => Scope::getInstance()->setScopeByAccessCodes(
|
||||
EntityEditorConfigDto::fromEntityFormConfig($scopeObject),
|
||||
array_keys($accessCodes),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return $scopeMembers;
|
||||
}
|
||||
|
||||
public function addAccessCodes(int $configId, array $accessCodes): Result
|
||||
@@ -453,7 +571,8 @@ class Scope
|
||||
{
|
||||
$accessCodeItem = EntityFormConfigAcTable::createObject()
|
||||
->setAccessCode($accessCode)
|
||||
->setConfigId($configId);
|
||||
->setConfigId($configId)
|
||||
;
|
||||
|
||||
$accessCodeCollection->add($accessCodeItem);
|
||||
}
|
||||
@@ -481,6 +600,7 @@ class Scope
|
||||
$result[$accessCodeEntity['ACCESS_CODE']] = $member->getMetaData();
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -497,51 +617,43 @@ class Scope
|
||||
$connection->query(sprintf(
|
||||
'DELETE FROM %s WHERE %s',
|
||||
$connection->getSqlHelper()->quote($entity->getDBTableName()),
|
||||
Query::buildFilterSql($entity, $filter)
|
||||
Query::buildFilterSql($entity, $filter),
|
||||
));
|
||||
}
|
||||
|
||||
public function updateScopeAutoApplyScope(int $id, bool $autoApplyScope): UpdateResult
|
||||
{
|
||||
return EntityFormConfigTable::update($id, [
|
||||
'AUTO_APPLY_SCOPE' => $autoApplyScope ? 'Y' : 'N',
|
||||
]);
|
||||
}
|
||||
|
||||
private function setScopeToDepartment(
|
||||
string $categoryName,
|
||||
string $guid,
|
||||
string $scope,
|
||||
int $userScopeId,
|
||||
int $departmentId
|
||||
): void
|
||||
private function setScopeToDepartment(EntityEditorConfigDto $config, int $departmentId): void
|
||||
{
|
||||
$userIds = $this->getUserIdsByDepartment($departmentId);
|
||||
foreach ($userIds as $userId)
|
||||
{
|
||||
$this->setScopeToUser($categoryName, $guid, $scope, $userScopeId, $userId);
|
||||
$config->setUserId($userId);
|
||||
$this->setScopeToUser($config);
|
||||
}
|
||||
}
|
||||
|
||||
private function setScopeToSocialGroup(
|
||||
string $categoryName,
|
||||
string $guid,
|
||||
string $scope,
|
||||
int $userScopeId,
|
||||
int $socialGroupId
|
||||
): void
|
||||
private function setScopeToSocialGroup(EntityEditorConfigDto $config, int $socialGroupId): void
|
||||
{
|
||||
$userIds = $this->getUserIdsBySocialGroup($socialGroupId);
|
||||
foreach ($userIds as $userId)
|
||||
{
|
||||
$this->setScopeToUser($categoryName, $guid, $scope, $userScopeId, $userId);
|
||||
$config->setUserId($userId);
|
||||
$this->setScopeToUser($config);
|
||||
}
|
||||
}
|
||||
|
||||
private function setScopeToStructureDepartment(EntityEditorConfigDto $config, mixed $structureDepartmentId): void
|
||||
{
|
||||
$userIds = $this->getUserIdsByStructureDepartment($structureDepartmentId);
|
||||
foreach ($userIds as $userId)
|
||||
{
|
||||
$config->setUserId($userId);
|
||||
$this->setScopeToUser($config);
|
||||
}
|
||||
}
|
||||
|
||||
public static function handleMemberAddedToDepartment(Event $event): void
|
||||
{
|
||||
Application::getInstance()->addBackgroundJob(static function() use ($event)
|
||||
{
|
||||
Application::getInstance()->addBackgroundJob(static function() use ($event) {
|
||||
$member = $event->getParameter('member');
|
||||
|
||||
$memberId = $member->entityId;
|
||||
@@ -549,28 +661,13 @@ class Scope
|
||||
$scopeType = EntityEditorConfigScope::CUSTOM;
|
||||
$scopes = Scope::getInstance()->getScopesByDepartment($departmentId, true);
|
||||
|
||||
$appliedEntities = [];
|
||||
foreach ($scopes as $scope)
|
||||
{
|
||||
if (!in_array($scope->getEntityTypeId(), $appliedEntities))
|
||||
{
|
||||
$appliedEntities[] = $scope->getEntityTypeId();
|
||||
Scope::getInstance()->setScopeToUser(
|
||||
$scope->getOptionCategory(),
|
||||
$scope->getEntityTypeId(),
|
||||
$scopeType,
|
||||
$scope->getId(),
|
||||
$memberId
|
||||
);
|
||||
}
|
||||
}
|
||||
self::applyScopesToMember($scopes, $scopeType, $memberId);
|
||||
});
|
||||
}
|
||||
|
||||
public static function handleMemberAddedToSocialGroup(int $id, array $fields): void
|
||||
{
|
||||
Application::getInstance()->addBackgroundJob(static function() use ($id, $fields)
|
||||
{
|
||||
Application::getInstance()->addBackgroundJob(static function() use ($id, $fields) {
|
||||
if (!\Bitrix\Main\Loader::includeModule('socialnetwork'))
|
||||
{
|
||||
return;
|
||||
@@ -602,21 +699,7 @@ class Scope
|
||||
$scopeType = EntityEditorConfigScope::CUSTOM;
|
||||
$scopes = Scope::getInstance()->getScopesBySocialGroupId($socialGroupId, true);
|
||||
|
||||
$appliedEntities = [];
|
||||
foreach ($scopes as $scope)
|
||||
{
|
||||
if (!in_array($scope->getEntityTypeId(), $appliedEntities))
|
||||
{
|
||||
$appliedEntities[] = $scope->getEntityTypeId();
|
||||
Scope::getInstance()->setScopeToUser(
|
||||
$scope->getOptionCategory(),
|
||||
$scope->getEntityTypeId(),
|
||||
$scopeType,
|
||||
$scope->getId(),
|
||||
$memberId
|
||||
);
|
||||
}
|
||||
}
|
||||
self::applyScopesToMember($scopes, $scopeType, $memberId);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -659,29 +742,24 @@ class Scope
|
||||
->setSelect(['ACCESS_CODE', 'CONFIG'])
|
||||
->setFilter($filter)
|
||||
->setOrder(['CONFIG.ID' => 'DESC'])
|
||||
->fetchCollection();
|
||||
->fetchCollection()
|
||||
;
|
||||
|
||||
return $scopes->getConfigList();
|
||||
}
|
||||
|
||||
public function setScopeForEligibleUsers(int $scopeId): void
|
||||
{
|
||||
$scope = EntityFormConfigTable::getById($scopeId)->fetchObject();
|
||||
$scopeObject = EntityFormConfigTable::getById($scopeId)->fetchObject();
|
||||
|
||||
if (!$scope)
|
||||
if (!$scopeObject)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$accessCodes = $this->getScopeAccessCodesByScopeId($scopeId);
|
||||
|
||||
$this->setScopeByAccessCodes(
|
||||
$scope->getOptionCategory(),
|
||||
$scope->getEntityTypeId(),
|
||||
EntityEditorConfigScope::CUSTOM,
|
||||
$scopeId,
|
||||
$accessCodes
|
||||
);
|
||||
$this->setScopeByAccessCodes(EntityEditorConfigDto::fromEntityFormConfig($scopeObject), $accessCodes);
|
||||
}
|
||||
|
||||
public function getScopeAccessCodesByScopeId(int $scopeId): array
|
||||
@@ -689,7 +767,8 @@ class Scope
|
||||
$accessCodes = EntityFormConfigAcTable::query()
|
||||
->setSelect(['ACCESS_CODE'])
|
||||
->setFilter(['=CONFIG_ID' => $scopeId])
|
||||
->fetchCollection();
|
||||
->fetchCollection()
|
||||
;
|
||||
$result = [];
|
||||
foreach ($accessCodes as $code)
|
||||
{
|
||||
@@ -699,49 +778,56 @@ class Scope
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function setScopeByAccessCodes(
|
||||
string $categoryName,
|
||||
string $entityTypeId,
|
||||
string $scope,
|
||||
int $scopeId,
|
||||
array $accessCodes
|
||||
): void
|
||||
public static function getScopeNameOnAdd(string $moduleId, string $entityTypeId): string
|
||||
{
|
||||
return self::getScopeNameWithSuffix($moduleId, $entityTypeId, '_on_add');
|
||||
}
|
||||
|
||||
public static function getScopeNameOnUpdate(string $moduleId, string $entityTypeId): string
|
||||
{
|
||||
return self::getScopeNameWithSuffix($moduleId, $entityTypeId, '_on_update');
|
||||
}
|
||||
|
||||
private static function getScopeNameWithSuffix(string $moduleId, string $entityTypeId, string $suffix): string
|
||||
{
|
||||
$scopeName = $entityTypeId . '_scope';
|
||||
|
||||
try
|
||||
{
|
||||
if (!ScopeAccess::getInstance($moduleId)->canUseOnAddOnUpdateSegregation())
|
||||
{
|
||||
return $scopeName;
|
||||
}
|
||||
}
|
||||
catch (ObjectNotFoundException $e)
|
||||
{
|
||||
return $scopeName;
|
||||
}
|
||||
|
||||
return $scopeName . $suffix;
|
||||
}
|
||||
|
||||
private function setScopeByAccessCodes(EntityEditorConfigDto $config, array $accessCodes): void
|
||||
{
|
||||
$userIdPattern = '/^U(\d+)$/';
|
||||
$departmentIdPattern = '/^DR(\d+)$/';
|
||||
$socialGroupIdPattern = '/^SG(\d+)$/';
|
||||
foreach ($accessCodes as $accessCode)
|
||||
{
|
||||
$matches = [];
|
||||
if (preg_match($userIdPattern, $accessCode, $matches))
|
||||
if (preg_match('/'. AccessCode::AC_USER . '/', $accessCode, $matches))
|
||||
{
|
||||
$this->setScopeToUser(
|
||||
$categoryName,
|
||||
$entityTypeId,
|
||||
$scope,
|
||||
$scopeId,
|
||||
$matches[1]
|
||||
);
|
||||
$config->setUserId($matches[2]);
|
||||
$this->setScopeToUser($config);
|
||||
}
|
||||
elseif (preg_match($departmentIdPattern, $accessCode, $matches))
|
||||
elseif (preg_match('/'. AccessCode::AC_ALL_DEPARTMENT . '/', $accessCode, $matches))
|
||||
{
|
||||
$this->setScopeToDepartment(
|
||||
$categoryName,
|
||||
$entityTypeId,
|
||||
$scope,
|
||||
$scopeId,
|
||||
$matches[1]
|
||||
);
|
||||
$this->setScopeToDepartment($config, $matches[2]);
|
||||
}
|
||||
elseif (preg_match($socialGroupIdPattern, $accessCode, $matches))
|
||||
elseif (preg_match('/'. AccessCode::AC_SOCNETGROUP . '/', $accessCode, $matches))
|
||||
{
|
||||
$this->setScopeToSocialGroup(
|
||||
$categoryName,
|
||||
$entityTypeId,
|
||||
$scope,
|
||||
$scopeId,
|
||||
$matches[1]
|
||||
);
|
||||
$this->setScopeToSocialGroup($config, $matches[2]);
|
||||
}
|
||||
elseif (preg_match('/'. AccessCode::AC_ALL_STRUCTURE_DEPARTMENT . '/', $accessCode, $matches))
|
||||
{
|
||||
$this->setScopeToStructureDepartment($config, $matches[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -753,7 +839,6 @@ class Scope
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
$userCollection = UserToGroupTable::query()
|
||||
->setSelect(['USER_ID'])
|
||||
->setFilter([
|
||||
@@ -762,9 +847,10 @@ class Scope
|
||||
UserToGroupTable::ROLE_MODERATOR,
|
||||
UserToGroupTable::ROLE_USER,
|
||||
UserToGroupTable::ROLE_OWNER,
|
||||
]
|
||||
],
|
||||
])
|
||||
->fetchCollection();
|
||||
->fetchCollection()
|
||||
;
|
||||
|
||||
$userIds = [];
|
||||
foreach ($userCollection as $user)
|
||||
@@ -776,15 +862,25 @@ class Scope
|
||||
}
|
||||
|
||||
private function getUserIdsByDepartment(int $departmentId): array
|
||||
{
|
||||
return $this->getUserIdsByAccessCode($departmentId, 'DR');
|
||||
}
|
||||
|
||||
private function getUserIdsByStructureDepartment(int $departmentId): array
|
||||
{
|
||||
return $this->getUserIdsByAccessCode($departmentId, 'SNDR');
|
||||
}
|
||||
|
||||
private function getUserIdsByAccessCode(int $departmentId, string $code): array
|
||||
{
|
||||
$userIds = [];
|
||||
if (!\Bitrix\Main\Loader::includeModule('humanresources'))
|
||||
if (!\Bitrix\Main\Loader::includeModule('humanresources') || !in_array($code, ['DR', 'SNDR'], true))
|
||||
{
|
||||
return $userIds;
|
||||
}
|
||||
|
||||
$hrServiceLocator = Container::instance();
|
||||
$accessCode = 'DR' . $departmentId;
|
||||
$accessCode = $code . $departmentId;
|
||||
$node = $hrServiceLocator::getNodeRepository()->getByAccessCode($accessCode);
|
||||
if (!$node)
|
||||
{
|
||||
@@ -804,4 +900,202 @@ class Scope
|
||||
{
|
||||
return CAccess::GetUserCodesArray($this->userId);
|
||||
}
|
||||
|
||||
private static function applyScopesToMember(array $scopes, string $scopeType, $memberId): void
|
||||
{
|
||||
$appliedEntities = [];
|
||||
/** @var EO_EntityFormConfig $scope */
|
||||
foreach ($scopes as $scope)
|
||||
{
|
||||
if (in_array($scope->getEntityTypeId(), $appliedEntities, true))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$appliedEntities[] = $scope->getEntityTypeId();
|
||||
self::getInstance()->setScopeToUser(
|
||||
new EntityEditorConfigDto(
|
||||
$scope->getOptionCategory(),
|
||||
$scope->getEntityTypeId(),
|
||||
$scopeType,
|
||||
$scope->getId(),
|
||||
$memberId,
|
||||
$scope->getOnAdd(),
|
||||
$scope->getOnUpdate(),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function getScopeName(EntityEditorConfigDto $config): string
|
||||
{
|
||||
$scopeName = "{$config->getEntityTypeId()}_scope";
|
||||
|
||||
if ($config->hasOnAdd() && !$config->hasOnUpdate())
|
||||
{
|
||||
return self::getScopeNameOnAdd($config->getModuleIdFromCategory(), $config->getEntityTypeId());
|
||||
}
|
||||
|
||||
if (!$config->hasOnAdd() && $config->hasOnUpdate())
|
||||
{
|
||||
return self::getScopeNameOnUpdate($config->getModuleIdFromCategory(), $config->getEntityTypeId());
|
||||
}
|
||||
|
||||
if (!$config->hasOnAdd() && !$config->hasOnUpdate())
|
||||
{
|
||||
return "{$scopeName}_disabled";
|
||||
}
|
||||
|
||||
return $scopeName;
|
||||
}
|
||||
|
||||
private function removeUsersScopeOptions(int $configId, string $optionCategory, string $scopeName): void
|
||||
{
|
||||
$accessCodes = $this->getScopeAccessCodesByScopeId($configId);
|
||||
|
||||
$userIds = [];
|
||||
foreach ($accessCodes as $accessCode)
|
||||
{
|
||||
$matches = [];
|
||||
if (preg_match(AccessCode::AC_USER, $accessCode, $matches))
|
||||
{
|
||||
$userIds = [$matches[1]];
|
||||
}
|
||||
elseif (preg_match(AccessCode::AC_ALL_DEPARTMENT, $accessCode, $matches))
|
||||
{
|
||||
$userIds = $this->getUserIdsByDepartment($matches[1]);
|
||||
}
|
||||
elseif (preg_match(AccessCode::AC_SOCNETGROUP, $accessCode, $matches))
|
||||
{
|
||||
$userIds = $this->getUserIdsBySocialGroup($matches[1]);
|
||||
}
|
||||
elseif (preg_match(AccessCode::AC_ALL_STRUCTURE_DEPARTMENT, $accessCode, $matches))
|
||||
{
|
||||
$userIds = $this->getUserIdsByStructureDepartment($matches[1]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($userIds as $userId)
|
||||
{
|
||||
CUserOptions::DeleteOption($optionCategory, $scopeName, false, $userId);
|
||||
}
|
||||
}
|
||||
|
||||
public function copyScope(int $scopeId, string $entityTypeId): null|int|array
|
||||
{
|
||||
$scope = $this->getById($scopeId);
|
||||
if (!$scope)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
$name = Loc::getMessage('UI_ENTITY_FORM_SCOPE_COPY', ['#NAME#' => $scope['NAME']]);
|
||||
|
||||
$params = [
|
||||
'common' => $scope['COMMON'],
|
||||
'forceSetToUsers' => $scope['AUTO_APPLY_SCOPE'],
|
||||
'categoryName' => $scope['OPTION_CATEGORY'],
|
||||
'availableOnAdd' => $scope['ON_ADD'],
|
||||
'availableOnUpdate' => $scope['ON_UPDATE'],
|
||||
];
|
||||
|
||||
$accessCodes = $this->getScopeAccessCodesByScopeId($scopeId);
|
||||
|
||||
$newAccessCodes = [];
|
||||
foreach ($accessCodes as $code)
|
||||
{
|
||||
$newAccessCodes[] = $this->unpackAccessCode($code);
|
||||
}
|
||||
|
||||
return $this->setScopeConfig(
|
||||
$scope['CATEGORY'],
|
||||
$entityTypeId,
|
||||
$name,
|
||||
$newAccessCodes,
|
||||
$scope['CONFIG'],
|
||||
$params,
|
||||
);
|
||||
}
|
||||
|
||||
private function unpackAccessCode(string $accessCode): ?array
|
||||
{
|
||||
if (str_starts_with($accessCode, self::CODE_USER))
|
||||
{
|
||||
return [
|
||||
'entityId' => self::TYPE_USER,
|
||||
'id' => str_replace(self::CODE_USER, '', $accessCode),
|
||||
];
|
||||
}
|
||||
if (str_starts_with($accessCode, self::CODE_PROJECT))
|
||||
{
|
||||
return [
|
||||
'entityId' => self::TYPE_PROJECT,
|
||||
'id' => str_replace(self::CODE_PROJECT, '', $accessCode),
|
||||
];
|
||||
}
|
||||
if (str_starts_with($accessCode, self::CODE_DEPARTMENT))
|
||||
{
|
||||
return [
|
||||
'entityId' => self::TYPE_DEPARTMENT,
|
||||
'id' => str_replace(self::CODE_DEPARTMENT, '', $accessCode),
|
||||
];
|
||||
}
|
||||
if (str_starts_with($accessCode, self::CODE_STRUCTURE_DEPARTMENT))
|
||||
{
|
||||
return [
|
||||
'entityId' => self::TYPE_STRUCTURE_NODE,
|
||||
'id' => str_replace(self::CODE_STRUCTURE_DEPARTMENT, '', $accessCode),
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getUserScopesEntityEditor(string $entityTypeId, ?string $moduleId): array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
$isAdminForEntity = $this->isAdminForEntity($entityTypeId, $moduleId);
|
||||
|
||||
$filter = ScopeListFilter::getInstance($moduleId)->prepareEntityEditorFilter($entityTypeId, $isAdminForEntity, $this);
|
||||
|
||||
if (!$isAdminForEntity && empty($filter['@ID']))
|
||||
{
|
||||
return $result;
|
||||
}
|
||||
|
||||
$scopes = EntityFormConfigTable::getList([
|
||||
'select' => [
|
||||
'ID',
|
||||
'ENTITY_TYPE_ID',
|
||||
'NAME',
|
||||
'ACCESS_CODE' => '\Bitrix\Ui\EntityForm\EntityFormConfigAcTable:CONFIG.ACCESS_CODE',
|
||||
'ON_ADD',
|
||||
'ON_UPDATE',
|
||||
],
|
||||
'filter' => $filter,
|
||||
]);
|
||||
|
||||
foreach ($scopes as $scope)
|
||||
{
|
||||
$result[$scope['ID']] = [
|
||||
'NAME' => HtmlFilter::encode($scope['NAME']),
|
||||
'AUTO_APPLY_SCOPE' => $scope['AUTO_APPLY_SCOPE'] ?? null,
|
||||
'ON_ADD' => $scope['ON_ADD'],
|
||||
'ON_UPDATE' => $scope['ON_UPDATE'],
|
||||
'ENTITY_TYPE_ID' => $scope['ENTITY_TYPE_ID'],
|
||||
];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function isAdminForEntity(string $entityTypeId, ?string $moduleId = null): bool
|
||||
{
|
||||
return $moduleId
|
||||
&& (
|
||||
($scopeAccess = ScopeAccess::getInstance($moduleId, $this->userId))
|
||||
&& $scopeAccess->isAdminForEntityTypeId($entityTypeId)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,4 +91,9 @@ class ScopeAccess
|
||||
{
|
||||
return $this->canAdd();
|
||||
}
|
||||
|
||||
public function canUseOnAddOnUpdateSegregation(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
65
core/bitrix/modules/ui/lib/entityform/scopelistfilter.php
Normal file
65
core/bitrix/modules/ui/lib/entityform/scopelistfilter.php
Normal file
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\Ui\EntityForm;
|
||||
|
||||
use Bitrix\Main\Config\Configuration;
|
||||
use Bitrix\Main\Loader;
|
||||
|
||||
class ScopeListFilter
|
||||
{
|
||||
private const SETTINGS_ENTITY_FORM_SCOPE_KEY = 'entityFormScope';
|
||||
private const SETTINGS_SCOPE_LIST_FILTER_CLASS_KEY = 'scopeListFilter';
|
||||
|
||||
public function __construct(
|
||||
) {
|
||||
}
|
||||
|
||||
public static function getInstance($moduleId): static
|
||||
{
|
||||
$configuration = Configuration::getInstance($moduleId);
|
||||
|
||||
$value = $configuration->get(static::SETTINGS_ENTITY_FORM_SCOPE_KEY);
|
||||
if (
|
||||
is_array($value)
|
||||
&& isset($value[static::SETTINGS_SCOPE_LIST_FILTER_CLASS_KEY])
|
||||
&& Loader::includeModule($moduleId)
|
||||
&& is_a($value[static::SETTINGS_SCOPE_LIST_FILTER_CLASS_KEY], self::class, true)
|
||||
) {
|
||||
return new $value[static::SETTINGS_SCOPE_LIST_FILTER_CLASS_KEY]();
|
||||
}
|
||||
|
||||
return new self();
|
||||
}
|
||||
|
||||
public function prepareFilter(string $entityTypeId, bool $isAdminForEntity, bool $excludeEmptyAccessCode, Scope $scope): array
|
||||
{
|
||||
$filter = [];
|
||||
if (!$isAdminForEntity)
|
||||
{
|
||||
$filter['@ID'] = $scope->getScopesIdByUser();
|
||||
}
|
||||
|
||||
$filter['@ENTITY_TYPE_ID'] = ($scope->getEntityTypeIdMap()[$entityTypeId] ?? [$entityTypeId]);
|
||||
|
||||
if ($excludeEmptyAccessCode)
|
||||
{
|
||||
$filter['!=ACCESS_CODE'] = '';
|
||||
}
|
||||
|
||||
return $filter;
|
||||
}
|
||||
|
||||
public function prepareEntityEditorFilter(string $entityTypeId, bool $isAdminForEntity, Scope $scope): array
|
||||
{
|
||||
$filter['!=ACCESS_CODE'] = '';
|
||||
|
||||
if (!$isAdminForEntity)
|
||||
{
|
||||
$filter['@ID'] = $scope->getScopesIdByUser();
|
||||
}
|
||||
|
||||
$filter['@ENTITY_TYPE_ID'] = ($scope->getEntityTypeIdMap()[$entityTypeId] ?? [$entityTypeId]);
|
||||
|
||||
return $filter;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Bitrix\UI\EntitySelector;
|
||||
|
||||
use Bitrix\Main\HttpApplication;
|
||||
use Bitrix\Main\Loader;
|
||||
use Bitrix\Main\ModuleManager;
|
||||
|
||||
@@ -197,7 +198,9 @@ final class Configuration
|
||||
}
|
||||
catch (\ReflectionException $exception)
|
||||
{
|
||||
|
||||
$application = HttpApplication::getInstance();
|
||||
$exceptionHandler = $application->getExceptionHandler();
|
||||
$exceptionHandler->writeToLog($exception);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -9,6 +9,11 @@ class EntityEditorConfiguration
|
||||
protected $categoryName;
|
||||
protected int $userId;
|
||||
|
||||
private const AVAILABLE_SCOPE_TYPES = [
|
||||
'on_add',
|
||||
'on_update',
|
||||
];
|
||||
|
||||
public static function canEditOtherSettings(): bool
|
||||
{
|
||||
return Main\Engine\CurrentUser::get()->canDoOperation('edit_other_settings');
|
||||
@@ -59,18 +64,24 @@ class EntityEditorConfiguration
|
||||
return "{$configID}_opts";
|
||||
}
|
||||
|
||||
public function getScope($configID)
|
||||
public function getScope($configID, bool $scopeNamePrepared = false)
|
||||
{
|
||||
if (!$this->userId)
|
||||
{
|
||||
return EntityEditorConfigScope::UNDEFINED;
|
||||
}
|
||||
|
||||
$scopeName = $configID;
|
||||
if (!$scopeNamePrepared)
|
||||
{
|
||||
$scopeName = $this->prepareScopeName($configID);
|
||||
}
|
||||
|
||||
return \CUserOptions::GetOption(
|
||||
$this->getCategoryName(),
|
||||
$this->prepareScopeName($configID),
|
||||
$scopeName,
|
||||
EntityEditorConfigScope::UNDEFINED,
|
||||
$this->userId
|
||||
$this->userId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -176,11 +187,12 @@ class EntityEditorConfiguration
|
||||
//todo check what to do with options for custom scopes
|
||||
}
|
||||
}
|
||||
public function reset($configID, array $params)
|
||||
|
||||
public function reset($configID, array $params): void
|
||||
{
|
||||
$categoryName = $this->getCategoryName();
|
||||
|
||||
$scope = isset($params['scope'])? mb_strtoupper($params['scope']) : EntityEditorConfigScope::UNDEFINED;
|
||||
$scope = isset($params['scope']) ? mb_strtoupper($params['scope']) : EntityEditorConfigScope::UNDEFINED;
|
||||
if(!EntityEditorConfigScope::isDefined($scope))
|
||||
{
|
||||
$scope = EntityEditorConfigScope::PERSONAL;
|
||||
@@ -196,22 +208,28 @@ class EntityEditorConfiguration
|
||||
$categoryName,
|
||||
$this->prepareName($configID, $scope),
|
||||
true,
|
||||
0
|
||||
0,
|
||||
);
|
||||
\CUserOptions::DeleteOption(
|
||||
$categoryName,
|
||||
static::prepareOptionsName($configID, $scope),
|
||||
true,
|
||||
0
|
||||
0,
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
$scopeName = $this->prepareScopeName($configID);
|
||||
if (isset($params['type']) && $this->isAvailableScopeType((string)$params['type']))
|
||||
{
|
||||
$scopeName .= '_' . $params['type'];
|
||||
}
|
||||
|
||||
if($forAllUsers)
|
||||
{
|
||||
\CUserOptions::DeleteOptionsByName($categoryName, $this->prepareName($configID, $scope));
|
||||
\CUserOptions::DeleteOptionsByName($categoryName, static::prepareOptionsName($configID, $scope));
|
||||
\CUserOptions::DeleteOptionsByName($categoryName, $this->prepareScopeName($configID));
|
||||
\CUserOptions::DeleteOptionsByName($categoryName, $scopeName);
|
||||
}
|
||||
elseif ($this->userId)
|
||||
{
|
||||
@@ -220,15 +238,16 @@ class EntityEditorConfiguration
|
||||
|
||||
\CUserOptions::SetOption(
|
||||
$categoryName,
|
||||
$this->prepareScopeName($configID),
|
||||
$scopeName,
|
||||
EntityEditorConfigScope::PERSONAL,
|
||||
false,
|
||||
$this->userId
|
||||
$this->userId,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function setScope($configID, $scope)
|
||||
{
|
||||
if(!EntityEditorConfigScope::isDefined($scope))
|
||||
@@ -241,19 +260,38 @@ class EntityEditorConfiguration
|
||||
\CUserOptions::SetOption($this->getCategoryName(), $this->prepareScopeName($configID), $scope, false, $this->userId);
|
||||
}
|
||||
}
|
||||
public function forceCommonScopeForAll($configID)
|
||||
|
||||
public function forceCommonScopeForAll(string $configID, string $moduleId, ?string $type = null): void
|
||||
{
|
||||
if(!self::canEditOtherSettings())
|
||||
$scopeNames = [
|
||||
$this->prepareScopeName($configID),
|
||||
];
|
||||
|
||||
if ($type === 'on_add')
|
||||
{
|
||||
return;
|
||||
$scopeNames[] = Scope::getScopeNameOnAdd($moduleId, $configID);
|
||||
}
|
||||
|
||||
if ($type === 'on_update')
|
||||
{
|
||||
$scopeNames[] = Scope::getScopeNameOnUpdate($moduleId, $configID);
|
||||
}
|
||||
$scopeNames = array_unique($scopeNames);
|
||||
|
||||
$categoryName = $this->getCategoryName();
|
||||
|
||||
\CUserOptions::DeleteOptionsByName(
|
||||
$categoryName,
|
||||
$this->prepareName($configID, EntityEditorConfigScope::PERSONAL)
|
||||
$this->prepareName($configID, EntityEditorConfigScope::PERSONAL),
|
||||
);
|
||||
\CUserOptions::DeleteOptionsByName($categoryName, $this->prepareScopeName($configID));
|
||||
foreach ($scopeNames as $scopeName)
|
||||
{
|
||||
\CUserOptions::DeleteOptionsByName($categoryName, $scopeName);
|
||||
}
|
||||
}
|
||||
|
||||
private function isAvailableScopeType(string $type): bool
|
||||
{
|
||||
return in_array($type, self::AVAILABLE_SCOPE_TYPES, true);
|
||||
}
|
||||
}
|
||||
@@ -156,7 +156,7 @@ class FeedbackForm
|
||||
*/
|
||||
private function findFormByZone(array $forms): array
|
||||
{
|
||||
$zone = $this->getZone();
|
||||
$zone = $this->getZone() ?? $this->getDefaultZone();
|
||||
$found = array_filter($forms, static function ($form) use ($zone)
|
||||
{
|
||||
return in_array($zone, $form->zones, true);
|
||||
@@ -219,9 +219,9 @@ class FeedbackForm
|
||||
$this->currentForm = $form;
|
||||
}
|
||||
|
||||
protected function getZone(): string
|
||||
protected function getZone(): ?string
|
||||
{
|
||||
return Application::getInstance()->getLicense()->getRegion() ?? $this->getDefaultZone();
|
||||
return Application::getInstance()->getLicense()->getRegion();
|
||||
}
|
||||
|
||||
private function getDefaultZone(): string
|
||||
@@ -241,9 +241,9 @@ class FeedbackForm
|
||||
|
||||
private function isCis(): bool
|
||||
{
|
||||
$region = Application::getInstance()->getLicense()->getRegion();
|
||||
$zone = $this->getZone() ?? '';
|
||||
|
||||
return in_array($region, ['ru', 'by', 'kz', 'uz']);
|
||||
return in_array($zone, ['ru', 'by', 'kz', 'uz']);
|
||||
}
|
||||
|
||||
public static function getCisZones(): array
|
||||
|
||||
56
core/bitrix/modules/ui/lib/form/formprovider.php
Normal file
56
core/bitrix/modules/ui/lib/form/formprovider.php
Normal file
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Bitrix\UI\Form;
|
||||
|
||||
/**
|
||||
* The FormProvider class provides a list of partner feedback forms with region zones, form IDs, languages, and security keys.
|
||||
*
|
||||
* For displaying partner feedback forms on the client side, use the PartnerForm class (see ui/partnerform/src/PartnerForm.js).
|
||||
*
|
||||
* Each form is associated with one or more zones (regions), a language code, and a unique security key.
|
||||
* The list is intended for localized feedback widgets or CRM forms.
|
||||
*
|
||||
* @package Bitrix\UI\Form
|
||||
*/
|
||||
class FormProvider
|
||||
{
|
||||
/**
|
||||
* Returns a list of feedback forms with their respective region zones, form IDs, languages, and security keys.
|
||||
*
|
||||
* Each form is associated with one or more zones (regions), a language code, and a unique security key.
|
||||
* These forms are typically used to display localized feedback widgets or CRM forms.
|
||||
* @return array[]
|
||||
*/
|
||||
public function getPartnerFormList(): array
|
||||
{
|
||||
$westZones = \Bitrix\UI\Form\FeedbackForm::getWestZones();
|
||||
|
||||
return [
|
||||
['zones' => $westZones, 'id' => 34, 'lang' => 'en', 'sec' => '940xiq'],
|
||||
['zones' => $westZones, 'id' => 58, 'lang' => 'br', 'sec' => 'db0u10'],
|
||||
['zones' => $westZones, 'id' => 82, 'lang' => 'la', 'sec' => 'f5cg69'],
|
||||
['zones' => $westZones, 'id' => 84, 'lang' => 'pl', 'sec' => 'xaq93h'],
|
||||
['zones' => $westZones, 'id' => 86, 'lang' => 'tr', 'sec' => '6xbruy'],
|
||||
['zones' => $westZones, 'id' => 88, 'lang' => 'vn', 'sec' => '8g591b'],
|
||||
['zones' => $westZones, 'id' => 90, 'lang' => 'it', 'sec' => 'mc95rg'],
|
||||
['zones' => $westZones, 'id' => 92, 'lang' => 'de', 'sec' => 'uokzr7'],
|
||||
['zones' => $westZones, 'id' => 94, 'lang' => 'fr', 'sec' => 'gyzkzb'],
|
||||
['zones' => $westZones, 'id' => 96, 'lang' => 'ms', 'sec' => 'zaetk0'],
|
||||
['zones' => $westZones, 'id' => 108, 'lang' => 'id', 'sec' => '3gs5vj'],
|
||||
['zones' => $westZones, 'id' => 98, 'lang' => 'sc', 'sec' => '532jfn'],
|
||||
['zones' => $westZones, 'id' => 100, 'lang' => 'th', 'sec' => '1q4cis'],
|
||||
['zones' => $westZones, 'id' => 102, 'lang' => 'ja', 'sec' => 'c84t56'],
|
||||
['zones' => $westZones, 'id' => 104, 'lang' => 'tc', 'sec' => '6s7a1m'],
|
||||
['zones' => $westZones, 'id' => 110, 'lang' => 'ar', 'sec' => 'zfkgno'],
|
||||
['zones' => $westZones, 'id' => 106, 'lang' => 'ru', 'sec' => 'j1h7w4'],
|
||||
['zones' => $westZones, 'id' => 34, 'lang' => 'ua', 'sec' => '940xiq'],
|
||||
['zones' => $westZones, 'id' => 34, 'lang' => 'kz', 'sec' => '940xiq'],
|
||||
['zones' => ['ru'], 'id' => 3282, 'lang' => 'ru', 'sec' => '8x81lp'],
|
||||
['zones' => ['by'], 'id' => 3, 'lang' => 'ru', 'sec' => 'kde6g5'],
|
||||
['zones' => ['kz'], 'id' => 4, 'lang' => 'kz', 'sec' => 'id3qfm'],
|
||||
['zones' => ['kz'], 'id' => 2, 'lang' => 'ru', 'sec' => 'po3skw'],
|
||||
['zones' => ['kz'], 'id' => 6, 'lang' => 'en', 'sec' => 'gozt5o'],
|
||||
['zones' => ['uz'], 'id' => 7, 'lang' => 'ru', 'sec' => 'xjkuqu'],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -2,44 +2,12 @@
|
||||
|
||||
namespace Bitrix\UI\Form;
|
||||
|
||||
/* @deprecated use Bitrix\UI\Form\FormProvider instead */
|
||||
class FormsProvider
|
||||
{
|
||||
/* @deprecated use (new Bitrix\UI\Form\FormProvider)->getPartnerFormList() instead */
|
||||
public static function getForms(): array
|
||||
{
|
||||
$westZones = \Bitrix\UI\Form\FeedbackForm::getWestZones();
|
||||
|
||||
return [
|
||||
['zones' => $westZones, 'id' => 34, 'lang' => 'en', 'sec' => '940xiq'],
|
||||
['zones' => $westZones, 'id' => 58, 'lang' => 'pt', 'sec' => 'db0u10'],
|
||||
['zones' => $westZones, 'id' => 82, 'lang' => 'es', 'sec' => 'f5cg69'],
|
||||
['zones' => $westZones, 'id' => 84, 'lang' => 'pl', 'sec' => 'xaq93h'],
|
||||
['zones' => $westZones, 'id' => 86, 'lang' => 'tr', 'sec' => '6xbruy'],
|
||||
['zones' => $westZones, 'id' => 88, 'lang' => 'vn', 'sec' => '8g591b'],
|
||||
['zones' => $westZones, 'id' => 90, 'lang' => 'it', 'sec' => 'mc95rg'],
|
||||
['zones' => $westZones, 'id' => 92, 'lang' => 'de', 'sec' => 'uokzr7'],
|
||||
['zones' => $westZones, 'id' => 94, 'lang' => 'fr', 'sec' => 'gyzkzb'],
|
||||
['zones' => $westZones, 'id' => 96, 'lang' => 'ms', 'sec' => 'zaetk0'],
|
||||
['zones' => $westZones, 'id' => 108, 'lang' => 'id', 'sec' => '3gs5vj'],
|
||||
['zones' => $westZones, 'id' => 98, 'lang' => 'sc', 'sec' => '532jfn'],
|
||||
['zones' => $westZones, 'id' => 100, 'lang' => 'th', 'sec' => '1q4cis'],
|
||||
['zones' => $westZones, 'id' => 102, 'lang' => 'jp', 'sec' => 'c84t56'],
|
||||
['zones' => $westZones, 'id' => 104, 'lang' => 'tc', 'sec' => '6s7a1m'],
|
||||
['zones' => $westZones, 'id' => 110, 'lang' => 'ar', 'sec' => 'zfkgno'],
|
||||
['zones' => $westZones, 'id' => 106, 'lang' => 'ru', 'sec' => 'j1h7w4'],
|
||||
['zones' => $westZones, 'id' => 34, 'lang' => 'ua', 'sec' => '940xiq'],
|
||||
['zones' => $westZones, 'id' => 34, 'lang' => 'kz', 'sec' => '940xiq'],
|
||||
['zones' => ['ru'], 'id' => 3282, 'sec' => '8x81lp'],
|
||||
['zones' => ['by'], 'id' => 3, 'sec' => 'kde6g5'],
|
||||
['zones' => ['kz'], 'id' => 4, 'lang' => 'kz', 'sec' => 'id3qfm'],
|
||||
['zones' => ['kz'], 'id' => 2, 'lang' => 'ru', 'sec' => 'po3skw'],
|
||||
['zones' => ['kz'], 'id' => 6, 'lang' => 'en', 'sec' => 'gozt5o'],
|
||||
['zones' => ['uz'], 'id' => 7, 'sec' => 'xjkuqu'],
|
||||
];
|
||||
return (new FormProvider())->getPartnerFormList();
|
||||
}
|
||||
|
||||
public static function getFormsForJS() : string
|
||||
{
|
||||
// Convert the array to JSON and replace the quotes around keys for UI.Feedback.Form compatibility
|
||||
return preg_replace('/"([a-zA-Z0-9_]+)":/', '$1:',\Bitrix\Main\Web\Json::encode(self::getForms()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,6 +207,7 @@ class Comment
|
||||
'FROM_USER_ID' => $fromUserId,
|
||||
'NOTIFY_TYPE' => IM_NOTIFY_FROM,
|
||||
'NOTIFY_MODULE' => Driver::MODULE_ID,
|
||||
'NOTIFY_EVENT' => 'mention',
|
||||
'NOTIFY_TAG' => 'RPA|MESSAGE_TIMELINE_MENTION|' . $id,
|
||||
'NOTIFY_MESSAGE' => $message,
|
||||
]);
|
||||
|
||||
Reference in New Issue
Block a user