Здравствуйте, где в коде можно найти логику автоматического изменения даты Окончания Активности при проставлении новой даты Начала. Мне нужно чтобы дата Окончания оставлялась такой, которую установил бизнес процесс, а по факту получается, что автоматически проставляется дата Начала + 3 дня (если мы ставим дату начала на 3 дня раньше чем было).

Нравится

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

Здравствуйте!

В базовой логике системы при изменении даты начала новой активности вызывается метод onStartDateChanged, который устанавливает значение в поле "Дата завершение".

Для новых записей интервал - 30 минут.

Для существующих записей интервал составляет разницу между "Датой завершения" и "Датой начала". Эта логика реализована на странице редактирования ActivityPageV2.

Что касается логики "Дата начала + 3 дня" - в базовой версии приложения такого нет. Необходимо выполнить отладку разработанной логики.

"Демьяник Алексей" написал:Для существующих записей интервал составляет разницу между "Датой завершения" и "Датой начала". Эта логика реализована на странице редактирования ActivityPageV2.

Как изменить эту логику? Что бы для существующих записей "дата завершения" не менялась при изменении "даты начала"?

Здравствуйте, Виталий.

Вам стоит смотреть в сторону изменения значения атрибута DifferStartDueDate (именно в нем хранится значение устанавливаемого интервала), который используется в методе onStartDateChanged. По умолчанию данному атрибуту устанавливаются значения в методе setDifferStartDueDate схемы ActivityDatesMixin(UIv2).

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

Добрый день!

Возникла проблема при разворачивании демо версии BPMonline. (версия 7.9.0.1228)

Был поднят сервер IIS с приложением. Проводилась настройка файлов конфигурации согласно инструкции по установке (https://academy.terrasoft.ru/documents/sales-enterprise/7-9/ustanovka-bp...). Веб-сокеты настраивал как в (https://academy.terrasoft.ru/documents/sales-enterprise/7-9/ustanovka-bp...) для windows server 2012.
Удалось попасть в приложение и пройти авторизацию, но часть функционала осталась нерабочей (вкладка "Рабочее место, Дизайнер системы, Профиль пользователя" не отзывается на нажатия).
Консоль выдает следующие ошибки:

Uncaught SyntaxError: Unexpected token

Uncaught TypeError: Cannot read property 'entitySchemaName' of undefined
at i. (ConfigurationBootstrap.js:21591)
at all-combined.js:292
at Object.execCb (require.js:1693)
at Module.check (require.js:881)
at Module. (require.js:1136)
at require.js:134
at require.js:1186
at each (require.js:59)
at Module.emit (require.js:1185)
at Module.check (require.js:936)

user: Supervisor/7f3b869f-34f3-4f20-ab4d-7480a5fdf647
file: http://terrasoft_demo.demo.oim:82/0/Nui/ViewModule.aspx
line: 3
column: 1
message: Uncaught SyntaxError: Unexpected token
date: Tue Dec 27 2016 13:08:43 GMT+0400 (Московское время (зима))
stack: SyntaxError: Unexpected token

WebitelVerto.js:3306 WebSocket connection to 'wss://ru1-webitel-switch.bpmonline.com:8082/' failed: WebSocket opening handshake timed out

Все роли и компоненты указанные в руководстве установлены, протокол Websocket стоит.
Единственным отличием от руководства было то, что при настройке пула приложения не удалось выбрать версию среды ASP.NET 4.0.30319 (он не отображался), пришлось выбрать CLR.NET той же версии.

Не могли бы вы подсказать в чем может быть проблема?

Файлы конфигурации прилагаю.

Нравится

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

Здравствуйте!

Это совершенно разные ошибки
Uncaught SyntaxError: Unexpected token <

Uncaught TypeError: Cannot read property 'entitySchemaName' of undefined
at i. (ConfigurationBootstrap.js:21591)
at all-combined.js:292
at Object.execCb (require.js:1693)
at Module.check (require.js:881)
at Module. (require.js:1136)
at require.js:134
at require.js:1186
at each (require.js:59)
at Module.emit (require.js:1185)
at Module.check (require.js:936)

Система не смогла прочитать название схемы. Возникает в следующих случаях:
1) Некорректно замещены конфигурационные схемы. Решение: исправить ошибку.
2) Удалена схема, однако SectionBundleModule не пересобрался. Решение: сохранить произвольную схему в конфигурации (нужно сохранить именно схему, а не процесс или объект).

