ModuleAsyncHandlers.cs 11.3 KB
using System;
using System.Collections.Generic;
using System.Linq;
using Sungero.Core;
using Sungero.CoreEntities;

namespace DirRX.CaseArchiving.Server
{
  public class ModuleAsyncHandlers
  {

    public virtual void ChangeCaseFileStageToTransferred(DirRX.CaseArchiving.Server.AsyncHandlerInvokeArgs.ChangeCaseFileStageToTransferredInvokeArgs args)
    {
      // Переместить дело в архив.
      var caseFile = DirRX.LongTermArchive.CaseFiles.Get(args.caseFileId);
      caseFile.LTAStageDirRX = DirRX.LongTermArchive.CaseFile.LTAStageDirRX.ArchivedDirRX;
      caseFile.LTAArchiveDateDirRX = args.archiveDate;
      caseFile.Save();
    }

    public virtual void TransferDocumentsToArchive(DirRX.CaseArchiving.Server.AsyncHandlerInvokeArgs.TransferDocumentsToArchiveInvokeArgs args)
    {
      const int MaxIterationCount = 100;
      args.Retry = false;
      var iteration = args.RetryIteration;

      var inventoryId = args.caseInventoryId;

      Logger.DebugFormat("CaseArchiving. Старт асинхронного обработчика TransferDocumentsToArchive для описи ИД {0}. Итерация {1}.", inventoryId, iteration);

      var inventory = CaseArchiving.CaseInventories.GetAll(x => x.Id == inventoryId).SingleOrDefault();
      if (inventory == null || Locks.GetLockInfo(inventory).IsLockedByOther)
      {
        Logger.DebugFormat("TransferDocumentsToArchive. Не удалось получить опись электронных дел ИД {0}.", inventoryId);
        args.Retry = true;
        return;
      }
      else if (inventory.ArchiveState == CaseArchiving.CaseInventory.ArchiveState.Complete)
      {
        Logger.DebugFormat("TransferDocumentsToArchive. Документы описи ИД {0} уже переданы на архивное храненение.", inventoryId);
        return;
      }
      
      // ------------------------------------------------------------------------------
      // Если описи используются в исходной системе, сформировать архивные контейнеры.
      // ------------------------------------------------------------------------------
      if (PublicFunctions.Module.Remote.IsCaseInventoryUsedInSourceSystem())
      {
        // При первом запуске получить список ИД документов для обработки из дел.
        if (!inventory.ArchiveState.HasValue || inventory.ArchiveState == DirRX.CaseArchiving.CaseInventory.ArchiveState.Approved)
        {
          inventory.ProcessingDate = Calendar.Now;
          inventory.ArchiveState = CaseArchiving.CaseInventory.ArchiveState.InQueue;
          inventory.Save();
          
          var caseFiles = CaseArchiving.PublicFunctions.CaseInventory.Remote.GetCaseFiles(inventory);
          
          foreach (var caseFile in caseFiles)
          {
            // Отправить каждый документ в обработку.
            var documentIds = new List<int>();
            foreach (var document in Sungero.Docflow.OfficialDocuments.GetAll(x => x.CaseFile.Equals(caseFile)))
            {
              var error = Container.PublicFunctions.Module.EnqueueDocumentForInventory(document, inventoryId);
              if (error == string.Empty)
                documentIds.Add(document.Id);
            }

            // Зафиксировать список ИД документов, включенных в каждое дело.
            caseFile.LTAArchiveDocumentsDirRX = "{" + string.Join(",", documentIds) + "}";
            caseFile.Save();
          }
          
          // Зафиксировать список ИД дел, включенных в опись.
          inventory.ApprovedIds = "{" + string.Join(",", caseFiles.Select(x => x.Id)) + "}";
          inventory.Save();
          
          args.Retry = true;
          args.NextRetryTime = Calendar.Now.AddMinutes(2);
        }
        else if (inventory.ArchiveState != CaseArchiving.CaseInventory.ArchiveState.Error)
        {
          // Убедиться, что этап обработки завершен для всех документов без ошибок.
          var allEventLogs = Container.TransferEventLogs.GetAll(x => x.InventoryId == inventoryId).ToList();
          
          var containerStates = allEventLogs.Select(x => x.CurrentState.HasValue ? x.CurrentState.Value.ToString() : "InQueue").Distinct().ToList();
          
          if (!containerStates.Any())
          {
            containerStates.Add("Error");
            Logger.DebugFormat("TransferDocumentsToArchive. ИД описи {0}. На найдены документы для обработки", inventoryId);
          }
          
          var currentState = containerStates.Any() ? containerStates.First() : "Error";
          
          Logger.DebugFormat("TransferDocumentsToArchive. ИД описи {0}. Итерация {1}. Статусы контейнеров: {2}. Статус описи {3}.", inventoryId, iteration, string.Join(", ", containerStates), inventory.ArchiveState.Value.ToString());
          
          // Если хотя бы один контейнер ошибочен, прекратить обработку.
          if (containerStates.Contains("Error"))
          {
            inventory.ArchiveState = CaseArchiving.CaseInventory.ArchiveState.Error;
            inventory.Save();
            
            args.Retry = false;
          }
          else if (containerStates.Count == 1 && currentState != "InQueue" && inventory.ArchiveState.Value.ToString() != currentState)
          {
            // Если все документы обработаны, перевести на след. этап.
            inventory.ArchiveState = new Sungero.Core.Enumeration(currentState);
            inventory.Save();
            
            if (currentState != "Complete")
            {
              foreach (var eventLogId in allEventLogs.Select(x => x.Id))
              {
                var asyncHandler = Container.AsyncHandlers.ProcessNextStageForInventory.Create();
                asyncHandler.eventLogId = eventLogId;
                asyncHandler.ExecuteAsync();
              }
              args.Retry = true;
              args.NextRetryTime = Calendar.Now.AddMinutes(2);
            }
            else
            {
              // После подтверждения приема контейнеров в архиве изменить статус в делах и поставить дату передачи в архив.
              var archiveDate = Calendar.Now;
              
              var caseFiles = CaseArchiving.PublicFunctions.CaseInventory.Remote.GetCaseFiles(inventory);
              foreach (var caseFileId in caseFiles.Select(x => x.Id))
              {
                var caseFileHandler = AsyncHandlers.ChangeCaseFileStageToTransferred.Create();
                caseFileHandler.caseFileId = caseFileId;
                caseFileHandler.archiveDate = archiveDate;
                caseFileHandler.ExecuteAsync();
              }
              inventory.ArchiveDate = archiveDate;
              inventory.Save();              
              
              args.Retry = false;
            }
          }
          else
          {
            // Обработка контейнеров не завершена. Необходимо подождать, либо выставить статус Ошибка, если превышено число итераций.
            if (iteration > MaxIterationCount)
            {
              inventory.ArchiveState = CaseArchiving.CaseInventory.ArchiveState.Error;
              inventory.Save();
              args.Retry = false;
            }
            else
            {
              args.Retry = true;
              args.NextRetryTime = Calendar.Now.AddSeconds(30);
            }
          }
          
          Logger.DebugFormat("TransferDocumentsToArchive. ИД описи {0}. Итерация {1}. Новый статус описи: {2}. Запланирован след. запуск: {3}", inventoryId, iteration,
                             inventory.ArchiveState.Value.ToString(), args.Retry ? args.NextRetryTime.ToString() : "false");
          
          if (inventory.ArchiveState == CaseArchiving.CaseInventory.ArchiveState.Error)
          {
            // Список ошибочных ИД.
            var errorIds = Container.TransferEventLogs.GetAll(x => x.InventoryId == inventoryId && x.CurrentState == Container.TransferEventLog.CurrentState.Error).Select(x => x.Id).ToList();
            var message = "Обработка отменена из-за ошибки обработки другого документа описи (ИД " + string.Join(", ", errorIds) + ").";
            foreach (var item in Container.TransferEventLogs.GetAll(x => x.InventoryId == inventoryId && !errorIds.Contains(x.Id)))
            {
              var record = item.Protocol.AddNew();
              record.Time = Calendar.Now;
              record.Action = Container.Resources.ActionCreateContainer;
              record.Message = message;
              item.CurrentState = Container.TransferEventLog.CurrentState.Error;
              item.Save();
            }
          }
        }
      }
      else if (PublicFunctions.Module.Remote.IsCaseInventoryUsedInArchiveSystem())
      {
        // ------------------------------------------------------------------------------
        // Если описи используются в архивной системе, проставить отметку в Журнале поступления и выбытия.
        // ------------------------------------------------------------------------------
        var archiveDate = Calendar.Now;
        
        // Для каждого дела, включенного в опись.
        var caseFiles = CaseArchiving.PublicFunctions.CaseInventory.Remote.GetCaseFiles(inventory);
        foreach (var caseFile in caseFiles)
        {
          // Зафиксировать список архивных документов, включенных в дело.
          var archiveDocumentIds = DirRX.Storage.PublicFunctions.Module.GetArchiveDocumentIds(caseFile.Id);
          
          foreach (var documentId in archiveDocumentIds)
          {
            // Связать архивный документ с описью через журнал событий.
            var error = DirRX.Storage.PublicFunctions.Module.LinkArchiveDocumentToInventory(documentId, inventoryId);
          }

          caseFile.LTAArchiveDocumentsDirRX = "{" + string.Join(",", archiveDocumentIds) + "}";
          caseFile.LTAArchiveDateDirRX = archiveDate;
          caseFile.Save();
        }
        
        // Зафиксировать список ИД дел, включенных в опись.
        inventory.ApprovedIds = "{" + string.Join(",", caseFiles.Select(x => x.Id)) + "}";
        inventory.ArchiveDate = archiveDate;
        inventory.ArchiveState = CaseArchiving.CaseInventory.ArchiveState.Complete;
        inventory.Save();
      }
      
      // Уведомить делопроизводителя и архивиста о завершении обработки описи.
      if (args.Retry == false)
        CaseArchiving.PublicFunctions.CaseInventory.SendCompletionNotification(inventory);      
    }

  }
}