Три года назад с целью автоматизации управления организационно-распорядительной документацией была приобретена система elma. Но после года эксплуатации стало понятно, что от нее придется отказаться.

Рассказ о том, как я ушел от elma к easla.com.

Прежде, чем приобрести elma был проведен тщательный анализ системы на адекватность поставленным задачам. Понравилось в системе следующее:
  • Современный веб-интерфейс
  • Возможность настройки бизнес-процессов с помощью блок-схем
  • Возможность написания кода на C#.

Жаль, что не смог увидеть подводных камней сразу. Не буду сильно вдаваться в подробности, но месяца через три после начала эксплуатации появились проблемы разного плана. Прежде всего, меня конечно беспокоили технические проблемы, например:
  • Крайне сложно именовать файлы объекта программно (помнится, техподдержка предложила для этого написать больше сотни строк кода в разных событиях), правда месяца через два разработчики исправили эту проблему.
  • Проблемы при создании процессов с ветвлениями. Был создан процесс рассмотрения входящего письма, который ветвился в соответствии с количеством ответственных исполнителей. Кода в процессе практически не было. Однако регулярно появлялись задачи-фантомы — я их так назвал. Назначено 5 задач, а получается 10. Решить проблему с помощью техподдержки не удалось и мне пришлось писать «костыли», которые уничтожали фантомов программно. Но все равно в непредсказуемых ситуациях они проявлялись.
  • Разработка новых процессов была возможна только на отдельном, тестовом сервере, для которого регулярно приходилось выпрашивать лицензию, т.к. она не включена в поставку. Готовый процесс приходилось вручную переносить с тестового сервера на боевой. При этом боевой сервер приходилось перезапускать. В рабочее время такое невозможно, что приводило к регулярному переносу рабочего времени на ночь.
  • Каждое обновление приносило свои исправления и свои баги. Однажды, обновление принесло баг, который был исправлен 2-3 обновления назад. Причем порой ошибки были смешные — детские. Например, два обновления подряд не могли главное меню развернуть на всю высоту браузера.

Были и другие проблемы. Но то, технические проблемы, которые конечных пользователей не касаются.
Однако и пользователи тоже регулярно жаловались на неудобства, например:
  • Поиск объектов осуществляется только на отдельной странице, что вроде бы логично, и даже критерии поиска можно вводить весьма сложные, но для конечного пользователя этот функционал оказался неудобным. Все давно привыкли, что искать удобно указывая критерии в шапке таблицы, а переход на отдельную страницу и многоходовой ввод критериев вызывал недовольство и отторжение.
  • Elma, работая в локальной сети, начала удивлять своей задумчивостью. Мы изучили систему изнутри. Оказалось, что для каждого объекта система создает отдельную таблицу и еще кучку смежных таблиц для хранения данных, т.е. торможения быть не должно. Однако, когда количество записей каждого объекта превысило тысяч пять, тормоза стали заметны на интуитивном уровне. Странички со списком открывались несколько секунд.

После года эксплуатации elma стало понятно, что система приведет организацию в тупик. Мы не сможем реализовать на ней другие процессы без деградации производительности. И нет гарантии, что реализовав процессы, они будут работать стабильно, учитывая постоянно «вылезающие баги». Все преимущества системы сошли на нет.

Поиск


Был осуществлен поиск системы взамен elma. Одним из критериев поиска была ее бесплатность или дешевизна, т.к. руководство организации не хотело тратиться на покупку новой системы, а мне, как руководителю отдела ИТ принявшему в свое время решение о приобретении elma и обосновав ее приобретение было стыдно в очередной раз просить деньги на тоже самое. Также, в списке критериев были:
  • Привычный пользователю веб-интерфейс
  • Разработка и изменение процессов в реальном времени
  • Гибкость хранения файлов
  • Возможность импорт данных из elma в новую систему.

Как раз easla.com подошла по всем пунктам.

Разработка


После регистрации в системе начал разработку соответствующих бизнес-процессов. Причем атрибуты объектов пришлось реализовывать так, чтобы они могли принимать импортируемые данные из elma.
Потребовалось реализовать четыре процесса:
  • Заказчики
  • Договоры
  • Переписка
  • Задачи.

Процесс "Заказчики" сложно назвать процессом. У объектов нет даже статусов. Фактически – это каталог контрагентов и контактов связанных между собой. Но контрагент отличается от всех других объектов числом атрибутов. Он позволяет хранить не только наименование, но и юридический, и почтовый адреса, а также банковские реквизиты. Всего 40 атрибутов! Контакт – это физическое лицо являющееся сотрудником контрагента.
Процесс «Договоры» в тот момент тоже представлял собой простой каталог договоров. Он был нужен исключительно для классификации писем.
Процесс "Переписка" – очень важный для организации процесс. Он управляет официальной входящей и исходящей корреспонденцией, которая влияет на принятие технических решений и участвует в разрешении конфликтных ситуации в суде. Входящие письма могут принести убытки из-за несвоевременного рассмотрения или ответа. Исходящие письма могут приносить шести-, а иногда и семизначную прибыль при их своевременной отправке. Важными отличиями объекта «Исходящий документ» являются:
  • Способ хранения файла письма
  • Способ хранения прилагаемых документов
  • Возможность разработки письма онлайн
  • Возможность отправки письма одним из десятка способов.

Процесс "Задачи" важен точно также, как «Переписка», т.к. является его логическим продолжением. С помощью задач осуществляется контроль исполнения поручений по каждому входящему или исходящему документу. Кроме этого, в каждой задаче осуществляется регистрация трудозатрат в минутах и связка с входящим и исходящим письмом.
Разработку процессов закончил за месяц и встал вопрос собственно импорта данных. Но прежде – экспорта из elma.

Экспорт-импорт


Импорт в easla.com обладает некоторыми особенностями, которые надо учитывать:
  • Первая строка файла с данными может содержать обозначения атрибутов
  • Можно импортировать только 1000 записей за один раз
  • Нескольких значений для одного атрибута надо разделить символом "|"
  • Импортируемые файлы должны иметь разные имена.

