Добрый день!

При попытке сделать вот так:

photo.Save();

contact.PhotoId = photo.Id;

contact.Save();

Начинает работать триггер:

ALTER TRIGGER [dbo].[TRILE9Mk5tdkf4ii5Xu52IJW7JlAIU] ON [dbo].[Contact]

AFTER INSERT, UPDATE

AS

BEGIN

        SET NOCOUNT ON

    IF (EXISTS(SELECT * FROM [DELETED]))

    BEGIN

        DELETE FROM [dbo].[SysImage]

        FROM [dbo].[SysImage]

            INNER JOIN [DELETED] ON [DELETED].[PhotoId] = [dbo].[SysImage].[Id]

            INNER JOIN [INSERTED] ON [INSERTED].[Id] = [DELETED].[Id]

        WHERE [INSERTED].[PhotoId] <> [DELETED].[PhotoId] 

            OR [INSERTED].[PhotoId] IS NULL

    END

    UPDATE [dbo].[SysImage]

    SET [HasRef] = 1

    FROM [dbo].[SysImage]

        INNER JOIN [INSERTED] ON [INSERTED].[PhotoId] = [dbo].[SysImage].[Id]

END

, который удаляет картинку, и возникает вот такая ошибка:

The DELETE statement conflicted with the REFERENCE constraint "FKamtHXQyIMFbLDoNyWpPJjYmE". The conflict occurred in database "sddhelp", table "dbo.Contact", column 'PhotoId'.

Если пытаться апдейтить картинку на null то же самое.

 

Нравится

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

Добрый день, довольно распространённая ошибка.

Немного отступления, дело в том что у сущности (фото которой вы пытаетесь изменить) текущее фото используется ещё какой-то сущностью.



Т.е. если Контакт1 имеет Фото1 и Контакт2 имеет Фото2, то при обновлении/удалении такого фото у любого из двух контактов возникнет исключение. Если не ошибаюсь то механика такова, что при попытке обновления фото, данное фото пытается удалиться из SysImage.



Как вариант могу предложить на время отключить данный constraint дабы почистить дубли фото во всей таблице, заранее выявив все такие дубли. Затем после очистки можно вернуть данный constraint обратно, вернуть его можно просто опубликовав объект таблицы (в конфигураторе) ещё раз, чтобы структура таблицы в БД обновилась согласно объекту.

Добрый день, довольно распространённая ошибка.

Немного отступления, дело в том что у сущности (фото которой вы пытаетесь изменить) текущее фото используется ещё какой-то сущностью.



Т.е. если Контакт1 имеет Фото1 и Контакт2 имеет Фото2, то при обновлении/удалении такого фото у любого из двух контактов возникнет исключение. Если не ошибаюсь то механика такова, что при попытке обновления фото, данное фото пытается удалиться из SysImage.



Как вариант могу предложить на время отключить данный constraint дабы почистить дубли фото во всей таблице, заранее выявив все такие дубли. Затем после очистки можно вернуть данный constraint обратно, вернуть его можно просто опубликовав объект таблицы (в конфигураторе) ещё раз, чтобы структура таблицы в БД обновилась согласно объекту.

Кисловский Михаил Андреевич,

Так это нормально, что на одну картинку две контакта ссылаются. такое вполне может произойти.

Разве?

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



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

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

Есть вот такой код.

