Вопрос

Добрый день! Столкнулись с такой проблемой: при выборе двух записей для объединения в контрагентах, через "Действия"-"Объединить выделенные записи". После выбора данных которые должны отображаться в итоговой записи и нажатии на кнопку "Объединить", вылетает ошибка "При слиянии записей произошла ошибка - Error converting data type nvarchar to int". Смысле ошибки понятен, что какие-то поля не конвертируются к нужному типу. Но проблема в том, что не получается отследить из-за каких полей могут быть косяки.
Может кто сталкивался с такой проблемой или знает как можно решить её, буду очень признателен!

У меня такой же вопрос

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

Здравствуйте, Николай.

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

"Maxim Gritsenko" написал:

Здравствуйте, Николай.

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

Большое спасибо за ответ!

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

Добрый день, TS Community. В запросе используется 2 Uniona. Создал пользовательский фильтр по строке в каждом select'е. В клиенте отображается 3 одноименных фильтра. Как обойти эту проблему? Буду благодарен за советы.

У меня такой же вопрос

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

Добрый день, Антон!

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

Спасибо

Антон, пожалуйста, предоставьте скриншот фильтр-билдера.

Выкладываю скрин:
FilterBuilder

Антон, спасибо за скриншот. Ваше обращение передано в департамент разработки. По факту предоставления решения мы с Вами свяжемся.

Вот решали эту проблему здесь

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

Антон, проблема рассматривается на уровне департамента разработки. Планируемый срок предоставления решения - 13.01.2014

Хорошо, спасибо, буду ждать

Антон, Вам необходимо в скрипте своего раздела в нужном месте подставить функцию очистки пользовательских фильтров, как описано здесь

Мне вот интересно, я 25 декабря писала эту ссылку, как сказано:

"Каневский Антон Владимирович" написал:Решение проблемы специфическое, относится к определенному скрипту в Проектах.

Но все-таки это оно и есть?

Пробую, как Вы сказали... Сопоставить раздел Проекты и применить это в своем, не получается. Можно, в общих чертах, описать, что нужно сделать с моими select'ами в коде?

Такое поведение компонента FiltersBuilder связано с логикой построения запросов. В компонент последовательно выводятся фильтра из SelectQuery dataset’а. Т.к. в запросе есть Union, согласно ядровой логики, пользовательские запросы добавляются для каждого select’а, т.е. 1 – union = 2 раза, 2 – union’а = 3 раза и т.д. Проблема решается конфигурационно, путём очистки пользовательских фильтров. Указанное решение рекомендуем применить, например, на BeforeOpen dataset’а грида.

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

Антон, добрый день.

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

Конечно, было бы замечательно, если бы в дальнейших сборках учли эту особенность фильтров.
Кстати, версия TS XRM 3.4.0.130.
Задачу решил так: вытянул в sq sql text column, в которую вытягиваю необходимые данные (в моем случае это данные с детали моего раздела) , по которым хочу фильтровать. В датасет запроса добавляю поле с соответствующим типом. Для меня вопрос закрыт, всем спасибо

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

Terrasoft CRM 3.4.1
При синхронизации стало вылезать окно, что запись дублируется:

Идет синхронизация контрагентов по коду и по ИНН, эти поля у записей в 1С и террасофте совпадают, т.е. должно идти обычное обновление/изменение записи.
Но даже если я закрываю появившееся окно, или нажимаю "Сохранить новую запись", новая запись не появляется, а старая спокойно обновляется, т.е. от этого окна мне нет толка. А при автоимпорте точно также вылезает это окно, но так как происходит фоново, то я этого не вижу, а автосинхронизация дальше не идет.
Как сделать чтобы оно не выводилось, т.е. в каком скрипте, какую строчку закомментировать или же можно обойтись нескриптовыми средствами?

У меня такой же вопрос

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

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

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

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

Подскажите пожалуйста. Вопрос у меня по работе с БД.
Необходимо осуществить добавления в БД не повторяющихся данных из файла. Как получить данные из файла и добавить я разобрался. Добавление делаю с помощью insert:

if (????????){
var insert = new Insert(UserConnection)
  .Into("ConfItemsCode")
  .Set("Name", Column.Const(str));
  insert.Execute();
}

Но передо добавлением в БД мне надо проверить есть ли в этой таблице уже такая запись. Делаю это так:
var select = new Select(UserConnection)
  .Column("Name")
  .From("ConfItemsCode")
  .Where("Name").IsEqual(str); // пробовал и IsLike

str - это переменная типа string - данный из файла.
Вопрос: Как мне узнать есть ли в select какие -либо записи. Пробовал RowCount, HasCondition. Подскажите как это сделать правильно. Желательно получить int или bool для того чтобы проверить а только потом добавлять.

У меня такой же вопрос

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

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

Проще всего воспользоваться EnitySchemaQuery классом:

string Str = "test";
 
 
var manager = UserConnection.EntitySchemaManager;
var query = new EntitySchemaQuery(manager, "Account");
var currentAccountId = query.AddColumn(query.RootSchema.PrimaryColumn.Name);
var accountPhone = query.AddColumn("Name").Name;
query.Filters.Add(query.CreateFilterWithParameters(FilterComparisonType.Equal, "Name", Str));
var queryResult = query.GetEntityCollection(UserConnection);
if (queryResult.Count == 0) 
{
       var insert = new Insert(UserConnection)
  .Into("ConfItemsCode")
  .Set("Name", Column.Const(str));
  insert.Execute();
}

