Вопрос

Здравствуйте, уважаемое сообщество!

В базе имеется много Контрагентов внесённых вручную, сделали интеграцию Контрагентов из 1С при помощи 1С Коннектора, естественно появились дубли

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

Вопрос, как повлиять на то какой объект оставить в системе во время объединения дублей, а какой удалить?

Проверяю следующим запросом к базе:

select * from Account where name = 'Высший Вкус ООО (ВВ)';
select * from SmrSyncHistory where localid in (select id from Account where name = 'Высший Вкус ООО (ВВ)');

 

До объединения:

 

После объединения:

 

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

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

Пока в стандартном механизме платформы нет выбора золотой записи.
В случае использования 1C Connector вы можете сразу настроить признак [Использовать для дедупликации] по полю Название, чтобы дубли вообще не создавались. Подробнее -https://samarasoft.com/docs/1c-connector/integration-setting-bpmonline/fields-mapping/

В стандартном механизме в качестве золотой берётся первое значение в коллекции. В схеме DeduplicationMergeHandler функция MergeEntityDublicates начинается так:

public void MergeEntityDublicates(string schemaName, int groupId, List<Guid> duplicateRecordIds, Dictionary<string, string> resolvedConflicts) {
	EntitySchema entitySchema = _userConnection.EntitySchemaManager.GetInstanceByName(schemaName);
	EntityCollection duplicates = GetEntityDublicates(schemaName, duplicateRecordIds);
	Entity goldenEntity = duplicates.FirstOrDefault();
	if (goldenEntity == null) {
		return;
	}
	duplicates.RemoveFirst();
	duplicateRecordIds.Remove(goldenEntity.PrimaryColumnValue);
	if (duplicates.Count == 0) {
		return;
	}

А коллекция отсортирована по дате создания, старые вначале:

public EntityCollection GetEntityDublicates(string schemaName, List<Guid> ids, List<string> columns = null) {
	EntitySchema schema = _userConnection.EntitySchemaManager
		.GetInstanceByName(schemaName);
	var esq = new EntitySchemaQuery(schema);
	if (columns == null) {
		esq.AddAllSchemaColumns();
	} else {
		esq.PrimaryQueryColumn.IsAlwaysSelect = true;
		if (!columns.Contains("CreatedOn")) {
			esq.AddColumn("CreatedOn");
		}
		foreach (string columnName in columns) {
			esq.AddColumn(columnName);
		}
	}
	esq.Filters.Add(esq.CreateFilterWithParameters(FilterComparisonType.Equal,
		esq.RootSchema.PrimaryColumn.Name, ids.Cast<object>()));
	EntityCollection entityCollection = esq.GetEntityCollection(_userConnection);
	entityCollection.Order("CreatedOn", OrderDirection.Ascending);
	return entityCollection;
}

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

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

Спасибо за советы, только сейчас пролучилось вернуться к этому кейсу

Я так понимаю что включать признак дедупликации в Коннекторе уже поздно, ну или чистить записи и проводить интеграцию заново

Хочу попробовать сделать по совету Зверева Александра, но не могу найти статью или ответы на комьюнити как правильно замещать "Исходный код", я так понял надо просто поменять Ascending на Descending.

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

Трефилов Павел Сергеевич,

ОМАЙГАДБЛ... всё гениальное просто, спасибо, попробую ))))))))

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

Sales Enterprise

Версия 7.13.3.481

Настраиваю новое правило поиска дублей по полю  "Основной телефон" согласно инструкции:
https://academy.terrasoft.ru/documents/technic-sdk/7-13/dobavlenie-pravila-poiska-dubley
Признак "Использовать правило при сохранении" установлен: https://yadi.sk/i/546AVOF8xgA95A

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

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

 

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

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

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

Правило отрабатывает корректно при глобальном поиске.
Дополнительных настроек кроме признака "Использовать при сохранении" в академии не нашёл.

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

Так же выявлено, что и базовые правила не отрабатывают при сохранении

Базовые правила должны отрабатывать при сохранении контакта и контрагента.

О сохранении Контрагента и идёт речь

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

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

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

Признак правила поиска "Использовать правило при сохранении" установлен.

Провел отладку: метод findDuplicates() модуля DuplicatesSearchUtilitiesV2 корректно передает данные в DeduplicationService.FindDuplicatesOnSave()

В свою очередь метод сервиса FindDuplicatesOnSave вызывает метод DeduplicationProcessing.FindDuplicates, из которого идет обращение к хранимой процедуре tsp_FindDuplicates.

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

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

В чем может быть проблема? Есть подозрение, что проблема появилась после перехода на версию 7.12

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

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

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

Если это сделано, дело ещё может быть в том, что в разделе Контакты есть несколько карточек редактирования. Работа в таком режиме была исправлена в 7.12.2.

Рекомендуем обновить до версии 7.12.2, после обновления проблема будет решена. А на версии 7.12.3 также работает поиск дублей при сохранении при создании контакта через мини-карточку.

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

Коллеги, выручайте. У меня были записи в разделе, которые создали разные контакты, но данные контакты по факту являются дубликатами.
Сделал поиск дубликатов для контактов, объединил найденные дубликаты. 

И получилось так, что у части записей затерлось поле "Создал", select возвращает данное поле со старым id создавшего, которого по факту уже нет так-как он объединился.

Как вернуть все обратно? Если возможность посмотреть логи дубликатов?

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

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

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

Добрый день!
 

Дедупликация записи - это не создание новой.
Фактически, Вы удаляете одну из записей, и обновляете значения оставшейся.

