Добавление нового разреза нумерации на примере договорных документов

26 1

Довольно подробно механизм регистрации описан в статье про добавление нового элемента номера в журнале регистрации. Продолжу эту тему и подробнее рассмотрю добавление нового разреза нумерации.

Цель: добавить новый разрез нумерации по категориям для договоров и доп. соглашений.

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

В общем и целом задачу можно разбить на 3 этапа:

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

Прежде чем перейти к основным доработкам, перекрываем справочник «Журнал регистрации» и добавляем новый элемент NumberingSection (разрез нумерации)

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

public override IEnumerable<Enumeration> NumberingSectionFiltering(IEnumerable<Enumeration> query)
{
	if (_obj.DocumentFlow != DocumentFlow.Contracts)
		return query.Where(s => s != finex.MotivContracts.DocumentRegister.NumberingSection.Category);
			
	return base.NumberingSectionFiltering(query);
}

 

Обновление таблицы в БД и изменение базовых SQL запросов

Для хранения очередного номера при регистрации или нумерации в базе данных используется таблица «Sungero_Docregister_Currentnumbers». Данная таблица, кроме очередного номера документа хранит информацию о ID сущностей, используемых при определении разреза нумерации (в коробочной версии доступно три варианта: наши организации, подразделения, ведущий документ). Следовательно, если мы хотим добавить свой разрез, нам необходимо провести следующие манипуляции:

1. Добавление нового столбца

Для добавления нового столбца в таблице «Sungero_Docregister_Currentnumbers», где будет хранится ID категории создаем следующий SQL запрос:

ALTER TABLE {0} ADD COLUMN IF NOT EXISTS {1} {2} NOT NULL DEFAULT {3};

2. Вызов запроса

Вызываем этот запрос в событии инициализации.

/// <summary>
/// Добавление колонок в таблицы
/// </summary>
public static void AlterTables()
{
	var query = string.Format(Queries.Module.AlterTables,
	                          Constants.Module.TablesNames.docRegisterTableName,
	                          "category",
	                          "integer",
	                          "(0)");
			
	InitializationLogger.Debug(query);
	Sungero.Docflow.PublicFunctions.Module.ExecuteSQLCommand(query);
}

3. Обновленные SQL-запросы

Переписываем SQL-запросы GetCurrentNumber, SetCurrentNumber в перекрытом журнале регистрации на получение и установку индекса,  добавляя новый параметр Category:

-- GetCurrentNymber
select
  CurrentNumber
from
  Sungero_DocRegister_CurrentNumbers
where
  DocRegisterId = {0}
  and Month = {1}
  and Year = {2}
  and LeadDocument = {3}
  and Quarter = {4}
  and Department = {5}
  and BUnit = {6}
  and Category = {7}
-- SetCurrentNumber
if exists (select
             * 
           from
             Sungero_DocRegister_CurrentNumbers
           where
             DocRegisterId = {0}
             and Month = {2}
             and Year = {3}
             and LeadDocument = {4}
             and Quarter = {5}
             and Department = {6}
             and BUnit = {7}
             and Category = {8})
  update
    Sungero_DocRegister_CurrentNumbers
  set
    CurrentNumber = {1}
  where
    DocRegisterId = {0}
    and Month = {2}
    and Year = {3}
    and LeadDocument = {4}
    and Quarter = {5}
    and Department = {6}
    and BUnit = {7}
    and Category = {8}
else
  insert into
    Sungero_DocRegister_CurrentNumbers (DocRegisterId, CurrentNumber, Month, Year, LeadDocument, Quarter, Department, BUnit, Category)
  values
    ({0}, {1}, {2}, {3}, {4}, {5}, {6}, {7},{8})

4. Присвоение нового номера

Присвоение нового номера производится в функции GetNextRegistrationNumber(), вызываемой в событии до сохранения (в транзакции) ТД OfficialDocument с использованием механизма  хранимых процедур (далее ХП). Таким образом необходимо переопределить их с параметром «Category». ХП описаны в SQL запросах модуля Docflow, нас интересует «Sungero_DocRegister_GetNextNumber».