Дмитрий, спасибо. Все получилось

Войдите или зарегистрируйтесь, чтобы комментировать
Публикация

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

Причина тому - разные наборы колонок в сервисе таблицы и полей в реальной таблице в БД. Такие поля могли возникнуть при удалении ошибочно созданных колонок в сервисе tbl_... или же созданы при помощи СУБД для нужд какой-то интеграции или работы хранимой процедуры. Обычно такие невидимые поля никак не проявляются и никому не мешают, но попытка объединения дублей на такой таблице порождает ошибку "wrong number or types of arguments in call to".

Чтобы всё заработало, пришлось создать такие поля в сервисе таблицы. Во избежание конфликтов, изначальные поля с данными были переименованы, а после сохранения сервиса переименованы обратно:

ALTER TABLE "tbl_Account"
RENAME COLUMN "SecretField" TO "SecretField1";

--сохраняем в TSAdmin сервис таблицы с новой колонкой SecretField

ALTER TABLE "tbl_Account" DROP COLUMN "SecretField";

ALTER TABLE "tbl_Account"
RENAME COLUMN "SecretField1" TO "SecretField";

Такой подход можно использовать и при разворачивании пакета исправлений, включающего сервисы и SQL-запросы.

Если же скрытые поля явно не нужны, их можно просто удалить одной лишь командой:

ALTER TABLE "tbl_Account" DROP COLUMN "SecretField";

После исправления таблицы стоит заново сгенерировать для неё настройки поиска дублей.

Но лучше всего сразу создавать новые поля в таблицах Terrasoft только посредством TSAdmin или TSClient, а не средствами СУБД.

Поделиться

0 комментариев
Войдите или зарегистрируйтесь, чтобы комментировать
Публикация

Настраивая механизм поиска дублей в проекте на Terrasoft 3.X, работающем на базе Oracle, для таблицы контактов получал ошибку при попытке объединить дубли. При автоматической генерации хранимых процедур для объединения дублей возникло несоответствие порядка двух полей в таблице, что и привело к проблемам. В сгенерированной серверной логике они были в одном порядке, а на стороне клиентского приложения они перебирались в другом. Поля назывались, для примера, Com1 и Communication.

При этом ошибка воспроизводилась, если поиск дублей настраивали из клиента Terrasoft на одном компьютере и не воспроизводилась, если настраивали на другом. К сожалению или к счастью, первым компьютером был мой.

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

 SELECT   column_name,
                 data_type,
                 data_precision,
                 data_scale,
                 char_length,
                 char_used
          FROM   all_tab_columns
         WHERE   table_name = 'tbl_Contact'
                 AND owner = SYS_CONTEXT ('USERENV', 'CURRENT_SCHEMA')
      ORDER BY   column_name;

На первый взгляд безобидная строка

ORDER BY column_name

сортирует различно в зависимости от локали на компьютере, откуда запускаем TSClient или Toad!

На моём ПК, если посмотреть:

 SELECT * FROM nls_session_parameters;

Получим:

Цитата:
NLS_LANGUAGE RUSSIAN
NLS_TERRITORY RUSSIA
NLS_CURRENCY р.
NLS_ISO_CURRENCY RUSSIA
NLS_NUMERIC_CHARACTERS ,
NLS_CALENDAR GREGORIAN
NLS_DATE_FORMAT DD.MM.RR
NLS_DATE_LANGUAGE RUSSIAN
NLS_SORT RUSSIAN
NLS_TIME_FORMAT HH24:MI:SSXFF
NLS_TIMESTAMP_FORMAT DD.MM.RR HH24:MI:SSXFF
NLS_TIME_TZ_FORMAT HH24:MI:SSXFF TZR
NLS_TIMESTAMP_TZ_FORMAT DD.MM.RR HH24:MI:SSXFF TZR
NLS_DUAL_CURRENCY р.
NLS_COMP BINARY
NLS_LENGTH_SEMANTICS BYTE
NLS_NCHAR_CONV_EXCP FALSE

Вот из-за чего проблема! Надо использовать вместо RUSSIAN режим сортировки BINARY, где цифры расположены впереди латинских букв. А в RUSSIAN – позади. И в хранимке для объединения дублей передаются поля таблицы не в том порядке, что в ядре программы-клиента. Использование функции NLSSORT принудительно сортирует нужным образом.

Проблемная строка была заменена на:

      ORDER BY  NLSSORT(column_name, 'NLS_SORT=BINARY');

Модификации подверглись tsp_GenerateSearchSP, tsp_GenerateLiveSearchSP, tsp_GenerateDuplicateSearch, и tsp_GenerateDuplicateMerge. В новых версиях Terrasoft 3.X изменение внесено, остальным рекомендую исправить самостоятельно.

Поделиться

0 комментариев
Войдите или зарегистрируйтесь, чтобы комментировать
Вопрос

Существует задача, есть контрагент 1 и контрагент 2, по ним есть ссылки в других таблицах(проекты, Задачи...) вдруг поняли что это одинаковые контрагенты(такое часто бывает), и нужно чтоб контрагент 2 стал тоже контрагентом 1 (слился). Есть поиск дублей функция Terrasoft с помощь которой можно руками все поправить, а вот если не руками, а автоматически у нас от внешней системы придут параметры о задвоении (процедура SQL) "параметр сливаемого"=контрагент 2 и "параметр на кого перекидывать ссылки (в кого сливаем)"=контрагент 1. Перед удалением ненужного котрагента (сливаемого), нужно все ссылки по нему привязать на другово контрагента как это можно реализовать?

