Есть справочник, унаследованный от базового справочника, со стандартными полями Id, Name, Description.

Изображение удалено.

Есть раздел, в котором есть поле, принимающее значения из этого справочника (UsrYesNo), а также ряд других полей, содержащих значения INTEGER (UsrIntValue), TEXT (UsrTextValue) и т.п.



Есть необходимость извлечь значение соответствующего поля в коде клиентской части. Примерно так:

 

// Возвращает целочиcленное значение, работает корректно
var a = this.get("UsrIntValue");
// Возвращает строковое значение, работает тоже корректно
var b = this.get("UsrTextValue");
// По идее, должно возвращать значение из справочника, выбранное для записи раздела.
// Но по факту выдает undefined.
var c = this.get("UsrYesNo.Name");

Что я делаю не так?

Нравится

4 комментария
Лучший ответ

Генин Юрий пишет:

var c = this.get("UsrYesNo").Name;

Да, верно. Мы берём поле и читаем его атрибуты. 

Указать эту колонку в attributes

attributes: {
     "UsrYesNo": {
          "dataValueType": Terrasoft.DataValueType.LOOKUP,
          "lookupListConfig": {
               "columns": ["Name"]
            }
      }
 }

Или в данном случае достаточно взять this.get("UsrYesNo").displayValue

Владимир Соколов,

Вариант с this.get("UsrYesNo").displayValue сработал, спасибо. Но добавление атрибута (в схему страницы редактирования) ничего не поменяло:  this.get("UsrYesNo.Name") все равно возвращает undefined. 

Владимир Соколов,

А вот так, кстати, сработало:

attributes: {
     "UsrYesNo": {          
          lookupListConfig: {
               columns: ["Name"]
            }
      }
 }

и

var c = this.get("UsrYesNo").Name;

Интересно, почему...

Генин Юрий пишет:

var c = this.get("UsrYesNo").Name;

Да, верно. Мы берём поле и читаем его атрибуты. 

Показать все комментарии

На странице просмотра наряда есть справочное поле Ответственный

Изображение удалено.

 

Если по нему кликнуть, откроется страница редактирования:

Изображение удалено.

Проблема, в том, что техники в спешке вместо установки ответственного в странице редактирования начинают менять ответственного через эту страницу.

В результате вместо смены ответственного меняют данные контакта и портят базу.



На странице редактирования наряда это-же поле выглядит уже по другому:

Изображение удалено.

 

И при клике разворачивается в список выбора (через кастомное правило фильтрации):

Изображение удалено.

 

 

Идеальным решением для нас был-бы показ из страницы просмотра списка выбора ответственного (как на странице редактирования), но как это сделать мне не понятно.



Как вариант не показывать окно редактирования контакта вообще (в принципе техники друг-друга знают и эти данные им особо не нужны).

Но блокировать это окно у меня не получилось... в лучшем случае показывается пустая страница да еще и с возможностью сохранения пустых данных.



Еще вариант страницу показывать, но делать все поля рид-онли....



Как-то я в растерянности. Какие есть варианты решения такой задачи?

Нравится

2 комментария

А запретите им менять записи с ответственными правами доступа

Решили дописыванием в манифест для Contact:

PreviewPage = ""



Черт его знает как это работает, но вместо страницы контакта теперь показывает группу ответственных за наряд - что нам и требовалось

Показать все комментарии

Добрый день. Прошу помощи - третий день мучаюсь с этой задачкой. Есть страница редактирования. В ней есть деталь, отображающая (только чтение) записи из того же реестра. Отбор записей в деталь должен проводиться по ряду условий, связанных с полями основной записи на странице редактирования. Мысль в том, чтобы по этим условиям отобрать через EntitySchemaQuery несколько Id и назначить их в фильтр детали через createColumnInFilterWithParameters.