-- Удалить процедуру получения очередных номеров
DROP FUNCTION IF EXISTS Sungero_DocRegister_GetNextNumber();
-- Создать функцию для получения очередных номеров
CREATE OR REPLACE FUNCTION Sungero_DocRegister_GetNextNumber(
  basevalue int,
  docregid int,
  newmonth int,
  newyear int,
  leaddoc int,
  newquarter int,
  newdep int,
  newbusinessunit int,
  newcategory int)
RETURNS int AS $$
BEGIN
  IF NOT EXISTS(SELECT *
                FROM sungero_docregister_currentnumbers
                WHERE docregisterid = docregid
                  AND month = newmonth
                  AND year = newyear
                  AND leaddocument = leaddoc
                  AND quarter = newquarter
                  AND department = newdep
                  AND bunit = newbusinessunit
                  AND category = newcategory)
  THEN
    INSERT INTO sungero_docregister_currentnumbers(docregisterid, currentnumber, month, year, leaddocument, quarter, department, bunit, category)
    VALUES (docregid, basevalue, newmonth, newyear, leaddoc, newquarter, newdep, newbusinessunit, newcategory);
    RETURN basevalue;
  ELSE
    UPDATE sungero_docregister_currentnumbers
    SET currentnumber = currentnumber + 1
    WHERE docregisterid = docregid
      AND month = newmonth
      AND year = newyear
      AND leaddocument = leaddoc
      AND quarter = newquarter
      AND department = newdep
      AND bunit = newbusinessunit
      AND category = newcategory;
    RETURN (SELECT currentnumber
            FROM sungero_docregister_currentnumbers
            WHERE docregisterid = docregid
              AND month = newmonth
              AND year = newyear
              AND leaddocument = leaddoc
              AND quarter = newquarter
              AND department = newdep
              AND bunit = newbusinessunit
              AND category = newcategory);
  END IF;
END;
$$
LANGUAGE plpgsql;

5. Свой запрос в событии инициализации

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

//Изменение хранимых процедур таблицы очередных номеров журналов регистрации
public static void ChangeDocumentRegisterNumberTable()
{
	var dropGetNextNumberProcedure = Queries.Module.DropProcedureSungeroDocRegisterGetNextNumber;
	var createGetNextNumberProcedure = Queries.Module.CreateProcedureSungeroDocRegisterGetNextNumber;
		
	Sungero.Docflow.PublicFunctions.Module.ExecuteSQLCommand(dropGetNextNumberProcedure);
	Sungero.Docflow.PublicFunctions.Module.ExecuteSQLCommand(createGetNextNumberProcedure);
}

 

Создание перегрузок функций для работы с новым разрезом нумерации

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

  • GetNextNumber 
  • GetNextIndex 
  • GetCurrentNumber 
  • SetCurrentNumber 
  • GetNextRegistrationNumber

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


 

Как видно из схемы, получение номера происходит:

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

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

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

 