У меня такой же вопрос

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

В конфигурации слияние дублей реализовано в скрипте scr_MergeDuplicates в функции DoMerge().
Вы можете использовать ее же, но передав параметры те, которые Вам нужны. Функция Merge в конфигурации вызывается по нажатию на кнопку ОК в обработчике btnMergeOnClick того же скрипта. Вы можете сделать подготовку параметров и вызвать ее же в автоматическом режиме.

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

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

Заранее спасибо!

У меня такой же вопрос

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

Данная тема уже подымалась на комьюнити. Насколько я знаю готовых решений нет. Вам следует посмотреть реализации алгоритмов "нечеткого поиска" на других интернет ресурсах, например на SQL.ru

Наверное, не совсем правильно описал проблему.
Хочу получить в списке дублей такие же результаты, как если в Настройках пользователя -> Общие -> Быстрый фильтр, фильтра типа like имеет значение "Включает" или по умолчанию).
И при сохранении КА выполнялась проверка существование подобных записей по типу:

WHERE (Name LIKE N'%' + @name + N'%')

Но я не знаю, где именно реализована эта проверка. Подскажите пожалуйста.

Спасибо.

McCoy, привожу пример реализации поиска дублей по like. К сожалению, из-за ограничения во времени пример доработан не полностью: дубли находит, но некорректно отображает их количество в реестре родительской детали (всегда равно 1). Но думаю, для примера пока будет достаточно и этого.

Для реализации необходимой Вам функциональности нужно следующее:

1. По аналогии с функцией AddDetailFilter скрипта scr_SubjectDuplicates, необходимо создать свою функцию, использующую Like-фильтр, и использовать её вместо AddDetailFilter в скриптах поиска дублей:

function AddDetailFilterLike(Select, Dataset, DataFieldName) {
	var DataField = Dataset.DataFields.ItemsByName(DataFieldName);
	var Filters = Select.Filters;
	var CompareFilter = AddLikeFieldFilter(Select, DataFieldName, DataFieldName, ltContain, Filters);
}

2. По аналогии с функцией AddCountCompareFilter скрипта scr_DuplicatesUtils создать свою функцию и использовать её вместо вышеуказанной:

function AddCountCompareFilterLike(ExpressionFilters, ParentFromTable, 
	ParentFromTableAlias, SelectFromTable, SelectFromTableAlias, 
	CheckFieldName) {
	var TestField = ParentFromTable.Fields.ItemsByName(CheckFieldName);
	var ValueField = SelectFromTable.Fields.ItemsByName(CheckFieldName);
	var CompareFilter = ExpressionFilters.CreateLikeFilter();
	CompareFilter.Code = GenNewKeyValueFromCollection(ExpressionFilters, 'LikeFilter');
	ExpressionFilters.Add(CompareFilter);
	CompareFilter.TestExpression = AddFieldExpression(ExpressionFilters, 
		CompareFilter, TestField, SelectFromTableAlias);
	CompareFilter.LikeType = ltContain;
	CompareFilter.ValueExpression = AddFieldExpression(ExpressionFilters, 
		CompareFilter, ValueField, ParentFromTableAlias);
	return CompareFilter;
}

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

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Спасибо!

Пожалуйста :).

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

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Войдите или зарегистрируйтесь, чтобы комментировать
Публикация

Долго не мог понять, почему если я вношу телефон в "Средство связи 1", а такой же указан в "Средство связи 2" другого контакта, то CRM меня не предупреждает?
Вижу, не только меня этот вопрос интересует...
http://community.terrasoft.ua/forum/topic/4121
Как можно решить?

Мой вариант (предлагаю использовать процедуру, для быстроты поиска)

CREATE PROCEDURE [dbo].[tsp_CheckForDoublet] (
        @ID AS uniqueidentifier,
        @Communication1 AS nvarchar(250),
        @Communication2 AS nvarchar(250),
        @Communication3 AS nvarchar(250),
        @Communication4 AS nvarchar(250),
        @NumOfDigits AS int,
        @ReturnResult AS int = 0 OUTPUT
        )
AS

SET @ReturnResult = 0