Для перехода в конфигурацию введите адрес [site]/0/dev

WebitelVerto.js:3306 WebSocket connection to 'wss://ru1-webitel-switch.bpmonline.com:8082/' failed: WebSocket opening handshake timed out - ошибка телефонии. Подключение идет по защищенному каналу (wss), а сайт работает на незащищенном канале http.

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

Здравствуйте, хотел написать свое правило поиска дублей для контактов пример того как сделать взял с академии но во время выполнения скрипта появляется ошибка что переменная @parsedConfig имеет недопустимый тип данных. и еще в таблице ContactDuplicateSearchResult нету поля SysAdminUnitId вместо него идет поле GroupHash. Как изменить скрипт чтобы он заработал? bpm 7.8.0

-- Проверка наличия хранимой процедуры с именем tsp_FindContactDuplicateByNameAndContragent.
IF NOT OBJECT_ID('[dbo].[tsp_FindContactDuplicateByNameAndContragent]') IS NULL
BEGIN
    -- Удаление хранимой процедуры.
    DROP PROCEDURE [dbo].[tsp_FindContactDuplicateByNameAndContragent];
END;
GO
-- Создание хранимой процедуры.
CREATE PROCEDURE [dbo].[tsp_FindContactDuplicateByNameAndContragent] (
    -- Этот табличный параметр передается только в случае сохранения нового контакта.
    -- Содержит данные нового контакта.
    -- В случае запуска процесса глобального поиска дублей переданный параметр не содержит данных.
    @parsedConfig CreatingObjectInfo READONLY,
    -- Уникальный идентификатор пользователя, который запустил поиск дублей.
    @sysAdminUnit UNIQUEIDENTIFIER,
    -- Идентификатор текущего правила из таблицы [ContactDuplicateSearchResult].
    -- Этот идентификатор создается после регистрации правила в системе.
    @ruleId UNIQUEIDENTIFIER
)
AS
BEGIN
    -- Получение количества записей из принимаемой таблицы для определения запуска глобального поиска дублей.
    DECLARE @parsedConfigRowsCount INT = (SELECT COUNT(*) FROM @parsedConfig);
    -- Создание временной таблицы с данными контактов для поиска.
    CREATE TABLE #searchContact (
        [Name] nvarchar(250),
                [AccountId] uniqueidentifier,
        [SortDate] DATETIME
    );
    -- В случае глобального поиска выполняется заполнение временной таблицы данными.
    IF @parsedConfigRowsCount = 0
    BEGIN
        -- Добавление во временную таблицу данных для поиска дублей.
        INSERT INTO #searchContact ([Name], [AccountId],[SortDate])
        -- Запрос на выборку данных контактов.
        SELECT
            -- Выбираются колонки ИНН даты модификации контакта.
            [Name],[AccountId],
            MAX([ModifiedOn])
        FROM [Contact]
        -- Добавляется группировка по полям для возможности использовать проверку на количество.
        GROUP BY [Name],[AccountId]
        -- Таблица заполняется только в случае наличия более одного контакта.
        HAVING COUNT(*) > 1;
    END;
   
    -- Заполнение таблицы результатов.
    INSERT INTO [ContactDuplicateSearchResult] ([ContactId], [GroupId], [RuleId], [SysAdminUnitId])
    SELECT
        -- Идентификатор дубля контакта.
        [vr].[Id],
        -- Формирование номера группы.
        DENSE_RANK() OVER (ORDER BY [vr].[SortDate] DESC, [vr].[Name],[vr].[AccountId]),
        -- Идентификатор правила.
        @ruleId RuleId,
        -- Идентификатор пользователя, под которым запущен процесс поиска дублей.
        @sysAdminUnit
    FROM (
        -- Подзапрос, из которого заполняется таблица дублей.
        SELECT
            -- Идентификатор контакта.
            [v].[Id],
            --ФИО контакта.
            [v].[Name],
           --ИД контрагента.
            [v].[AccountId],
            -- Дата сортировки.
            [r].[SortDate]
        -- Таблицы, из которых берутся данные.
        FROM [Contact] [v], #searchContact r
        -- Правило, по которому определяется, что контакты — дубли.
        WHERE [v].[Name] = [r].[Name] AND [v].[AccountId] = [r].[AccountId]
        -- Группировка результата поиска.
        GROUP BY [v].[Name],[v].[AccountId], [r].[SortDate], [v].[Id]
    ) [vr];