/// <summary>
/// Получить следующий регистрационный номер.
/// </summary>
/// <param name="date">Дата регистрации.</param>
/// <param name="leadDocumentId">ID ведущего документа.</param>
/// <param name="document">Документ.</param>
/// <param name="leadingDocumentNumber">Номер ведущего документа.</param>
/// <param name="departmentId">ИД подразделения.</param>
/// <param name="businessUnitId">ID НОР.</param>
/// <param name="categoryId">ID категории.</param>
/// <param name="caseFileIndex">Индекс дела.</param>
/// <param name="docKindCode">Код вида документа.</param>
/// <param name="indexLeadingSymbol">Ведущий символ индекса.</param>
/// <returns>Регистрационный номер.</returns>
[Public, Remote(IsPure = true)]
public virtual string GetNextNumber(DateTime date, int leadDocumentId, IOfficialDocument document, string leadingDocumentNumber,
                                    int departmentId, int businessUnitId, int categoryId, string caseFileIndex, string docKindCode, string indexLeadingSymbol)
{
	#region CUSTOM
	var index = this.GetNextIndex(date, leadDocumentId, departmentId, businessUnitId, categoryId, document).ToString();
	#endregion

	var departmentCode = string.Empty;
	if (departmentId != 0)
	{
		var department = Sungero.Company.Departments.Get(departmentId);
		if (department != null)
			departmentCode = department.Code ?? string.Empty;
	}

	var businessUnitCode = string.Empty;
	if (businessUnitId != 0)
	{
		var businessUnit = Sungero.Company.BusinessUnits.Get(businessUnitId);
		if (businessUnit != null)
			businessUnitCode = businessUnit.Code ?? string.Empty;
	}

	var counterpartyCode = Sungero.Docflow.PublicFunctions.OfficialDocument.GetCounterpartyCode(document);
	var number = Sungero.Docflow.PublicFunctions.DocumentRegister.GenerateRegistrationNumber(_obj, date, index, leadingDocumentNumber, departmentCode,
			                                                                                         businessUnitCode, caseFileIndex, docKindCode, counterpartyCode,
			                                                                                         indexLeadingSymbol);

	var contract = Contracts.As(document);
	if (contract == null)
		return number;
		
	var replaceCode = contract.DocumentGroup != null
		? contract.DocumentGroup.Codefinex
		: "";
		
	var replaceCSCode = contract.Subjectfinex != null
		? contract.Subjectfinex.Code
		: replaceCode;
			
	string codeFinex = Constants.Docflow.DocumentRegister.CodeFinex;
	string csCodeFinex = Constants.Docflow.DocumentRegister.CSCodeFinex;

	return number.Replace(codeFinex, replaceCode).Replace(csCodeFinex, replaceCSCode);
}
		
/// <summary>
/// Получить следующий порядковый номер для журнала.
/// </summary>
/// <param name="date">Дата.</param>
/// <param name="leadDocumentId">Ведущий документ.</param>
/// <param name="departmentId">Подразделение.</param>
/// <param name="businessUnitId">НОР.</param>
/// <param name="document">Текущий документ.</param>
/// <returns>Порядковый номер.</returns>
public virtual int? GetNextIndex(DateTime date, int leadDocumentId, int departmentId, int businessUnitId, int categoryId, IOfficialDocument document)
{
	#region CUSTOM
	var index = this.GetCurrentNumber(date, leadDocumentId, departmentId, businessUnitId, categoryId) + 1;
			
	var documents = GetOtherDocumentsInPeriodBySections(document, date)
		.Where(l => l.Index >= index)
		.Where(l => leadDocumentId == 0 || l.LeadingDocument != null && Equals(l.LeadingDocument.Id, leadDocumentId))
		.Where(l => departmentId == 0 || l.Department != null && Equals(l.Department.Id, departmentId))
		.Where(l => businessUnitId == 0 || l.BusinessUnit != null && Equals(l.BusinessUnit.Id, businessUnitId));
			
	// Условие для категорий договоров и доп. соглашений.
	if (Contracts.Is(document))
		documents = documents.Where(l => categoryId == 0 || Contracts.Is(l) && Contracts.As(l).DocumentGroup != null && Contracts.As(l).DocumentGroup.Id == categoryId);
	else if (SupAgreements.Is(document))
		documents = documents.Where(l => categoryId == 0 || SupAgreements.Is(l) && SupAgreements.As(l).DocumentGroup != null && SupAgreements.As(l).DocumentGroup.Id == categoryId);
	#endregion
			
	var documentslist = documents.Select(i => i.Index).ToList();
			
	// Вернуть следующий номер, если он не занят.
	if (!documentslist.Contains(index))
		return index;
		
	// Найти следующий незанятый номер.
	index = documentslist.Where(d => !documentslist.Contains(d.Value + 1)).Min(d => d.Value) + 1;
	return index;
}
		