IF EXISTS (SELECT [ID] FROM [dbo].[tbl_Contact] WHERE
[ID] @ID AND (  
RIGHT(REPLACE(REPLACE([Communication1], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4)
OR
RIGHT(REPLACE(REPLACE([Communication2], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4)
OR
RIGHT(REPLACE(REPLACE([Communication3], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4)
OR
RIGHT(REPLACE(REPLACE([Communication4], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4)
) ) SET @ReturnResult = 1

RETURN

Процедура вылавливает дубли даже с тире и пробелами :lol:
8-032-229-99-99 и 2299999 - в данном случае считаются дублями. Если Вас это не устраивает, просто в параметр NumOfDigits большое количество символов для обработки

CreateSPParameter(Parameters, 'NumOfDigits', pdtInteger, 12);

Добавим права доступа на запуск данной процедуры группой "Все пользователи"

Правим событие в файле scr_Contact

function SelfOnDatasetBeforePost(Dataset, DoPost) {

..........
/* START */
        var Parameters = CreateSPParameters();
        CreateSPParameter(Parameters, 'ID', pdtGUID, Dataset('ID'));
        CreateSPParameter(Parameters, 'Communication1', pdtString, Dataset('Communication1'));
        CreateSPParameter(Parameters, 'Communication2', pdtString, Dataset('Communication2'));
        CreateSPParameter(Parameters, 'Communication3', pdtString, Dataset('Communication3'));
        CreateSPParameter(Parameters, 'Communication4', pdtString, Dataset('Communication4'));
        CreateSPParameter(Parameters, 'NumOfDigits', pdtInteger, 7); //количество символов
        CreateSPParameter(Parameters, 'isDoublet', pdtInteger, 0);
        Parameters.ItemsByName('isDoublet').ParamType = 1;
        var SQLText = 'exec dbo.tsp_CheckForDoublet :ID, :Communication1, :Communication2, :Communication3, :Communication4, :NumOfDigits, :isDoublet OUTPUT';
        Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
        var isDoublet = Parameters.ItemsByName('isDoublet').ValAsInt;  
        if (isDoublet == 1) {
                var Message = 'Дублируются средства связи!';
                ShowWarningDialog(Message);
                DoPost.Value = false; // не сохранять в базу
        }
/* END */
}

Доработки - возвращать массив ID и заполнять реестр нового окна ссылками на контактов, с возможностью "перейти к" (В данном варианте мы не знаем где именно дубль, но зато проверяем по всей базе, даже если отсутствуют права на чтение)

Развиваем идею здесь!

Поделиться

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

"Виталий Ковалишин aka samael" написал:но зато проверяем по всей базе, даже если отсутствуют права на чтение

:twisted:

"Underscore a.k.a. _" написал::twisted:

Спасибо! А "плюс Адин" где? :wink:

--
www.it-sfera.com.ua

Сорри, забыл. Плюсанул :)

Оооо, другое дело!

Спасибо! :biggrin:

--
www.it-sfera.com.ua

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

SelfOnDatasetBeforePost

BeforePost может же быть и при редактировании существующей записи.

Согласен!
Нужно добавить проверку на ID :wink:
подправим...

--
www.it-sfera.com.ua

"Раловец Ольга" написал:BeforePost может же быть и при редактировании существующей записи.

Да что Вы говорите /*шепотом так и с большими круглыми глазами*/ :) Но проверка дублей делается только при вставке, или я ошибаюсь?

"Underscore a.k.a. _" написал:Но проверка дублей делается только при вставке, или я ошибаюсь?

"Да что Вы говорите" (с) я вижу вызов процедуры прямо в обработчике события DatasetBeforePost, или я ошибаюсь?

Там жирных 10 точек стоит перед вызовом, или я ошибаюсь?

Не ошибаетесь, ровно 10.

"Underscore a.k.a. _" написал:Там жирных 10 точек стоит

Надо же посчитали :)
Ну и что что точки?
Нигде не написано, что проверку делать надо только при вставке записи. Кроме того это логически не правильно. Проверку делать надо и при обновлении записи.

"Агутин Алексей" написал:Проверку делать надо и при обновлении записи.

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

"Раловец Ольга" написал:Не ошибаетесь, ровно 10.

Учите матчасть, мадам. Ну и не ленитесь смотреть в исходники.

Поулыбался над комментами :smile:

Виталий, огромное спасибо.
Но нубский вопрос - Куда вставлять данную процедуру?
И можно полностью разжевать, а?
______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

Как малые дети! :lol:

1. Проверка и так на стороне сервера (процедуры), не должно быть напрягов :)
2. Можно не на датасет а на карточку повесить, тогда она не будет закрываться (как это сейчас происходит и мы заново должны все набирать из-за одного телефона)
3. Да, точек 10 - но это случайно получилось
4. Сегодня постараюсь подправить процедуру на проверку по ID (вместо баловства - могли бы и помочь) -- уже подправил
5. После - полностью разъясню куда и что вставить (я о процедуре) :)

Спасибо, не ожидал такого бурного обсуждения! :biggrin:

--
www.it-sfera.com.ua

"Евгений Лемеш" написал:Поулыбался над комментами

Видать вчера магнитные бури были. Сам себе удивляюсь :)

"Биккинин Т.Р." написал:Куда вставлять данную процедуру?

Вам необходимо открыть SQL Server Management Studio на сервере и выполнить данный скрип - процедура будет создана. После, добавить права доступа (иначе, только Supervisor сможет нею воспользоваться):

GRANT EXECUTE ON PROCEDURE [dbo].[tsp_CheckForDoublet] TO public

Дальше код в админке :)

Это быстрое решение, для большего удобства пользования, оно еще нуждается в доработке... :lol:

--
www.it-sfera.com.ua

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

 
GRANT EXECUTE ON PROCEDURE [dbo].[tsp_CheckForDoublet] TO public 

выдает следующее:
Server: Msg 156, Level 15, State 1, Line 1
Incorrect syntax near the keyword 'PROCEDURE'.

Что я делаю не так?
______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

GRANT EXECUTE ON [dbo].[tsp_CheckForDoublet] TO public 

А так?

Копи-пейст он до добра не доводит :)

Ольга,

Server: Msg 208, Level 16, State 11, Line 1
Invalid object name 'dbo.tsp_CheckForDoublet'.

______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

С помощью скрипта Виталия процедура создалась успешно, правильно я понимаю? Убедитесь, что она действительно существует, и что grant execute... Вы выполняете для той же базы данных.

Ольга,