END;
GO

Нравится

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

Здравствуйте, я новичок в системе. Но насколько, я понял, статья https://academy.terrasoft.ru/documents/technic-sdk/7-8/dobavlenie-pravi… с примером справедлива для bpm 7.8.3 и выше... В версии 7.8.0 в таблице DuplicatesRule нет поля "Название процедуры"... Поэтому непонятно, как будет происходить вызов вновь созданной процедуры в 7.8.0, если только изменить DeduplicationSearch...

Здравствуйте,
Правила дедупликации расположены в таблице [DuplicatesRule]
Там же в колонке [ProcedureName] указаны имена хранимых процедур, ответственных за обработку.
Почитайте код любой из данных процедур и напишите свой по аналогии.
К примеру, во вложении, код процедуры [tsp_FindAccountDuplicateByWeb]

new_text_document.txt

Здраствуйте
1. Касательно этого блока:
IF @parsedConfigRowsCount = 0
BEGIN
-- Добавление во временную таблицу данных для поиска дублей.
INSERT INTO #searchContact ([Name], [AccountId],[SortDate])
-- Запрос на выборку данных контактов.
SELECT
-- Выбираются колонки ИНН даты модификации контакта.
[Name],[AccountId],
MAX([ModifiedOn])
FROM [Contact]
-- Добавляется группировка по полям для возможности использовать проверку на количество.
GROUP BY [Name],[AccountId]
-- Таблица заполняется только в случае наличия более одного контакта.
HAVING COUNT(*) > 1;
END;

Я бы сделал как в базовой хранимке:
IF @parsedConfigRowsCount = 0
BEGIN
INSERT INTO #searchAccount ([Name], [SortDate])
SELECT
[dedup].[Name],
MAX([dedup].[SortDate]) [SortDate]
FROM (
SELECT [Id],
[dbo].[fn_NormalizeString]([Name], @validChar) AS [Name],
MAX([ModifiedOn]) [SortDate]
FROM [Account]
GROUP BY [Id], [Name]
) AS [dedup]
GROUP BY [dedup].[Name]
HAVING COUNT(*) > 1;
END;
ELSE
BEGIN
INSERT INTO #searchAccount ([Name], [SortDate])
SELECT
[Name],
GETDATE() AS [SortDate]
FROM @parsedConfig
END;
2. В версии 7.8 в таблице ContactDuplicateSearchResult были поля ContactId, GroupId, RuleId, GroupHash
А где-то с 7.8.3 добавилось ещё поле SysAdminUnitId
Но GroupHash не добавлялось и раньше, было так:
INSERT INTO [ContactDuplicateSearchResult] ([ContactId], [GroupId], [RuleId])
А теперь так:
INSERT INTO [ContactDuplicateSearchResult] ([ContactId], [GroupId], [RuleId], [SysAdminUnitId])

3. Что касается "Названия процедуры", то это поле действительно появилось с 7.8.3. Так что инструкция с академии подходит именно для версий 7.8.3+, т.к.

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