/// <summary>
/// Получить документы, зарегистрированные в журнале в тот же период по тем же разрезам.
/// </summary>
/// <param name="doc">Документ.</param>
/// <param name="registrationDate">Дата регистрации.</param>
/// <returns>Документы, зарегистрированные в журнале в тот же период по тем же разрезам.</returns>
[Public]
public override IQueryable<IOfficialDocument> GetOtherDocumentsInPeriodBySections(IOfficialDocument doc, DateTime registrationDate)
{
	var documents = base.GetOtherDocumentsInPeriodBySections(doc, registrationDate);
		
	#region CUSTOM
	if (_obj.NumberingSection == finex.MotivContracts.DocumentRegister.NumberingSection.Category)
	{
		if (Contracts.Is(doc))
			documents = documents.Where(d => Contracts.Is(d) && Equals(Contracts.As(d).DocumentGroup, Contracts.As(doc).DocumentGroup));
		else if (SupAgreements.Is(doc))
			documents = documents.Where(d => SupAgreements.Is(d) && Equals(SupAgreements.As(d).DocumentGroup, SupAgreements.As(doc).DocumentGroup));
	}
	#endregion
			
	return documents;
}
	
/// <summary>
/// Получить текущий порядковый номер для журнала.
/// </summary>
/// <param name="date">Дата.</param>
/// <param name="leadDocumentId">ID ведущего документа.</param>
/// <param name="departmentId">ID подразделения.</param>
/// <param name="businessUnitId">ID НОР.</param>
/// <param name="categoryId">ID категории.</param>
/// <returns>Порядковый номер.</returns>
[Public, Remote(IsPure = true)]
public virtual int GetCurrentNumber(DateTime date, int leadDocumentId, int departmentId, int businessUnitId, int categoryId)
{
	var month = Sungero.Docflow.PublicFunctions.DocumentRegister.GetCurrentMonth(_obj, date);
	var year = Sungero.Docflow.PublicFunctions.DocumentRegister.GetCurrentYear(_obj, date);
	var quarter = Sungero.Docflow.PublicFunctions.DocumentRegister.GetCurrentQuarter(_obj, date);
			
	if (_obj.NumberingSection != Sungero.Docflow.DocumentRegister.NumberingSection.LeadingDocument)
		leadDocumentId = 0;
			
	if (_obj.NumberingSection != Sungero.Docflow.DocumentRegister.NumberingSection.Department)
		departmentId = 0;
			
	if (_obj.NumberingSection != Sungero.Docflow.DocumentRegister.NumberingSection.BusinessUnit)
		businessUnitId = 0;
			
	#region CUSTOM
	if (_obj.NumberingSection != finex.MotivContracts.DocumentRegister.NumberingSection.Category)
		categoryId = 0;
			
	// Вызываем свою реализацию запроса GetCurrentNumber		
	var command = string.Format(finex.MotivContracts.Queries.DocumentRegister.GetCurrentNumber,
			                            _obj.Id, month, year, leadDocumentId, quarter, departmentId, businessUnitId, categoryId);
	#endregion
			
	var executionResult = Sungero.Docflow.PublicFunctions.Module.ExecuteScalarSQLCommand(command);
	var result = 0;
	if (!(executionResult is DBNull) && executionResult != null)
		int.TryParse(executionResult.ToString(), out result);
			
	return result;
}
		