в том то и дело, что процедура создалась успешно, только я не понял для какой именно базы. на сервере у меня их 3 лежит. Таким же образом добавляю grant execute, но она не проходит. ______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

Для начала нужно определиться с именем нужной базы данных :) Приблизительная последовательность действий: открываем SQL Server Management Studio, подключаемся к серверу, далее слева в инспекторе объектов разворачиваем ветку "Databases" и останавливаемся на той, в которой хотим создать процедуру. Далее нажимаем кнопочку "New Query", откроется окно редактирования и появится еще одна строчка в меню, там будет выпадающий список, в котором выбрана та база данных, на которой мы стояли в инспекторе объектов. Если сразу нажать "New Query", то будет выбрана бд "master".

Ольга, спасибо. Пошел проверять. Отпишусь позднее.
______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

Вот, что называется отсутствие знаний!
Ольга, все сделал, как Вы сказали, обе процедуры прошли успешно. Добавил функцию в скрипт scr_Contact, но новая функция не работает.
Вот так выглядит теперь функция SelfOnDatasetBeforePost:

function SelfOnDatasetBeforePost(Dataset, DoPost) {
	var ContactsDataset = Dataset;
	Contact.NeedActualizeCommunication = GetFieldsValuesAreChanged(Dataset,
		'Communication1', 'Communication2', 'Communication3',
		'Communication4', 'Communication1TypeID', 'Communication2TypeID',
		'Communication3TypeID', 'Communication4TypeID');
	Contact.NeedActualizeAddress = GetFieldsValuesAreChanged(Dataset, 'Address',
		'CountryID', 'AddressTypeID', 'StateID', 'CityID', 'TerritoryID');
	Contact.NeedActualizeCareer = GetFieldsValuesAreChanged(Dataset, 'AccountID',
		'JobID','JobTitle','DepartmentID');
	/* MODULE CAMPAIGNS */
	Contact.NeedActualizeCampaign = GetFieldsValuesAreChanged(Dataset,
		'CampaignID');
	/* ENDMODULE CAMPAIGNS */
	if(!IsEmptyValue(Dataset.Values('AccountID')))
	{
	Dataset.Values('WorkName') = Dataset.Values('Name')+' , '+GetDatasetFieldValueByID('ds_Account',Dataset.Values('AccountID'),'Name');
	}
	else
	{
	Dataset.Values('WorkName') = Dataset.Values('Name');
}
 
        Contact.IsAppend = (Dataset.State == dstInsert);  
        //SetItemSystemNumber('Contact', Dataset, 'ClientNumber');
 
    var Parameters = CreateSPParameters();
        CreateSPParameter(Parameters, 'ID', pdtGUID, Dataset('ID'));
        CreateSPParameter(Parameters, 'Communication1', pdtString, Dataset('Communication1'));
        CreateSPParameter(Parameters, 'Communication2', pdtString, Dataset('Communication2'));
        CreateSPParameter(Parameters, 'Communication3', pdtString, Dataset('Communication3'));
        CreateSPParameter(Parameters, 'Communication4', pdtString, Dataset('Communication4'));
        CreateSPParameter(Parameters, 'NumOfDigits', pdtInteger, 7); //количество символов
        CreateSPParameter(Parameters, 'isDoublet', pdtInteger, 0);
        Parameters.ItemsByName('isDoublet').ParamType = 1;
        var SQLText = 'exec dbo.tsp_CheckForDoublet :ID, :Communication1, :Communication2, :Communication3, :Communication4, :NumOfDigits, :isDoublet OUTPUT';
        Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
        var isDoublet = Parameters.ItemsByName('isDoublet').ValAsInt;  
        if (isDoublet == 1) {
                var Message = 'Дублируются средства связи!';
                ShowWarningDialog(Message);
                DoPost.Value = false; // не сохранять в базу
        }    
}

Что неправильно?
______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

Я вот подумала, что не очень-то хорошо прописывать строки, среди которых есть вывод сообщения пользователю в скрипте датасета. Лучше сделать это в скрипте карточки (scr_ContactEdit). Открываете окно wnd_ContactEdit, переходите на закладку не визуальные(в левой верхней стороне), становитесь на dlData, ниже среди событий находите OnDatasetBeforePost, нажимаете 2 раза и пишете

if (Dataset.State == dstInsert) {
var Parameters = CreateSPParameters();
        CreateSPParameter(Parameters, 'ID', pdtGUID, Dataset('ID'));
        CreateSPParameter(Parameters, 'Communication1', pdtString, Dataset('Communication1'));
        CreateSPParameter(Parameters, 'Communication2', pdtString, Dataset('Communication2'));
        CreateSPParameter(Parameters, 'Communication3', pdtString, Dataset('Communication3'));
        CreateSPParameter(Parameters, 'Communication4', pdtString, Dataset('Communication4'));
        CreateSPParameter(Parameters, 'NumOfDigits', pdtInteger, 7); //количество символов
        CreateSPParameter(Parameters, 'isDoublet', pdtInteger, 0);
        Parameters.ItemsByName('isDoublet').ParamType = 1;
        var SQLText = 'exec dbo.tsp_CheckForDoublet :ID, :Communication1, :Communication2, :Communication3, :Communication4, :NumOfDigits, :isDoublet OUTPUT';
        Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
        var isDoublet = Parameters.ItemsByName('isDoublet').ValAsInt;  
        IF (isDoublet == 1) {
                var Message = 'Дублируются средства связи!';
                ShowWarningDialog(Message);
                DoPost.Value = false; // не сохранять в базу
        }    
}
}