Сделал новую страницу в «Активностях» пропала логика поиска «Счета». Т.е. Если открыть справочник счета в стандартной «задаче» - отображает все счета которые выписаны на этого контрагента. Если же открыть справочник поля «счет» в новой странице активности — справочник вообще пустой.

Нравится

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

Здравствуйте, Виталий!

По умолчанию фильтрация счетов реализована бизнес-правилами в схеме ActivityPageV2. Если на новой странице счета не отображаются, тогда могут быть следующие варианты:
1) У пользователя нет прав (маловероятно)
2) При добавлении на страницу редактирования было добавлено новое поле "Счет" на основании нового объекта. В результате в новом объекте нет записей
3) Были настроены бизнес-правила для фильтрации записей, однако они были настроены некорректно.

Первый и второй вариант отпадают. а вот с 3-м не могу разобраться есть 3 типа страниц в "Активности" бизнес-правила для фильтрации записей во 2й и 3й прописаны одни и те же, но во второй счета отображаются, а в 3 - нет.

П.С. счет не отображается если заполнено поля "Контрагент" и "Контакт" (если только "Контрагент" - все ок)

Что нужно поправить?

"Полищук Виталий Романович" написал:отображает все счета которые выписаны на этого контрагента

Точно? В пакете Invoice валяется ActivityPageV2:

"Invoice": {
	"FiltrationInvoiceByAccount": {
		"ruleType": BusinessRuleModule.enums.RuleType.FILTRATION,
		"autocomplete": true,
		"autoClean": true,
		"baseAttributePatch": "Account",
		"comparisonType": Terrasoft.ComparisonType.EQUAL,
		"type": BusinessRuleModule.enums.ValueType.ATTRIBUTE,
		"attribute": "Account"
	},
	"FiltrationInvoiceByContact": {
		"ruleType": BusinessRuleModule.enums.RuleType.FILTRATION,
		"autocomplete": true,
		"autoClean": true,
		"baseAttributePatch": "Contact",
		"comparisonType": Terrasoft.ComparisonType.EQUAL,
		"type": BusinessRuleModule.enums.ValueType.ATTRIBUTE,
		"attribute": "Contact"
	}
}

Это ж вроде как фильтрация и по контакту, и по контрагенту.

Здравствуйте,
Проблема связана с тем, что в счете, на данный момент поля «Контакт» и «Контрагент» нет возможности установить одновременно, только через мультилукап «Клиент», то есть в любом случае будет проставлен ИЛИ Контрагент, ИЛИ Контакт.
В Активностях же, если выбрать контакта, будет проставлен и контрагент, и фильтрация бизнес правилами: описанная тут: http://www.community.terrasoft.ua/forum/topic/24928#comment-66209
Будет работать через условное «И». То есть попытается найти счета, в которых И Контрагент, И Контакт равны тем что указаны в Активности. А таких нет, т.к. в счетах стоит или контакт, или контрагент.
Вам нужно отключить данную фильтрацию бизнес правилами, как это указано тут: http://www.community.terrasoft.ru/forum/topic/24861#comment-65997
После чего вам будут доступны все счета, в данной колонке, так же, для удобства можно написать фильтрацию с условным «ИЛИ», но не бизнес правилом, а через атрибут по примеру: http://www.community.terrasoft.ru/forum/topic/24859#comment-65965

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

Здравствуйте.
Есть задача создать уведомление для пользователя, при условии, оформления 3-х заказов для одного клиента. В случае когда будет оформлено 3 заказа для одного клиента для пользователя системы будет приходить уведомление.
Помогите пожалуйста создать данный БП. Быть может уже кто-то делал такое и есть конкретные примеры?
Благодарю

Нравится

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

В объекте заказ вставляете событие после сохранения. Далее лепите процесс. Навскидку:
1) Взять клиента, относительно которого только что был создан заказ
1) проверить кол-во заказов где он указан
2) если кол-во заказов >= 3 создаём активность с напоминанием ответственному (ну или фиксированному пользователю)