Жирным выделены строки с ошибкой

 public SDDHelpOrder CaseToSDDHelpOrder(Case caseItem)

        {

            var cc = new ContactConverter(_userConnection);

            var spi = new ServicePactIntegration(_userConnection);

            return new SDDHelpOrder

            {

                guid = caseItem.Id.ToString()

               , bitrixId = caseItem.UsrBitrixId

               , subject = caseItem.Subject

               , description = caseItem.Symptoms

               , status = caseItem.Status.UsrCode

               , client = cc.ContactToSDDHelpUser(caseItem.Contact)

               , clientVote = caseItem.SatisfactionLevel.Point

               , clientVoteComment = caseItem.SatisfactionLevelComment

               , license = caseItem.ServicePactName

               , dexter_license = spi.GetDexterLicense(caseItem.ServicePactName)

               , fromSource = caseItem.OriginId.ToString()

               , agent = cc.ContactToSDDHelpUser(caseItem.Owner)

               , dateCreate = caseItem.RegisteredOn.ToString()

               , dateInWork = caseItem.RespondedOn.ToString()

               , dateCompleted = caseItem.SolutionProvidedOn.ToString()

               , dateFinish = caseItem.ClosureDate.ToString()

               , device = caseItem.UsrDeviceTypeId.ToString()

               , problem = caseItem.UsrProblemTypeId.ToString()

            };

        }

Т.е. в модели есть поле Status, например, а у него есть поле UsrCode. Я хочу красиво его получить в одну строчку. При таком написании возникает исключение "Невозможно получить значение колонки, так как она не была загружена". 

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

Можно сделать что-то типа этого:

((CaseStatus)UsrEntityExtended.GetEntity(_userConnection, "CaseStatus", "Id", caseItem.StatusId.ToString())).UsrCode

Но это не очень. Подсказывайте, друзья)

Нравится

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

Для получения из EntitySchemaQuery значений колонок по прямым связям нужно сначала эти колонки добавить. См. примеры тут:

// Создание экземпляра запроса EntitySchemaQuery с корневой схемой "City".
var esqQuery = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "City");
// Добавление в запрос колонки с именем контакта, который добавил страну конкретного города.
esqQuery.AddColumn("Country.CreatedBy.Name");

Потом, когда будет вызван GetEntityCollection, в полученных Entity это поле будет загружено.

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

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

Добрый день!

Не могу понять как изменить колонку для поиска по умолчанию. Если открывается lookup (this.openLookup(config, this.lookupCallback, this);) - то как изменить эту самую колонку с базового "Название" на "Полное имя"? Суть в том, чтобы когда открывалось окно - можно было сразу писать в поиске, а не выбирать каждый раз "Полное имя"

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

Нравится

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

Можно просто в EntitySchema таблицы этого справочника изменить поле для отображения или же есть более сложный вариант - обсуждение посмотрите в посте.

Можно просто в EntitySchema таблицы этого справочника изменить поле для отображения или же есть более сложный вариант - обсуждение посмотрите в посте.

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

Существует ли что-то похожее на "Генератор динамических групп"?

К примеру хочу создать в разделе Заказы родительскую "по Городам" и нагенерить в ней столько групп, сколько есть в справочнике Города, с автоматической установкой в каждой группе фильтра Заказ.Контрагент.Город = {город указанный в названии группы}

 

 

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

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

Власов Михаил Викторович, спасибо за предложение, но хотелось понять есть ли что-то готовое (в том числе БП)? Какими способами реализовать, наверно можно придумать варианты. 

Если такое уже кто-то реализует, то опубликует в маркете. Сейчас таких не вижу.

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

В качестве идеи реализации могу предложить следующее:

1) Реализовать новую кнопку в SystemDesigner, по нажатию которой будет открываться форма с 2мя полями:

- название раздела (для которого будет создан фильтр)

- справочное поле (по которому создать фильтр)

2) Создать динамические группы: каждая группа - одна запись в таблице <Название раздела>Folder (например, ContactFolder и тд).

Значение фильтра находится в колонке SearchData: по сути это сериализованное значение объекта класса  Nui.ServiceModel.DataContract.Filters.

Подробнее с работой динамических групп можно ознакомиться в схеме CommonUtilities.

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

Добрый день.

Есть такой случай: есть сервис где для авторизации нужно постом отправить данные clientID, secretID и grant_type, а в ответ приходит токен, тип токена и скрок действия токена. Для вызова других методов этого api нужно в header передавать Authorization : "тип токена" "токен". 