Проблема в том, что результаты EntitySchemaQuery.getEntityCollection отрабатываются в callback-функции, и происходит это в большинстве случаев позже, чем завершается работа функции filterMethod детали, в которой делается вызов getEntityCollection. Фильтр получается пустым.



Ниже проблемный код:

// функция назначена как "filterMethod" детали
applyFilter: function() {
    //
    var vFGroup = Terrasoft.createFilterGroup();
    vFGroup.logicalOperation = Terrasoft.LogicalOperatorType.AND;
 
    //
 
    var esq = Ext.create("Terrasoft.EntitySchemaQuery", {
        rootSchemaName: "Tenants"
    });
 
    esq.addColumn("Id");
    esq.addColumn("ReportMonth");
    esq.addColumn("Area");
 
    var vArea = this.get("Area");
 
    // фильтры запроса - должна совпадать дата, и площадь быть в +-20%                    
    esq.filters.add("ReportMonthFilter", 
        esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, 
            "ReportMonth", this.get("ReportMonth")));
    esq.filters.add("AreaFilter", 
        esq.createColumnBetweenFilterWithParameters("Area", 
            vArea * 0.8, vArea * 1.2));
 
    // до этого места все работает корректно 
    // теперь запускаем запрос и получаем данные
     // насколько я понимаю, архитектурно система распараллеливает задачи,
    // т.е. function(result) и следующая инструкция после getEntityCollection()
    // начинают отрабатываться одновременно
    esq.getEntityCollection(function (result) {
        if (result.success) {
 
            // добавляем фильтр как UID по списку
            // здесь так можно, больших выборок не предполагается
            var vSelected = [];                        
            result.collection.each(function (item) {
                vSelected.push(item.get("Id"));
            });
 
            var vIdF = Terrasoft.createColumnInFilterWithParameters("Id", vSelected);
 
            // нужно как-то гарантировать, чтобы эта операция всегда выполнялась раньше, чем 
            // return vFGroup; в конце функции. Иначе в фильтры попадает пустой список, и фильтр
            // не работает. 
            vFGroup.add("vIdF", vIdF);
        }
    }, this);
 
    // Интересно, что при первом открытии детали после обновления 
    // страницы операция return vFGroup; 
    // выполняется корректно, т.е. после vFGroup.add("vIdF", vIdF);. 
    //Если дальше закрыть страницу и через реестр
    // открыть другую запись - уже не работает.
 
    // Также интересно, что если вбить вот сюда:
    // window.alert("!");
    // то пауза будет достаточна для формирования vFGroup 
    // независимо от того, в первый раз я открываю
    // запись или нет
 
    return vFGroup;
},

 

Нравится

4 комментария
Лучший ответ

Согласен с Александр Зверев

Недавно сам мучался с подобным, гораздо приятнее когда вся логика связок таблиц завернута во фьюху.

Главное не забыть что во фьюхе должны быть также служебные поля:



DROP VIEW IF EXISTS dbo.VwCaseGroup

GO

CREATE VIEW dbo.VwCaseGroup

AS SELECT

  SAU.ContactId AS Id,

  SUR.SysRoleId,

  SUR.CreatedById,---------<

  SUR.ModifiedById,---------<

  SUR.CreatedOn,---------<

  SUR.ModifiedOn,---------<

  SUR.ProcessListeners---------<

FROM dbo.SysAdminUnit SAU

JOIN dbo.SysUserInRole SUR ON SAU.Id = SUR.SysUserId

GO

Сорри, уже сам разобрался. Надо было всего-то создать property для списка UID и перенести его подгрузку в onEntityInitialized, оставив в applyFilter только сортировку и создание итогового фильтра для детали. 

В ней есть деталь, отображающая (только чтение) записи из того же реестра. Отбор записей в деталь должен проводиться по ряду условий, связанных с полями основной записи на странице редактирования.

Юрий, вообще, такая постановка намекает, что можно в БД сделать view с нужными данными: каждому Id записи в основном разделе будет соответствовать несколько строк для отображения на детали по нужному условию.

 