Ольга, спасибо.
Заработало. Результатом является появление диалогового сообщения, причем повторного и карточка не сохраняется. И при этом система не различает телефон 123456, 123-456, 12-34-56 и 123 456. По идее должно же?

______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

"Биккинин Т.Р." написал:Результатом является появление диалогового сообщения, причем повторного и карточка не сохраняется.

Что значит повторного? Вы, наверное, не убрали из скрипта датасета то, что внесли до того, как я посоветовала редактировать scr_ContactEdit.
"Биккинин Т.Р." написал:И при этом система не различает телефон 123456, 123-456, 12-34-56 и 123 456. По идее должно же?

Судя по тому, что написал Виталий, должно считать их одним и тем же.
"Виталий Ковалишин aka samael" написал:Процедура вылавливает дубли даже с тире и пробелами :lol:
8-032-229-99-99 и 2299999 - в данном случае считаются дублями. Если Вас это не устраивает, просто в параметр NumOfDigits большое количество символов для обработки

Еще обратите внимание, что проверка выполняется только при попытке сохранить новую запись.

Ольга,

"Раловец Ольга" написал:Что значит повторного? Вы, наверное, не убрали из скрипта датасета то, что внесли до того, как я посоветовала редактировать scr_ContactEdit.
Да, действительно не удалил.
[br]
"Раловец Ольга" написал:Судя по тому, что написал Виталий, должно считать их одним и тем же.
Походу не считает, даже если дубль записывается в то же поле "средство связи".
[br]
"Раловец Ольга" написал:Еще обратите внимание, что проверка выполняется только при попытке сохранить новую запись.
Так оно и есть, тем не менее, что-то здесь с тире и пробелами не так.

______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

В качестве примера:
Есть карточка, с телефонов 379007 в поле "Средство связи 1".
Если я создаю другую карточку с телефоном 379-007 или 379 007 в этом же поле, то система не воспринимает это как дубль и карточку сохраняет.
______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

Добрый день!

Проверил - считает дублями записи 2233445 и 22-33-44-5!
У Вас 6-ти значные номера телефонов? Попробуйте заменить

CreateSPParameter(Parameters, 'NumOfDigits', pdtInteger, 7); //количество символов

На:

CreateSPParameter(Parameters, 'NumOfDigits', pdtInteger, 6); //количество символов

--
www.it-sfera.com.ua

Как-то странно отрабатывает:
1) Не различает 123456, 1-23-456, 12 34 56. При этом абсолютно одинаковые номера отлавливает.
2) Если одно или более средств связи остаются пустыми, срабатывает как на дубль;
3) Не проверяет средства связи не отображенные в карточке.

"Виталий Ковалишин aka samael" написал:У Вас 6-ти значные номера телефонов? Попробуйте заменить

В системе хранятся номера с различным кол-вом знаков, каким тогда задавать параметр NumOfDigits?

"Виталий Ковалишин aka samael" написал:Это быстрое решение, для большего удобства пользования, оно еще нуждается в доработке...

Я написал как пример реализации. Вы можете внести свой вклад в развитие идеи и ее совершенствования (Доработки - читали? А никто так ничего и не предложил...)

"Виталий Ковалишин aka samael" написал:вместо баловства - могли бы и помочь

Welcome to OpenSource :) Развиваем!

--
www.it-sfera.com.ua

Подтверждаю слова Олега.
Все аналогично
______________
www.abs.com.kz
Агентство недвижимости АБС Royal Estate

"Виталий Ковалишин aka samael" написал:Я написал как пример реализации. Вы можете внести свой вклад в развитие идеи и ее совершенствования

Сорь, упустил этот момент.:biggrin:

У меня предварительно получилось что-то такое:
1) Хранимка

CREATE PROCEDURE [dbo].[tsp_CheckForDoublet] (
        @ID AS uniqueidentifier,
        @Communication1 AS nvarchar(250),
        @Communication2 AS nvarchar(250),
        @Communication3 AS nvarchar(250),
        @Communication4 AS nvarchar(250),
        @ReturnResult AS int = 0 OUTPUT
        )
AS
 
SET @ReturnResult = 0
SET @Communication1 = REPLACE(REPLACE(@Communication1, '-', ''), ' ', '')
SET @Communication2 = REPLACE(REPLACE(@Communication2, '-', ''), ' ', '')
SET @Communication3 = REPLACE(REPLACE(@Communication3, '-', ''), ' ', '')
SET @Communication4 = REPLACE(REPLACE(@Communication4, '-', ''), ' ', '')
 
IF EXISTS (SELECT [ID] FROM [dbo].[tbl_ContactCommunication] WHERE 
[ContactID] <> @ID AND (  
REPLACE(REPLACE([Number], '-', ''), ' ', '') IN (@Communication1, @Communication2, @Communication3, @Communication4)
) ) SET @ReturnResult = 1
 
RETURN
GO

2) Функция:

function CheckContactCommunication(Dataset) {
	var Parameters = CreateSPParameters();
	CreateSPParameter(Parameters, 'ID', pdtGUID, Dataset.ValAsGUID('ID'));
	CreateSPParameter(Parameters, 'Communication1', pdtString, 
		Dataset.ValAsStr('Communication1'));
	CreateSPParameter(Parameters, 'Communication2', pdtString, 
		Dataset.ValAsStr('Communication2'));
	CreateSPParameter(Parameters, 'Communication3', pdtString,
		Dataset.ValAsStr('Communication3'));
	CreateSPParameter(Parameters, 'Communication4', pdtString,
		Dataset.ValAsStr('Communication4'));
	CreateSPParameter(Parameters, 'isDoublet', pdtInteger, 0);
    Parameters.ItemsByName('isDoublet').ParamType = 1;
    var SQLText = 'exec dbo.tsp_CheckForDoublet :ID,:Communication1,:Communication2,:Communication3,:Communication4,:isDoublet OUTPUT';
    Connector.DBEngine.ExecuteCustomSQL(SQLText, Parameters);
    var isDoublet = Parameters.ItemsByName('isDoublet').ValAsInt;   
    if (isDoublet == 1) {
        ShowWarningDialog('Дублируются средства связи!');
        return false;
    }
    return true;
}

3)Вызов функции:

function dlDataOnDatasetBeforePost(Dataset, DoPost) {
	if (!CheckContactCommunication(Dataset)) {
		DoPost.Value = false;
	}
}

Возник вопрос:
Если в процедуру добавляю еще один параметр, то выпадает ошибка:
Formal parameter 'такой-то' was defined as OUTPUT but the actual parameter not declared OUTPUT.
На сколько я смог понять, это связанно с типом параметра, но не могу понять как. Может кто-то сталкивался?

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

Parameters.ItemsByName('isDoublet').ParamType = 1;

Так в том то и вопрос что параметр входящий, а для них(входящих), я так понял, указывать тип не надо.

По умолчанию тип входящий. Может, каким-то образом порядок повлиял?

Действительно. Поставил параметр в описании первым и все заработало.:confused:

Я думаю, было бы удобно повесить этот алгоритм поиска на сервис проверки дублей, для поиска в уже введенных контактах.
Может кто подскажет, как это сделать.

Руслан, думаю, адаптировать проверку дублей в базовой версии для реализации данного функционала будет не совсем верно, так как он является универсальным для поиска по одному полю. Данный пример реализации таковым не является, так как с физической точки зрения поля Communication1 и Communication4 отличаются между собой так же, например, как Communication1 и Name.

Решить данную задачу можно, например, с помощью отдельного действия. Вначале придётся немного переработать хранимую процедуру, чтобы она возвращала все ID дубликатов для определённой записи. Например, так:

CREATE PROCEDURE [dbo].[tsp_CheckForDoublet]
			@ContactID uniqueidentifier,
			@NumOfDigits int