Штатных средств выгрузки данных из elma не нашел, поэтому пришлось лезть в базу данных. В базе elma море разных таблиц, необходимые таблицы были найдены интуитивно. Все-таки программисты мыслят одинаково.
Начал экспорт с простых объектов. Сперва контрагенты. Написал вот такой SQL запрос:
ELMA_export_contragents.sql
SELECT DISTINCT 
	   [ELMA].[dbo].[Contractor].[Name] AS [crm_management_contragent_name]
	  ,[LF].[LongName] AS [crm_management_contragent_opf]	  
      ,[ELMA].[dbo].[ContractorType].[Name] AS [crm_management_contragent_type]
      ,[Site] AS [crm_management_contragent_url]
      ,[crm_management_contragent_email] = STUFF((
		SELECT '|' + [ELMA].[dbo].[Email].[EmailString]
		FROM [ELMA].[dbo].[Contractor_Email]
		LEFT OUTER JOIN [ELMA].[dbo].[Email] ON [ELMA].[dbo].[Email].[Id] = [ELMA].[dbo].[Contractor_Email].[Email]
		WHERE [ELMA].[dbo].[Contractor_Email].[Contractor] = [ELMA].[dbo].[Contractor].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
	  ,[Fax] AS [crm_management_contragent_fax]	
      ,[crm_management_contragent_phone] = STUFF((
		SELECT '|' + [ELMA].[dbo].[Phone].[PhoneString]
		FROM [ELMA].[dbo].[Contractor_Phone]
		LEFT OUTER JOIN [ELMA].[dbo].[Phone] ON [ELMA].[dbo].[Phone].[Id] = [ELMA].[dbo].[Contractor_Phone].[Phone]
		WHERE [ELMA].[dbo].[Contractor_Phone].[Contractor] = [ELMA].[dbo].[Contractor].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
      ,[LAC].[Name] AS [crm_management_contragent_legal_country]
      ,[LA].[Region] AS [crm_management_contragent_legal_region]
      ,[LA].[District] AS [crm_management_contragent_legal_district]
      ,[LA].[City] AS [crm_management_contragent_legal_city]
      ,[LA].[Locality] AS [crm_management_contragent_legal_locality]
      ,[LA].[Street] AS [crm_management_contragent_legal_street]
      ,[LA].[Building] AS [crm_management_contragent_legal_house]
      ,[LA].[Stroenie] AS [crm_management_contragent_legal_building]
      ,[LA].[Korpus] AS [crm_management_contragent_legal_corp]
      ,[LA].[Appartment] AS [crm_management_contragent_legal_apartment]
      ,[LA].[Zip] AS [crm_management_contragent_legal_postcode]     
      ,[PAC].[Name] AS [crm_management_contragent_post_country]
      ,[PA].[Region] AS [crm_management_contragent_post_region]
      ,[PA].[District] AS [crm_management_contragent_post_district]
      ,[PA].[City] AS [crm_management_contragent_post_city]
      ,[PA].[Locality] AS [crm_management_contragent_post_locality]
      ,[PA].[Street] AS [crm_management_contragent_post_street]
      ,[PA].[Building] AS [crm_management_contragent_post_house]
      ,[PA].[Stroenie] AS [crm_management_contragent_post_building]
      ,[PA].[Korpus] AS [crm_management_contragent_post_corp]
      ,[PA].[Appartment] AS [crm_management_contragent_post_apartment]
      ,[PA].[Zip] AS [crm_management_contragent_post_postcode]
      ,[INN] AS [crm_management_contragent_inn]
      ,[ELMA].[dbo].[ContractorLegal].[KPP] AS [crm_management_contragent_kpp]
      ,[ELMA].[dbo].[ContractorLegal].[OGRN] AS [crm_management_contragent_ogrn]
      ,[ELMA].[dbo].[ContractorLegal].[BIK] AS [crm_management_contragent_bik]
      ,[ELMA].[dbo].[ContractorLegal].[BANK] AS [crm_management_contragent_bank]
      ,[ELMA].[dbo].[ContractorLegal].[KS] AS [crm_management_contragent_ks]
      ,[ELMA].[dbo].[ContractorLegal].[RS] AS [crm_management_contragent_rs]         
  FROM [ELMA].[dbo].[Contractor]
  LEFT OUTER JOIN [ELMA].[dbo].[ContractorType] ON [ELMA].[dbo].[ContractorType].[Id] = [ELMA].[dbo].[Contractor].[Type]
  LEFT OUTER JOIN [ELMA].[dbo].[ContractorLegal] ON [ELMA].[dbo].[ContractorLegal].[Id] = [ELMA].[dbo].[Contractor].[Id]
  LEFT OUTER JOIN [ELMA].[dbo].[Address] AS [LA] ON [LA].[Id] = [ELMA].[dbo].[Contractor].[LegalAddress]
  LEFT OUTER JOIN [ELMA].[dbo].[Country] AS [LAC] ON [LAC].[Id] = [LA].[Country]
  LEFT OUTER JOIN [ELMA].[dbo].[Address] AS [PA] ON [PA].[Id] = [ELMA].[dbo].[Contractor].[PostalAddress]
  LEFT OUTER JOIN [ELMA].[dbo].[Country] AS [PAC] ON [PAC].[Id] = [PA].[Country]
  LEFT OUTER JOIN [ELMA].[dbo].[LegalForm] AS [LF] ON [LF].[Id] = [ELMA].[dbo].[ContractorLegal].[LegalForm]
  
  WHERE [ELMA].[dbo].[Contractor].[IsDeleted] = 0 AND [ELMA].[dbo].[Contractor].[Name] IS NOT NULL AND [ELMA].[dbo].[Contractor].[id] > 500


Несколько значений для одного атрибута объединил в одно с помощью STUFF(...). Результат запроса сохранил в формате csv с разделителем ";". Первой строкой в файле добавил обозначения атрибутов в easla.com. Загрузил файл в разделе «Импорт объектов». Потом указал кодировку файла и пользователя, от имени которого выполнить импорт. Запустил импорт. Процедура импорта не очень быстрая, на создание каждого объекта может уходить порядка одной секунды. Количество импортированных записей было примерно 500. Выглядело это примерно так:

Теперь контакты. Написал вот такой SQL запрос:
ELMA_export_contacts.sql
SELECT 
	   [Surname] AS [crm_management_contact_lastname]
      ,[Firstname] AS [crm_management_contact_firstname]
      ,[Middlename] AS [crm_management_contact_middlename]
      ,[ELMA].[dbo].[Contractor].[Name] AS [crm_management_contact_contragent]
      ,[Department] AS [cnt_management_contact_department]
      ,[Position] AS [cnt_management_contact_position]
      ,[crm_management_contact_email] = STUFF((
		SELECT '|' + [ELMA].[dbo].[Email].[EmailString]
		FROM [ELMA].[dbo].[Contact_Email]
		LEFT OUTER JOIN [ELMA].[dbo].[Email] ON [ELMA].[dbo].[Email].[Id] = [ELMA].[dbo].[Contact_Email].[Email]
		WHERE [ELMA].[dbo].[Contact_Email].[Contact] = [ELMA].[dbo].[Contact].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
      ,[crm_management_contact_phone] = STUFF((
		SELECT '|' + [ELMA].[dbo].[Phone].[PhoneString]
		FROM [ELMA].[dbo].[Contact_Phone]
		LEFT OUTER JOIN [ELMA].[dbo].[Phone] ON [ELMA].[dbo].[Phone].[Id] = [ELMA].[dbo].[Contact_Phone].[Phone]
		WHERE [ELMA].[dbo].[Contact_Phone].[Contact] = [ELMA].[dbo].[Contact].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
	  ,CASE WHEN [Year] IS NULL THEN NULL ELSE CONVERT(varchar, [Birthday],104) END AS [crm_management_contact_birthday]
	  ,[RAC].[Name] AS [crm_management_contact_country]
      ,[RA].[Region] AS [crm_management_contact_region]
      ,[RA].[District] AS [crm_management_contact_district]
      ,[RA].[City] AS [crm_management_contact_city]
      ,[RA].[Locality] AS [crm_management_contact_locality]
      ,[RA].[Street] AS [crm_management_contact_street]
      ,[RA].[Building] AS [crm_management_contact_house]
      ,[RA].[Stroenie] AS [crm_management_contact_building]
      ,[RA].[Korpus] AS [crm_management_contact_corp]
      ,[RA].[Appartment] AS [crm_management_contact_apartment]
      ,[RA].[Zip] AS [crm_management_contact_postcode]	         
  FROM [ELMA].[dbo].[Contact]
  LEFT OUTER JOIN [ELMA].[dbo].[Contractor] ON [ELMA].[dbo].[Contractor].[Id] = [ELMA].[dbo].[Contact].[Contractor]
  LEFT OUTER JOIN [ELMA].[dbo].[Address] AS [RA] ON [RA].[Id] = [ELMA].[dbo].[Contact].[RegistrationAddress]
  LEFT OUTER JOIN [ELMA].[dbo].[Country] AS [RAC] ON [RAC].[Id] = [RA].[Country]
  WHERE [ELMA].[dbo].[Contact].[Id] > 1919


Все действия аналогичны предыдущему импорту. Особенность импорта контактов после контрагентов заключалась в том, что контакт обладает атрибутом «Контрагент», который ссылается на контрагента. Поэтому, в первую очередь были импортированы контрагенты, а за ними контакты. При импорте контактов в поле «Контрагент» easla.com находила и подставляла ссылки на контрагентов! Количество импортированных записей было примерно 1800.
После импорта контрагентов и контактов получилась структурированная база данных, в которой все контакты принадлежат определенным контрагентам. На импорт данных ушло примерно 2 часа. Причем половину времени потратил на разработку SQL запросов. В результате получил две готовые и взаимосвязанные таблицы.
Реестр контрагентов:

Реестр контактов:

На очереди стоял импорт договоров. Выгрузил их с помощью вот такого SQL запроса:
ELMA_export_contracts.sql
SELECT 
      [RegYear] AS [agr_management_contract_year]
      ,[RegNum] AS [agr_management_contract_num]
      ,[RegAppendixFront] AS [agr_management_contract_appendix_front]
      ,[RegAppendixBack] AS [agr_management_contract_appendix_back]
      ,[RegCode]
      ,[ELMA].[dbo].[Contractor].[Name] AS [agr_management_contract_contragent]
      ,'"'+REPLACE(REPLACE(REPLACE([Title],CHAR(10),''),CHAR(13),''),';',',')+'"' AS [agr_management_contract_title]
      ,CONVERT(varchar, [RegDate],104) AS [agr_management_contract_reg_date]
      ,CONVERT(varchar, [SignDate],104) AS [agr_management_contract_sign_date]
      ,[PM1].[EMail] AS [agr_management_contract_project_manager]
      ,[PM2].[EMail] AS [agr_management_contract_project_manager_helper]
      ,agr_management_contract_fields = STUFF((
		SELECT '|' + [F1].[Title]
		FROM [ELMA].[dbo].[Project_Fields]
		LEFT OUTER JOIN [ELMA].[dbo].[Field] AS [F1] ON [F1].[Id] = [ELMA].[dbo].[Project_Fields].[Field]
		WHERE [ELMA].[dbo].[Project_Fields].[Parent] = [ELMA].[dbo].[Project].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
  FROM [ELMA].[dbo].[Project]
  LEFT JOIN [ELMA].[dbo].[Contractor] ON [ELMA].[dbo].[Contractor].[Id] = [ELMA].[dbo].[Project].[Contragent]
  LEFT JOIN [ELMA].[dbo].[User] AS [PM1] ON [PM1].[Id] = [ELMA].[dbo].[Project].[ProjectManager]
  LEFT JOIN [ELMA].[dbo].[User] AS [PM2] ON [PM2].[Id] = [ELMA].[dbo].[Project].[ProjectManagerHelper]


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

Вот теперь, когда все контрагенты, контакты и договоры, на которые ссылаются входящие и исходящие документы находились в easla.com, можно было приступить к импорту переписки.
Количество входящих и исходящих писем было большим — примерно 5400 и 5300 соответственно.
Интересно то, что входящие и исходящие письма ссылаются друг на друга, т.е. исходящее может быть отправлено в ответ на входящее и информации об этом сохраняется в соответствующем атрибуте исходящего документа. Входящий документ может быть получен в ответ на исходящий и информация об этом хранится в соответствующем атрибуте входящего документа. Таким образом, при импорте одного из типов объектов обеспечить формирование всех связей невозможно. Первыми были импортированы входящие документы, но перед этим, тип атрибута хранящего ссылку на исходящий документ был изменен с «Объект» на «Строка». Это позволило сохранить в атрибуте описание исходящего документа, которого пока нет в базе данных и использовать его позже, после импорта исходящих документов. В конечном счете, для выгрузки входящих документов получился вот такой SQL запрос:
ELMA_export_incomings.sql
SELECT 
       CASE [DocMethod] WHEN 1 THEN 'Эл. письмо' WHEN 2 THEN 'Бумажное письмо' WHEN 3 THEN 'Факсимиле' WHEN 4 THEN 'Передан лично' END AS [crs_management_incoming_method]
      ,[ELMA].[dbo].[Contractor].[Name] AS [crs_management_incoming_contragent]
      ,[ELMA].[dbo].[Contact].[Surname] + ' ' + SUBSTRING([ELMA].[dbo].[Contact].[Firstname],1,1) + '.' + SUBSTRING([ELMA].[dbo].[Contact].[Middlename],1,1) + '.' AS [crs_management_incoming_contact]
      ,[crs_management_incoming_performers] = STUFF((
		SELECT '|' + [C1].[Surname] + ' ' + SUBSTRING([C1].[Firstname],1,1) + '.' + SUBSTRING([C1].[Middlename],1,1) + '.'
		FROM [ELMA].[dbo].[IncomingDoc_Performers]
		LEFT OUTER JOIN [ELMA].[dbo].[Contact] AS [C1] ON [C1].[Id] = [ELMA].[dbo].[IncomingDoc_Performers].[Performer]
		WHERE [ELMA].[dbo].[IncomingDoc_Performers].[Parent] = [ELMA].[dbo].[IncomingDoc].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
      ,CONVERT(varchar, [ELMA].[dbo].[IncomingDoc].[ContragentDate], 104) AS [crs_management_incoming_contragent_date]
      ,[ELMA].[dbo].[IncomingDoc].[ContragentRegNum] AS [crs_management_incoming_contragent_regnum]
      ,CONVERT(VARCHAR,[ELMA].[dbo].[IncomingDoc].[ReceiveDate],20) AS [crs_management_incoming_receive_date]
      ,[ELMA].[dbo].[IncomingDoc].[ReceiveOriginalDate] AS [crs_management_incoming_receive_original_date]
      ,[ReceiveOriginalDateFlag] AS [crs_management_incoming_receive_original_flag]
      ,[ELMA].[dbo].[IncomingDoc].[ReceiveRegNum] AS [crs_management_incoming_receive_regnum]
      ,REPLACE(REPLACE([ELMA].[dbo].[IncomingDoc].[Subj],CHAR(13),''),CHAR(10),'') AS [crs_management_incoming_subj]
      ,CASE [ELMA].[dbo].[IncomingDoc].[DocType] 
		WHEN 0 THEN 'Задания'
		WHEN 1 THEN 'Замечания'
		WHEN 2 THEN 'Ответы на замечания'
		WHEN 3 THEN 'Запрос исходных данных'
		WHEN 4 THEN 'Выдача исходных данных'
		WHEN 5 THEN 'Запрос согласования'
		WHEN 6 THEN 'Согласование ранее направленных материалов'
		WHEN 7 THEN 'Запрос информации'
		WHEN 8 THEN 'Пожелания контрагента'		
		WHEN 9 THEN 'Претензия'
		WHEN 13 THEN 'Постановление'
		WHEN 14 THEN 'Отзыв'
		WHEN 17 THEN 'Ходатайство'
		WHEN 15 THEN 'Определение'
		WHEN 10 THEN 'Приглашение'
		WHEN 18 THEN 'О подтверждении технической возможности'
		WHEN 11 THEN 'Запрос коммерческого предложения'
		WHEN 12 THEN 'Договорная документация'
		WHEN 16 THEN 'Коммерческое предложение'
		WHEN 99 THEN 'Прочее'
		END AS [crs_management_incoming_content]
      ,[U1].[UserName]+'@sngp.ru' AS [crs_management_incoming_to]
      ,[U2].[UserName]+'@sngp.ru' AS [crs_management_incoming_forwardto]
      ,[ELMA].[dbo].[OutgoingDoc].[RegNum] AS [crs_management_incoming_outgoing]
      ,[ELMA].[dbo].[Project].[RegCode] AS [crs_management_incoming_contract]
	  ,[crs_management_incoming_attachments] = STUFF((
		SELECT '|' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(LTRIM(STR([F0].[Id]) + ' ' + [F0].[Name]),'«',''),'»',''),'–','-'),'.zip.zip','.zip'),'.docx','.docx'),'  ',' ') 
		FROM [ELMA].[dbo].[IncomingDoc_DocAttachments]
		LEFT OUTER JOIN [ELMA].[dbo].[FS_FILES] AS [F0] ON [F0].[Uid] = [ELMA].[dbo].[IncomingDoc_DocAttachments].[DocAttachment]		
		WHERE [ELMA].[dbo].[IncomingDoc_DocAttachments].[Parent] = [ELMA].[dbo].[IncomingDoc].[Id]
		FOR XML PATH(''), TYPE).value('.', 'VARCHAR(MAX)'), 1, 1, '') 
	  ,LTRIM(STR(ISNULL([F1].[Id],[F2].[Id]))) + REVERSE(SUBSTRING(REVERSE(ISNULL([F1].[Name],[F2].[Name])), 0, CHARINDEX('.',REVERSE(ISNULL([F1].[Name],[F2].[Name]))) + 1)) AS [crs_management_incoming_document]
	  ,[S].[Name] AS [status]
  FROM [ELMA].[dbo].[IncomingDoc]
  LEFT OUTER JOIN [ELMA].[dbo].[Contractor] ON [ELMA].[dbo].[Contractor].[Id] = [ELMA].[dbo].[IncomingDoc].[Contragent]
  LEFT OUTER JOIN [ELMA].[dbo].[Contact] ON [ELMA].[dbo].[Contact].[Id] = [ELMA].[dbo].[IncomingDoc].[Contact]
  LEFT JOIN [ELMA].[dbo].[User] AS [U1] ON [U1].[Id] = [ELMA].[dbo].[IncomingDoc].[To]
  LEFT JOIN [ELMA].[dbo].[User] AS [U2] ON [U2].[Id] = [ELMA].[dbo].[IncomingDoc].[ForwardTo]
  LEFT JOIN [ELMA].[dbo].[Project] ON [ELMA].[dbo].[Project].[Id] = [ELMA].[dbo].[IncomingDoc].[Project]
  LEFT JOIN [ELMA].[dbo].[OutgoingDoc] ON [ELMA].[dbo].[OutgoingDoc].[Id] = [ELMA].[dbo].[IncomingDoc].[OutgoingDoc]
  LEFT JOIN [ELMA].[dbo].[DocumentVersion] AS [DV1] ON [DV1].[DocumentId] = [ELMA].[dbo].[IncomingDoc].[Id] AND [DV1].[Status] = 2 AND ISNUMERIC([DV1].[File]) = 1
  LEFT JOIN [ELMA].[dbo].[DocumentVersion] AS [DV2] ON [DV2].[DocumentId] = [ELMA].[dbo].[IncomingDoc].[Id] AND [DV2].[Status] = 2 AND ISNUMERIC([DV1].[File]) = 0
  LEFT JOIN [ELMA].[dbo].[FS_FILES] AS [F1] ON [F1].[Id] = [DV1].[File]  
  LEFT JOIN [ELMA].[dbo].[FS_FILES] AS [F2] ON [F2].[Uid] = [DV2].[File]  
  LEFT JOIN [ELMA].[dbo].[Document] ON [ELMA].[dbo].[Document].[Id] = [ELMA].[dbo].[IncomingDoc].[Id]
  LEFT JOIN [ELMA].[dbo].[LifeCycleStatus] AS [S] ON [S].[Id] = [ELMA].[dbo].[Document].[Status]
  WHERE --[ELMA].[dbo].[IncomingDoc].[Subj] NOT LIKE 'тест%' AND [ELMA].[dbo].[IncomingDoc].[Subj] NOT LIKE 'test%'
  [ELMA].[dbo].[IncomingDoc].[Id] > 12193
  ORDER BY [ELMA].[dbo].[IncomingDoc].[ReceiveDate]


Кстати, осложнялась ситуация еще и тем, что вместе с данными нужно было выгрузить и импортировать все файлы.
Совершенной неожиданностью стало то, что разработчики elma в какой-то момент изменили способ хранения файлов, поэтому пришлось создавать два разных запроса и объединять их вместе для выгрузки файлов. При первой попытке выгрузки возникла проблема. Имена некоторых файлов повторялись и перезаписывали друг друга. Пришлось изменить в запросе имя конечного файла, добавив к нему id. Кроме, собственно, файла и его имени нужно было перенести в easla.com и дополнительные данные, хранящиеся вместе с файлом. Их тоже пришлось вписать в имя файла. Таким образом, конечное имя файла формировалось по принципу: id data filename.ext. Так как elma хранит файлы в отдельном каталоге, результат запроса планировалось преобразовать в bat файл для выгрузки файлов в нужное место. В конечном счете, для выгрузки файлов входящих документов получился вот такой запрос:
ELMA_export_incoming_files.sql
SELECT 
'copy "\\ssv11\c$\ELMA3-Standart.cfg\UserConfig\Files\' + [FNAME] + '" "c:\temp\elma\incoming\' + REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(ISNULL([ENDNAME],[FNAME]),'«',''),'»',''),'–','-'),'.zip.zip','.zip'),'.docx','.docx'),'  ',' ') + '"'
FROM (
	SELECT [ELMA].[dbo].[IncomingDoc].[Id] AS [Id], [ELMA].[dbo].[IncomingDoc].[Subj] AS [Subj], [ELMA].[dbo].[IncomingDoc].[ReceiveDate] AS [RD], LTRIM(STR([F0].[Id])) + REVERSE(SUBSTRING(REVERSE([F0].[Name]), 0, CHARINDEX('.',REVERSE([F0].[Name])) + 1)) AS [FNAME], LTRIM(STR([F0].[Id]) + ' ' + [Name]) AS [ENDNAME]
	FROM [ELMA].[dbo].[IncomingDoc]
    LEFT JOIN [ELMA].[dbo].[IncomingDoc_DocAttachments] ON [ELMA].[dbo].[IncomingDoc_DocAttachments].[Parent] = [ELMA].[dbo].[IncomingDoc].[Id]
    LEFT OUTER JOIN [ELMA].[dbo].[FS_FILES] AS [F0] ON [F0].[Uid] = [ELMA].[dbo].[IncomingDoc_DocAttachments].[DocAttachment]	    
	UNION
	
	SELECT [ELMA].[dbo].[IncomingDoc].[Id] AS [Id], [ELMA].[dbo].[IncomingDoc].[Subj] AS [Subj], [ELMA].[dbo].[IncomingDoc].[ReceiveDate] AS [RD], LTRIM(STR(ISNULL([F1].[Id],[F2].[Id]))) + REVERSE(SUBSTRING(REVERSE(ISNULL([F1].[Name],[F2].[Name])), 0, CHARINDEX('.',REVERSE(ISNULL([F1].[Name],[F2].[Name]))) + 1)) AS [FNAME], NULL AS [ENDNAME]
	FROM [ELMA].[dbo].[IncomingDoc]
    LEFT JOIN [ELMA].[dbo].[DocumentVersion] AS [DV1] ON [DV1].[DocumentId] = [ELMA].[dbo].[IncomingDoc].[Id] AND [DV1].[Status] = 2 AND ISNUMERIC([DV1].[File]) = 1
    LEFT JOIN [ELMA].[dbo].[DocumentVersion] AS [DV2] ON [DV2].[DocumentId] = [ELMA].[dbo].[IncomingDoc].[Id] AND [DV2].[Status] = 2 AND ISNUMERIC([DV1].[File]) = 0
    LEFT JOIN [ELMA].[dbo].[FS_FILES] AS [F1] ON [F1].[Id] = [DV1].[File]  
    LEFT JOIN [ELMA].[dbo].[FS_FILES] AS [F2] ON [F2].[Uid] = [DV2].[File]  
) AS [F]
WHERE [FNAME] IS NOT NULL 
ORDER BY [RD]


Загрузил csv файл, загрузил все файлы входящих. Процедура оказалась долгой, т.к. общий объем файлов был несколько гигабайт. Хорошо, что импорт данных по 1000 записей, т.к. без накладок не обошлось. Обязательно в каждой тысяче всплывало по 10-15 ошибок. Выявить ошибки удалось перед процедурой импорта, с помощью предварительного просмотра. Очень удобно. В общем, каждая тысяча требовала предварительной подготовки.
Таким же образом импортировал все исходящие документы.
После этого, в объектах была написана процедура преобразования имен файлов. Она удаляла id, а data, переносила в revdata файла в easla.com. Таким образом, файлы приложений получили исходные имена filename.ext.
function updateAttachmentsFileName()
{
    $files = cobjectref()->attributeref('crs_management_incoming_attachments')->availableFiles();
    foreach ($files as $f)
    {
        $parts = explode(' ', $f->nowname, 2);
        if (count($parts) == 2)
        {
            $f->nowname = $parts[1];
            $f->save();
        }
    }
}

Специально для входящих писем была написана процедура, которая заменяла описания ссылок на исходящие документы на их идентификаторы.
function updateOutgoing()
{
    if (empty(cobjectref()->attributeref('crs_management_incoming_outgoing')->value))
        return;
        
    $outgoing_doc = selectAll(      
        'crs_management',
        'crs_management_outgoing',
        array(),
        array('crs_management_outgoing_regnum'=>cobjectref()->attributeref('crs_management_incoming_outgoing')->value)
    );
    
    if (empty($outgoing_doc))
        return;
        
    cobjectref()->attributeref('crs_management_incoming_outgoing')->value = $outgoing_doc['id'];
}


Проверив работу этих процедур запустил пакетное обновление объектов. Медленно, но верно easla.com обновила все объекты! После этого, изменил тип атрибута ссылающегося на исходящий документ во входящем документе со «Строка» на «Объект», чтобы идентификаторы объекта стали объектами.
Таким образом, easla.com переименовала файлы и организовала перекрестные ссылки между входящими и исходящими документами!
В целом, процедура экспорта и импорта заняла примерно 3 рабочих дня. Загрузку файлов на easla.com осуществлял по вечерам, когда канал Интернет был свободен. Импорт данных по 1000 был удобен еще и потому, что старые письма можно было импортировать сразу, не беспокоясь о целостности данных. И только перед «боевым» запуском загрузил и импортировал остатки – последние пару сотен писем.
Миграцию осуществил в конце 2014 года, а запустил в эксплуатацию все описанные бизнес-процессы 12 января 2015 года.
Прошло уже больше года. Общий объем писем превысил 20 тысяч. Количество задач перевалило за 10 тысяч. Вот свежие данные из главного меню:


Итоги


Могу с уверенностью сказать, что год назад все сделал правильно. Вот основные выгоды:
  • Время на регистрацию писем сократилось до секунд или минут
  • Время на отправку исходящего письма сократилось с 30-40 минут до секунд
  • Появилась возможность размещать файлы исходящих писем на файлообменнике easla.com
  • Разработка письма стала проще, т.к. теперь файл в формате docx хранится в объекте easla.com, а не где попало у пользователя
  • Связь задач и писем позволяет формировать и выгружать сложные отчеты, которые приносят организации прибыль
  • Получил развитие процесс управления договорами, если раньше он был простым каталогом, то теперь он настоящий процесс со статусами, контролем выполнения, подписанием актов и поступлением средств.

В настоящий момент развитие получили и другие процессы: управление задачам, согласованиями, субподрядными договорами. Все то, что опасались ранее делать в elma, теперь сделано в easla.com!

P.S. Прошу не расценивать статью как антирекламу elma. Система не подошла нам, но вполне может подойти другим, если они не будут «выжимать из нее соки», как мы.

Комментарии (44)


  1. A4E
    28.04.2016 11:51
    +4

    Не совсем понял. В статье Вы «переходите» от одного вендора к другому, но при этом сама статья находится в платном корпоративном блоге вендора к которому Вы «перешли». Как так?
    Джинса?


    1. Alxdhere
      28.04.2016 11:57
      -2

      Я так и думал, что примут за антирекламу, а не объективную оценку. Ну хорошо, убрал бы я в статье упоминания об elma и easla.com — это было бы политкорректно, но неинформативно?
      Я подошел к написанию статьи как программист, который внедрял систему elma, отгреб шишек и перешел на другую, которую, кстати, сам и написал. Показал объективные причины перехода. Недостатки предыдущего решения. Преимущества нынешнего инструмента.
      P.S. Скажем так, я в составе команды разработчиков easla.com, поэтому в платном блоге. Это важно?


      1. A4E
        28.04.2016 12:00
        +2

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


        1. Alxdhere
          28.04.2016 12:03
          -3

          А если я и пользователь, и сотрудник, как быть?! Как насчет «бест практик», когда разработчик сам пользуется тем, что написал? :)
          Убрать их оплаченного хаба?


          1. A4E
            28.04.2016 12:04
            +3

            А если я и пользователь, и сотрудник, как быть?!

            Просто не делать таких заявлений.
            Это неприлично.


            1. Alxdhere
              28.04.2016 12:21
              -3

              Я не понимаю, что именно «неприлично»? Я что, написал в блоге, что elma плохая система? Я как-то дискредитировал ее? Я как пользователь elma указал на проблемы, с которым столкнулся лично. Лично! И даже не указывал на их систематичность, и нигде явным образом не написал, что «не покупайте elma». Напротив, в конце дописал, что кому-то она подойдет, но нам не подошла.
              Статья может быть интересна как потенциальным потребителям elma, ищущим отзывы о системе, так и нынешним пользователям системы, которые, возможно, столкнулись с похожими проблемами.
              Цель статьи, поделиться опытом перехода с одной системы на другую. Только и всего!

              P.S. Я могу только предположить, что всполошились представители команды разработчиков elma. Надо же позаботиться о том, чтобы заминусовать статью и она не нашла большого круга читателей.


              1. A4E
                28.04.2016 12:31
                +4

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


  1. Alxdhere
    28.04.2016 11:51
    -3

    О! Я так понял, разработчики elma решили меня отхабрить…


    1. Itimora
      28.04.2016 12:31
      +3

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

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


      1. Alxdhere
        28.04.2016 13:12
        -2

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


      1. tearexs
        28.04.2016 14:48

        Разработчики есть, но занимать оправдательную позицию нет смысла — как ни оправдывайся, все равно окажешься виноватым. Опыт внедрения и эксплуатации ELMA как в маленьких, так и больших компаниях показывает, что с нашей системой все в порядке. Возможности написания сценариев на C# позволяют реализовать самые смелые желания клиентов, но иногда люди стреляют себе в ногу — система падает, какая она плохая.


        1. Alxdhere
          28.04.2016 15:06
          +3

          Вы, tearexs, похоже из техподдержки elma. Вот поясните, почему нативный код вида:
          var manager = EntityManager.Instance;
          DateTime startdate = new DateTime(entity.RegDate.Value.Year, 1, 1);
          DateTime enddate = new DateTime(entity.RegDate.Value.Year, 12, 31);
          var allInYear = from d in manager.FindAll()
          where d.RegDate.Value >= startdate && d.RegDate.Value <= enddate
          orderby d.CntNum
          select d;
          if (allInYear.Count() == 0)
          entity.CntNum = 1;
          else
          entity.CntNum = allInYear.Last().CntNum + 1;
          Выполняется примерно в 1000 раз медленнее обращения к базе через c#'овский SqlConnection?!


          1. tearexs
            28.04.2016 15:28

            Потому что вы делаете сначала полный фетч при помощи FindAll, а потом фильтруете все это на веб-сервере. Правильно делать Manager.Find(«EQL filter»)


            1. Alxdhere
              28.04.2016 16:00
              +3

              Раз уж комментарии перешли в техподдержку elma, то вы же видите фрагмент кода. Он самодостаточный. Напишите так, как он должен быть.


              1. tearexs
                29.04.2016 15:23

                Например, вот так:

                Console.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff"));
                var filter = (ITaskFilter)InterfaceActivator.Create<ITaskFilter>();
                filter.Query = "CreationDate>DateTime(2016, 01, 01) and CreationDate<DateTime(2016, 12, 31)";							
                var task = EntityManager<Task>.Instance.Find(filter,null).OrderByDescending(f=>f.CreationDate).First();			
                Console.WriteLine(task.Description);
                Console.WriteLine(DateTime.Now.ToString("hh:mm:ss.fff"));
                


        1. Alxdhere
          28.04.2016 16:06
          +2

          Насчет внедрения «как в маленьких, так и больших компаниях» можно отдельную статью написать. Я насмотрелся и наслушался. Вкратце, не все внедрения можно считать удачными, даже если от них нет обратной связи, но они исправно платят мзду. Хотя, кому что является критерием успешности.
          Мой жизненный опыт показывает, что 80% внедрений выполненных интеграторами попадают в категорию «ежики плакали, но продолжали жрать кактусы».


  1. DmitryDM
    28.04.2016 12:22
    +1

    понимаю, что корпоративный блог и реклама, но все равно поинтересуюсь:
    1. на скриншотах интерфейс от разработчиков easla, или что-то допиливалось руками?
    2. как производится разработка интерфейса?
    3. в статье упоминают бизнес-процессы, как они редактируются в системе, какую нотацию поддерживает система? делали ли процесс с нуля, сколько времени ушло на отрисовку процесса?
    4. какое максимальное число пользователей Вы в своем кейсе пускали разом на боевую среду?


    1. Alxdhere
      28.04.2016 12:36
      -4

      1. На скриншотах интерфейс easla.com как он есть. Ничего не допиливалось. Есть темы (theme), если это важно.
      2. Разработка интерфейса чего, простите? Вы про разработку easla.com или про разработку процессов в ней? Если последнее, то никак. Просто создаете объект, накидываете в него атрибуты и все готово. Про это есть отдельные статьи. Например: https://habrahabr.ru/company/easla/blog/281839/
      3. В easla.com нет понятия «отрисовка процесса», т.к. в ней нет редактора блок-схем, как в elma или в Lotsia PDM Plus. Я работал с обеими этими системами и в обеих настраивал процессы с помощью блок-схем. Или мои требования завышены, или возможности систем ограничены, но в конечном счете проблем больше, чем преимуществ. Работая несколько лет с системой TDMS, которая описывает поведение кодом, сделал для себя вывод, что такой подход оптимальный. Именно он и реализован в easla.com. Все поведение объектов описывается кодом на PHP. Разумеется, возможности PHP урезаны в целях безопасности.
      Все описанные выше процессы сделаны «с нуля». Подробнее, см. другие статьи, например: https://habrahabr.ru/company/easla/blog/281999/
      В части затрат времени, если вы PHP-программист, то наверняка знаете, что такое ООП :) Поэтому идеологию easla.com поймете минут за 20. После этого сможете сваять новый объект с атрибутами и действиями за час. Проще понять что и как работает на конкретном примере, поэтому была статья: https://habrahabr.ru/company/easla/blog/281479/
      4. На текущий момент несколько сотен пользователей онлайн.


      1. AKablukov
        28.04.2016 12:50
        +2

        А если Вы такой любитель кода, что Вам мешало дописать нужный функционал или отдельный модуль для ELMA? (точных цифр не знаю, но по моему опыту процентов 95 кода открыто)…


        1. Alxdhere
          28.04.2016 12:56
          -2

          Дописывал. Что поделать. Вот здесь кратенько, чтобы не дискредитировать: https://habrahabr.ru/company/easla/blog/281999/


          1. AKablukov
            28.04.2016 13:01

            В описанном кейсе ничего сложного нет для реализации средствами ELMA.
            Решались задачи НАМНОГО сложнее. ( и я не разработчик )
            Прекратите подчеркивать свой непрофессионализм и «высоту рук...»


  1. AKablukov
    28.04.2016 12:23
    +1

    Это и есть антиреклама!..
    Уважаемый, автор, не пугайте публику «высотой своих рук над уровнем моря»… Если у Вас не хватило денег (или Вы их пожалели) на оплату внедрения или компетенций на самостоятельное нормальное внедрение ELMA, то не надо вводить пользователей в заблуждение и пытаться очернить столь замечательный продукт. А выводы, относительно возможностей системы в умелых руках, профессиональная публика данного сайта вполне сделать сама. И поверьте, результат будет далеко не в пользу easla.com ))


    1. Alxdhere
      28.04.2016 13:03

      Уважаемый автор комментария. Вы похоже даже не прочитали статью. Я явно указал на то, что систему elma изучил и довольно детально. Более того, я запустил ее в эксплуатацию! И она успешно работала до 2015 года! Почти 2 года! Поэтому не надо упирать на недостаток средств или компетенции. Техподдержка elma получила от меня, как они сами писали, «очень полезный фидбек».
      Укажите мне место в статье, которое очерняет «столь замечательный продукт».


    1. gimntut
      28.04.2016 15:13
      +2

      AKablukov, раз уж вы затронули тему нормального внедрения. Не подскажете, как бороться с задумчивостью ELMA. Страницы которые грузятся до одной минуты при 20-ти активных пользователях — это несколько не нормально. При этом сервер практически не нагружен.
      CPU — 5%
      Память — 50% (20/40 ГБ)
      Диск — 5% (SSD)

      А что касается возможностей, то полностью соглашусь, другого продукта с таким же набором возможностей для России — просто нет. Но задумчивость ELMA просто выводит из себя, как меня так и пользователей.


      1. tearexs
        28.04.2016 15:38
        -2

        gimntut, а вы к нам в поддержку уже писали? Можно номер запроса в личку?


        1. Alxdhere
          28.04.2016 16:15
          +2

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


          1. tearexs
            28.04.2016 16:17
            -1

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


            1. Alxdhere
              28.04.2016 16:21

              Какой номер? gimntut спросил «как бороться с задумчивостью ELMA».


              1. tearexs
                29.04.2016 15:34

                Из того, что клиент может сделать самостоятельно — держать индексы в бд в актуальном состоянии, писать оптимальные скрипты («не делать FindAll()») — информацию об основных источниках проблем можно найти в системных отчетах о производительности и текущей активности в системе. При увеличении нагрузки на IIS можно поднять веб-ферму.
                Не зная, какая конфигурация у gimntut, сложно давать конкретные советы.


        1. gimntut
          28.04.2016 19:55
          +2

          Я бы с удовольствием написал бы, но...:
          1. срок поддержки вышел, а о средствах на продление поддержки речи не идёт, т.к. на предприятии идут сокращения. Самому бы под сокращение не попасть бы.
          2. базовая поддержка не подразумевает работу на стороне клиента, а дополнительная поддержка требует заключения отдельных договоров
          3. тормозит базовый функционал, а сообщать о багах нет ни какого интереса, так как обновление в котором этот баг будет исправлен получить нельзя, пока не будет заключен следующий договор. Если был бы багбаунти, когда взамен пачки найденных багов, получаешь право на скачивание любой новой версии, тогда был бы интерес.
          4. когда к нам для знакомства приезжал внедренец ELMA, то было понятно, что десятисекундная загрузка страницы на пустой базе — это нормально. Тогда мы ещё грешили на железо. После окончания тех.поддержки мы прокачали сервер по полной, стало лучше, но не на столько, чтобы сказать что задумчивость исчезла.


  1. Alxdhere
    28.04.2016 13:42
    -4

    Судя по всему, один из комментаторов продавец elma, а другая — маркетолог elma. :)


    1. A4E
      28.04.2016 13:44
      +4

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


      1. Alxdhere
        28.04.2016 13:49
        -2

        Для этого не нужно быть любителем теории заговоров. Достаточно просто погуглить. :)


        1. Itimora
          28.04.2016 13:55
          +2

          У вас какой-то другой Google. Поделитесь нагугленным-то.


  1. Kotskin
    28.04.2016 15:15
    +1

    Всем привет. Я директор по развитию в «Импелтехе», мы последние 4 года занимается внедрением\разработкой только под ELMA BPM и являемся золотыми партнёрами. Я лично сертифицирован по всем компетенциям ELMA.

    Возможно, вам не удалось выработать определённый workflow работы с системой, поэтому её использование было неудачным. Сожалею, в системе очень много интересного и полезного для бизнеса.

    Я, как и все люди, склонен защищать инструмент, который помогает зарабатывать на жизнь, но попробую конструктивно:

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

    Не знаю, зачем вам могло это понадобится, но раз исправили за 2 месяца, в этом был какой-то резон.

    >>Проблемы при создании процессов с ветвлениями. Был создан процесс рассмотрения входящего письма, который ветвился в соответствии с количеством ответственных исполнителей. Кода в процессе практически не было. Однако регулярно появлялись задачи-фантомы — я их так назвал. Назначено 5 задач, а получается 10. Решить проблему с помощью техподдержки не удалось и мне пришлось писать «костыли», которые уничтожали фантомов программно. Но все равно в непредсказуемых ситуациях они проявлялись.

    Очень сложно быть конструктивным, потому что информации мало. Такое могло быть при использовании динамических зон ответственности, установленных на группы сотрудников и раздачей по «round-robin». Но это работает именно так, как и задумано. Давайте попробуем разобраться — сможете прислать экспорт процесса?

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

    Скорее всего вопросы к тому, как вы работали, а не то как система позволяет это сделать. У наших клиентов маленькие процессы разрабатываются на том же сервере, без перезагрузки. Новые процессы — на отдельном сервере.
    Если вы меняете метаданные объектной модели, то сервер нужно перезапускать, потому что c# — это компилируемый язык. Обычно это занимает 5 минут, о которых сотрудников можно предупредить заранее.

    >>Каждое обновление приносило свои исправления и свои баги. Однажды, обновление принесло баг, который был исправлен 2-3 обновления назад. Причем порой ошибки были смешные — детские. Например, два обновления подряд не могли главное меню развернуть на всю высоту браузера.

    Такое бывает, но это нормально — ELMA это серьезный продукт с огромным функционалом.

    Были и другие проблемы. Но то, технические проблемы, которые конечных пользователей не касаются.
    Однако и пользователи тоже регулярно жаловались на неудобства, например:
    >>Поиск объектов осуществляется только на отдельной странице, что вроде бы логично, и даже критерии поиска можно вводить весьма сложные, но для конечного пользователя этот функционал оказался неудобным. Все давно привыкли, что искать удобно указывая критерии в шапке таблицы, а переход на отдельную страницу и многоходовой ввод критериев вызывал недовольство и отторжение.

    Это стало для вас новостью в середине эксплуатации системы? У нас можно взять 30-дневный триал на любое количество пользователей, чтобы исключить любые вопрос юзабилити.
    Кроме того, критерии можно сохранить в виде заранее настроенных фильтров, в том числе централизованно силами администратора.

    >>Elma, работая в локальной сети, начала удивлять своей задумчивостью. Мы изучили систему изнутри. Оказалось, что для каждого объекта система создает отдельную таблицу и еще кучку смежных таблиц для хранения данных, т.е. торможения быть не должно. Однако, когда количество записей каждого объекта превысило тысяч пять, тормоза стали заметны на интуитивном уровне. Странички со списком открывались несколько секунд.

    ELMA работает на firebird, MS SQL и Oracle, у вендора есть рекомендованные требования к железу. Можете уточнить, какое у вас железо и бд использовалось? Про таблички — используется ORM Nhibernate, поэтому и создаются таблички.


    1. tearexs
      28.04.2016 15:47

      Автор уже ушел писать свою систему, нет смысла ворошить прошлое.
      >> Однако, когда количество записей каждого объекта превысило тысяч пять, тормоза стали заметны на интуитивном уровне. Странички со списком открывались несколько секунд.
      Вероятнее всего, список в этом случае открывался с сортировкой по неиндексированному полю. В этом случае хорошей помощью системе со стороны DBA будет создание индекса по этому полю. Также по умолчанию система создает строковые поля неограниченной длины. Если вы знаете, что, например, название не может быть длиннее 100 символов — имеет смысл установить это ограничение при создании поля. Это сильно поможет серверу в построении индекса и сортировке по этому полю.


    1. Alxdhere
      28.04.2016 15:54
      +2

      >>Не знаю, зачем вам могло это понадобится, но раз исправили за 2 месяца, в этом был какой-то резон.
      Какая разница зачем? Есть потребность. Есть доступ к файлам в коде. Присваиваю новое имя, ан нет. Оказывается так нельзя! Но решили и ладно. Правда 2 месяца ждать возможности переименовать файл… круто! Если вы контачите с разработчиками: ticket 19492

      >>сможете прислать экспорт процесса?
      Сейчас в этом нет смысла. Добавлю только, что в техподдержку отправлял всю базу. Если верно понял, ребята на своей стороне поднимали нашу базу, запускали процессы и изучали причины. ticket #19556

      >>ELMA это серьезный продукт с огромным функционалом
      Да кто спорит, но не наивные же ошибки! Когда ошибка глубоко, как с теми же дубликатами задач, я был готов простить и понять и терпеливо ждал исправления. Ситуации бывают разные, может и впрямь я создал такую, что система повела себя неожиданно.
      Windows, Word, Excel, серьезные продукты с огромным функционалом, но они же не допускают подобных смешных ошибок. Ошибки есть, не спорю и некоторые клонируются и из версии в версию (например, Excel до сих пор не переваривает множество квадратных скобок в именах файлов).

      Про поиск.
      Нет конечно, не было новостью. Но это стало еще одной «ложкой дегтя» среди прочих. Кстати, поиск глючил, но сейчас точно не вспомню как именно. Нестабильно искал, что ли. Скажем, пользователь ищет — не находит документа, который точно есть, а на другом компьютере под другим пользователем находится. Права в порядке. На след. день такой проблемы нет. И в техподдержку не напишешь.

      Про скорость.
      Суть ведь не в используемой базе данных. Сервер мощный и под elma и под ms sql. Но система тормозит страшно! Я даже знаю ответ почему, но мне от этого не легче. Повлиять на это не могу. Кстати, я не один такой (читайте комментарии выше).

      P.S. Самый фееричный ticket — 20973. Меня убеждали в том, что XML ответ на SOAP запрос с encoding=utf-8 может (!) и совершенно нормально, что содержит русские символы в кодировке 1251! Где это видано, чтобы XML с encoding=utf8 допускал содержание национальных символов в другой кодировке? Мне пришлось строки кодировать в base64, передавать и раскодировать обратно.


      1. Kotskin
        28.04.2016 16:23

        >>Не знаю, зачем вам могло это понадобится, но раз исправили за 2 месяца, в этом был какой-то резон.
        >>>>Какая разница зачем? Есть потребность. Есть доступ к файлам в коде. Присваиваю новое имя, ан нет. Оказывается так нельзя! Но решили и ладно. Правда 2 месяца ждать возможности переименовать файл… круто! Если вы контачите с разработчиками: ticket 19492

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

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

        >>сможете прислать экспорт процесса?
        Сейчас в этом нет смысла. Добавлю только, что в техподдержку отправлял всю базу. Если верно понял, ребята на своей стороне поднимали нашу базу, запускали процессы и изучали причины. ticket #19556

        >>ELMA это серьезный продукт с огромным функционалом
        >>>>Да кто спорит, но не наивные же ошибки! Когда ошибка глубоко, как с теми же дубликатами задач, я был готов простить и понять и терпеливо ждал исправления. Ситуации бывают разные, может и впрямь я создал такую, что система повела себя неожиданно.
        Windows, Word, Excel, серьезные продукты с огромным функционалом, но они же не допускают подобных смешных ошибок. Ошибки есть, не спорю и некоторые клонируются и из версии в версию (например, Excel до сих пор не переваривает множество квадратных скобок в именах файлов).

        Кому наивные, кому не наивные. С радостью ознакомился бы со справочником «наивных» багов в программных продуктах в издании O'Reilly, чтобы иметь возможность так же смело использовать их в конкурентной борьбе.

        >>Про поиск.
        >>>Нет конечно, не было новостью. Но это стало еще одной «ложкой дегтя» среди прочих. Кстати, поиск глючил, но сейчас точно не вспомню >>>как именно. Нестабильно искал, что ли. Скажем, пользователь ищет — не находит документа, который точно есть, а на другом компьютере >>>>под другим пользователем находится. Права в порядке. На след. день такой проблемы нет. И в техподдержку не напишешь.
        >>>>Про скорость.
        >>>>Суть ведь не в используемой базе данных. Сервер мощный и под elma и под ms sql. Но система тормозит страшно! Я даже знаю ответ почему, но мне от этого не легче. Повлиять на это не могу. Кстати, я не один такой (читайте комментарии выше).

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

        >>>P.S. Самый фееричный ticket — 20973. Меня убеждали в том, что XML ответ на SOAP запрос с encoding=utf-8 может (!) и совершенно нормально, что содержит русские символы в кодировке 1251! Где это видано, чтобы XML с encoding=utf8 допускал содержание национальных символов в другой кодировке? Мне пришлось строки кодировать в base64, передавать и раскодировать обратно.

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


        1. Alxdhere
          28.04.2016 16:32
          +1

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

          Наивные, см. ticket 23220

          Мне уже не нужна помощь, спасибо. Я себе помог.

          >>Тут нечего сказать, рад что вы смогли справиться с проблемой.
          Я то как рад был бороться с проблемой, которой не должно быть!

          Очередной раз подчеркну, что система работала почти 2 года. Я заставил ее делать все что нужно. Проблема была именно в том, что начала деградировать производительность и мне было реально страшно запускать на ней другие процессы, если она с существующими кое-как справляется.


          1. Kotskin
            28.04.2016 16:46

            >>Идея переименования файла заключалась в том, чтобы имя файла всегда соответствовало обозначению документа. Таким образом, при регистрации документа вычислялось обозначение документа. Сохранялось в атрибуте. При импорте файла с любыми именем в elma, должно было происходить его переименование. При изменении обозначения документа и уже существующем файле его имя тоже должно было измениться. Не велика сложность, неправда ли?

            Т.е, например, загрузили в систему файл «Премирование_продажников.xls», создали на его базе документ типа «Мотивационные схемы», зарегистрировали его с номером «111». При скачивании версии файла он должен называться «111_Мотивационные_схемы_премирование_продажников.xls»?

            >>Мне уже не нужна помощь, спасибо. Я себе помог.
            А сообществу не помогли, хотя именно это заявляли в своей статье.

            >>Тут нечего сказать, рад что вы смогли справиться с проблемой.
            Я то как рад был бороться с проблемой, которой не должно быть!

            >>Очередной раз подчеркну, что система работала почти 2 года. Я заставил ее делать все что нужно. Проблема была именно в том, что начала деградировать производительность и мне было реально страшно запускать на ней другие процессы, если она с существующими кое-как справляется.

            Получается, вам было проще разработать свою систему, чем разобраться со своими страхами и производительностью системы?


            1. Alxdhere
              28.04.2016 16:56
              +1

              Нет, не так. Зарегистрировал письмо с номером 11/Аб-1234. Вложил в него файл с именем «файл.doc». Файл должен получить имя «11/Аб-1234.doc». Упс, пришло ценное указание, меняется номер письма, оно станет 11/Ба-4321. Нет проблем. Редактируем объект. Меняется значение атрибута и меняется имя файла на «11/Ба-4321.doc».

              Но мне сообщество как «помогло»! Прям закачаешься!

              >>Получается, вам было проще разработать свою систему, чем разобраться со своими страхами и производительностью системы?
              Поверьте, разбирались и со страхами, и с производительностью. И техподдержка завалена обращениями — 144 тикета. А что толку, если проблема в архитектуре?

              Вы же понимаете, что просто так с бухты барахты никто за написание своей PDM системы не берется. Нужен опыт программирования, внедрения, интеграции, работы с системами. И желательно с разными системами. Решающими задачи разных подразделений с разными видами деятельности. В общем, накопилось.
              Мой опыт работы с СЭД уже лет 15-16. Разные видел. Разные запускал. Надоело взвешивать преимущества и недостатки. Разумеется, и в easla.com найдутся недостатки, ведь все зависит от требований.


              1. Kotskin
                28.04.2016 17:19

                >>>Нет, не так. Зарегистрировал письмо с номером 11/Аб-1234. Вложил в него файл с именем «файл.doc». Файл должен получить имя «11/Аб-1234.doc». Упс, пришло ценное указание, меняется номер письма, оно станет 11/Ба-4321. Нет проблем. Редактируем объект. Меняется значение атрибута и меняется имя файла на «11/Ба-4321.doc».

                Понял. Скорее всего вы столкнулись с тем, что имя файла генерируется в контроллере скачивания динамически, потому что сам файл лежит в файловой структуре просто с айдишником, а имя берется из БД, при этом на базе имени и размера генерируется хеш, который помогает защититься от подмены файла в файловой структуре.

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

                >>>Но мне сообщество как «помогло»! Прям закачаешься!

                Ну, на страничке о хабре «В «Хабрахабр» заложена уникальная модель совместного творчества, позволяющая людям собирать и структурировать информацию, выделяя из неё наиболее полезную и ценную. Используя заложенные в проект механизмы, пользователи самостоятельно наделяют правами друг друга, давая или ограничивая возможности.» Тут уж ничего не поделаешь.

                >>Получается, вам было проще разработать свою систему, чем разобраться со своими страхами и производительностью системы?
                Поверьте, разбирались и со страхами, и с производительностью. И техподдержка завалена обращениями — 144 тикета. А что толку, если проблема в архитектуре?

                >>>Вы же понимаете, что просто так с бухты барахты никто за написание своей PDM системы не берется. Нужен опыт программирования, внедрения, интеграции, работы с системами. И желательно с разными системами. Решающими задачи разных подразделений с разными видами деятельности. В общем, накопилось.
                Мой опыт работы с СЭД уже лет 15-16. Разные видел. Разные запускал. Надоело взвешивать преимущества и недостатки. Разумеется, и в easla.com найдутся недостатки, ведь все зависит от требований.

                Согласен, к тому же ELMA совсем не PDM и не очень-то СЭД. Понимаю ваше разочарование, согласен с тем что каждому требованию свой инструмент — иногда нужно взять и сделать что-то своё, где всё полностью подвластно тебе. Могу представить что вы чувствовали, когда запустили пользователей в свою на 100% систему.


                1. Alxdhere
                  29.04.2016 06:34
                  +1

                  Как вы и написали, изначально мне предлагали много-много строчек кода только ради переименования файла. Мне пришлось указать, как бы это помягче сказать, на нелепость такого решения. В общем, я бился 2 месяца ради вот такого решения:
                  if (!lastver.File.Name.Equals(fname))
                  {
                  lastver.File.Rename(fname);
                  }

                  Уверен, и приватные комментарии добавляют мне этой уверенности, что те, кто прочитал статью, выделили из нее «наиболее полезную и ценную» информацию. Благодарен всем, кто подошел к чтению объективно и без эмоций.

                  Моя цель при разработке easla.com была не столько создать инструмент подвластный мне, сколько подвластный любому. Без оглядок на разработчика. Собственно, и о существовании системы смело заявил только после написания подробного руководства разработчика.
                  Признаюсь, и я того не скрывал, что за образец для подражания взята TDMS. Некоторые вещи сделаны иначе, например, файловые атрибуты. Кое-что добавлено — например, рабочий календарь, интеграция с почтовой системой.


  1. GarbageIntegrator
    29.04.2016 08:36

    Насчет этически неприемлемого выражу личное мнение.
    1. Этически неприемлемо — разносить сплетни. Т.е. «у одних знакомых моих знакомых есть проблемы с этим продуктом». А если проблемы были у того, кто о них рассказал — что тут неприемлемого?
    2. Этически неприемлемо — давать обещания и не выполнять их.
    3. Этически неприемлемы «темные паттерны». https://habrahabr.ru/post/198044/

    Ну и…
    4. Этически неприемлема перезагрузка сервера с сотнями активных пользователей для правки бага, который мешает нажать кнопку одному человеку. Важную кнопку, например, нужен некий реестр, для Заказчика, через 15 минут! Но — сотни пользователей!
    Да, я понимаю, что в дотнете либо есть возможность изолировать плагин доменом и вызвать тем самым геморроидальный синдром при обмене с другими частями бизнес-логики (но зато обеспечить выгрузку и вгрузку «на лету»), либо заставить систему постепенно жрать ресурсы загрузкой новых версий плагина в текущий домен. Но — сотни пользователей! Либо меняйте технологию, либо правильно выбирайте компромисс и предупреждайте клиентов о некоторых нюансах заранее.

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