Здравствуйте!

1. Стартовый сигнал по добавлению записи в Заказ.
2. Читать данные в заказах, где Id = Пункт 1. Id
3. Читать кол-во записей в заказах, где Контрагент = Пункт 2. Контрагент.
4. Условный поток [Пункт 3. Кол-во записей] >= 3.
5. Письмо или активность.

Здравствуйте. Спасибо большое. Настроил работает данная система. Однако, активность появляется при каждом последующем заказе. Нужно чтобы уведомление приходило только при 3-х заказах. Пытаюсь прописать таким образом [Пункт 3. Кол-во записей] = 3, но выдаёт ошибку и не сохраняется

Дмитрий,

Для сравнения на равенство используйте "==" вместо "="

"Бондарь Наталия" написал:

Дмитрий,

Для сравнения на равенство используйте "==" вместо "="


Большое спасибо

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

Нужна следующая функция в CRM: отправление ценового предложения клиенту
из CRM. или чтобы файл с ценовым предложением крепился к истории
клиента. В общем, чтобы информация о цене, которую менеджер дал клиенту,
сохранялась в CRM. Есть ли такая возможность? Версия 7.2.0.1184 bpmonline crm
Я так поняла, необходима доработка приложения, но что именно? Пожалуйста, помогите!

Нравится

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

Татьяна, добрый день!

Обе задачи требуют навыков программирования.

Для решения можно создать бизнес процесс. Логика процесса:
1) Создать активность с типом "Email". запись может быть создана элементом "Добавить данные". Обязательно нужно заполнить поля "Кому", "От кого", "Тема", "Тело"
2) Элементом "Задание-сценарий" необходимо:

  • Сформировать ценовое предложение. Для этого можно использовать методы из схемы ReportService
  • Заинсертить сформированный файл в таблицу ActivityFile, обязательно указав в поле ActivityId значение Id созданной на первом шаге активности
  • Отправить письмо

Не уверен, что в версии 7.2.0 есть пример такой отправки. Рекомендую зарегистрировать себе trial версию продукта service enterprise. В процессе "Отправка email сообщения контакту обращения" вы сможете найти пример кода.

3) Конец процесса

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

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

Быстрое добавление записи в справочник не работает для некоторых полей страницы. При этом на другой странице это же поле прекрасно работает.

1
2

Нравится

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

Андрей,
Возможность быстрого добавления записи в справочник доступна для тех полей, которые не ссылаются на системный объект. В Вашем примере поле [Группа ответственных] ссылается на системный объект SysAdminUnit, поэтому быстрого добавления нет. Если взять для сравнения поле [Ответственный], оно ссылается на простой объект Contact.

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

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

Есть ли какая либо возможность сделать "копию", а не переписывать его вручную основываясь на схемах и объектах пакета "CoreForecast".

PS: Данный раздел явно не является типовым, его отличает как минимум то что у него есть только "представление раздела" и отсутствует какое либо представление записей основного объекта.
"Страница раздела" не является потомком обычных типовых страниц раздела, которые унаследованы от "Базовая схема раздела (NUI)", а является потомком "Базовая схема карточки ( NUI )".

По этому его даже невозможно воссоздать на основании сгенерированного мастером нового раздела,
Даже если удается повторить схемы и объекты, как такой раздел зарегистрировать вручную ?

Нравится

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

"Севостьянов Илья Сергеевич" написал:

Есть необходимость внедрить в систему копию штатного раздела "Планирование".

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

Есть ли какая либо возможность сделать "копию", а не переписывать его вручную основываясь на схемах и объектах пакета "CoreForecast".

PS: Данный раздел явно не является типовым, его отличает как минимум то что у него есть только "представление раздела" и отсутствует какое либо представление записей основного объекта.

"Страница раздела" не является потомком обычных типовых страниц раздела, которые унаследованы от "Базовая схема раздела (NUI)", а является потомком "Базовая схема карточки ( NUI )".