AS
begin
 
	declare @SecondID uniqueidentifier
	declare @ContactName nvarchar(250)
	declare @SecondName nvarchar(250)
	declare @Communication1 nvarchar(250)
        	declare @Communication2 nvarchar(250)
        	declare @Communication3 nvarchar(250)
        	declare @Communication4 nvarchar(250)
	create table #tmp (
		ID uniqueidentifier,
		ParentRecordID uniqueidentifier,
		ChildRecordID uniqueidentifier,
		ParentRecordValue nvarchar(250),
		ChildRecordValue nvarchar(250))
 
 
	SELECT @ContactName = [Name], @Communication1 = RIGHT(REPLACE(REPLACE([Communication1], '-', ''), ' ', ''), @NumOfDigits),
		@Communication2 = RIGHT(REPLACE(REPLACE([Communication2], '-', ''), ' ', ''), @NumOfDigits),
		@Communication3 = RIGHT(REPLACE(REPLACE([Communication3], '-', ''), ' ', ''), @NumOfDigits),
		@Communication4 = RIGHT(REPLACE(REPLACE([Communication1], '-', ''), ' ', ''), @NumOfDigits) FROM tbl_Contact
	WHERE [ID] = @ContactID
 
 
	declare c_Contact cursor for
		SELECT [ID], Name FROM [dbo].[tbl_Contact] WHERE
		[ID] <> @ContactID AND (  
		(RIGHT(REPLACE(REPLACE([Communication1], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4) and RIGHT(REPLACE(REPLACE([Communication1], '-', ''), ' ', ''), @NumOfDigits) <> '')
		OR
		(RIGHT(REPLACE(REPLACE([Communication2], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4) and RIGHT(REPLACE(REPLACE([Communication2], '-', ''), ' ', ''), @NumOfDigits) <> '')
		OR
		(RIGHT(REPLACE(REPLACE([Communication3], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4) and RIGHT(REPLACE(REPLACE([Communication3], '-', ''), ' ', ''), @NumOfDigits) <> '')
		OR
		(RIGHT(REPLACE(REPLACE([Communication4], '-', ''), ' ', ''), @NumOfDigits) IN (@Communication1, @Communication2, @Communication3, @Communication4) and RIGHT(REPLACE(REPLACE([Communication4], '-', ''), ' ', ''), @NumOfDigits) <> '')
		)
 
	open c_Contact
	while 1 = 1
	begin
		fetch next from c_Contact into @SecondID, @SecondName
		if @@fetch_status = -1 break
		if @@fetch_status = -2 continue
 
		insert into #tmp (ID, ParentRecordID, ChildRecordID, ParentRecordValue, ChildRecordValue)
		values (NewID(), @ContactID, @SecondID, @ContactName, @SecondName)
	end
 
	close c_Contact
	deallocate c_Contact
 
	select distinct ParentRecordID, ChildRecordID, ChildRecordValue from #tmp
	--where ParentRecordID = @ContactID
 
	drop table #tmp
 
end
GO

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

Олег Лабьяк,
разработчик,
3-я линия Службы поддержки Terrasoft.

Доброго времени суток!
Возникла необходимость реализовать поиск дублей в уже введенных контактах.
Подскажите пожалуйста, т.к. я новичок еще в доработках CRM, какие изменения возможно внести в уже готовый сервис поиска дублей для решения поставленной задачи или есть какое-то альтернативное решение?

Здравствуйте,
Подскажите какую версию Terrasoft вы используете ?
Ознакомьтесь, пожалуйста, с вложением "Настройка поиска дублей", такова реализация в 3.4.0

Здравствуйте.
Используется Terrasoft Press версии 3.3.0.45.
С вложением ознакомился, но видимо данный функционал в имеющейся версии не представлен.

Хатемкин В.А.
ОАО "Пилот-Медиа"

Функционал поиска дублей в существующих записях полноценно реализован начиная с версии 3.3.2

Для 3.3.0 его можно только дорабатывать вручную, а это довольно серьезный объем работы.

Алгоритм таков:

1. Создать зранимую процедуру поиска дублей в БД;
2. Создать интерфейсную часть в Terrasoft, которая позволила бы пользователям задавать настройки поиска и слияния дублей;
3. Интегрировать поиск дублей в систему.

В качестве примера поиска и слияния дублей могу привести процедуру поиска и слияния дублей в состояниях продажи для MSSQL.

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

Добрый день! В базовой версии имеется проверка на дубли Контактов и Контрагентов. Появилась необходимость в такой функциональности для проверки дублей в разделе "Продукты" - по имени продукта. Вопрос: возможно ли дописать своими силами еще такую проверку и насколько ресурскоёмко это будет? Заранее спасибо!

У меня такой же вопрос

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

Здравствуйте!
Мы проанализировали Ваш запрос и можем Вам сообщить следующее.
На самом деле Вы можете реализовать проверку дублирующихся значений в разделе продуктов. Проверку Вы можете осуществлять например, на нажатию на кнопку "ОК" карточки продукта. А именно, Вам необходимо добавить в запрос на выборку новый фильтр по названию продукта. Затем в обработчике события нажатия на кнопку "ОК" карточки продукта, необходимо "включить фильтр" (вызов функции ApplyDatasetFilter), а затем реализовать проверку наличия аналогичной записи и появление сообщения о наличии дублирующейся записи в датасете.
Как Вы наверное успели заметить, в приложении Terrasoft CRM настройка поиска дублирующихся значений по контактам и контрагентам осуществляется путем вызова окна. В том случае если Вам необходимо реализовать поиск дублирующихся значений аналогичным образом по продуктам, то это является значительной доработкой конфигурации приложения, реализовать которую у Вас есть возможность путем проектного решения специалистами отдела разработки Terrasoft.

Желаем удачи!

Спасибо за ответ! Пошёл вторым путём, доработал поиск дублирующихся записей

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

А нельзя ли поподробней объяснить реализацию первого метода? Необходимо фильтровать сразу по двум параметрам.
Не совсем понятно, как будет происходить фильтрация записей, если датасет уже отфильтрован и в нем находится только одна запись(которая только что была добавлена). Или я что-то путаю?

Спасибо!!!

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

Для реализации необходимой Вам функциональности требуется выполнить следующее:
1. В запросе на выборку SelectQuery раздела "Продукты" создать два фильтра сравнения CompareFilter по двум полям и с использованием необходимых параметров.
2. Затем в обработчике нажатия кнопки OK карточки Вам необходимо открыть новый датасет без фильтров (используя GetNewItemByUSI ('USI датасета продуктов')).
3. После открытия датасета необходимо применить созданные фильтры (ApplyDatasetFilter для каждого фильтра).
4. Затем открыть датасет Dataset.Open и проверить наличие в нем записей. По полученным результатам выполнить уже их обработку (либо запретить ввод значения, либо разрешить).

Terrasoft Support Team

Таким образом не удалось сделать, тк фильтры не применялись (запросы в базу не отправлялись).
Пошли другим путем. Использовали вот такую функцию:

function GetDatasetFilteredByParams(Dataset, Param1Name, Param1Val, Param2Name, Param2Val) {
var SelectQuery = Dataset.SelectQuery;
var PrimarySelect = GetSelectQueryPrimarySelect(SelectQuery);
EnableAllFilters(PrimarySelect.Filters, false);
EnableFilter(PrimarySelect.Filters, Param1Name, true);
EnableFilter(PrimarySelect.Filters, Param2Name, true);
SetParameterValue(SelectQuery.Parameters, Param1Name, Param1Val);
SetParameterValue(SelectQuery.Parameters, Param2Name, Param2Val);
var TempDataset = SelectQuery.Open();
EnableAllFilters(PrimarySelect.Filters, false);
EnableFilter(PrimarySelect.Filters, 'ID', true);
return TempDataset;
}

получилось громоздко, но результатом довольны. Функция вызывается из события BeforePost. Это показалось удобным, поскольку в случае дублирования записи свойству DoPost присваиваем false и запись в базу не идет.
Единственный вопрос, необходимо ли закрывать TempDataset? если да, то когда?

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

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

Terrasoft Support Team

Войдите или зарегистрируйтесь, чтобы комментировать