/// <summary>
/// Установить текущий номер документа для журнала.
/// </summary>
/// <param name="index">Текущий номер.</param>
/// <param name="leadDocumentId">ID ведущего документа.</param>
/// <param name="departmentId">ID подразделения.</param>
/// <param name="businessUnitId">ID НОР.</param>
/// <param name="categoryId">ID категории.</param>
/// <param name="date">Дата регистрации документа.</param>
[Public, Remote]
public virtual void SetCurrentNumber(int index, int leadDocumentId, int departmentId, int businessUnitId, int categoryId, DateTime date)
{
	var month = Sungero.Docflow.PublicFunctions.DocumentRegister.GetCurrentMonth(_obj, date);
	var year = Sungero.Docflow.PublicFunctions.DocumentRegister.GetCurrentYear(_obj, date);
	var quarter = Sungero.Docflow.PublicFunctions.DocumentRegister.GetCurrentQuarter(_obj, date);
		
	if (_obj.NumberingSection != Sungero.Docflow.DocumentRegister.NumberingSection.LeadingDocument)
		leadDocumentId = 0;
		
	if (_obj.NumberingSection != Sungero.Docflow.DocumentRegister.NumberingSection.Department)
		departmentId = 0;
		
	if (_obj.NumberingSection != Sungero.Docflow.DocumentRegister.NumberingSection.BusinessUnit)
		businessUnitId = 0;
		
	#region CUSTOM
	if (_obj.NumberingSection != finex.MotivContracts.DocumentRegister.NumberingSection.Category)
		categoryId = 0;
	
        // Вызываем свою реализацию запроса SetCurrentNumber 	
	var commandText = string.Format(finex.MotivContracts.Queries.DocumentRegister.SetCurrentNumber,
	                                _obj.Id, index, month, year, leadDocumentId, quarter, departmentId, businessUnitId, categoryId);
	#endregion
			
	Sungero.Docflow.PublicFunctions.Module.ExecuteSQLCommand(commandText);
}	
		
/// <summary>
/// Получить следующий регистрационный номер.
/// </summary>
/// <param name="registrationDate">Дата регистрации.</param>
/// <param name="leadDocument">Ведущий документ.</param>
/// <param name="department">Подразделение.</param>
/// <param name="businessUnit">НОР.</param>
/// <param name="category">Категория.</param>
/// <returns>Следующий регистрационный номер.</returns>
[Public]
public virtual int GetNextRegistrationNumber(DateTime registrationDate, int leadDocument = 0, int department = 0, int businessUnit = 0, int category = 0)
{
	if (_obj.NumberingSection != Sungero.Docflow.DocumentRegister.NumberingSection.LeadingDocument)
		leadDocument = 0;
			
	if (_obj.NumberingSection != Sungero.Docflow.DocumentRegister.NumberingSection.Department)
		department = 0;
			
	if (_obj.NumberingSection != Sungero.Docflow.DocumentRegister.NumberingSection.BusinessUnit)
		businessUnit = 0;
			
	#region CUSTOM
	if (_obj.NumberingSection != finex.MotivContracts.DocumentRegister.NumberingSection.Category)
		category = 0;
	#endregion
			
	using (var command = SQL.GetCurrentConnection().CreateCommand())
	{
		command.CommandType = System.Data.CommandType.StoredProcedure;
				
		command.CommandText = "Sungero_DocRegister_GetNextNumber";

		Sungero.Docflow.PublicFunctions.Module.AddIntegerParameterToCommand(command, "@basevalue", 1);
		Sungero.Docflow.PublicFunctions.Module.AddIntegerParameterToCommand(command, "@docregid", _obj.Id);
		Sungero.Docflow.PublicFunctions.Module.AddIntegerParameterToCommand(command, "@newmonth", Sungero.Docflow.PublicFunctions.DocumentRegister.GetCurrentMonth(_obj, registrationDate));
		Sungero.Docflow.PublicFunctions.Module.AddIntegerParameterToCommand(command, "@newyear", Sungero.Docflow.PublicFunctions.DocumentRegister.GetCurrentYear(_obj, registrationDate));
		Sungero.Docflow.PublicFunctions.Module.AddIntegerParameterToCommand(command, "@leaddoc", leadDocument);
		Sungero.Docflow.PublicFunctions.Module.AddIntegerParameterToCommand(command, "@newquarter", Sungero.Docflow.PublicFunctions.DocumentRegister.GetCurrentQuarter(_obj, registrationDate));
		Sungero.Docflow.PublicFunctions.Module.AddIntegerParameterToCommand(command, "@newdep", department);
		Sungero.Docflow.PublicFunctions.Module.AddIntegerParameterToCommand(command, "@newbusinessunit", businessUnit);
		// CUSTOM Передача нового параметра Id категории в обновленную процедуру GeNextNumber
		Sungero.Docflow.PublicFunctions.Module.AddIntegerParameterToCommand(command, "@newcategory", category);
				
		var code = Sungero.Docflow.PublicFunctions.Module.AddIntegerOutputParameterToCommand(command, "@result");

		command.ExecuteNonQuery();
		var registrationIndex = 0;
		int.TryParse(code.Value.ToString(), out registrationIndex);
		return registrationIndex;
	}
}

 