Вернуть результат дедупликации пользовательскими средствами нельзя.
Вы можете поднять бэкап БД до обновления и перенести значения CreatedBy при помощи запроса в БД.

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

Здравствуйте, хотел написать свое правило поиска дублей для контактов пример того как сделать взял с академии но во время выполнения скрипта появляется ошибка что переменная @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+, т.к.

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

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

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

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

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

Права на поиск и объединение дублей ограничены системной операцией "Поиск дублей"
Для решения:
1) Перейдите в "Дизайнер системы"
2) Перейдите в "Права доступа на операции"
3) Найдите операцию "Поиск дублей"
4) Выдайте права нужным пользователям.

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

подскажите, как повторить функционал поиска дублей, но для Лидов. Версия 7.5

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

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

Добрый день!
Лид в bpm'online - потребность клиента. Для одного и того же контакта/контрагента может быть несколько одинаковых лидов(потребностей) в разные промежутки времени. В случае поиска дублей лидов все эти потребности объединятся, что является логически некорректным.

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

предусмотрено ведение различных задач по различным продуктам для одного лида. поиск дублей должен производится по детали «Средства связи» (по полям, содержащим телефон, а также по полю «E-mail»).

Валентин, добрый день!

Функциональность поиска дублей по лидам уже присутствует в версии 7.7
В данном случае оптимальным решением является обновление до последней версии.

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

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

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

Для того, чтобы объединить дубли лидов необходимо выполнить следующие действия:
1) Создать процесс для поиска лидов (аналогично процессу StartGlobalContactDuplicatesSearch). Для поиска необходимо создать процедуру в базе данных, аналогичную tsp_GloballySearchForDuplicates. Код процедуры tsp_GloballySearchForDuplicates можно найти в конфигурации, перейдя на вкладку "SQL сценарии". Процедура будет записывать данные в созданный Вами объект LeadDuplicates (создайте объект по аналогии с объектом ContactDuplicate)

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

А теперь самое интересное - слияние лидов и удаление лишних. Так как удалить лид средствами системы не получится (связи, запущенный процесс...), то придется придумывать что-то новое.
Я бы в этот момент создавал бы новую запись лида и изменял данной записи значение в поле "Стадия" на нужное. Остальным дублям изменял бы стадию на "Дисквалифицирован" и указывал причину дисквалификации "Дубль".

Но лучше, наверное, обновиться до 7.7.0.:smile:

Спасибо.
Процесс StartGlobalContactDuplicatesSearch запускается в действии процесса StartGlobalDuplicatesSearch. Как теперь правильно заместить StartGlobalDuplicatesSearch, чтобы добавить в него запуск процесса StartGlobalLeadDuplicatesSearch? или если создать подобное действие процесса со своей логикой, где оно должно запускаться?

"Медведев Валентин Николаевич" написал:

Как теперь правильно заместить StartGlobalDuplicatesSearch, чтобы добавить в него запуск процесса StartGlobalLeadDuplicatesSearch?

Замещение процессов в системе не предусмотрено. Вам необходимо создать новый процесс и запускать его.

"Медведев Валентин Николаевич" написал:

или если создать подобное действие процесса со своей логикой, где оно должно запускаться?

Запускать новый процесс Вы можете, например, из библиотеки процессов (самая простая реализация). Также Вы можете добавить соответствующее действие в раздел "Лиды". Более подробно о создании действий, Вы можете прочитать в Академии.

имелось в виду
что собой и представляет StartGlobalDuplicatesSearch.

Добрый день!

Добавить соответствующее действие в раздел "Лиды" – подразумевается в замещающей странице редактирования лидов добавить новую кнопку в меню “Дейсвтия”. Также добавить обработчик, который будет запускать процесс по нажатию на эту кнопку.

StartGlobalDuplicatesSearch(Действие процесса) содержит сценарий:

string jobProcessName = (SchemaName == "Account") ? "StartGlobalAccountDuplicatesSearch" : "StartGlobalContactDuplicatesSearch";
AppScheduler.ScheduleImmediateProcessJob("DuplicatesSearchJob", "DuplicatesSearchGroup",
jobProcessName, UserConnection.Workspace.Name, UserConnection.CurrentUser.Name);
return true;

если я создам подобное, в котором переменная jobProcessName будет получать "StartGlobalLeadDuplicatesSearch", то где оно должно вызываться?

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

Этот код добавляет в планировщик Quartz процесс StartGlobalAccountDuplicatesSearch, если поиск осуществляется со схемы Account, StartGlobalContactDuplicatesSearch - при поиске с другой схемы.

Для Вашей задачи, Вы можете действие процесса заменить на следующее:

string jobProcessName = "StartGlobalLeadDuplicatesSearch";
AppScheduler.ScheduleImmediateProcessJob("DuplicatesSearchJob", "DuplicatesSearchGroup",
jobProcessName, UserConnection.Workspace.Name, UserConnection.CurrentUser.Name);
return true;

спасибо всем за помощь! разобрался.
теперь такой вопрос... можно ли изменить логику поиска дублей Лидов при импорте данных из Exel? например, чтобы телефоны "+7 (978) 123 12 31" и "+79781231231" считались совпадением. в каких модулях реализована стандартная логика?

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

При импорте из Excel записи +7 (978) 123 12 31 и +79781231231 действительно будут считаться разными записями. Проверка на тождественность этих записей не осуществляется.

При импорте из Excel Вы можете проверять уникальность по другим полям/признакам. Также непосредственно перед импортом Вы можете в файле Excel автозаменой символов "(", ")", " " на "".

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