Допустим, для использования этого аpi, создаем процесс который по времени будет обновлять токен и сохранять его например в системную переменную(настройку). Но как с помощью веб-сервисов сделать запрос  и вставить в него header с "Authorization" ?

Нравится

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

Сергей приветствую

Способ авторизации у вас отличен от OAuth2? Каким способов Авторизации вы пользуетесь при работе с Веб-сервисом? немного этого не допонял. Спаисбо.

Власов Михаил Викторович,

Добрый день Михаил вот документации  https://sendpulse.ua/integrations/api#url но увы я не вижу  там описания какой версии OAuth2

Немного покопавшись в интернете и сопоставив с  документацие - сделал вывод, что там описан метод авторизации "Bearer token". А из коробки bpmonline готовой реализации такой авторизации нету.

Если речь об обращению к стороннему сервису в C#-коде, то в стандартных примерах  есть добавление в заголовки токена BPMCSRF:

// Добавление CSRF токена в заголовок запроса.
CookieCollection cookieCollection = AuthCookie.GetCookies(new Uri(authServiceUri));
string csrfToken = cookieCollection["BPMCSRF"].Value;
updateRequest.Headers.Add("BPMCSRF", csrfToken);

А в готовом элементе БП по вызову веб-сервиса есть только базовая аутентификация  и OAuth 2.0.

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

Простой и в то же время распространенный вопрос: как узнать разницу между временем на у клиента и на сервере. К примеру: передаем из клиента на сервер датувремя для сравнения, из сервера возвращает какой то результат. Разница составляет 2 или 3 часа, вопрос, как получить значение на которое нужно увеличивать(уменшать) дату от клиента

Нравится

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

Посмотрите в конфигурации реализацию TimezoneService и TimezoneHelper.

Посмотрите в конфигурации реализацию TimezoneService и TimezoneHelper.

Добрый день. Если речь идет именно о сравнении, то дату и время лучше сравнивать в UTC.

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

Добрый день!

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

+ Подскажите пожалуйста, каким методом реализации пользовались?

Нравится

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

у цб рф есть api, поэтому:

-в vs добавляете в проект ссылку на службу (https://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?wsdl)

-генерится класс, его копипастом переносим в crm

-в бп просто вызываем

DailyInfoSoapClient cl = new DailyInfoSoapClient();
var set = cl.DragMetDynamic(new DateTime(2018,12,3), new DateTime(2018, 12, 4));

и разбираем данные в нужные таблицы

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

у цб рф есть api, поэтому:

-в vs добавляете в проект ссылку на службу (https://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx?wsdl)

-генерится класс, его копипастом переносим в crm

-в бп просто вызываем

DailyInfoSoapClient cl = new DailyInfoSoapClient();
var set = cl.DragMetDynamic(new DateTime(2018,12,3), new DateTime(2018, 12, 4));

и разбираем данные в нужные таблицы

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

Добрый день!

Мне необходимо создать правило поиска дублей Сервисных договоров по полю Name.

Нашел пример в академии с созданием хранимой процедуры. 

https://academy.terrasoft.ru/documents/technic-sdk/7-13/dobavlenie-prav…

В ней указано:

INSERT INTO [ContactDuplicateSearchResult]. В моем случае таблицы [ServicePactDuplicateSearchResult] нет. Нужно ли ее создавать? В коробке правило поиска дублей работает только для контактов и контрагентов что ли?

Нравится

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

В коробке да реализованы правила поиска дублей, только по сущностям:

- Контакты

- Контрагенты 

- Лиды

Все остальное, это Кастомная доработка.

В коробке да реализованы правила поиска дублей, только по сущностям:

- Контакты

- Контрагенты 

- Лиды

Все остальное, это Кастомная доработка.

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

Но, в общем, реализация этой функциональности очень обьемна и сводится к следующему:



1. Создать процесс для поиска записей в своем разделе (аналогично процессу StartGlobalContactDuplicatesSearch).

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

3. Процедура будет записывать данные в созданный Вами объект MyObjectDuplicates (создайте объект по аналогии с объектом ContactDuplicate)

4. Необходимо создать новую страницу редактирования, которая будет отображать данные из созданного объекта MyObjectDuplicates по аналогии со страницей DuplicatesPageV2 (либо заместите DuplicatesPageV2, добавив в нее нужную логику).

ууу...

А вам надо именно поиск дублей или запрет создавать договоры с одинаковым именем?

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

в корень зрите, так тоже можно решить проблему)

Мотков Илья пишет:

Но, в общем, реализация этой функциональности очень обьемна и сводится к следующему:

1. Создать процесс для поиска записей в своем разделе (аналогично процессу StartGlobalContactDuplicatesSearch).

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

3. Процедура будет записывать данные в созданный Вами объект MyObjectDuplicates (создайте объект по аналогии с объектом ContactDuplicate)

4. Необходимо создать новую страницу редактирования, которая будет отображать данные из созданного объекта MyObjectDuplicates по аналогии со страницей DuplicatesPageV2 (либо заместите DuplicatesPageV2, добавив в нее нужную логику).

Уважаемые коллеги, подскажите, пожалуйста, подробнее (очень актуально)

1. Правильно ли я понимаю, что процесс надо создать уже с использованием своей хранимой процедуры "tcp_Find...", а не глобальной как  в процессе StartGlobalContactDuplicatesSearch

2. понятно

3. Правильно ли я понимаю, что здесь таблица, созданная непосредственно в SQL (без бизнес-объекта в Creatio, аналогично, например, AccountDuplicateSearchResult )

4. вот тут , пожалуйста, поподробнее, если возможно. Не получается разобраться со страницей DuplicatesPageV2, как связать новую страницу с новым объектом 

Хранимая процедура отрабатывает при запуске непосредственно в SQL, правило в интерфейсе Creatio появилось, но что нужно сделать (хотя бы концептуально) для работы страницы?

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

По нажатию на кастомную кнопку реализовала вызов карточки редактирования для изменения данных:

this.openCardInChain({
   "id": recordId,
   "schemaName": "BTSampInShipment1PageV2",
   "moduleId": this.sandbox.id + "BTSampInShipment1PageV2",
   "isSeparateMode": false,
   "operation": Enums.CardStateV2.EDIT,
   "defaultValues": defaultValues,
});

Но при открытии карточки редактирования вместо заголовка отображается 'New record'.

Если открывать эту же карточку редактирования через стандартный пункт меню 'Edit' заголовок карточки отображается корректно.

Подкажите, что нужно ещё передать в конфиг, чтобы отображался заголовок?

Нравится

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

Здравствуйте! если ничего не путаю, то в самой карточке Вам необходимо переопределить метод 

getHeader: function() {
				return Resources.localizableStrings.PageSettingsCaption;
			}

Я так делал. Но у меня значение было статическим. А Вам просто передать в метод свое значение

 

Здравствуйте! если ничего не путаю, то в самой карточке Вам необходимо переопределить метод 

getHeader: function() {
				return Resources.localizableStrings.PageSettingsCaption;
			}

Я так делал. Но у меня значение было статическим. А Вам просто передать в метод свое значение

 

Нигрескул Алексей,

Решила данную проблему немного другим способом.

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

var defaultValues = [
	{
		name: "BTSampleCIN",
		displayValue: sampleID
	}
];

 

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

Добрый день!

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

Нравится

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

Поскольку по действию «Печать» реально происходит генерация PDF-файла и его скачивание, можно на уровне браузера настроить папку для скачивания на нужный путь. В Windows 10 стандартно есть интеграция с OneDrive, когда он видится как обычная папка, можно указать туда.

Click image for larger version. </p>
<p>Name:	change_Google_Chrome_download_location-2.png <br />
Views:	679 <br />
Size:	62.8 KB <br />
ID:	116341

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