Что бы базовый механизм регистрации продолжал исправно работать во всех других ТД, переопределяем все вышеуказанные функции. Вместо базовой логики вызываем свои перегрузки с передачей параметра Id категории равным 0. Таким образом при вызове базовых функций код неизбежно придет в наши перегрузки.

/// <summary>
/// Получить следующий регистрационный номер.
/// </summary>
[Remote(IsPure = true)]
public override string GetNextNumber(DateTime date, int leadDocumentId, IOfficialDocument document, string leadingDocumentNumber,
                                     int departmentId, int businessUnitId, string caseFileIndex, string docKindCode, string indexLeadingSymbol)
{
	return this.GetNextNumber(date, leadDocumentId, document, leadingDocumentNumber, departmentId, businessUnitId, 0, caseFileIndex, docKindCode, indexLeadingSymbol);
}

/// <summary>
/// Получить следующий порядковый номер для журнала.
/// </summary>
public override int? GetNextIndex(DateTime date, int leadDocumentId, int departmentId, int businessUnitId, IOfficialDocument document)
{
	return this.GetNextIndex(date, leadDocumentId, departmentId, businessUnitId, 0, document);
}

/// <summary>
/// Получить текущий порядковый номер для журнала.
/// </summary>
[Remote(IsPure = true)]
public override int GetCurrentNumber(DateTime date, int leadDocumentId, int departmentId, int businessUnitId)
{
	return Functions.DocumentRegister.GetCurrentNumber(_obj, date, leadDocumentId, departmentId, businessUnitId, 0);
}

/// <summary>
/// Установить текущий номер документа для журнала.
/// </summary>
[Public, Remote]
public override void SetCurrentNumber(int index, int leadDocumentId, int departmentId, int businessUnitId, DateTime date)
{
	this.SetCurrentNumber(index, leadDocumentId, departmentId, businessUnitId, 0, date);
}

/// <summary>
/// Получить следующий регистрационный номер.
/// </summary>
[Public]
public override int GetNextRegistrationNumber(DateTime registrationDate, int leadDocument, int department, int businessUnit)
{
	return this.GetNextRegistrationNumber(registrationDate, leadDocument, department, businessUnit, 0);
}

 

Изменение событий

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

  • при формировании отчета пропущенных номеров;
  • при присвоении нового номера из журнала регистрации;
  • при сохранении документа.
  • в обработчике действия "Регистрация".

Так как обработчики последних двух пунктов зашиты в OfficialDocument, нужно учитывать, что в версиях ниже 4.0 придется перекрывать все ТД, в которых нумерация может идти по новому разрезу (в нашем случае это договоры и доп. соглашения).

Что бы нумерация проходила в новом разрезе, необходимо заменить функцию Functions.OfficialDocument.Register(), вызываемую в обработчике действия «регистрация» ТД OfficialDocument, т.к. она не является виртуальной.