Создать объект с такими же колонками, привязать к этой view и далее в разделе настроить деталь стандартными средствами без всякого кода.

Согласен с Александр Зверев

Недавно сам мучался с подобным, гораздо приятнее когда вся логика связок таблиц завернута во фьюху.

Главное не забыть что во фьюхе должны быть также служебные поля:



DROP VIEW IF EXISTS dbo.VwCaseGroup

GO

CREATE VIEW dbo.VwCaseGroup

AS SELECT

  SAU.ContactId AS Id,

  SUR.SysRoleId,

  SUR.CreatedById,---------<

  SUR.ModifiedById,---------<

  SUR.CreatedOn,---------<

  SUR.ModifiedOn,---------<

  SUR.ProcessListeners---------<

FROM dbo.SysAdminUnit SAU

JOIN dbo.SysUserInRole SUR ON SAU.Id = SUR.SysUserId

GO

Генин Юрий,

На всякий случай, для будущих читателей этого треда: вариант с EntitySchemaQuery плох тем, что при больших выборках не успевает отработать до открытия пользователем вкладки с деталью, что приводит к визуальному отсутствию фильтрации. Схема с VIEW этого недочета лишена.

 

 

 

 

 

Показать все комментарии

Коллеги, привет!

 

Подскажите, пожалуйста, возможно ли создать кнопку для пользователей с ролью Администратор, которая бы позволяла логиниться в учетную запись без ввода логина и пароля. То бишь просто нажимаем один раз, например, в разделе Пользователи (в Дизайнере, на самой карточке) и мы залогинились под ним. Речь исключительно о веб-версии.

 

Может быть кто-то реализовал уже?

Спасибо!

 

Нравится

1 комментарий

Пароль хранится в зашифрованном виде, нельзя так просто взять его из базы.

 

Стандартно существует механизм безопасного доступа в систему для поддержки, в версии 7.16.4 появляется бета-версия входа в систему извне под OAuth 2.0 с client_id и client_secret без необходимости ввода пароля. Возможно, нужно смотреть в сторону этих механизмов. Логика безопасного доступа реализована в схемах в пакете ExternalAccess.

Показать все комментарии

Добрый вечер, Коллеги.

У кого-нибудь возникала на странице еще "одна страница с полями" (см. скрин внизу)

В мастере разделов нижней страницы нет.

Изображение удалено.

Нравится

2 комментария
Лучший ответ

На странице описано поле(в diff),  у которого неправильно указан родительский контейнер

Похоже на деталь "Связи". Вы делали новую страницу на основе Активности?

На странице описано поле(в diff),  у которого неправильно указан родительский контейнер

Показать все комментарии

Добрый день.

Поставлена задача - регулярно пополнять раздел Продукты из прайслистов + в каждый продукт добавлять фото.

Фото хранятся 

1. в отдельных файлах (в структурированных папках) 

2. в файлах excel

3. в 1С

 

Коллеги, у кого есть опыт массовой загрузки файлов в карточки продуктов?

Спасибо.

 

Видела подобную тему двухгодичной давности ИМПОРТ ФОТО ИЗ EXCEL

Есть ли подвижки?

 

Нравится

1 комментарий

Марина, стандартного решения, скорее всего, нет.

Тем более, Вы хотите загружать из трёх разнотипных мест: ФС, Excel и 1С. Для каждого нужно искать или разрабатывать свои инструменты.

 

Для файлов, проверьте возможности дополнения «File manager», там упоминается работа с галереями фото продуктов.

 

По Excel — сомневаюсь, что такое стандартно будет, нужно смотреть либо в строну встроенных скриптов на Бейсике, либо разбирать формат файла или использовать библиотеки для работы с ним. Кстати, xlsx  — это просто zip-архив, если файл переименовать и распаковать в папку, все картинки там будут.

 

С системой 1С тоже есть несколько интеграций, нужно смотреть их возможности.

 

Показать все комментарии