По этому его даже невозможно воссоздать на основании сгенерированного мастером нового раздела,

Даже если удается повторить схемы и объекты, как такой раздел зарегистрировать вручную ?

Подписаться на обновления этого материала

Здравствуйте,

К сожалению, это даже не раздел в привычном понимании этого слова, и скопировать его не удастся, вы можете попробовать создать аналогичную функциональность, взяв за основу оригинальный ForecastsModule, из пакета CoreForecast, но вам, в зависимости от того, какую логику вы будете менять, может понадобится создать собственные объекты\сервисы\хелперы. В общем изучите все содержимое пакета CoreForecast, начиная с ForecastsModule. А регистрацию «раздела» делайте в:
SELECT * FROM SysModule

Да, мы уже смотрели "по аналогии",
Подскажите пожалуйста верны ли мои утверждения касаемо значений в соответствующих колонках
таблицы SysModule:
SysModuleEntityId
(Значение поля "Id" базового объекта раздела из таблицы SysModuleEntity, там регистрируются все объекты автоматически при добавлении их через конфигуратор, в нашем случае это будет копия объекта Forecast)
SectionModuleSchemaUId (Значение поля "UId" из таблицы SysSchema, аналогично - регистрируются ли там схема автоматически)

Есть так же еще некоторые связанные записи в таблице SysModuleEdit
За что она отвечает ?

Илья, думаю, что данная тема будет Вам полезна
http://www.community.terrasoft.ru/forum/topic/13357

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

Обычно если мы в ESQ используем произвольные или обратные связи то обычно строиться LEFT OUTER JOIN с наименованием колонки по которой присоединил.

Например:

SELECT CC.SpecializationId
FROM TsMarketingApplication tsma
     LEFT OUTER JOIN Activity a ON a.Id=tsma.TsActivityId

Если корневая схема TsMarketingApplication то будет

.AddColumn("[Activity:Id:TsActivityId].Имя нужной колонки");

Но если мне нужен JOIN по двух колонках сразу, как быть?
например:

SELECT CC.SpecializationId
FROM TsMarketingApplication tsma
     LEFT OUTER JOIN Activity a ON a.Id=tsma.TsActivityId
     LEFT OUTER JOIN ContactCareer CC ON CC.ContactId = A.OwnerId AND CC.AccountId=A.AccountId

Заранее признателен

Нравится

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

Виталий, здравствуйте,

Ознакомтесь, пожалуйста, со статьей на академии по данному вопросу:

https://academy.terrasoft.ru/documents/technic-sdk/7-9/ispolzovanie-ent…

Хорошего вечера!

С уважением,
Валерия

Но там как раз описывается пример с JOIN по одной колонке. Я правильно понимаю что ESQ такого не умеет?

Здравствуйте, Виталий.

Подробную информацию о возможностях ESQ, Вы можете найти в SDK.

Так же, для построение более сложных запросов, рекомендую Вам смотреть на более низкоуровневый класс Select. Данный класс используется внутри ESQ и позволяет построить более сложные запросы к базе данных.

SELECT

Я бы через Select брал.

Select select = new Select(userConnection)
	.Column(@"ContactCareer", @"SpecializationId").As("SpecId")
	.From(@"TsMarketingApplication")
 
	.LeftOuterJoin("Activity").On("Activity", "Id").IsEqual("TsMarketingApplication", "TsActivityId")
	.LeftOuterJoin("ContactCareer").On("ContactCareer", "ContactId").IsEqual("Activity", "OwnerId")
		.And("ContactCareer", "AccountId").IsEqual("Activity", "AccountId")
 
	as Select;
 
using (DBExecutor executor = userConnection.EnsureDBConnection())
{
	using (IDataReader reader = executor.ExecuteReader(select.GetSqlText(), select.Parameters))
	{
		while (reader.Read())
		{
			string result = reader.GetColumnValue<Guid>(@"SpecId").ToString();
                        //Обработка результатов
		}
 
		reader.Close();
	}
}

Спасибище!!!

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