public override void Register(Sungero.Domain.Client.ExecuteActionArgs e)
{
	var originalNumber = _obj.State.Properties.RegistrationNumber.OriginalValue;
	var originalDate = _obj.State.Properties.RegistrationDate.OriginalValue;
	
	// Если документ в процессе верификации, то игнорировать изменение полей регистрационных данных.
	if (_obj.VerificationState == Sungero.Docflow.OfficialDocument.VerificationState.InProcess)
		e.Params.Remove(Sungero.Docflow.Constants.OfficialDocument.NeedValidateRegisterFormat);
	
	#region Custom Вызов функции для регистрации.
	finex.MotivContracts.Module.Docflow.Functions.Module.CustomContractsRegister(_obj, e);
	#endregion
	
	if (_obj.RegistrationNumber != originalNumber)
		_obj.State.Properties.RegistrationNumber.HighlightColor = Colors.Empty;
	if (_obj.RegistrationDate != originalDate)
		_obj.State.Properties.RegistrationDate.HighlightColor = Colors.Empty;
}
/// <summary>
/// Зарегистрировать документ.
/// </summary>
public virtual void CustomContractsRegister(Sungero.Docflow.IOfficialDocument document, Sungero.Domain.Client.ExecuteActionArgs e)
{
	if (!e.Validate())
		return;
	
	var officalDocumentsClientFunctions = new Sungero.Docflow.Client.OfficialDocumentFunctions(document);
	// Регистрация документа с зарезервированным номером.
	if (document.RegistrationState == Sungero.Docflow.OfficialDocument.RegistrationState.Reserved)
	{
		officalDocumentsClientFunctions.RegisterWithReservedNumber(e);
		return;
	}
			
	#region Custom Список доступных журналов (свой вариант реализации).
	var dialogParams = CustomContracts.PublicFunctions.Module.Remote.GetRegistrationDialogParams(document, Sungero.Docflow.RegistrationSetting.SettingType.Registration);
        #endregion

	if (dialogParams.Registers == null || !dialogParams.Registers.Any())
	{
		e.AddError(Sungero.Docflow.Resources.NoDocumentRegistersAvailable);
		return;
	}

	#region Custom Вызвать диалог (свой вариант реализации).
	var result = RunRegistrationDialog(document, dialogParams);
	#endregion
		
	if (result != null)
	{
		Sungero.Docflow.PublicFunctions.OfficialDocument.RegisterDocument(document, result.Register, result.Date, result.Number, false, true);		
		Dialogs.NotifyMessage(Sungero.Docflow.Resources.SuccessRegisterNotice);
	}
	return;
}

Здесь нам потребуется заменить статические функции GetRegistrationDialogParams и RunRegistrationDialog, а весь остальной функционал берется из базовой логики. Так же стоит учесть, что функция GetRegistrationDialogParams возвращает параметры диалога в виде структуры DialogParams модуля Docflow, следовательно необходимо создать новую структуру в своем модуле с добавлением нового свойства для категории договора.