Задача: округлять дробную часть десятичного числа вверх.

Нашёл статью с методом на Microsoft https://docs.microsoft.com/en-us/dotnet/api/system.midpointrounding?vie…;

 

В БП пробую применять формулу Decimal.Round(([#Исходное дробное число#]), 1, MidpointRounding.AwayFromZero) - ругается, что "Допущена ошибка в формуле: Параметр "MidpointRounding" не найден.]."



При этом, если не использовать MidpointRounding, а просто указывать количество знаков после запятой Decimal.Round(([#Исходное дробное число#]), 1) - то формулу принимает и пересчёт ведёт, но по правилам округления, а не в бОльшую сторону, как мне нужно.

 

Может быть кто-то сталкивался с такой же задачей? Как решали?

Нравится

1 комментарий
Лучший ответ

Сергей, в отличие от старого движка процессов, в котором можно было указать в элементе-формуле или условии произвольный фрагмент C#-кода, в нынешнем, интерпретируемом, работа с формулами может не поддерживать все особенности функций от Microsoft.

 

Как обходной вариант, можно создать блок-скрипт, где считать значение из параметра, вычислить округление нужным способом и записать в другой.

decimal positiveValue = Get&lt;decimal&gt;("ProcessSchemaParameterPositiveValue");
decimal result = Math.Round(positiveValue, 1, MidpointRounding.ToEven);
Set&lt;decimal&gt;("ProcessSchemaParameterResult", result);
return true;

А если таких вычислений у Вас в процессах много, можно создать свой UserTask с параметрами, куда передавать значения и способ округления.

Сергей, в отличие от старого движка процессов, в котором можно было указать в элементе-формуле или условии произвольный фрагмент C#-кода, в нынешнем, интерпретируемом, работа с формулами может не поддерживать все особенности функций от Microsoft.

 

Как обходной вариант, можно создать блок-скрипт, где считать значение из параметра, вычислить округление нужным способом и записать в другой.

decimal positiveValue = Get&lt;decimal&gt;("ProcessSchemaParameterPositiveValue");
decimal result = Math.Round(positiveValue, 1, MidpointRounding.ToEven);
Set&lt;decimal&gt;("ProcessSchemaParameterResult", result);
return true;

А если таких вычислений у Вас в процессах много, можно создать свой UserTask с параметрами, куда передавать значения и способ округления.

Показать все комментарии

Создали новый бизнес-процесс, в нем необходимо открыть новую страницу продаж с результатами выполнения бизнес-процесса.



Добавить новую страницу продаж с помощью мастера раздела "Продажи" не имеем возможности по историческим причинам (он тупо не сохраняет результаты).



Создали новую страницу в Конфигурации, унаследовав ее от существующей страницы продажи.



Однако, в списке доступных для открытия страниц в блоке "Открыть страницу редактирования" бизнес-процесса она отсутствует.



Какие есть обходные варианты добавления в этот список новой страницы без использования мастера?

Изображение удалено.

Нравится

1 комментарий

Виктор, если открыть в браузере «инструменты разработчика» и посмотреть в уходящие на сервер запросы при выпадении этого списка, видно, что он получает данные из SysModule, таблицы, где хранятся данные о заведенных разделах.

То есть либо чинить мастер, либо добавлять или менять раздел вручную, как делали в старых версиях, когда не было мастера.

 

Также страницу раздела невозможно выбрать в элементе Открыть страницу редактирования, если в SysModule запись есть, но по какой-то причине проставилось значение true колонки IsSystem. 

Показать все комментарии

Коллеги, добрый день. Версия 7.15.3.

 

Имеется бизнес-процесс, стартующий по сигналу создания письма (активности, но именно с типом Email). Письмо отправляется в другом процессе автоматически.

Как можно найти шаблон, по которому создано письмо?

Нравится

7 комментариев

Денис, как именно создаёте письмо по шаблону? Действием или кодом? Если Вы сами создаёте, то зачем его отдельно вычислять? Сделать в активности скрытое справочное поле и дать ссылку на шаблон туда, тегом пометить активность, ещё как-то.

Александр, письмо с помощью стандартного блочка "Отправить email" бизнес-процесса оптравляется https://academy.terrasoft.ua/documents/technic-bpms/7-16/element-proces…

 

Отправка происходит автоматически, шаблон мультиязычный с макросами.

 

 

Там шаблон задаётся как параметр элемента. Если он задан статически, то что мешает посмотреть? А если вычисляется в скрипте или берётся из какого-то параметра, то можно тоже где-то зафиксировать.

Зверев Александр,

 

Здесь можно, да. Проблема в том, что при отправке создаётся активность с типом Email.

 

И шаблон нужно найти  и связать с этой самой активностью, которая создаётся при отправке автоматического email, причём, скорее всего это нужно делать в процессе, который запускается по сигналу от создания активности. Потому что в основном процессе, где отправляется письмо, её (активность) не найти -  параметр "Id задачи" в элементе "Отправить email" тут не помогает, там пустое значение после отправки.

Судя по комментарию тут https://community.terrasoft.ru/ideas/pozvolit-svyazyvat-pisma-otpravlen… при отправке письма автоматически происходит запрос в какой-то сервис, который и отправляет письмо, и где создаётся активность. При этом процесс, в котором было отправлено письмо, идёт дальше, поэтому id задачи там и не доступен.

Я пробовал ещё вызывать код в блоке "После сохранения активности", но он почему-то тоже не срабатывает.

 

 

Смородинов Денис пишет:

Я пробовал ещё вызывать код в блоке "После сохранения активности", но он почему-то тоже не срабатывает.

Данный блок срабатывает только при значении [Как выполняется отправка] =>Отправить email вручную

Если блоком получить не выйдет, можно кодом создать активность по шаблону и отправить с использованием функций в схемах, упомянутых тут.

Показать все комментарии

Добрый вечер.

 

Подскажите, пжл, куда в Системе необходимо смотреть (где производить настройки/разработку), чтобы выполнить следующие требования в представлении "Календарь" раздела "Активности":

- закрепить шапку календаря (при наличии большого количества многодневных задач шапка после прокрутки скрывается, оставаясь "сверху")

- отсортировать записи не по полю "Начало", а по полю "Завершения"

Изображение удалено.

Нравится

5 комментариев
Лучший ответ

Попробовал уменьшить окно браузера.

Да, похоже шапка вместе с многодневными задачами закрепляется сверху над обычными задачами. А если они сами не влазят целиком, то вместе прокручиваются и шапка исчезает, остаётся только блок фильтров и всё, что выше его.

 

Это компонент ядра Terrasoft.controls.ScheduleEdit, он реализован в файле https://сайт/0/core/hash/Terrasoft/controls/schedule-edit/schedule-edit…

 

Там, если смотреть HTML-код страницы, есть три блока, сверху вниз: title-area, multi-day-item-area, scroll-area. Даже по названию видно, что прокручиваться предназначен третий, с обычными задачами.

 

То есть, это код ядра, не конфигурации.

Сортировка по началу, видимо, там же:

	/**
	 * Returns the sorted list of calendar items.
	 * @private
	 * @param {Array} schedulerItemList List of calendar items.
	 * @return {Array} Sorted list of calendar items.
	 */
	sortScheduleItemList: function(schedulerItemList) {
		const sortItemList = [];
		Terrasoft.each(schedulerItemList, function(item) {
			if (!item.isMultiDayItem()) {
				sortItemList.push(item);
			}
		});
		sortItemList.sort(this.sortScheduleItemListByStartDate);
		return sortItemList;
	},
 
	/**
	 * Returns the result of comparing 2 calendar items by date.
	 * @private
	 * @param {Object} itemA Item #.
	 * @param {Object} itemB Item B.
	 * @return {Array} The result of comparing 2 calendar items by date.
	 */
	sortScheduleItemListByStartDate: function(itemA, itemB) {
		let result = 0;
		const itemAStartDate = itemA.startDate;
		const itemADuration = itemA.dueDate - itemAStartDate;
		const itemBStartDate = itemB.startDate;
		const itemBDuration = itemB.dueDate - itemBStartDate;
		if ((itemAStartDate === itemBStartDate) &amp;&amp; (itemADuration === itemBDuration)) {
			result = 0;
		} else if (itemAStartDate &gt; itemBStartDate) {
			result = 1;
		} else if (itemAStartDate &lt; itemBStartDate) {
			result = -1;
		} else if (itemADuration &gt; itemBDuration) {
			result = -1;
		} else if (itemADuration &lt; itemBDuration) {
			result = 1;
		}
		return result;
	},

 

Уточните, где именно на скриншоте у Вас скрылась шапка? И блок фильтрации, и многодневные задачи там видны.

 

Возможно, если у Вас так много в расписании многодневных задач, есть смысл применить диаграмму Ганта? Есть пара дополнений с её реализацией.

Зверев Александр,

Вот как раз, если много задач, то при пролистывании ползунком скрывается шапка, прилагаю скриншот:

// + где настроить, чтобы  <отсортировать записи не по полю "Начало", а по полю "Завершения">/

Попробовал уменьшить окно браузера.

Да, похоже шапка вместе с многодневными задачами закрепляется сверху над обычными задачами. А если они сами не влазят целиком, то вместе прокручиваются и шапка исчезает, остаётся только блок фильтров и всё, что выше его.

 

Это компонент ядра Terrasoft.controls.ScheduleEdit, он реализован в файле https://сайт/0/core/hash/Terrasoft/controls/schedule-edit/schedule-edit…

 

Там, если смотреть HTML-код страницы, есть три блока, сверху вниз: title-area, multi-day-item-area, scroll-area. Даже по названию видно, что прокручиваться предназначен третий, с обычными задачами.

 

То есть, это код ядра, не конфигурации.

Сортировка по началу, видимо, там же:

	/**
	 * Returns the sorted list of calendar items.
	 * @private
	 * @param {Array} schedulerItemList List of calendar items.
	 * @return {Array} Sorted list of calendar items.
	 */
	sortScheduleItemList: function(schedulerItemList) {
		const sortItemList = [];
		Terrasoft.each(schedulerItemList, function(item) {
			if (!item.isMultiDayItem()) {
				sortItemList.push(item);
			}
		});
		sortItemList.sort(this.sortScheduleItemListByStartDate);
		return sortItemList;
	},
 
	/**
	 * Returns the result of comparing 2 calendar items by date.
	 * @private
	 * @param {Object} itemA Item #.
	 * @param {Object} itemB Item B.
	 * @return {Array} The result of comparing 2 calendar items by date.
	 */
	sortScheduleItemListByStartDate: function(itemA, itemB) {
		let result = 0;
		const itemAStartDate = itemA.startDate;
		const itemADuration = itemA.dueDate - itemAStartDate;
		const itemBStartDate = itemB.startDate;
		const itemBDuration = itemB.dueDate - itemBStartDate;
		if ((itemAStartDate === itemBStartDate) &amp;&amp; (itemADuration === itemBDuration)) {
			result = 0;
		} else if (itemAStartDate &gt; itemBStartDate) {
			result = 1;
		} else if (itemAStartDate &lt; itemBStartDate) {
			result = -1;
		} else if (itemADuration &gt; itemBDuration) {
			result = -1;
		} else if (itemADuration &lt; itemBDuration) {
			result = 1;
		}
		return result;
	},

 

Зверев Александр,

Спасибо за ответ. Возможно ли запланировать в базовой функциональности фиксацию шапки календаря и возможность настройки сортировки?

Завёл идеи о шапке многодневных и способе сортировки.

Показать все комментарии