/// <summary>
/// Получить все данные для отображения диалога регистрации.
/// </summary>
/// <param name="document">Документ.</param>
/// <param name="operation">Операция.</param>
/// <returns>Параметры диалога.</returns>
[Public, Remote(IsPure = true)]
public virtual CustomContracts.Structures.Module.IDialogParams GetRegistrationDialogParams(Sungero.Docflow.IOfficialDocument document, Enumeration operation)
{
	// Получить функции разделяемого и серверного слоя OfficialDocument.
	var officialDocumentSharedFunctions = new Sungero.Docflow.Shared.OfficialDocumentFunctions(document);
	var officialDocumentServerFunctions = new Sungero.Docflow.Server.OfficialDocumentFunctions(document);
	
	var leadDocumentId = officialDocumentSharedFunctions.GetLeadDocumentId();
	var leadDocumentNumber = officialDocumentSharedFunctions.GetLeadDocumentNumber();
	var numberValidationDisabled = officialDocumentServerFunctions.IsNumberValidationDisabled();
	var departmentId = document.Department != null ? document.Department.Id : 0;
	var departmentCode = document.Department != null ? document.Department.Code : string.Empty;
	var businessUnitId = document.BusinessUnit != null ? document.BusinessUnit.Id : 0;
	var businessUnitCode = document.BusinessUnit != null ? document.BusinessUnit.Code : string.Empty;
	var docKindCode = document.DocumentKind != null ? document.DocumentKind.Code : string.Empty;
	var caseFileIndex = document.CaseFile != null ? document.CaseFile.Index : string.Empty;
	var isClerk = document.AccessRights.CanRegister();
	var counterpartyCode = Sungero.Docflow.PublicFunctions.OfficialDocument.GetCounterpartyCode(document);
	var currentRegistrationDate = document.RegistrationDate ?? Calendar.UserToday;
	
	#region Custom вычисляем id записи категории для получения очередного номера.
	var categoryId = 0;
	if (Contracts.Is(document))
		categoryId = Contracts.As(document).DocumentGroup.Id;
	else if (SupAgreements.Is(document))
		categoryId = SupAgreements.As(document).DocumentGroup.Id;
	#endregion
	
	var registers = Sungero.Docflow.PublicFunctions.OfficialDocument.GetDocumentRegistersByDocument(document, operation);
	var defaultDocumentRegister = MotivContracts.PublicFunctions.DocumentRegister.MotivGetDefaultDocRegister(document, registers, operation);
	string nextNumber = string.Empty;

	#region Custom заменяем вызов базового запроса GetNextNumber
	if (defaultDocumentRegister != null)
		nextNumber = MotivContracts.PublicFunctions.DocumentRegister.Remote.GetNextNumber(MotivContracts.DocumentRegisters.As(defaultDocumentRegister), currentRegistrationDate, leadDocumentId, document,
		                                                                                  leadDocumentNumber, departmentId, businessUnitId, categoryId, caseFileIndex, docKindCode,
		                                                                                  Sungero.Docflow.Constants.OfficialDocument.DefaultIndexLeadingSymbol);
	
	// Функция должна возвращать структуру с учетом новых элементов в нашем случае categoryId.
	return Structures.Module.DialogParams.Create(registers.Select(r => MotivContracts.DocumentRegisters.As(r)).ToList(),
	                                             operation, MotivContracts.DocumentRegisters.As(defaultDocumentRegister),
	                                             document.RegistrationNumber, currentRegistrationDate, nextNumber,
	                                             leadDocumentId, leadDocumentNumber, numberValidationDisabled,
	                                             departmentId, departmentCode, businessUnitCode, businessUnitId,
	                                             caseFileIndex, docKindCode, counterpartyCode, isClerk, categoryId);
	#endregion
}

Функция  RunRegistrationDialog , запускающая обработчик диалога регистрации, на входе принимает структуру с данными для отображения диалога. В событиях диалога, функции RunRegistrationDialog, вызывается функция GetNextNumber, соответственно переписываем ее с добавлением нового параметра. Например событие изменения значения журнала регистрации:

register.SetOnValueChanged((e) =>
                           {
                           	hyperlink.IsEnabled = e.NewValue != null && date.Value.HasValue;
                           	number.IsEnabled = isManual.Value.Value && e.NewValue != null && date.Value.HasValue;
                           	
                           	if (e.NewValue != null)
                           	{
                           		var previewDate = date.Value ?? Calendar.UserToday;
                           		#region Custom Заменяем вызов базового запроса GetNextNumber
                           		var previewNumber = MotivContracts.PublicFunctions.DocumentRegister.Remote
                           			.GetNextNumber(e.NewValue, previewDate, leadDocumentId, document, leadDocumentNumber, departmentId,
                           			               businessUnitId, categoryId, caseFileIndex, docKindCode, Sungero.Docflow.Constants.OfficialDocument.DefaultIndexLeadingSymbol);
                           		#endregion
                           		number.Value = previewNumber;
                           	}
                           	else
                           		number.Value = string.Empty;
                           });

Как итог демонстрация присвоения номера регистрации в разрезе категории договора.


 

Михаил Чернов

Спасибо за статью! Может быть, я что-то не то сделал, но только мне пришлось перекрыть модуль Docflow и до базовой инициализации удалить хранимую процедуру. Иначе базовая инициализация Docflow завершается с ошибкой, связанной с уникальностью имени процедуры. 

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