using System; using System.Collections.Generic; using System.Data; using Microsoft.Data.SqlClient; using System.Linq; using System.Threading; using System.Threading.Tasks; using XLAB2.Infrastructure; namespace XLAB2 { internal sealed class PsvDataService { public bool DocumentNumberExists(string documentNumber, string excludeDocumentNumber) { var normalizedNumber = NormalizeDocumentNumber(documentNumber); if (normalizedNumber == null) { return false; } using (var connection = CreateConnection()) using (var command = new SqlCommand( @" SELECT COUNT(1) FROM dbo.EKZMK WHERE NNZVPV = @DocumentNumber AND (@ExcludeDocumentNumber = N'' OR NNZVPV <> @ExcludeDocumentNumber);", connection)) { connection.Open(); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = normalizedNumber; command.Parameters.Add("@ExcludeDocumentNumber", SqlDbType.NVarChar, 60).Value = excludeDocumentNumber ?? string.Empty; return Convert.ToInt32(command.ExecuteScalar()) > 0; } } public async Task DocumentNumberExistsAsync(string documentNumber, string excludeDocumentNumber, CancellationToken cancellationToken = default) { var normalizedNumber = NormalizeDocumentNumber(documentNumber); if (normalizedNumber == null) { return false; } await using (var connection = await SqlServerConnectionFactory.Current.OpenConnectionAsync(cancellationToken).ConfigureAwait(false)) { return await DocumentNumberExistsAsync(connection, null, normalizedNumber, excludeDocumentNumber, cancellationToken).ConfigureAwait(false); } } public IReadOnlyList LoadCustomers() { const string sql = @" SELECT z.IDFRPDV AS CustomerId, fr.NMFRPD AS CustomerName FROM dbo.EKZ z JOIN dbo.FRPD fr ON fr.IDFRPD = z.IDFRPDV WHERE z.IDFRPDV IS NOT NULL GROUP BY z.IDFRPDV, fr.NMFRPD ORDER BY fr.NMFRPD;"; var customers = new List(); using (var connection = CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; using (var reader = command.ExecuteReader()) { while (reader.Read()) { customers.Add(new CustomerReference { CustomerId = GetInt32(reader, "CustomerId"), CustomerName = GetString(reader, "CustomerName") }); } } } return customers; } public Task> LoadCustomersAsync(CancellationToken cancellationToken = default) { const string sql = @" SELECT z.IDFRPDV AS CustomerId, fr.NMFRPD AS CustomerName FROM dbo.EKZ z JOIN dbo.FRPD fr ON fr.IDFRPD = z.IDFRPDV WHERE z.IDFRPDV IS NOT NULL GROUP BY z.IDFRPDV, fr.NMFRPD ORDER BY fr.NMFRPD;"; return SqlServerConnectionFactory.Current.QueryOpenConnectionAsync( sql, delegate(SqlDataReader reader) { return new CustomerReference { CustomerId = GetInt32(reader, "CustomerId"), CustomerName = GetString(reader, "CustomerName") }; }, ConfigureCommandTimeout, cancellationToken).ContinueWith>(delegate(Task> task) { return task.Result; }, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } public IReadOnlyList LoadVerifiers() { const string sql = @" SELECT p.IDPRSN AS PersonId, p.PRFIO AS FullName FROM dbo.PRSN p WHERE NULLIF(LTRIM(RTRIM(p.PRFIO)), N'') IS NOT NULL ORDER BY p.PRFIO;"; var verifiers = new List(); using (var connection = CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; using (var reader = command.ExecuteReader()) { while (reader.Read()) { verifiers.Add(new PersonReference { PersonId = GetInt32(reader, "PersonId"), FullName = GetString(reader, "FullName") }); } } } return verifiers; } public Task> LoadVerifiersAsync(CancellationToken cancellationToken = default) { const string sql = @" SELECT p.IDPRSN AS PersonId, p.PRFIO AS FullName FROM dbo.PRSN p WHERE NULLIF(LTRIM(RTRIM(p.PRFIO)), N'') IS NOT NULL ORDER BY p.PRFIO;"; return SqlServerConnectionFactory.Current.QueryOpenConnectionAsync( sql, delegate(SqlDataReader reader) { return new PersonReference { PersonId = GetInt32(reader, "PersonId"), FullName = GetString(reader, "FullName") }; }, ConfigureCommandTimeout, cancellationToken).ContinueWith>(delegate(Task> task) { return task.Result; }, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } public IReadOnlyList LoadVerificationDocumentForms(bool isPassed) { const string sql = @" SELECT DISTINCT fr.IDFRDMS AS DocumentFormId, v.IDVDODVDD AS LinkTypeId, sp.NMVDD AS DocumentKindName, fr.NMFRD AS DocumentFormName FROM dbo.FRDMS fr JOIN dbo.SPVDD sp ON sp.IDSPVDD = fr.IDSPVDD JOIN dbo.VDODVDD v ON v.IDSPVDD = fr.IDSPVDD WHERE v.IDSPVDOD = 2 AND fr.IDSPVDD = @DocumentTypeId ORDER BY fr.NMFRD, v.IDVDODVDD;"; var forms = new List(); using (var connection = CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@DocumentTypeId", SqlDbType.Int).Value = isPassed ? 6 : 2; using (var reader = command.ExecuteReader()) { while (reader.Read()) { forms.Add(new DocumentFormReference { DocumentFormId = GetInt32(reader, "DocumentFormId"), LinkTypeId = GetInt32(reader, "LinkTypeId"), DocumentKindName = GetString(reader, "DocumentKindName"), DocumentFormName = GetString(reader, "DocumentFormName") }); } } } return forms; } public Task> LoadVerificationDocumentFormsAsync(bool isPassed, CancellationToken cancellationToken = default) { const string sql = @" SELECT DISTINCT fr.IDFRDMS AS DocumentFormId, v.IDVDODVDD AS LinkTypeId, sp.NMVDD AS DocumentKindName, fr.NMFRD AS DocumentFormName FROM dbo.FRDMS fr JOIN dbo.SPVDD sp ON sp.IDSPVDD = fr.IDSPVDD JOIN dbo.VDODVDD v ON v.IDSPVDD = fr.IDSPVDD WHERE v.IDSPVDOD = 2 AND fr.IDSPVDD = @DocumentTypeId ORDER BY fr.NMFRD, v.IDVDODVDD;"; return SqlServerConnectionFactory.Current.QueryOpenConnectionAsync( sql, delegate(SqlDataReader reader) { return new DocumentFormReference { DocumentFormId = GetInt32(reader, "DocumentFormId"), LinkTypeId = GetInt32(reader, "LinkTypeId"), DocumentKindName = GetString(reader, "DocumentKindName"), DocumentFormName = GetString(reader, "DocumentFormName") }; }, delegate(SqlCommand command) { ConfigureCommandTimeout(command); command.Parameters.Add("@DocumentTypeId", SqlDbType.Int).Value = isPassed ? 6 : 2; }, cancellationToken).ContinueWith>(delegate(Task> task) { return task.Result; }, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } public IReadOnlyList LoadSpoiItems() { const string sql = @" SELECT s.IDSPOI AS Id, s.KDOI AS Code, s.NMOI AS Name FROM dbo.SPOI s ORDER BY s.NMOI, s.KDOI, s.IDSPOI;"; var items = new List(); using (var connection = CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; using (var reader = command.ExecuteReader()) { while (reader.Read()) { items.Add(new SpoiDirectoryItem { Id = GetInt32(reader, "Id"), Code = GetString(reader, "Code"), Name = GetString(reader, "Name") }); } } } return items; } public Task> LoadSpoiItemsAsync(CancellationToken cancellationToken = default) { const string sql = @" SELECT s.IDSPOI AS Id, s.KDOI AS Code, s.NMOI AS Name FROM dbo.SPOI s ORDER BY s.NMOI, s.KDOI, s.IDSPOI;"; return SqlServerConnectionFactory.Current.QueryOpenConnectionAsync( sql, delegate(SqlDataReader reader) { return new SpoiDirectoryItem { Id = GetInt32(reader, "Id"), Code = GetString(reader, "Code"), Name = GetString(reader, "Name") }; }, ConfigureCommandTimeout, cancellationToken).ContinueWith>(delegate(Task> task) { return task.Result; }, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } public int AddSpoiItem(SpoiDirectoryItem item) { var normalizedItem = NormalizeSpoiItem(item); const string sql = @" INSERT INTO dbo.SPOI ( KDOI, NMOI ) VALUES ( @Code, @Name ); SELECT CAST(SCOPE_IDENTITY() AS int);"; using (var connection = CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); EnsureSpoiCodeIsUnique(connection, normalizedItem.Code, null); EnsureSpoiNameIsUnique(connection, normalizedItem.Name, null); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@Code", SqlDbType.VarChar, SpoiDirectoryRules.CodeMaxLength).Value = normalizedItem.Code; command.Parameters.Add("@Name", SqlDbType.VarChar, SpoiDirectoryRules.NameMaxLength).Value = normalizedItem.Name; try { return Convert.ToInt32(command.ExecuteScalar()); } catch (SqlException ex) when (IsSpoiDuplicateCodeViolation(ex)) { throw CreateSpoiDuplicateCodeException(normalizedItem.Code, ex); } catch (SqlException ex) when (IsSpoiDuplicateNameViolation(ex)) { throw CreateSpoiDuplicateNameException(normalizedItem.Name, ex); } } } public void UpdateSpoiItem(SpoiDirectoryItem item) { var normalizedItem = NormalizeSpoiItem(item); if (normalizedItem.Id <= 0) { throw new InvalidOperationException("РќРµ выбрана запись SPOI для изменения."); } const string sql = @" UPDATE dbo.SPOI SET KDOI = @Code, NMOI = @Name WHERE IDSPOI = @Id; SELECT @@ROWCOUNT;"; using (var connection = CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); EnsureSpoiCodeIsUnique(connection, normalizedItem.Code, normalizedItem.Id); EnsureSpoiNameIsUnique(connection, normalizedItem.Name, normalizedItem.Id); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@Id", SqlDbType.Int).Value = normalizedItem.Id; command.Parameters.Add("@Code", SqlDbType.VarChar, SpoiDirectoryRules.CodeMaxLength).Value = normalizedItem.Code; command.Parameters.Add("@Name", SqlDbType.VarChar, SpoiDirectoryRules.NameMaxLength).Value = normalizedItem.Name; try { if (Convert.ToInt32(command.ExecuteScalar()) == 0) { throw new InvalidOperationException("Запись SPOI для изменения РЅРµ найдена."); } } catch (SqlException ex) when (IsSpoiDuplicateCodeViolation(ex)) { throw CreateSpoiDuplicateCodeException(normalizedItem.Code, ex); } catch (SqlException ex) when (IsSpoiDuplicateNameViolation(ex)) { throw CreateSpoiDuplicateNameException(normalizedItem.Name, ex); } } } public SpoiDeleteResult DeleteSpoiItem(int id) { if (id <= 0) { throw new InvalidOperationException("РќРµ выбрана запись SPOI для удаления."); } const string sql = @" DELETE FROM dbo.SPOI WHERE IDSPOI = @Id; SELECT @@ROWCOUNT;"; try { using (var connection = CreateConnection()) { connection.Open(); var blockers = LoadSpoiDeleteBlockers(connection, id); if (blockers.Count > 0) { return new SpoiDeleteResult { IsDeleted = false, WarningMessage = CreateSpoiDeleteBlockedMessage(blockers) }; } using (var command = new SqlCommand(sql, connection)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@Id", SqlDbType.Int).Value = id; if (Convert.ToInt32(command.ExecuteScalar()) == 0) { throw new InvalidOperationException("Запись SPOI для удаления РЅРµ найдена."); } } return new SpoiDeleteResult { IsDeleted = true }; } } catch (SqlException ex) when (ex.Number == 547) { return new SpoiDeleteResult { IsDeleted = false, WarningMessage = CreateSpoiDeleteBlockedMessage(ex) }; } } public IReadOnlyList LoadSpnmtpItems() { const string sql = @" SELECT s.IDSPNMTP AS Id, s.NMTP AS Name, s.NMTPSP AS SpecialName FROM dbo.SPNMTP s ORDER BY s.NMTP, s.IDSPNMTP;"; var items = new List(); using (var connection = CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; using (var reader = command.ExecuteReader()) { while (reader.Read()) { items.Add(new SpnmtpDirectoryItem { Id = GetInt32(reader, "Id"), Name = GetString(reader, "Name"), SpecialName = GetString(reader, "SpecialName") }); } } } return items; } public Task> LoadSpnmtpItemsAsync(CancellationToken cancellationToken = default) { const string sql = @" SELECT s.IDSPNMTP AS Id, s.NMTP AS Name, s.NMTPSP AS SpecialName FROM dbo.SPNMTP s ORDER BY s.NMTP, s.IDSPNMTP;"; return SqlServerConnectionFactory.Current.QueryOpenConnectionAsync( sql, delegate(SqlDataReader reader) { return new SpnmtpDirectoryItem { Id = GetInt32(reader, "Id"), Name = GetString(reader, "Name"), SpecialName = GetString(reader, "SpecialName") }; }, ConfigureCommandTimeout, cancellationToken).ContinueWith>(delegate(Task> task) { return task.Result; }, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } public int AddSpnmtpItem(SpnmtpDirectoryItem item) { var normalizedItem = NormalizeSpnmtpItem(item); const string sql = @" INSERT INTO dbo.SPNMTP ( NMTP, NMTPSP ) VALUES ( @Name, @SpecialName ); SELECT CAST(SCOPE_IDENTITY() AS int);"; using (var connection = CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); EnsureSpnmtpNameIsUnique(connection, normalizedItem.Name, null); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@Name", SqlDbType.NVarChar, SpnmtpDirectoryRules.NameMaxLength).Value = normalizedItem.Name; command.Parameters.Add("@SpecialName", SqlDbType.VarChar, SpnmtpDirectoryRules.SpecialNameMaxLength).Value = (object)normalizedItem.SpecialName ?? DBNull.Value; try { return Convert.ToInt32(command.ExecuteScalar()); } catch (SqlException ex) when (IsSpnmtpDuplicateNameViolation(ex)) { throw CreateSpnmtpDuplicateNameException(normalizedItem.Name, ex); } } } public void UpdateSpnmtpItem(SpnmtpDirectoryItem item) { var normalizedItem = NormalizeSpnmtpItem(item); if (normalizedItem.Id <= 0) { throw new InvalidOperationException("РќРµ выбрана запись SPNMTP для изменения."); } const string sql = @" UPDATE dbo.SPNMTP SET NMTP = @Name, NMTPSP = @SpecialName WHERE IDSPNMTP = @Id; SELECT @@ROWCOUNT;"; using (var connection = CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); EnsureSpnmtpNameIsUnique(connection, normalizedItem.Name, normalizedItem.Id); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@Id", SqlDbType.Int).Value = normalizedItem.Id; command.Parameters.Add("@Name", SqlDbType.NVarChar, SpnmtpDirectoryRules.NameMaxLength).Value = normalizedItem.Name; command.Parameters.Add("@SpecialName", SqlDbType.VarChar, SpnmtpDirectoryRules.SpecialNameMaxLength).Value = (object)normalizedItem.SpecialName ?? DBNull.Value; try { if (Convert.ToInt32(command.ExecuteScalar()) == 0) { throw new InvalidOperationException("Запись SPNMTP для изменения РЅРµ найдена."); } } catch (SqlException ex) when (IsSpnmtpDuplicateNameViolation(ex)) { throw CreateSpnmtpDuplicateNameException(normalizedItem.Name, ex); } } } public SpnmtpDeleteResult DeleteSpnmtpItem(int id) { if (id <= 0) { throw new InvalidOperationException("РќРµ выбрана запись SPNMTP для удаления."); } const string sql = @" DELETE FROM dbo.SPNMTP WHERE IDSPNMTP = @Id; SELECT @@ROWCOUNT;"; try { using (var connection = CreateConnection()) { connection.Open(); var blockers = LoadSpnmtpDeleteBlockers(connection, id); if (blockers.Count > 0) { return new SpnmtpDeleteResult { IsDeleted = false, WarningMessage = CreateSpnmtpDeleteBlockedMessage(blockers) }; } using (var command = new SqlCommand(sql, connection)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@Id", SqlDbType.Int).Value = id; if (Convert.ToInt32(command.ExecuteScalar()) == 0) { throw new InvalidOperationException("Запись SPNMTP для удаления РЅРµ найдена."); } } return new SpnmtpDeleteResult { IsDeleted = true }; } } catch (SqlException ex) when (ex.Number == 547) { return new SpnmtpDeleteResult { IsDeleted = false, WarningMessage = CreateSpnmtpDeleteBlockedMessage(ex) }; } } public IReadOnlyList LoadDocuments(bool loadClosedDocumentsForCurrentYear) { var sql = @" SELECT m.NNZVPV AS DocumentNumber, MAX(m.DTPRM) AS AcceptedOn, MAX(m.DTVDM) AS IssuedOn, MIN(dep.NMFRPD) AS DepartmentName, CASE WHEN COUNT(DISTINCT z.IDFRPDV) = 1 THEN MIN(z.IDFRPDV) ELSE NULL END AS CustomerId, CASE WHEN COUNT(DISTINCT z.IDFRPDV) = 1 THEN MIN(ownerOrg.NMFRPD) ELSE N'' END AS CustomerName, COUNT(*) AS ItemCount, SUM(CASE WHEN m.DTVDM IS NOT NULL THEN 1 ELSE 0 END) AS IssuedCount, SUM(CASE WHEN m.GDN = 1 THEN 1 ELSE 0 END) AS PassedCount, SUM(CASE WHEN m.GDN = 0 THEN 1 ELSE 0 END) AS FailedCount FROM dbo.EKZMK m JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ LEFT JOIN dbo.FRPD dep ON dep.IDFRPD = m.IDFRPD LEFT JOIN dbo.FRPD ownerOrg ON ownerOrg.IDFRPD = z.IDFRPDV WHERE NULLIF(LTRIM(RTRIM(m.NNZVPV)), N'') IS NOT NULL GROUP BY m.NNZVPV HAVING " + (loadClosedDocumentsForCurrentYear ? "MAX(m.DTVDM) >= @IssuedFrom AND MAX(m.DTVDM) < @IssuedTo" : "MAX(m.DTVDM) IS NULL") + @" ORDER BY " + (loadClosedDocumentsForCurrentYear ? "MAX(m.DTVDM) DESC" : "MAX(m.DTPRM) DESC") + @", m.NNZVPV DESC;"; var documents = new List(); var today = DateTime.Today; var currentYearStart = new DateTime(today.Year, 1, 1); var nextYearStart = currentYearStart.AddYears(1); using (var connection = CreateConnection()) using (var command = new SqlCommand(sql, connection)) { if (loadClosedDocumentsForCurrentYear) { command.Parameters.Add("@IssuedFrom", SqlDbType.DateTime).Value = currentYearStart; command.Parameters.Add("@IssuedTo", SqlDbType.DateTime).Value = nextYearStart; } connection.Open(); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; using (var reader = command.ExecuteReader()) { while (reader.Read()) { var documentNumber = GetString(reader, "DocumentNumber"); documents.Add(new PsvDocumentSummary { DocumentKey = documentNumber, DocumentNumber = documentNumber, AcceptedOn = GetNullableDateTime(reader, "AcceptedOn"), IssuedOn = GetNullableDateTime(reader, "IssuedOn"), DepartmentName = GetString(reader, "DepartmentName"), CustomerId = GetNullableInt32(reader, "CustomerId"), CustomerName = GetString(reader, "CustomerName"), ItemCount = GetInt32(reader, "ItemCount"), IssuedCount = GetInt32(reader, "IssuedCount"), PassedCount = GetInt32(reader, "PassedCount"), FailedCount = GetInt32(reader, "FailedCount"), IsDraft = false }); } } } return documents; } public Task> LoadDocumentsAsync(bool loadClosedDocumentsForCurrentYear, CancellationToken cancellationToken = default) { var sql = @" SELECT m.NNZVPV AS DocumentNumber, MAX(m.DTPRM) AS AcceptedOn, MAX(m.DTVDM) AS IssuedOn, MIN(dep.NMFRPD) AS DepartmentName, CASE WHEN COUNT(DISTINCT z.IDFRPDV) = 1 THEN MIN(z.IDFRPDV) ELSE NULL END AS CustomerId, CASE WHEN COUNT(DISTINCT z.IDFRPDV) = 1 THEN MIN(ownerOrg.NMFRPD) ELSE N'' END AS CustomerName, COUNT(*) AS ItemCount, SUM(CASE WHEN m.DTVDM IS NOT NULL THEN 1 ELSE 0 END) AS IssuedCount, SUM(CASE WHEN m.GDN = 1 THEN 1 ELSE 0 END) AS PassedCount, SUM(CASE WHEN m.GDN = 0 THEN 1 ELSE 0 END) AS FailedCount FROM dbo.EKZMK m JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ LEFT JOIN dbo.FRPD dep ON dep.IDFRPD = m.IDFRPD LEFT JOIN dbo.FRPD ownerOrg ON ownerOrg.IDFRPD = z.IDFRPDV WHERE NULLIF(LTRIM(RTRIM(m.NNZVPV)), N'') IS NOT NULL GROUP BY m.NNZVPV HAVING " + (loadClosedDocumentsForCurrentYear ? "MAX(m.DTVDM) >= @IssuedFrom AND MAX(m.DTVDM) < @IssuedTo" : "MAX(m.DTVDM) IS NULL") + @" ORDER BY " + (loadClosedDocumentsForCurrentYear ? "MAX(m.DTVDM) DESC" : "MAX(m.DTPRM) DESC") + @", m.NNZVPV DESC;"; var today = DateTime.Today; var currentYearStart = new DateTime(today.Year, 1, 1); var nextYearStart = currentYearStart.AddYears(1); return SqlServerConnectionFactory.Current.QueryOpenConnectionAsync( sql, delegate(SqlDataReader reader) { var documentNumber = GetString(reader, "DocumentNumber"); return new PsvDocumentSummary { DocumentKey = documentNumber, DocumentNumber = documentNumber, AcceptedOn = GetNullableDateTime(reader, "AcceptedOn"), IssuedOn = GetNullableDateTime(reader, "IssuedOn"), DepartmentName = GetString(reader, "DepartmentName"), CustomerId = GetNullableInt32(reader, "CustomerId"), CustomerName = GetString(reader, "CustomerName"), ItemCount = GetInt32(reader, "ItemCount"), IssuedCount = GetInt32(reader, "IssuedCount"), PassedCount = GetInt32(reader, "PassedCount"), FailedCount = GetInt32(reader, "FailedCount"), IsDraft = false }; }, delegate(SqlCommand command) { ConfigureCommandTimeout(command); if (loadClosedDocumentsForCurrentYear) { command.Parameters.Add("@IssuedFrom", SqlDbType.DateTime).Value = currentYearStart; command.Parameters.Add("@IssuedTo", SqlDbType.DateTime).Value = nextYearStart; } }, cancellationToken).ContinueWith>(delegate(Task> task) { return task.Result; }, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } public IReadOnlyList LoadDocumentLines(string documentNumber) { const string sql = @" SELECT m.IDEKZMK AS CardId, z.IDEKZ AS InstrumentId, z.IDTPRZ AS TypeSizeId, z.NNZV AS SerialNumber, z.NNIN AS InventoryNumber, ownerOrg.NMFRPD AS CustomerName, tips.TP AS InstrumentType, names.NMTP AS InstrumentName, areas.NMOI AS MeasurementArea, sizeInfo.DPZN AS RangeText, sizeInfo.NNGSRS AS RegistryNumber, sizeInfo.HRTC AS AccuracyText, verificationType.NMVDMK AS VerificationType, m.PRMK AS PeriodMonths, m.DTPRM AS AcceptedOn, m.DTVDM AS IssuedOn, m.GDN AS IsPassed, m.DTMKFK AS VerificationPerformedOn, m.IDPRSN AS VerifierId, verifier.PRFIO AS VerifierName, m.NNNKL AS StickerNumber, verificationDocument.IDFRDMS AS VerificationDocumentFormId, verificationDocument.IDVDODVDD AS VerificationDocumentLinkTypeId, verificationDocument.NNDMS AS VerificationDocumentNumber, verificationDocument.DTDMS AS VerificationDocumentDate, m.PRCHNPGDN AS RejectionReason, m.DSEKZMK AS Notes FROM dbo.EKZMK m JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ LEFT JOIN dbo.FRPD ownerOrg ON ownerOrg.IDFRPD = z.IDFRPDV LEFT JOIN dbo.TPRZ sizeInfo ON sizeInfo.IDTPRZ = z.IDTPRZ LEFT JOIN dbo.TIPS tips ON tips.IDTIPS = sizeInfo.IDTIPS LEFT JOIN dbo.SPNMTP names ON names.IDSPNMTP = tips.IDSPNMTP LEFT JOIN dbo.SPOI areas ON areas.IDSPOI = tips.IDSPOI LEFT JOIN dbo.SPVDMK verificationType ON verificationType.IDSPVDMK = m.IDSPVDMK LEFT JOIN dbo.PRSN verifier ON verifier.IDPRSN = m.IDPRSN OUTER APPLY ( SELECT TOP (1) d.IDFRDMS, d.IDVDODVDD, d.NND AS NNDMS, d.DTD AS DTDMS FROM dbo.DMS d JOIN dbo.VDODVDD vdd ON vdd.IDVDODVDD = d.IDVDODVDD JOIN dbo.FRDMS frdms ON frdms.IDFRDMS = d.IDFRDMS JOIN dbo.SPVDD spvdd ON spvdd.IDSPVDD = frdms.IDSPVDD WHERE d.IDOD = m.IDEKZMK AND vdd.IDSPVDOD = 2 AND spvdd.IDSPVDD IN (2, 6, 8) ORDER BY d.DTD DESC ) verificationDocument WHERE m.NNZVPV = @DocumentNumber ORDER BY areas.NMOI, names.NMTP, tips.TP, z.NNZV;"; var lines = new List(); using (var connection = CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; using (var reader = command.ExecuteReader()) { while (reader.Read()) { lines.Add(new PsvDocumentLine { CardId = GetInt32(reader, "CardId"), InstrumentId = GetInt32(reader, "InstrumentId"), TypeSizeId = GetInt32(reader, "TypeSizeId"), SerialNumber = GetString(reader, "SerialNumber"), InventoryNumber = GetString(reader, "InventoryNumber"), CustomerName = GetString(reader, "CustomerName"), InstrumentType = GetString(reader, "InstrumentType"), InstrumentName = GetString(reader, "InstrumentName"), MeasurementArea = GetString(reader, "MeasurementArea"), RangeText = GetString(reader, "RangeText"), RegistryNumber = GetString(reader, "RegistryNumber"), AccuracyText = GetString(reader, "AccuracyText"), VerificationType = GetString(reader, "VerificationType"), PeriodMonths = GetInt32(reader, "PeriodMonths"), AcceptedOn = GetNullableDateTime(reader, "AcceptedOn"), IssuedOn = GetNullableDateTime(reader, "IssuedOn"), IsPassed = GetNullableBoolean(reader, "IsPassed"), VerificationPerformedOn = GetNullableDateTime(reader, "VerificationPerformedOn"), VerifierId = GetNullableInt32(reader, "VerifierId"), VerifierName = GetString(reader, "VerifierName"), StickerNumber = GetString(reader, "StickerNumber"), VerificationDocumentFormId = GetNullableInt32(reader, "VerificationDocumentFormId"), VerificationDocumentLinkTypeId = GetNullableInt32(reader, "VerificationDocumentLinkTypeId"), VerificationDocumentNumber = GetString(reader, "VerificationDocumentNumber"), VerificationDocumentDate = GetNullableDateTime(reader, "VerificationDocumentDate"), RejectionReason = GetString(reader, "RejectionReason"), Notes = GetString(reader, "Notes"), IsPendingInsert = false }); } } } return lines; } public async Task> LoadDocumentLinesAsync(string documentNumber, CancellationToken cancellationToken = default) { const string sql = @" SELECT m.IDEKZMK AS CardId, z.IDEKZ AS InstrumentId, z.IDTPRZ AS TypeSizeId, z.NNZV AS SerialNumber, z.NNIN AS InventoryNumber, ownerOrg.NMFRPD AS CustomerName, tips.TP AS InstrumentType, names.NMTP AS InstrumentName, areas.NMOI AS MeasurementArea, sizeInfo.DPZN AS RangeText, sizeInfo.NNGSRS AS RegistryNumber, sizeInfo.HRTC AS AccuracyText, verificationType.NMVDMK AS VerificationType, m.PRMK AS PeriodMonths, m.DTPRM AS AcceptedOn, m.DTVDM AS IssuedOn, m.GDN AS IsPassed, m.DTMKFK AS VerificationPerformedOn, m.IDPRSN AS VerifierId, verifier.PRFIO AS VerifierName, m.NNNKL AS StickerNumber, verificationDocument.IDFRDMS AS VerificationDocumentFormId, verificationDocument.IDVDODVDD AS VerificationDocumentLinkTypeId, verificationDocument.NNDMS AS VerificationDocumentNumber, verificationDocument.DTDMS AS VerificationDocumentDate, m.PRCHNPGDN AS RejectionReason, m.DSEKZMK AS Notes FROM dbo.EKZMK m JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ LEFT JOIN dbo.FRPD ownerOrg ON ownerOrg.IDFRPD = z.IDFRPDV LEFT JOIN dbo.TPRZ sizeInfo ON sizeInfo.IDTPRZ = z.IDTPRZ LEFT JOIN dbo.TIPS tips ON tips.IDTIPS = sizeInfo.IDTIPS LEFT JOIN dbo.SPNMTP names ON names.IDSPNMTP = tips.IDSPNMTP LEFT JOIN dbo.SPOI areas ON areas.IDSPOI = tips.IDSPOI LEFT JOIN dbo.SPVDMK verificationType ON verificationType.IDSPVDMK = m.IDSPVDMK LEFT JOIN dbo.PRSN verifier ON verifier.IDPRSN = m.IDPRSN OUTER APPLY ( SELECT TOP (1) d.IDFRDMS, d.IDVDODVDD, d.NND AS NNDMS, d.DTD AS DTDMS FROM dbo.DMS d JOIN dbo.VDODVDD vdd ON vdd.IDVDODVDD = d.IDVDODVDD JOIN dbo.FRDMS frdms ON frdms.IDFRDMS = d.IDFRDMS JOIN dbo.SPVDD spvdd ON spvdd.IDSPVDD = frdms.IDSPVDD WHERE d.IDOD = m.IDEKZMK AND vdd.IDSPVDOD = 2 AND spvdd.IDSPVDD IN (2, 6, 8) ORDER BY d.DTD DESC ) verificationDocument WHERE m.NNZVPV = @DocumentNumber ORDER BY areas.NMOI, names.NMTP, tips.TP, z.NNZV;"; var lines = await SqlServerConnectionFactory.Current.QueryOpenConnectionAsync( sql, delegate(SqlDataReader reader) { return new PsvDocumentLine { CardId = GetInt32(reader, "CardId"), InstrumentId = GetInt32(reader, "InstrumentId"), TypeSizeId = GetInt32(reader, "TypeSizeId"), SerialNumber = GetString(reader, "SerialNumber"), InventoryNumber = GetString(reader, "InventoryNumber"), CustomerName = GetString(reader, "CustomerName"), InstrumentType = GetString(reader, "InstrumentType"), InstrumentName = GetString(reader, "InstrumentName"), MeasurementArea = GetString(reader, "MeasurementArea"), RangeText = GetString(reader, "RangeText"), RegistryNumber = GetString(reader, "RegistryNumber"), AccuracyText = GetString(reader, "AccuracyText"), VerificationType = GetString(reader, "VerificationType"), PeriodMonths = GetInt32(reader, "PeriodMonths"), AcceptedOn = GetNullableDateTime(reader, "AcceptedOn"), IssuedOn = GetNullableDateTime(reader, "IssuedOn"), IsPassed = GetNullableBoolean(reader, "IsPassed"), VerificationPerformedOn = GetNullableDateTime(reader, "VerificationPerformedOn"), VerifierId = GetNullableInt32(reader, "VerifierId"), VerifierName = GetString(reader, "VerifierName"), StickerNumber = GetString(reader, "StickerNumber"), VerificationDocumentFormId = GetNullableInt32(reader, "VerificationDocumentFormId"), VerificationDocumentLinkTypeId = GetNullableInt32(reader, "VerificationDocumentLinkTypeId"), VerificationDocumentNumber = GetString(reader, "VerificationDocumentNumber"), VerificationDocumentDate = GetNullableDateTime(reader, "VerificationDocumentDate"), RejectionReason = GetString(reader, "RejectionReason"), Notes = GetString(reader, "Notes"), IsPendingInsert = false }; }, delegate(SqlCommand command) { ConfigureCommandTimeout(command); command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; }, cancellationToken).ConfigureAwait(false); return lines; } public IReadOnlyList LoadCustomerInstruments(int customerId) { const string sql = @" SELECT z.IDEKZ AS InstrumentId, z.IDTPRZ AS TypeSizeId, z.NNZV AS SerialNumber, z.NNIN AS InventoryNumber, ownerOrg.NMFRPD AS CustomerName, tips.TP AS InstrumentType, names.NMTP AS InstrumentName, areas.NMOI AS MeasurementArea, sizeInfo.NNGSRS AS RegistryNumber, sizeInfo.DPZN AS RangeText, sizeInfo.HRTC AS AccuracyText, CASE WHEN instrumentTemplate.LastDocumentNumber IS NOT NULL OR typeTemplate.LastDocumentNumber IS NOT NULL OR COALESCE(periodByInstrument.PRMK, periodByType.PRMK, tips.PRMKGR) IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS HasTemplate, COALESCE(instrumentTemplate.LastDocumentNumber, typeTemplate.LastDocumentNumber) AS LastDocumentNumber, COALESCE(instrumentTemplate.LastAcceptedOn, typeTemplate.LastAcceptedOn) AS LastAcceptedOn, CASE WHEN instrumentTemplate.LastDocumentNumber IS NOT NULL THEN N'История РїСЂРёР±РѕСЂР°' WHEN typeTemplate.LastDocumentNumber IS NOT NULL THEN N'Шаблон РїРѕ типоразмеру' WHEN COALESCE(periodByInstrument.PRMK, periodByType.PRMK) IS NOT NULL THEN N'Период РёР· TPRMCP' WHEN tips.PRMKGR IS NOT NULL THEN N'Регистрационный период РёР· TIPS' ELSE N'' END AS TemplateSource FROM dbo.EKZ z LEFT JOIN dbo.FRPD ownerOrg ON ownerOrg.IDFRPD = z.IDFRPDV LEFT JOIN dbo.TPRZ sizeInfo ON sizeInfo.IDTPRZ = z.IDTPRZ LEFT JOIN dbo.TIPS tips ON tips.IDTIPS = sizeInfo.IDTIPS LEFT JOIN dbo.SPNMTP names ON names.IDSPNMTP = tips.IDSPNMTP LEFT JOIN dbo.SPOI areas ON areas.IDSPOI = tips.IDSPOI OUTER APPLY ( SELECT TOP (1) history.NNZVPV AS LastDocumentNumber, history.DTPRM AS LastAcceptedOn FROM dbo.EKZMK history WHERE history.IDEKZ = z.IDEKZ ORDER BY ISNULL(history.DTPRM, CONVERT(datetime, '19000101', 112)) DESC, history.IDEKZMK DESC ) instrumentTemplate OUTER APPLY ( SELECT TOP (1) history.NNZVPV AS LastDocumentNumber, history.DTPRM AS LastAcceptedOn FROM dbo.EKZMK history JOIN dbo.EKZ instrumentOfSameType ON instrumentOfSameType.IDEKZ = history.IDEKZ WHERE instrumentOfSameType.IDTPRZ = z.IDTPRZ ORDER BY ISNULL(history.DTPRM, CONVERT(datetime, '19000101', 112)) DESC, history.IDEKZMK DESC ) typeTemplate OUTER APPLY ( SELECT TOP (1) t.PRMK FROM dbo.EKZMCP e JOIN dbo.TPRMCP t ON t.IDTPRMCP = e.IDTPRMCP WHERE e.IDEKZ = z.IDEKZ ORDER BY e.IDEKZMCP DESC, t.IDTPRMCP DESC ) periodByInstrument OUTER APPLY ( SELECT TOP (1) t.PRMK FROM dbo.TPRMCP t WHERE t.IDTPRZ = z.IDTPRZ ORDER BY t.IDTPRMCP DESC ) periodByType WHERE z.IDFRPDV = @CustomerId ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, z.NNZV;"; var instruments = new List(); using (var connection = CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@CustomerId", SqlDbType.Int).Value = customerId; using (var reader = command.ExecuteReader()) { while (reader.Read()) { instruments.Add(new AvailableInstrumentItem { InstrumentId = GetInt32(reader, "InstrumentId"), TypeSizeId = GetInt32(reader, "TypeSizeId"), SerialNumber = GetString(reader, "SerialNumber"), InventoryNumber = GetString(reader, "InventoryNumber"), CustomerName = GetString(reader, "CustomerName"), InstrumentType = GetString(reader, "InstrumentType"), InstrumentName = GetString(reader, "InstrumentName"), MeasurementArea = GetString(reader, "MeasurementArea"), RegistryNumber = GetString(reader, "RegistryNumber"), RangeText = GetString(reader, "RangeText"), AccuracyText = GetString(reader, "AccuracyText"), HasTemplate = GetBoolean(reader, "HasTemplate"), LastDocumentNumber = GetString(reader, "LastDocumentNumber"), LastAcceptedOn = GetNullableDateTime(reader, "LastAcceptedOn"), TemplateSource = GetString(reader, "TemplateSource") }); } } } return instruments; } public Task> LoadCustomerInstrumentsAsync(int customerId, CancellationToken cancellationToken = default) { const string sql = @" SELECT z.IDEKZ AS InstrumentId, z.IDTPRZ AS TypeSizeId, z.NNZV AS SerialNumber, z.NNIN AS InventoryNumber, ownerOrg.NMFRPD AS CustomerName, tips.TP AS InstrumentType, names.NMTP AS InstrumentName, areas.NMOI AS MeasurementArea, sizeInfo.NNGSRS AS RegistryNumber, sizeInfo.DPZN AS RangeText, sizeInfo.HRTC AS AccuracyText, CASE WHEN instrumentTemplate.LastDocumentNumber IS NOT NULL OR typeTemplate.LastDocumentNumber IS NOT NULL OR COALESCE(periodByInstrument.PRMK, periodByType.PRMK, tips.PRMKGR) IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS HasTemplate, COALESCE(instrumentTemplate.LastDocumentNumber, typeTemplate.LastDocumentNumber) AS LastDocumentNumber, COALESCE(instrumentTemplate.LastAcceptedOn, typeTemplate.LastAcceptedOn) AS LastAcceptedOn, CASE WHEN instrumentTemplate.LastDocumentNumber IS NOT NULL THEN N'История прибора' WHEN typeTemplate.LastDocumentNumber IS NOT NULL THEN N'Шаблон по типоразмеру' WHEN COALESCE(periodByInstrument.PRMK, periodByType.PRMK) IS NOT NULL THEN N'Период из TPRMCP' WHEN tips.PRMKGR IS NOT NULL THEN N'Регистрационный период из TIPS' ELSE N'' END AS TemplateSource FROM dbo.EKZ z LEFT JOIN dbo.FRPD ownerOrg ON ownerOrg.IDFRPD = z.IDFRPDV LEFT JOIN dbo.TPRZ sizeInfo ON sizeInfo.IDTPRZ = z.IDTPRZ LEFT JOIN dbo.TIPS tips ON tips.IDTIPS = sizeInfo.IDTIPS LEFT JOIN dbo.SPNMTP names ON names.IDSPNMTP = tips.IDSPNMTP LEFT JOIN dbo.SPOI areas ON areas.IDSPOI = tips.IDSPOI OUTER APPLY ( SELECT TOP (1) history.NNZVPV AS LastDocumentNumber, history.DTPRM AS LastAcceptedOn FROM dbo.EKZMK history WHERE history.IDEKZ = z.IDEKZ ORDER BY ISNULL(history.DTPRM, CONVERT(datetime, '19000101', 112)) DESC, history.IDEKZMK DESC ) instrumentTemplate OUTER APPLY ( SELECT TOP (1) history.NNZVPV AS LastDocumentNumber, history.DTPRM AS LastAcceptedOn FROM dbo.EKZMK history JOIN dbo.EKZ instrumentOfSameType ON instrumentOfSameType.IDEKZ = history.IDEKZ WHERE instrumentOfSameType.IDTPRZ = z.IDTPRZ ORDER BY ISNULL(history.DTPRM, CONVERT(datetime, '19000101', 112)) DESC, history.IDEKZMK DESC ) typeTemplate OUTER APPLY ( SELECT TOP (1) t.PRMK FROM dbo.EKZMCP e JOIN dbo.TPRMCP t ON t.IDTPRMCP = e.IDTPRMCP WHERE e.IDEKZ = z.IDEKZ ORDER BY e.IDEKZMCP DESC, t.IDTPRMCP DESC ) periodByInstrument OUTER APPLY ( SELECT TOP (1) t.PRMK FROM dbo.TPRMCP t WHERE t.IDTPRZ = z.IDTPRZ ORDER BY t.IDTPRMCP DESC ) periodByType WHERE z.IDFRPDV = @CustomerId ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, z.NNZV;"; return SqlServerConnectionFactory.Current.QueryOpenConnectionAsync( sql, delegate(SqlDataReader reader) { return new AvailableInstrumentItem { InstrumentId = GetInt32(reader, "InstrumentId"), TypeSizeId = GetInt32(reader, "TypeSizeId"), SerialNumber = GetString(reader, "SerialNumber"), InventoryNumber = GetString(reader, "InventoryNumber"), CustomerName = GetString(reader, "CustomerName"), InstrumentType = GetString(reader, "InstrumentType"), InstrumentName = GetString(reader, "InstrumentName"), MeasurementArea = GetString(reader, "MeasurementArea"), RegistryNumber = GetString(reader, "RegistryNumber"), RangeText = GetString(reader, "RangeText"), AccuracyText = GetString(reader, "AccuracyText"), HasTemplate = GetBoolean(reader, "HasTemplate"), LastDocumentNumber = GetString(reader, "LastDocumentNumber"), LastAcceptedOn = GetNullableDateTime(reader, "LastAcceptedOn"), TemplateSource = GetString(reader, "TemplateSource") }; }, delegate(SqlCommand command) { ConfigureCommandTimeout(command); command.Parameters.Add("@CustomerId", SqlDbType.Int).Value = customerId; }, cancellationToken).ContinueWith>(delegate(Task> task) { return task.Result; }, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } public IReadOnlyList LoadInstrumentTypes() { const string sql = @" SELECT 0 AS InstrumentId, sizeInfo.IDTPRZ AS TypeSizeId, CAST(N'' AS nvarchar(30)) AS SerialNumber, CAST(N'' AS nvarchar(30)) AS InventoryNumber, CAST(N'' AS nvarchar(255)) AS CustomerName, tips.TP AS InstrumentType, names.NMTP AS InstrumentName, areas.NMOI AS MeasurementArea, sizeInfo.NNGSRS AS RegistryNumber, sizeInfo.DPZN AS RangeText, sizeInfo.HRTC AS AccuracyText, CASE WHEN typeTemplate.LastDocumentNumber IS NOT NULL OR periodByType.PRMK IS NOT NULL OR tips.PRMKGR IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS HasTemplate, typeTemplate.LastDocumentNumber AS LastDocumentNumber, typeTemplate.LastAcceptedOn AS LastAcceptedOn, CASE WHEN typeTemplate.LastDocumentNumber IS NOT NULL THEN N'Шаблон РїРѕ типоразмеру' WHEN periodByType.PRMK IS NOT NULL THEN N'Период РёР· TPRMCP' WHEN tips.PRMKGR IS NOT NULL THEN N'Регистрационный период РёР· TIPS' ELSE N'' END AS TemplateSource FROM dbo.TPRZ sizeInfo LEFT JOIN dbo.TIPS tips ON tips.IDTIPS = sizeInfo.IDTIPS LEFT JOIN dbo.SPNMTP names ON names.IDSPNMTP = tips.IDSPNMTP LEFT JOIN dbo.SPOI areas ON areas.IDSPOI = tips.IDSPOI OUTER APPLY ( SELECT TOP (1) history.NNZVPV AS LastDocumentNumber, history.DTPRM AS LastAcceptedOn FROM dbo.EKZMK history JOIN dbo.EKZ instrumentOfSameType ON instrumentOfSameType.IDEKZ = history.IDEKZ WHERE instrumentOfSameType.IDTPRZ = sizeInfo.IDTPRZ ORDER BY ISNULL(history.DTPRM, CONVERT(datetime, '19000101', 112)) DESC, history.IDEKZMK DESC ) typeTemplate OUTER APPLY ( SELECT TOP (1) t.PRMK FROM dbo.TPRMCP t WHERE t.IDTPRZ = sizeInfo.IDTPRZ ORDER BY t.IDTPRMCP DESC ) periodByType ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, sizeInfo.NNGSRS;"; var instrumentTypes = new List(); using (var connection = CreateConnection()) using (var command = new SqlCommand(sql, connection)) { connection.Open(); command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; using (var reader = command.ExecuteReader()) { while (reader.Read()) { instrumentTypes.Add(new AvailableInstrumentItem { InstrumentId = GetInt32(reader, "InstrumentId"), TypeSizeId = GetInt32(reader, "TypeSizeId"), SerialNumber = GetString(reader, "SerialNumber"), InventoryNumber = GetString(reader, "InventoryNumber"), CustomerName = GetString(reader, "CustomerName"), InstrumentType = GetString(reader, "InstrumentType"), InstrumentName = GetString(reader, "InstrumentName"), MeasurementArea = GetString(reader, "MeasurementArea"), RegistryNumber = GetString(reader, "RegistryNumber"), RangeText = GetString(reader, "RangeText"), AccuracyText = GetString(reader, "AccuracyText"), HasTemplate = GetBoolean(reader, "HasTemplate"), LastDocumentNumber = GetString(reader, "LastDocumentNumber"), LastAcceptedOn = GetNullableDateTime(reader, "LastAcceptedOn"), TemplateSource = GetString(reader, "TemplateSource") }); } } } return instrumentTypes; } public Task> LoadInstrumentTypesAsync(CancellationToken cancellationToken = default) { const string sql = @" SELECT 0 AS InstrumentId, sizeInfo.IDTPRZ AS TypeSizeId, CAST(N'' AS nvarchar(30)) AS SerialNumber, CAST(N'' AS nvarchar(30)) AS InventoryNumber, CAST(N'' AS nvarchar(255)) AS CustomerName, tips.TP AS InstrumentType, names.NMTP AS InstrumentName, areas.NMOI AS MeasurementArea, sizeInfo.NNGSRS AS RegistryNumber, sizeInfo.DPZN AS RangeText, sizeInfo.HRTC AS AccuracyText, CASE WHEN typeTemplate.LastDocumentNumber IS NOT NULL OR periodByType.PRMK IS NOT NULL OR tips.PRMKGR IS NOT NULL THEN CAST(1 AS bit) ELSE CAST(0 AS bit) END AS HasTemplate, typeTemplate.LastDocumentNumber AS LastDocumentNumber, typeTemplate.LastAcceptedOn AS LastAcceptedOn, CASE WHEN typeTemplate.LastDocumentNumber IS NOT NULL THEN N'Шаблон по типоразмеру' WHEN periodByType.PRMK IS NOT NULL THEN N'Период из TPRMCP' WHEN tips.PRMKGR IS NOT NULL THEN N'Регистрационный период из TIPS' ELSE N'' END AS TemplateSource FROM dbo.TPRZ sizeInfo LEFT JOIN dbo.TIPS tips ON tips.IDTIPS = sizeInfo.IDTIPS LEFT JOIN dbo.SPNMTP names ON names.IDSPNMTP = tips.IDSPNMTP LEFT JOIN dbo.SPOI areas ON areas.IDSPOI = tips.IDSPOI OUTER APPLY ( SELECT TOP (1) history.NNZVPV AS LastDocumentNumber, history.DTPRM AS LastAcceptedOn FROM dbo.EKZMK history JOIN dbo.EKZ instrumentOfSameType ON instrumentOfSameType.IDEKZ = history.IDEKZ WHERE instrumentOfSameType.IDTPRZ = sizeInfo.IDTPRZ ORDER BY ISNULL(history.DTPRM, CONVERT(datetime, '19000101', 112)) DESC, history.IDEKZMK DESC ) typeTemplate OUTER APPLY ( SELECT TOP (1) t.PRMK FROM dbo.TPRMCP t WHERE t.IDTPRZ = sizeInfo.IDTPRZ ORDER BY t.IDTPRMCP DESC ) periodByType ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, sizeInfo.NNGSRS;"; return SqlServerConnectionFactory.Current.QueryOpenConnectionAsync( sql, delegate(SqlDataReader reader) { return new AvailableInstrumentItem { InstrumentId = GetInt32(reader, "InstrumentId"), TypeSizeId = GetInt32(reader, "TypeSizeId"), SerialNumber = GetString(reader, "SerialNumber"), InventoryNumber = GetString(reader, "InventoryNumber"), CustomerName = GetString(reader, "CustomerName"), InstrumentType = GetString(reader, "InstrumentType"), InstrumentName = GetString(reader, "InstrumentName"), MeasurementArea = GetString(reader, "MeasurementArea"), RegistryNumber = GetString(reader, "RegistryNumber"), RangeText = GetString(reader, "RangeText"), AccuracyText = GetString(reader, "AccuracyText"), HasTemplate = GetBoolean(reader, "HasTemplate"), LastDocumentNumber = GetString(reader, "LastDocumentNumber"), LastAcceptedOn = GetNullableDateTime(reader, "LastAcceptedOn"), TemplateSource = GetString(reader, "TemplateSource") }; }, ConfigureCommandTimeout, cancellationToken).ContinueWith>(delegate(Task> task) { return task.Result; }, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } public IReadOnlyList FindOpenDocumentConflicts(int customerId, string currentDocumentNumber, IEnumerable candidateLines) { if (customerId <= 0 || candidateLines == null) { return new List(); } using (var connection = CreateConnection()) { connection.Open(); return LoadOpenDocumentConflicts(connection, null, customerId, currentDocumentNumber, candidateLines); } } public void ResetLineVerification(int cardId) { if (cardId <= 0) { throw new InvalidOperationException("РќРµ выбрана строка EKZMK для отмены проверки."); } using (var connection = CreateConnection()) { connection.Open(); using (var transaction = connection.BeginTransaction()) { ClearLineVerificationCore(connection, transaction, cardId); DeleteVerificationDocuments(connection, transaction, cardId); transaction.Commit(); } } } public async Task ResetLineVerificationAsync(int cardId, CancellationToken cancellationToken = default) { if (cardId <= 0) { throw new InvalidOperationException("Не выбрана строка EKZMK для отмены поверки."); } await using (var connection = await SqlServerConnectionFactory.Current.OpenConnectionAsync(cancellationToken).ConfigureAwait(false)) using (var transaction = (SqlTransaction)await connection.BeginTransactionAsync(cancellationToken).ConfigureAwait(false)) { await ClearLineVerificationCoreAsync(connection, transaction, cardId, cancellationToken).ConfigureAwait(false); await DeleteVerificationDocumentsAsync(connection, transaction, cardId, cancellationToken).ConfigureAwait(false); await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); } } public void SaveLineVerification(int cardId, VerificationEditResult result) { if (cardId <= 0) { throw new InvalidOperationException("РќРµ выбрана строка EKZMK для сохранения результата поверки."); } if (result == null) { throw new ArgumentNullException("result"); } using (var connection = CreateConnection()) { connection.Open(); using (var transaction = connection.BeginTransaction()) { SaveLineVerificationCore(connection, transaction, cardId, result); DeleteVerificationDocuments(connection, transaction, cardId); if (!string.IsNullOrWhiteSpace(result.VerificationDocumentNumber)) { if (result.DocumentFormId <= 0 || result.DocumentLinkTypeId <= 0) { throw new InvalidOperationException("Для документа поверки РЅРµ определена форма или СЃРІСЏР·СЊ СЃ объектом."); } InsertVerificationDocument( connection, transaction, cardId, result.DocumentLinkTypeId, result.DocumentFormId, result.VerificationDocumentNumber, result.VerificationDate); } transaction.Commit(); } } } public async Task SaveLineVerificationAsync(int cardId, VerificationEditResult result, CancellationToken cancellationToken = default) { if (cardId <= 0) { throw new InvalidOperationException("Не выбрана строка EKZMK для сохранения результата поверки."); } if (result == null) { throw new ArgumentNullException("result"); } await using (var connection = await SqlServerConnectionFactory.Current.OpenConnectionAsync(cancellationToken).ConfigureAwait(false)) using (var transaction = (SqlTransaction)await connection.BeginTransactionAsync(cancellationToken).ConfigureAwait(false)) { await SaveLineVerificationCoreAsync(connection, transaction, cardId, result, cancellationToken).ConfigureAwait(false); await DeleteVerificationDocumentsAsync(connection, transaction, cardId, cancellationToken).ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(result.VerificationDocumentNumber)) { if (result.DocumentFormId <= 0 || result.DocumentLinkTypeId <= 0) { throw new InvalidOperationException("Для документа поверки не определена форма или связь с объектом."); } await InsertVerificationDocumentAsync( connection, transaction, cardId, result.DocumentLinkTypeId, result.DocumentFormId, result.VerificationDocumentNumber, result.VerificationDate, cancellationToken).ConfigureAwait(false); } await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); } } public void ResetLineVerification(IEnumerable cardIds) { var normalizedCardIds = NormalizeCardIds( cardIds, "РќРµ выбрана строка EKZMK для отмены поверки.", "РќРµ выбрано РЅРё РѕРґРЅРѕР№ строки EKZMK для отмены поверки."); using (var connection = CreateConnection()) { connection.Open(); using (var transaction = connection.BeginTransaction()) { foreach (var cardId in normalizedCardIds) { ClearLineVerificationCore(connection, transaction, cardId); DeleteVerificationDocuments(connection, transaction, cardId); } transaction.Commit(); } } } public async Task ResetLineVerificationAsync(IEnumerable cardIds, CancellationToken cancellationToken = default) { var normalizedCardIds = NormalizeCardIds( cardIds, "Не выбрана строка EKZMK для отмены поверки.", "Не выбрано ни одной строки EKZMK для отмены поверки."); await using (var connection = await SqlServerConnectionFactory.Current.OpenConnectionAsync(cancellationToken).ConfigureAwait(false)) using (var transaction = (SqlTransaction)await connection.BeginTransactionAsync(cancellationToken).ConfigureAwait(false)) { foreach (var cardId in normalizedCardIds) { await ClearLineVerificationCoreAsync(connection, transaction, cardId, cancellationToken).ConfigureAwait(false); await DeleteVerificationDocumentsAsync(connection, transaction, cardId, cancellationToken).ConfigureAwait(false); } await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); } } public void SaveLineVerification(IEnumerable cardIds, VerificationEditResult result) { if (result == null) { throw new ArgumentNullException("result"); } var normalizedCardIds = NormalizeCardIds( cardIds, "РќРµ выбрана строка EKZMK для сохранения результата поверки.", "РќРµ выбрано РЅРё РѕРґРЅРѕР№ строки EKZMK для сохранения результата поверки."); using (var connection = CreateConnection()) { connection.Open(); using (var transaction = connection.BeginTransaction()) { foreach (var cardId in normalizedCardIds) { SaveLineVerificationCore(connection, transaction, cardId, result); DeleteVerificationDocuments(connection, transaction, cardId); if (!string.IsNullOrWhiteSpace(result.VerificationDocumentNumber)) { if (result.DocumentFormId <= 0 || result.DocumentLinkTypeId <= 0) { throw new InvalidOperationException("Для документа поверки РЅРµ определена форма или СЃРІСЏР·СЊ СЃ объектом."); } InsertVerificationDocument( connection, transaction, cardId, result.DocumentLinkTypeId, result.DocumentFormId, result.VerificationDocumentNumber, result.VerificationDate); } } transaction.Commit(); } } } public async Task SaveLineVerificationAsync(IEnumerable cardIds, VerificationEditResult result, CancellationToken cancellationToken = default) { if (result == null) { throw new ArgumentNullException("result"); } var normalizedCardIds = NormalizeCardIds( cardIds, "Не выбрана строка EKZMK для сохранения результата поверки.", "Не выбрано ни одной строки EKZMK для сохранения результата поверки."); await using (var connection = await SqlServerConnectionFactory.Current.OpenConnectionAsync(cancellationToken).ConfigureAwait(false)) using (var transaction = (SqlTransaction)await connection.BeginTransactionAsync(cancellationToken).ConfigureAwait(false)) { foreach (var cardId in normalizedCardIds) { await SaveLineVerificationCoreAsync(connection, transaction, cardId, result, cancellationToken).ConfigureAwait(false); await DeleteVerificationDocumentsAsync(connection, transaction, cardId, cancellationToken).ConfigureAwait(false); if (!string.IsNullOrWhiteSpace(result.VerificationDocumentNumber)) { if (result.DocumentFormId <= 0 || result.DocumentLinkTypeId <= 0) { throw new InvalidOperationException("Для документа поверки не определена форма или связь с объектом."); } await InsertVerificationDocumentAsync( connection, transaction, cardId, result.DocumentLinkTypeId, result.DocumentFormId, result.VerificationDocumentNumber, result.VerificationDate, cancellationToken).ConfigureAwait(false); } } await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); } } public DocumentSaveResult SaveDocument(string currentDocumentNumber, DocumentEditorResult document, IEnumerable pendingLines) { if (document == null) { throw new ArgumentNullException("document"); } var normalizedNumber = NormalizeDocumentNumber(document.DocumentNumber); if (normalizedNumber == null) { throw new InvalidOperationException("Номер РџРЎР’ РЅРµ заполнен."); } document.DocumentNumber = normalizedNumber; var distinctPendingLines = pendingLines == null ? new List() : pendingLines .Where(IsPendingLineReadyForSave) .GroupBy(GetPendingLineSaveKey, StringComparer.OrdinalIgnoreCase) .Select(delegate(IGrouping group) { return group.First(); }) .ToList(); using (var connection = CreateConnection()) { connection.Open(); using (var transaction = connection.BeginTransaction()) { if (DocumentNumberExists(connection, transaction, normalizedNumber, currentDocumentNumber)) { throw new InvalidOperationException(string.Format("РџРЎР’ СЃ номером \"{0}\" СѓР¶Рµ существует.", normalizedNumber)); } if (document.CustomerId.HasValue) { var openDocumentConflicts = LoadOpenDocumentConflicts( connection, transaction, document.CustomerId.Value, currentDocumentNumber, distinctPendingLines); if (openDocumentConflicts.Count > 0) { throw new InvalidOperationException(BuildOpenDocumentConflictMessage(openDocumentConflicts)); } } var updatedEkzMkCount = 0; if (!string.IsNullOrWhiteSpace(currentDocumentNumber)) { updatedEkzMkCount = UpdateDocumentHeader(connection, transaction, currentDocumentNumber, document); if (updatedEkzMkCount == 0) { throw new InvalidOperationException("Строки EKZMK для выбранного РџРЎР’ РЅРµ найдены."); } } var insertedEkzMkCount = 0; var skippedDuplicateCount = 0; var skippedWithoutTemplateCount = 0; var duplicateKeys = LoadDocumentDuplicateKeys(connection, transaction, normalizedNumber); var verificationTypeId = 0; var verificationTypeLoaded = false; foreach (var pendingLine in distinctPendingLines) { var duplicateKey = pendingLine.DuplicateKey; if (string.IsNullOrWhiteSpace(duplicateKey)) { throw new InvalidOperationException("РќРµ удалось определить ключ дубликата для строки РџРЎР’."); } var instrumentId = pendingLine.InstrumentId; var instrumentIdentity = new InstrumentIdentityInfo { DuplicateKey = duplicateKey }; if (string.IsNullOrWhiteSpace(duplicateKey)) { throw new InvalidOperationException(string.Format("РџСЂРёР±РѕСЂ IDEKZ={0} РЅРµ найден.", instrumentId)); } if (duplicateKeys.Contains(instrumentIdentity.DuplicateKey)) { skippedDuplicateCount++; continue; } instrumentId = ResolveInstrumentIdForPendingLine(connection, transaction, document, pendingLine); var template = LoadTemplate(connection, transaction, instrumentId); if (template == null) { skippedWithoutTemplateCount++; continue; } if (!verificationTypeLoaded) { verificationTypeId = LoadVerificationTypeId(connection, transaction); verificationTypeLoaded = true; } var cardId = InsertEkzMk(connection, transaction, verificationTypeId, document, normalizedNumber, instrumentId, template, pendingLine); if (!string.IsNullOrWhiteSpace(pendingLine.VerificationDocumentNumber)) { if (!pendingLine.VerificationDocumentFormId.HasValue || !pendingLine.VerificationDocumentLinkTypeId.HasValue) { throw new InvalidOperationException("Для РЅРѕРІРѕР№ строки EKZMK РЅРµ определена форма документа поверки."); } InsertVerificationDocument( connection, transaction, cardId, pendingLine.VerificationDocumentLinkTypeId.GetValueOrDefault(), pendingLine.VerificationDocumentFormId.GetValueOrDefault(), pendingLine.VerificationDocumentNumber, pendingLine.VerificationDocumentDate ?? pendingLine.VerificationPerformedOn ?? document.AcceptedOn); } duplicateKeys.Add(instrumentIdentity.DuplicateKey); insertedEkzMkCount++; } if (string.IsNullOrWhiteSpace(currentDocumentNumber) && insertedEkzMkCount == 0) { throw new InvalidOperationException("Черновик нельзя сохранить без строк EKZMK."); } transaction.Commit(); return new DocumentSaveResult { DocumentNumber = normalizedNumber, InsertedEkzMkCount = insertedEkzMkCount, SkippedDuplicateCount = skippedDuplicateCount, SkippedWithoutTemplateCount = skippedWithoutTemplateCount, UpdatedEkzMkCount = updatedEkzMkCount }; } } } public DocumentDeleteResult DeleteDocument(string documentNumber) { if (string.IsNullOrWhiteSpace(documentNumber)) { throw new InvalidOperationException("РќРµ выбран документ для удаления."); } using (var connection = CreateConnection()) { connection.Open(); using (var transaction = connection.BeginTransaction()) { var blockers = LoadDeleteBlockers(connection, transaction, documentNumber); if (blockers.Count > 0) { var details = string.Join(", ", blockers.Select(delegate(DeleteBlockerInfo blocker) { return string.Format("{0}: {1}", blocker.TableName, blocker.RowCount); })); throw new InvalidOperationException( string.Format( "РџРЎР’ РЅРµ может быть удалён, потому что РЅР° его строки EKZMK есть ссылки РІ таблицах: {0}. РџРѕ вашему правилу приложение РЅРµ трогает эти таблицы.", details)); } var deletedEkzMkFctvlCount = DeleteDocumentEkzMkFctvl(connection, transaction, documentNumber); var deletedDmsCount = DeleteDocumentDms(connection, transaction, documentNumber); var deletedEkzMkCount = DeleteDocumentEkzMk(connection, transaction, documentNumber); if (deletedEkzMkCount == 0) { throw new InvalidOperationException("Строки EKZMK для выбранного РџРЎР’ РЅРµ найдены."); } transaction.Commit(); return new DocumentDeleteResult { DeletedEkzMkFctvlCount = deletedEkzMkFctvlCount, DeletedDmsCount = deletedDmsCount, DeletedEkzMkCount = deletedEkzMkCount }; } } } public async Task DeleteDocumentAsync(string documentNumber, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(documentNumber)) { throw new InvalidOperationException("Не выбран документ для удаления."); } await using (var connection = await SqlServerConnectionFactory.Current.OpenConnectionAsync(cancellationToken).ConfigureAwait(false)) using (var transaction = (SqlTransaction)await connection.BeginTransactionAsync(cancellationToken).ConfigureAwait(false)) { var blockers = await LoadDeleteBlockersAsync(connection, transaction, documentNumber, cancellationToken).ConfigureAwait(false); if (blockers.Count > 0) { var details = string.Join(", ", blockers.Select(delegate(DeleteBlockerInfo blocker) { return string.Format("{0}: {1}", blocker.TableName, blocker.RowCount); })); throw new InvalidOperationException( string.Format( "ПСВ не может быть удалён, потому что на его строки EKZMK есть ссылки в таблицах: {0}. По вашему правилу приложение не трогает эти таблицы.", details)); } var deletedEkzMkFctvlCount = await DeleteDocumentEkzMkFctvlAsync(connection, transaction, documentNumber, cancellationToken).ConfigureAwait(false); var deletedDmsCount = await DeleteDocumentDmsAsync(connection, transaction, documentNumber, cancellationToken).ConfigureAwait(false); var deletedEkzMkCount = await DeleteDocumentEkzMkAsync(connection, transaction, documentNumber, cancellationToken).ConfigureAwait(false); if (deletedEkzMkCount == 0) { throw new InvalidOperationException("Строки EKZMK для выбранного ПСВ не найдены."); } await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); return new DocumentDeleteResult { DeletedEkzMkFctvlCount = deletedEkzMkFctvlCount, DeletedDmsCount = deletedDmsCount, DeletedEkzMkCount = deletedEkzMkCount }; } } public DocumentGroupDeleteResult DeleteDocumentGroups(string documentNumber, IEnumerable cardIds) { if (string.IsNullOrWhiteSpace(documentNumber)) { throw new InvalidOperationException("Р СњР Вµ выбран документ для удаления РіСЂСѓРїРї."); } var normalizedCardIds = NormalizeCardIds( cardIds, "Р’ СЃРїРёСЃРєРµ удаляемых строк есть некорректный IDEKZMK.", "Р СњР Вµ выбрано Р Р…Р С‘ РѕРґРЅРѕР№ строки EKZMK для удаления."); using (var connection = CreateConnection()) { connection.Open(); using (var transaction = connection.BeginTransaction()) { var blockers = LoadDeleteBlockers(connection, transaction, normalizedCardIds); if (blockers.Count > 0) { var details = string.Join(", ", blockers.Select(delegate(DeleteBlockerInfo blocker) { return string.Format("{0}: {1}", blocker.TableName, blocker.RowCount); })); throw new InvalidOperationException( string.Format( "Выбранные строки EKZMK РЅРµ РјРѕРіСѓС‚ быть удалены, потому что РЅР° РЅРёС… есть ссылки РІ таблицах: {0}. РџРѕ вашему правилу приложение РЅРµ трогает эти таблицы.", details)); } var deletedEkzMkFctvlCount = 0; var deletedDmsCount = 0; var deletedEkzMkCount = 0; foreach (var cardId in normalizedCardIds) { deletedEkzMkFctvlCount += DeleteLineEkzMkFctvl(connection, transaction, documentNumber, cardId); deletedDmsCount += DeleteLineDms(connection, transaction, documentNumber, cardId); deletedEkzMkCount += DeleteLineEkzMk(connection, transaction, documentNumber, cardId); } if (deletedEkzMkCount == 0) { throw new InvalidOperationException("Строки EKZMK для выбранных РіСЂСѓРїРї РЅРµ найдены."); } transaction.Commit(); return new DocumentGroupDeleteResult { DeletedEkzMkFctvlCount = deletedEkzMkFctvlCount, DeletedEkzMkCount = deletedEkzMkCount, DeletedDmsCount = deletedDmsCount }; } } } public async Task DeleteDocumentGroupsAsync(string documentNumber, IEnumerable cardIds, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(documentNumber)) { throw new InvalidOperationException("Не выбран документ для удаления групп."); } var normalizedCardIds = NormalizeCardIds( cardIds, "В списке удаляемых строк есть некорректный IDEKZMK.", "Не выбрано ни одной строки EKZMK для удаления."); await using (var connection = await SqlServerConnectionFactory.Current.OpenConnectionAsync(cancellationToken).ConfigureAwait(false)) using (var transaction = (SqlTransaction)await connection.BeginTransactionAsync(cancellationToken).ConfigureAwait(false)) { var blockers = await LoadDeleteBlockersAsync(connection, transaction, normalizedCardIds, cancellationToken).ConfigureAwait(false); if (blockers.Count > 0) { var details = string.Join(", ", blockers.Select(delegate(DeleteBlockerInfo blocker) { return string.Format("{0}: {1}", blocker.TableName, blocker.RowCount); })); throw new InvalidOperationException( string.Format( "Выбранные строки EKZMK не могут быть удалены, потому что на них есть ссылки в таблицах: {0}. По вашему правилу приложение не трогает эти таблицы.", details)); } var deletedEkzMkFctvlCount = 0; var deletedDmsCount = 0; var deletedEkzMkCount = 0; foreach (var cardId in normalizedCardIds) { deletedEkzMkFctvlCount += await DeleteLineEkzMkFctvlAsync(connection, transaction, documentNumber, cardId, cancellationToken).ConfigureAwait(false); deletedDmsCount += await DeleteLineDmsAsync(connection, transaction, documentNumber, cardId, cancellationToken).ConfigureAwait(false); deletedEkzMkCount += await DeleteLineEkzMkAsync(connection, transaction, documentNumber, cardId, cancellationToken).ConfigureAwait(false); } if (deletedEkzMkCount == 0) { throw new InvalidOperationException("Строки EKZMK для выбранных групп не найдены."); } await transaction.CommitAsync(cancellationToken).ConfigureAwait(false); return new DocumentGroupDeleteResult { DeletedEkzMkFctvlCount = deletedEkzMkFctvlCount, DeletedEkzMkCount = deletedEkzMkCount, DeletedDmsCount = deletedDmsCount }; } } private static string GetPendingLineSaveKey(PsvDocumentLine line) { if (line == null) { return string.Empty; } return line.InstrumentId > 0 ? string.Format("ID:{0}", line.InstrumentId) : string.Format("NEW:{0}", line.DuplicateKey ?? string.Empty); } private static bool IsPendingLineReadyForSave(PsvDocumentLine line) { return line != null && (line.InstrumentId > 0 || (line.TypeSizeId > 0 && !string.IsNullOrWhiteSpace(line.SerialNumber))); } private static int ResolveInstrumentIdForPendingLine(SqlConnection connection, SqlTransaction transaction, DocumentEditorResult document, PsvDocumentLine pendingLine) { if (pendingLine == null) { throw new InvalidOperationException("Строка РџРЎР’ для сохранения РЅРµ задана."); } if (pendingLine.InstrumentId > 0) { return pendingLine.InstrumentId; } if (pendingLine.TypeSizeId <= 0) { throw new InvalidOperationException("Для РЅРѕРІРѕР№ строки РџРЎР’ РЅРµ указан типоразмер РїСЂРёР±РѕСЂР°."); } var serialNumber = string.IsNullOrWhiteSpace(pendingLine.SerialNumber) ? null : pendingLine.SerialNumber.Trim(); if (serialNumber == null) { throw new InvalidOperationException("Для РЅРѕРІРѕР№ строки РџРЎР’ РЅРµ указан заводской номер."); } if (!document.CustomerId.HasValue) { throw new InvalidOperationException("Для добавления РїСЂРёР±РѕСЂР° РїРѕ типу должен быть выбран заказчик РџРЎР’."); } var existingInstrumentId = FindExistingInstrumentId(connection, transaction, pendingLine.TypeSizeId, document.CustomerId.Value, serialNumber); if (existingInstrumentId.HasValue) { return existingInstrumentId.Value; } return InsertInstrument(connection, transaction, pendingLine.TypeSizeId, document.CustomerId.Value, serialNumber); } private static List NormalizeCardIds(IEnumerable cardIds, string invalidCardMessage, string emptyListMessage) { if (cardIds == null) { throw new InvalidOperationException(emptyListMessage); } var normalizedCardIds = cardIds.Distinct().ToList(); if (normalizedCardIds.Count == 0) { throw new InvalidOperationException(emptyListMessage); } if (normalizedCardIds.Any(delegate(int cardId) { return cardId <= 0; })) { throw new InvalidOperationException(invalidCardMessage); } return normalizedCardIds; } private static int? FindExistingInstrumentId(SqlConnection connection, SqlTransaction transaction, int typeSizeId, int customerId, string serialNumber) { const string sql = @" SELECT TOP (1) z.IDEKZ FROM dbo.EKZ z WHERE z.IDTPRZ = @TypeSizeId AND z.IDFRPDV = @CustomerId AND z.NNZV = @SerialNumber AND ISNULL(z.IsDeleted, 0) = 0 ORDER BY z.IDEKZ DESC;"; using (var command = new SqlCommand(sql, connection, transaction)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@TypeSizeId", SqlDbType.Int).Value = typeSizeId; command.Parameters.Add("@CustomerId", SqlDbType.Int).Value = customerId; command.Parameters.Add("@SerialNumber", SqlDbType.VarChar, 30).Value = serialNumber; var result = command.ExecuteScalar(); return result == null || result == DBNull.Value ? (int?)null : Convert.ToInt32(result); } } private static int InsertInstrument(SqlConnection connection, SqlTransaction transaction, int typeSizeId, int customerId, string serialNumber) { const string sql = @" INSERT INTO dbo.EKZ ( IDTPRZ, IDFRPDV, KLSIPR, NNZV, GUIDEKZ, IsDeleted ) VALUES ( @TypeSizeId, @CustomerId, @Klsipr, @SerialNumber, @GuidEkz, 0 ); SELECT CAST(SCOPE_IDENTITY() AS int);"; using (var command = new SqlCommand(sql, connection, transaction)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@TypeSizeId", SqlDbType.Int).Value = typeSizeId; command.Parameters.Add("@CustomerId", SqlDbType.Int).Value = customerId; command.Parameters.Add("@Klsipr", SqlDbType.Int).Value = 1; command.Parameters.Add("@SerialNumber", SqlDbType.VarChar, 30).Value = serialNumber; command.Parameters.Add("@GuidEkz", SqlDbType.UniqueIdentifier).Value = Guid.NewGuid(); return Convert.ToInt32(command.ExecuteScalar()); } } private static string BuildOpenDocumentConflictMessage(IEnumerable conflicts) { var materializedConflicts = conflicts == null ? new List() : conflicts .Where(delegate(OpenDocumentConflictInfo conflict) { return conflict != null; }) .GroupBy(delegate(OpenDocumentConflictInfo conflict) { return string.Format( "{0}|{1}|{2}", conflict.DocumentNumber ?? string.Empty, conflict.TypeSizeId, conflict.SerialNumber ?? string.Empty); }, StringComparer.OrdinalIgnoreCase) .Select(delegate(IGrouping group) { return group.First(); }) .OrderBy(delegate(OpenDocumentConflictInfo conflict) { return conflict.SerialNumber ?? string.Empty; }) .ThenBy(delegate(OpenDocumentConflictInfo conflict) { return conflict.DocumentNumber ?? string.Empty; }) .ToList(); if (materializedConflicts.Count == 0) { return "РџСЂРёР±РѕСЂ СѓР¶Рµ находится РІ РґСЂСѓРіРѕР№ открытой РџРЎР’ этого заказчика."; } var preview = materializedConflicts .Take(5) .Select(delegate(OpenDocumentConflictInfo conflict) { return string.Format("зав. в„– {0} -> {1}", conflict.SerialNumber, conflict.DocumentNumber); }) .ToList(); var suffix = materializedConflicts.Count > preview.Count ? string.Format(" Еще конфликтов: {0}.", materializedConflicts.Count - preview.Count) : string.Empty; return string.Format( "РџСЂРёР±РѕСЂС‹ СѓР¶Рµ находятся РІ РґСЂСѓРіРёС… открытых РџРЎР’ этого заказчика: {0}.{1}", string.Join("; ", preview.ToArray()), suffix); } private static List LoadOpenDocumentConflicts( SqlConnection connection, SqlTransaction transaction, int customerId, string currentDocumentNumber, IEnumerable candidateLines) { var normalizedCandidates = candidateLines == null ? new List() : candidateLines .Where(delegate(PsvDocumentLine line) { return line != null && line.TypeSizeId > 0 && !string.IsNullOrWhiteSpace(line.SerialNumber); }) .GroupBy(delegate(PsvDocumentLine line) { return line.OpenDocumentConflictKey; }, StringComparer.OrdinalIgnoreCase) .Select(delegate(IGrouping group) { return group.First(); }) .ToList(); if (customerId <= 0 || normalizedCandidates.Count == 0) { return new List(); } const string sql = @" WITH ActiveDocuments AS ( SELECT m.NNZVPV FROM dbo.EKZMK m WHERE NULLIF(LTRIM(RTRIM(m.NNZVPV)), N'') IS NOT NULL GROUP BY m.NNZVPV HAVING MAX(m.DTVDM) IS NULL ) SELECT DISTINCT m.NNZVPV AS DocumentNumber, z.IDTPRZ AS TypeSizeId, LTRIM(RTRIM(z.NNZV)) AS SerialNumber FROM ActiveDocuments activeDocuments JOIN dbo.EKZMK m ON m.NNZVPV = activeDocuments.NNZVPV JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ WHERE z.IDFRPDV = @CustomerId AND z.IDTPRZ = @TypeSizeId AND LTRIM(RTRIM(z.NNZV)) = @SerialNumber AND (@CurrentDocumentNumber = N'' OR m.NNZVPV <> @CurrentDocumentNumber) ORDER BY m.NNZVPV;"; var conflicts = new List(); foreach (var candidateLine in normalizedCandidates) { using (var command = new SqlCommand(sql, connection, transaction)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@CustomerId", SqlDbType.Int).Value = customerId; command.Parameters.Add("@TypeSizeId", SqlDbType.Int).Value = candidateLine.TypeSizeId; command.Parameters.Add("@SerialNumber", SqlDbType.VarChar, 30).Value = candidateLine.SerialNumber.Trim(); command.Parameters.Add("@CurrentDocumentNumber", SqlDbType.NVarChar, 60).Value = currentDocumentNumber ?? string.Empty; using (var reader = command.ExecuteReader()) { while (reader.Read()) { conflicts.Add(new OpenDocumentConflictInfo { DocumentNumber = GetString(reader, "DocumentNumber"), TypeSizeId = GetInt32(reader, "TypeSizeId"), SerialNumber = GetString(reader, "SerialNumber") }); } } } } return conflicts .GroupBy(delegate(OpenDocumentConflictInfo conflict) { return string.Format( "{0}|{1}|{2}", conflict.DocumentNumber ?? string.Empty, conflict.TypeSizeId, conflict.SerialNumber ?? string.Empty); }, StringComparer.OrdinalIgnoreCase) .Select(delegate(IGrouping group) { return group.First(); }) .OrderBy(delegate(OpenDocumentConflictInfo conflict) { return conflict.SerialNumber ?? string.Empty; }) .ThenBy(delegate(OpenDocumentConflictInfo conflict) { return conflict.DocumentNumber ?? string.Empty; }) .ToList(); } private static async Task> LoadOpenDocumentConflictsAsync( SqlConnection connection, SqlTransaction transaction, int customerId, string currentDocumentNumber, IEnumerable candidateLines, CancellationToken cancellationToken = default) { var normalizedCandidates = candidateLines == null ? new List() : candidateLines .Where(delegate(PsvDocumentLine line) { return line != null && line.TypeSizeId > 0 && !string.IsNullOrWhiteSpace(line.SerialNumber); }) .GroupBy(delegate(PsvDocumentLine line) { return line.OpenDocumentConflictKey; }, StringComparer.OrdinalIgnoreCase) .Select(delegate(IGrouping group) { return group.First(); }) .ToList(); if (customerId <= 0 || normalizedCandidates.Count == 0) { return new List(); } const string sql = @" WITH ActiveDocuments AS ( SELECT m.NNZVPV FROM dbo.EKZMK m WHERE NULLIF(LTRIM(RTRIM(m.NNZVPV)), N'') IS NOT NULL GROUP BY m.NNZVPV HAVING MAX(m.DTVDM) IS NULL ) SELECT DISTINCT m.NNZVPV AS DocumentNumber, z.IDTPRZ AS TypeSizeId, LTRIM(RTRIM(z.NNZV)) AS SerialNumber FROM ActiveDocuments activeDocuments JOIN dbo.EKZMK m ON m.NNZVPV = activeDocuments.NNZVPV JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ WHERE z.IDFRPDV = @CustomerId AND z.IDTPRZ = @TypeSizeId AND LTRIM(RTRIM(z.NNZV)) = @SerialNumber AND (@CurrentDocumentNumber = N'' OR m.NNZVPV <> @CurrentDocumentNumber) ORDER BY m.NNZVPV;"; var conflicts = new List(); foreach (var candidateLine in normalizedCandidates) { var candidateConflicts = await connection.QueryAsync( transaction, sql, delegate(SqlDataReader reader) { return new OpenDocumentConflictInfo { DocumentNumber = GetString(reader, "DocumentNumber"), TypeSizeId = GetInt32(reader, "TypeSizeId"), SerialNumber = GetString(reader, "SerialNumber") }; }, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@CustomerId", SqlDbType.Int).Value = customerId; command.Parameters.Add("@TypeSizeId", SqlDbType.Int).Value = candidateLine.TypeSizeId; command.Parameters.Add("@SerialNumber", SqlDbType.VarChar, 30).Value = candidateLine.SerialNumber.Trim(); command.Parameters.Add("@CurrentDocumentNumber", SqlDbType.NVarChar, 60).Value = currentDocumentNumber ?? string.Empty; }, cancellationToken).ConfigureAwait(false); conflicts.AddRange(candidateConflicts); } return conflicts .GroupBy(delegate(OpenDocumentConflictInfo conflict) { return string.Format( "{0}|{1}|{2}", conflict.DocumentNumber ?? string.Empty, conflict.TypeSizeId, conflict.SerialNumber ?? string.Empty); }, StringComparer.OrdinalIgnoreCase) .Select(delegate(IGrouping group) { return group.First(); }) .OrderBy(delegate(OpenDocumentConflictInfo conflict) { return conflict.SerialNumber ?? string.Empty; }) .ThenBy(delegate(OpenDocumentConflictInfo conflict) { return conflict.DocumentNumber ?? string.Empty; }) .ToList(); } private static SqlConnection CreateConnection() { return SqlServerConnectionFactory.Current.CreateConnection(); } private static void ClearLineVerificationCore(SqlConnection connection, SqlTransaction transaction, int cardId) { const string sql = @" UPDATE dbo.EKZMK SET IDPRSN = NULL, NNNKL = NULL, GDN = NULL, DTMKFK = NULL, PRCHNPGDN = NULL WHERE IDEKZMK = @CardId; SELECT @@ROWCOUNT;"; using (var command = new SqlCommand(sql, connection, transaction)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; if (Convert.ToInt32(command.ExecuteScalar()) == 0) { throw new InvalidOperationException("Строка EKZMK для изменения результата поверки РЅРµ найдена."); } } } private static async Task ClearLineVerificationCoreAsync(SqlConnection connection, SqlTransaction transaction, int cardId, CancellationToken cancellationToken = default) { const string sql = @" UPDATE dbo.EKZMK SET IDPRSN = NULL, NNNKL = NULL, GDN = NULL, DTMKFK = NULL, PRCHNPGDN = NULL WHERE IDEKZMK = @CardId; SELECT @@ROWCOUNT;"; var affectedRowCount = await connection.ExecuteScalarAsync( transaction, sql, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; }, cancellationToken).ConfigureAwait(false); if (affectedRowCount == 0) { throw new InvalidOperationException("Строка EKZMK для изменения результата поверки не найдена."); } } private static void DeleteVerificationDocuments(SqlConnection connection, SqlTransaction transaction, int cardId) { const string sql = @" DELETE d FROM dbo.DMS d JOIN dbo.VDODVDD vdd ON vdd.IDVDODVDD = d.IDVDODVDD JOIN dbo.FRDMS frdms ON frdms.IDFRDMS = d.IDFRDMS JOIN dbo.SPVDD spvdd ON spvdd.IDSPVDD = frdms.IDSPVDD WHERE d.IDOD = @CardId AND vdd.IDSPVDOD = 2 AND spvdd.IDSPVDD IN (2, 6, 8);"; using (var command = new SqlCommand(sql, connection, transaction)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; command.ExecuteNonQuery(); } } private static Task DeleteVerificationDocumentsAsync(SqlConnection connection, SqlTransaction transaction, int cardId, CancellationToken cancellationToken = default) { const string sql = @" DELETE d FROM dbo.DMS d JOIN dbo.VDODVDD vdd ON vdd.IDVDODVDD = d.IDVDODVDD JOIN dbo.FRDMS frdms ON frdms.IDFRDMS = d.IDFRDMS JOIN dbo.SPVDD spvdd ON spvdd.IDSPVDD = frdms.IDSPVDD WHERE d.IDOD = @CardId AND vdd.IDSPVDOD = 2 AND spvdd.IDSPVDD IN (2, 6, 8);"; return connection.ExecuteNonQueryAsync( transaction, sql, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; }, cancellationToken); } private static void InsertVerificationDocument( SqlConnection connection, SqlTransaction transaction, int cardId, int linkTypeId, int formId, string documentNumber, DateTime documentDate) { const string sql = @" INSERT INTO dbo.DMS ( IDOD, IDVDODVDD, IDFRDMS, NND, DTD, PTTXDMS, GUIDDMS ) VALUES ( @CardId, @LinkTypeId, @FormId, @DocumentNumber, @DocumentDate, NULL, @Guid );"; using (var command = new SqlCommand(sql, connection, transaction)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; command.Parameters.Add("@LinkTypeId", SqlDbType.Int).Value = linkTypeId; command.Parameters.Add("@FormId", SqlDbType.Int).Value = formId; command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber.Trim(); command.Parameters.Add("@DocumentDate", SqlDbType.DateTime).Value = documentDate; command.Parameters.Add("@Guid", SqlDbType.UniqueIdentifier).Value = Guid.NewGuid(); command.ExecuteNonQuery(); } } private static Task InsertVerificationDocumentAsync( SqlConnection connection, SqlTransaction transaction, int cardId, int linkTypeId, int formId, string documentNumber, DateTime documentDate, CancellationToken cancellationToken = default) { const string sql = @" INSERT INTO dbo.DMS ( IDOD, IDVDODVDD, IDFRDMS, NND, DTD, PTTXDMS, GUIDDMS ) VALUES ( @CardId, @LinkTypeId, @FormId, @DocumentNumber, @DocumentDate, NULL, @Guid );"; return connection.ExecuteNonQueryAsync( transaction, sql, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; command.Parameters.Add("@LinkTypeId", SqlDbType.Int).Value = linkTypeId; command.Parameters.Add("@FormId", SqlDbType.Int).Value = formId; command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber.Trim(); command.Parameters.Add("@DocumentDate", SqlDbType.DateTime).Value = documentDate; command.Parameters.Add("@Guid", SqlDbType.UniqueIdentifier).Value = Guid.NewGuid(); }, cancellationToken); } private static void SaveLineVerificationCore(SqlConnection connection, SqlTransaction transaction, int cardId, VerificationEditResult result) { const string sql = @" UPDATE dbo.EKZMK SET IDPRSN = @VerifierId, NNNKL = @StickerNumber, GDN = @IsPassed, DTMKFK = @VerificationDate, PRCHNPGDN = @RejectionReason WHERE IDEKZMK = @CardId; SELECT @@ROWCOUNT;"; using (var command = new SqlCommand(sql, connection, transaction)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; command.Parameters.Add("@VerifierId", SqlDbType.Int).Value = result.VerifierId; command.Parameters.Add("@StickerNumber", SqlDbType.NVarChar, 30).Value = result.IsPassed && !string.IsNullOrWhiteSpace(result.StickerNumber) ? (object)result.StickerNumber.Trim() : DBNull.Value; command.Parameters.Add("@IsPassed", SqlDbType.Bit).Value = result.IsPassed; command.Parameters.Add("@VerificationDate", SqlDbType.DateTime).Value = result.VerificationDate; command.Parameters.Add("@RejectionReason", SqlDbType.NVarChar, 1024).Value = !result.IsPassed && !string.IsNullOrWhiteSpace(result.RejectionReason) ? (object)result.RejectionReason.Trim() : DBNull.Value; if (Convert.ToInt32(command.ExecuteScalar()) == 0) { throw new InvalidOperationException("Строка EKZMK для сохранения результата поверки РЅРµ найдена."); } } } private static async Task SaveLineVerificationCoreAsync(SqlConnection connection, SqlTransaction transaction, int cardId, VerificationEditResult result, CancellationToken cancellationToken = default) { const string sql = @" UPDATE dbo.EKZMK SET IDPRSN = @VerifierId, NNNKL = @StickerNumber, GDN = @IsPassed, DTMKFK = @VerificationDate, PRCHNPGDN = @RejectionReason WHERE IDEKZMK = @CardId; SELECT @@ROWCOUNT;"; var affectedRowCount = await connection.ExecuteScalarAsync( transaction, sql, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; command.Parameters.Add("@VerifierId", SqlDbType.Int).Value = result.VerifierId; command.Parameters.Add("@StickerNumber", SqlDbType.NVarChar, 30).Value = result.IsPassed && !string.IsNullOrWhiteSpace(result.StickerNumber) ? (object)result.StickerNumber.Trim() : DBNull.Value; command.Parameters.Add("@IsPassed", SqlDbType.Bit).Value = result.IsPassed; command.Parameters.Add("@VerificationDate", SqlDbType.DateTime).Value = result.VerificationDate; command.Parameters.Add("@RejectionReason", SqlDbType.NVarChar, 1024).Value = !result.IsPassed && !string.IsNullOrWhiteSpace(result.RejectionReason) ? (object)result.RejectionReason.Trim() : DBNull.Value; }, cancellationToken).ConfigureAwait(false); if (affectedRowCount == 0) { throw new InvalidOperationException("Строка EKZMK для сохранения результата поверки не найдена."); } } private static int DeleteLineDms(SqlConnection connection, SqlTransaction transaction, string documentNumber, int cardId) { const string sql = @" DELETE d FROM dbo.DMS d JOIN dbo.VDODVDD vdd ON vdd.IDVDODVDD = d.IDVDODVDD JOIN dbo.EKZMK m ON m.IDEKZMK = d.IDOD WHERE m.NNZVPV = @DocumentNumber AND m.IDEKZMK = @CardId AND vdd.IDSPVDOD = 2; SELECT @@ROWCOUNT;"; using (var command = new SqlCommand(sql, connection, transaction)) { command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; return Convert.ToInt32(command.ExecuteScalar()); } } private static Task DeleteLineDmsAsync(SqlConnection connection, SqlTransaction transaction, string documentNumber, int cardId, CancellationToken cancellationToken = default) { const string sql = @" DELETE d FROM dbo.DMS d JOIN dbo.VDODVDD vdd ON vdd.IDVDODVDD = d.IDVDODVDD JOIN dbo.EKZMK m ON m.IDEKZMK = d.IDOD WHERE m.NNZVPV = @DocumentNumber AND m.IDEKZMK = @CardId AND vdd.IDSPVDOD = 2; SELECT @@ROWCOUNT;"; return connection.ExecuteScalarAsync( transaction, sql, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; }, cancellationToken); } private static int DeleteLineEkzMk(SqlConnection connection, SqlTransaction transaction, string documentNumber, int cardId) { const string sql = @" DELETE FROM dbo.EKZMK WHERE NNZVPV = @DocumentNumber AND IDEKZMK = @CardId; SELECT @@ROWCOUNT;"; using (var command = new SqlCommand(sql, connection, transaction)) { command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; return Convert.ToInt32(command.ExecuteScalar()); } } private static Task DeleteLineEkzMkAsync(SqlConnection connection, SqlTransaction transaction, string documentNumber, int cardId, CancellationToken cancellationToken = default) { const string sql = @" DELETE FROM dbo.EKZMK WHERE NNZVPV = @DocumentNumber AND IDEKZMK = @CardId; SELECT @@ROWCOUNT;"; return connection.ExecuteScalarAsync( transaction, sql, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; }, cancellationToken); } private static int DeleteLineEkzMkFctvl(SqlConnection connection, SqlTransaction transaction, string documentNumber, int cardId) { const string sql = @" DELETE child FROM dbo.EKZMKFCTVL child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber AND parent.IDEKZMK = @CardId; SELECT @@ROWCOUNT;"; using (var command = new SqlCommand(sql, connection, transaction)) { command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; return Convert.ToInt32(command.ExecuteScalar()); } } private static Task DeleteLineEkzMkFctvlAsync(SqlConnection connection, SqlTransaction transaction, string documentNumber, int cardId, CancellationToken cancellationToken = default) { const string sql = @" DELETE child FROM dbo.EKZMKFCTVL child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber AND parent.IDEKZMK = @CardId; SELECT @@ROWCOUNT;"; return connection.ExecuteScalarAsync( transaction, sql, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; }, cancellationToken); } private static int DeleteDocumentDms(SqlConnection connection, SqlTransaction transaction, string documentNumber) { const string sql = @" DELETE d FROM dbo.DMS d JOIN dbo.VDODVDD vdd ON vdd.IDVDODVDD = d.IDVDODVDD JOIN dbo.EKZMK m ON m.IDEKZMK = d.IDOD WHERE m.NNZVPV = @DocumentNumber AND vdd.IDSPVDOD = 2; SELECT @@ROWCOUNT;"; using (var command = new SqlCommand(sql, connection, transaction)) { command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; return Convert.ToInt32(command.ExecuteScalar()); } } private static Task DeleteDocumentDmsAsync(SqlConnection connection, SqlTransaction transaction, string documentNumber, CancellationToken cancellationToken = default) { const string sql = @" DELETE d FROM dbo.DMS d JOIN dbo.VDODVDD vdd ON vdd.IDVDODVDD = d.IDVDODVDD JOIN dbo.EKZMK m ON m.IDEKZMK = d.IDOD WHERE m.NNZVPV = @DocumentNumber AND vdd.IDSPVDOD = 2; SELECT @@ROWCOUNT;"; return connection.ExecuteScalarAsync( transaction, sql, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; }, cancellationToken); } private static int DeleteDocumentEkzMk(SqlConnection connection, SqlTransaction transaction, string documentNumber) { const string sql = @" DELETE FROM dbo.EKZMK WHERE NNZVPV = @DocumentNumber; SELECT @@ROWCOUNT;"; using (var command = new SqlCommand(sql, connection, transaction)) { command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; return Convert.ToInt32(command.ExecuteScalar()); } } private static Task DeleteDocumentEkzMkAsync(SqlConnection connection, SqlTransaction transaction, string documentNumber, CancellationToken cancellationToken = default) { const string sql = @" DELETE FROM dbo.EKZMK WHERE NNZVPV = @DocumentNumber; SELECT @@ROWCOUNT;"; return connection.ExecuteScalarAsync( transaction, sql, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; }, cancellationToken); } private static int DeleteDocumentEkzMkFctvl(SqlConnection connection, SqlTransaction transaction, string documentNumber) { const string sql = @" DELETE child FROM dbo.EKZMKFCTVL child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber; SELECT @@ROWCOUNT;"; using (var command = new SqlCommand(sql, connection, transaction)) { command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; return Convert.ToInt32(command.ExecuteScalar()); } } private static Task DeleteDocumentEkzMkFctvlAsync(SqlConnection connection, SqlTransaction transaction, string documentNumber, CancellationToken cancellationToken = default) { const string sql = @" DELETE child FROM dbo.EKZMKFCTVL child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber; SELECT @@ROWCOUNT;"; return connection.ExecuteScalarAsync( transaction, sql, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; }, cancellationToken); } private static bool DocumentNumberExists(SqlConnection connection, SqlTransaction transaction, string documentNumber, string excludeDocumentNumber) { const string sql = @" SELECT COUNT(1) FROM dbo.EKZMK WHERE NNZVPV = @DocumentNumber AND (@ExcludeDocumentNumber = N'' OR NNZVPV <> @ExcludeDocumentNumber);"; using (var command = new SqlCommand(sql, connection, transaction)) { command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; command.Parameters.Add("@ExcludeDocumentNumber", SqlDbType.NVarChar, 60).Value = excludeDocumentNumber ?? string.Empty; return Convert.ToInt32(command.ExecuteScalar()) > 0; } } private static async Task DocumentNumberExistsAsync(SqlConnection connection, SqlTransaction transaction, string documentNumber, string excludeDocumentNumber, CancellationToken cancellationToken = default) { const string sql = @" SELECT COUNT(1) FROM dbo.EKZMK WHERE NNZVPV = @DocumentNumber AND (@ExcludeDocumentNumber = N'' OR NNZVPV <> @ExcludeDocumentNumber);"; var matchCount = await connection.ExecuteScalarAsync( transaction, sql, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; command.Parameters.Add("@ExcludeDocumentNumber", SqlDbType.NVarChar, 60).Value = excludeDocumentNumber ?? string.Empty; }, cancellationToken).ConfigureAwait(false); return matchCount > 0; } private static bool GetBoolean(IDataRecord record, string columnName) { return Convert.ToBoolean(record[columnName]); } private static int GetInt32(IDataRecord record, string columnName) { return Convert.ToInt32(record[columnName]); } private static string GetString(IDataRecord record, string columnName) { return record[columnName] == DBNull.Value ? string.Empty : Convert.ToString(record[columnName]); } private static DateTime? GetNullableDateTime(IDataRecord record, string columnName) { return record[columnName] == DBNull.Value ? (DateTime?)null : Convert.ToDateTime(record[columnName]); } private static decimal? GetNullableDecimal(IDataRecord record, string columnName) { return record[columnName] == DBNull.Value ? (decimal?)null : Convert.ToDecimal(record[columnName]); } private static bool? GetNullableBoolean(IDataRecord record, string columnName) { return record[columnName] == DBNull.Value ? (bool?)null : Convert.ToBoolean(record[columnName]); } private static int? GetNullableInt32(IDataRecord record, string columnName) { return record[columnName] == DBNull.Value ? (int?)null : Convert.ToInt32(record[columnName]); } private static int InsertEkzMk( SqlConnection connection, SqlTransaction transaction, int verificationTypeId, DocumentEditorResult document, string normalizedNumber, int instrumentId, EkzMkTemplate template, PsvDocumentLine pendingLine) { const string sql = @" INSERT INTO dbo.EKZMK ( IDEKZ, IDSPMU, IDGRSI, IDKSPRL, IDSPVDMK, IDSPVDMC, IDFRPD, IDSPMPOB, IDPRSN, IDSPKMMK, IDEKZRM, IDSPVDKL, IDPRSNVD, IDEKZTO, IDEKZOT, NNZVPV, SHFKL, NNNKL, PRMK, DTMKFK, DTMKPL, DTPRM, DTVDM, GDN, PZMC, STMK, STMKDP, NCSRMK, idprsnsd, idprsnpr, idprsnvy, idsptsmp, idspssmp, GUIDEKZMK, DSEKZMK, DTOTM, DTVZM, IDPRSNOTM, IDPRSNVZM, NRVRMNDmp, NRVRMmp, VRMKFK, IDKSP, DPZNmp, HRTCmp, IDSPVDSBMK, PRCHNPGDN, IDEKZETL ) VALUES ( @IDEKZ, @IDSPMU, @IDGRSI, @IDKSPRL, @IDSPVDMK, @IDSPVDMC, @IDFRPD, @IDSPMPOB, @IDPRSN, @IDSPKMMK, NULL, @IDSPVDKL, @IDPRSNVD, NULL, NULL, @NNZVPV, NULL, @NNNKL, @PRMK, @DTMKFK, NULL, @DTPRM, @DTVDM, @GDN, NULL, @STMK, @STMKDP, @NCSRMK, @idprsnsd, @idprsnpr, @idprsnvy, @idsptsmp, @idspssmp, @GUIDEKZMK, NULL, NULL, NULL, NULL, NULL, @NRVRMNDmp, @NRVRMmp, @VRMKFK, @IDKSP, @DPZNmp, @HRTCmp, @IDSPVDSBMK, @PRCHNPGDN, @IDEKZETL ); SELECT CAST(SCOPE_IDENTITY() AS int);"; using (var command = new SqlCommand(sql, connection, transaction)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@IDEKZ", SqlDbType.Int).Value = instrumentId; command.Parameters.Add("@IDSPMU", SqlDbType.Int).Value = (object)template.IdSpmu ?? DBNull.Value; command.Parameters.Add("@IDGRSI", SqlDbType.Int).Value = (object)template.IdGrsi ?? DBNull.Value; command.Parameters.Add("@IDKSPRL", SqlDbType.Int).Value = (object)template.IdKsprl ?? DBNull.Value; command.Parameters.Add("@IDSPVDMK", SqlDbType.Int).Value = verificationTypeId; command.Parameters.Add("@IDSPVDMC", SqlDbType.Int).Value = (object)template.IdSpvdmc ?? DBNull.Value; command.Parameters.Add("@IDFRPD", SqlDbType.Int).Value = template.IdFrpd; command.Parameters.Add("@IDSPMPOB", SqlDbType.Int).Value = (object)template.IdSpmpob ?? DBNull.Value; command.Parameters.Add("@IDPRSN", SqlDbType.Int).Value = pendingLine == null ? DBNull.Value : (object)pendingLine.VerifierId ?? DBNull.Value; command.Parameters.Add("@IDSPKMMK", SqlDbType.Int).Value = (object)template.IdSpkmmk ?? DBNull.Value; command.Parameters.Add("@IDSPVDKL", SqlDbType.Int).Value = (object)template.IdSpvdkl ?? DBNull.Value; command.Parameters.Add("@IDPRSNVD", SqlDbType.Int).Value = (object)template.IdPrsnvd ?? DBNull.Value; command.Parameters.Add("@NNZVPV", SqlDbType.NVarChar, 60).Value = normalizedNumber; command.Parameters.Add("@NNNKL", SqlDbType.NVarChar, 30).Value = pendingLine != null && pendingLine.IsPassed == true ? (object)(string.IsNullOrWhiteSpace(pendingLine.StickerNumber) ? null : pendingLine.StickerNumber.Trim()) : DBNull.Value; command.Parameters.Add("@PRMK", SqlDbType.Int).Value = template.Prmk; command.Parameters.Add("@DTMKFK", SqlDbType.DateTime).Value = pendingLine == null ? DBNull.Value : (object)(pendingLine.VerificationPerformedOn ?? pendingLine.VerificationDocumentDate) ?? DBNull.Value; command.Parameters.Add("@DTPRM", SqlDbType.DateTime).Value = document.AcceptedOn; command.Parameters.Add("@DTVDM", SqlDbType.DateTime).Value = (object)document.IssuedOn ?? DBNull.Value; command.Parameters.Add("@GDN", SqlDbType.Bit).Value = pendingLine == null ? DBNull.Value : (object)pendingLine.IsPassed ?? DBNull.Value; command.Parameters.Add("@STMK", SqlDbType.Money).Value = (object)template.Stmk ?? DBNull.Value; command.Parameters.Add("@STMKDP", SqlDbType.Money).Value = (object)template.Stmkdp ?? DBNull.Value; command.Parameters.Add("@NCSRMK", SqlDbType.Money).Value = (object)template.NcSrmk ?? DBNull.Value; command.Parameters.Add("@idprsnsd", SqlDbType.Int).Value = (object)template.IdPrsnsd ?? DBNull.Value; command.Parameters.Add("@idprsnpr", SqlDbType.Int).Value = (object)template.IdPrsnpr ?? DBNull.Value; command.Parameters.Add("@idprsnvy", SqlDbType.Int).Value = (object)template.IdPrsnvy ?? DBNull.Value; command.Parameters.Add("@idsptsmp", SqlDbType.Int).Value = (object)template.IdSptsmp ?? DBNull.Value; command.Parameters.Add("@idspssmp", SqlDbType.Int).Value = (object)template.IdSpssmp ?? DBNull.Value; command.Parameters.Add("@GUIDEKZMK", SqlDbType.UniqueIdentifier).Value = Guid.NewGuid(); command.Parameters.Add("@NRVRMNDmp", SqlDbType.Decimal).Value = (object)template.Nrvrmndmp ?? DBNull.Value; command.Parameters["@NRVRMNDmp"].Precision = 10; command.Parameters["@NRVRMNDmp"].Scale = 2; command.Parameters.Add("@NRVRMmp", SqlDbType.Decimal).Value = (object)template.Nrvrmmp ?? DBNull.Value; command.Parameters["@NRVRMmp"].Precision = 10; command.Parameters["@NRVRMmp"].Scale = 2; command.Parameters.Add("@VRMKFK", SqlDbType.Decimal).Value = (object)template.Vrmkfk ?? DBNull.Value; command.Parameters["@VRMKFK"].Precision = 10; command.Parameters["@VRMKFK"].Scale = 2; command.Parameters.Add("@IDKSP", SqlDbType.Int).Value = (object)template.IdKsp ?? DBNull.Value; command.Parameters.Add("@DPZNmp", SqlDbType.NVarChar, 100).Value = (object)template.Dpznmp ?? DBNull.Value; command.Parameters.Add("@HRTCmp", SqlDbType.NVarChar, 80).Value = (object)template.Hrtcmp ?? DBNull.Value; command.Parameters.Add("@IDSPVDSBMK", SqlDbType.Int).Value = (object)template.IdSpvdsbmk ?? DBNull.Value; command.Parameters.Add("@PRCHNPGDN", SqlDbType.NVarChar, 1024).Value = pendingLine != null && pendingLine.IsPassed == false ? (object)(string.IsNullOrWhiteSpace(pendingLine.RejectionReason) ? null : pendingLine.RejectionReason.Trim()) : DBNull.Value; command.Parameters.Add("@IDEKZETL", SqlDbType.Int).Value = (object)template.IdEkzetl ?? DBNull.Value; return Convert.ToInt32(command.ExecuteScalar()); } } private static HashSet LoadDocumentDuplicateKeys(SqlConnection connection, SqlTransaction transaction, string documentNumber) { const string sql = @" SELECT DISTINCT tips.TP AS InstrumentType, sizeInfo.DPZN AS RangeText, sizeInfo.NNGSRS AS RegistryNumber, z.NNZV AS SerialNumber FROM dbo.EKZMK m JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ LEFT JOIN dbo.TPRZ sizeInfo ON sizeInfo.IDTPRZ = z.IDTPRZ LEFT JOIN dbo.TIPS tips ON tips.IDTIPS = sizeInfo.IDTIPS WHERE m.NNZVPV = @DocumentNumber;"; var keys = new HashSet(StringComparer.OrdinalIgnoreCase); using (var command = new SqlCommand(sql, connection, transaction)) { command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; using (var reader = command.ExecuteReader()) { while (reader.Read()) { keys.Add(PsvDocumentLine.BuildDuplicateKey( GetString(reader, "InstrumentType"), GetString(reader, "RangeText"), GetString(reader, "RegistryNumber"), GetString(reader, "SerialNumber"))); } } } return keys; } private static List LoadDeleteBlockers(SqlConnection connection, SqlTransaction transaction, IEnumerable cardIds) { var aggregated = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (var cardId in cardIds) { foreach (var blocker in LoadDeleteBlockers(connection, transaction, cardId)) { int currentCount; if (!aggregated.TryGetValue(blocker.TableName, out currentCount)) { currentCount = 0; } aggregated[blocker.TableName] = currentCount + blocker.RowCount; } } return aggregated .OrderBy(delegate(KeyValuePair blocker) { return blocker.Key; }) .Select(delegate(KeyValuePair blocker) { return new DeleteBlockerInfo { TableName = blocker.Key, RowCount = blocker.Value }; }) .ToList(); } private static List LoadDeleteBlockers(SqlConnection connection, SqlTransaction transaction, int cardId) { const string sql = @" SELECT blocker.TableName, blocker.LinkCount FROM ( SELECT N'EKZMKDH' AS TableName, COUNT(*) AS LinkCount FROM dbo.EKZMKDH child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZMK = @CardId UNION ALL SELECT N'EKZMKEKZK', COUNT(*) FROM dbo.EKZMKEKZK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZMK = @CardId UNION ALL SELECT N'EKZMKND', COUNT(*) FROM dbo.EKZMKND child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZMK = @CardId UNION ALL SELECT N'FRPTMK', COUNT(*) FROM dbo.FRPTMK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZMK = @CardId UNION ALL SELECT N'KSPELEKZMK', COUNT(*) FROM dbo.KSPELEKZMK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZMK = @CardId ) blocker WHERE blocker.LinkCount > 0 ORDER BY blocker.TableName;"; var blockers = new List(); using (var command = new SqlCommand(sql, connection, transaction)) { command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; using (var reader = command.ExecuteReader()) { while (reader.Read()) { blockers.Add(new DeleteBlockerInfo { TableName = GetString(reader, "TableName"), RowCount = GetInt32(reader, "LinkCount") }); } } } return blockers; } private static List LoadDeleteBlockers(SqlConnection connection, SqlTransaction transaction, string documentNumber) { const string sql = @" SELECT blocker.TableName, blocker.LinkCount FROM ( SELECT N'EKZMKDH' AS TableName, COUNT(*) AS LinkCount FROM dbo.EKZMKDH child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber UNION ALL SELECT N'EKZMKEKZK', COUNT(*) FROM dbo.EKZMKEKZK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber UNION ALL SELECT N'EKZMKND', COUNT(*) FROM dbo.EKZMKND child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber UNION ALL SELECT N'FRPTMK', COUNT(*) FROM dbo.FRPTMK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber UNION ALL SELECT N'KSPELEKZMK', COUNT(*) FROM dbo.KSPELEKZMK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber ) blocker WHERE blocker.LinkCount > 0 ORDER BY blocker.TableName;"; var blockers = new List(); using (var command = new SqlCommand(sql, connection, transaction)) { command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; using (var reader = command.ExecuteReader()) { while (reader.Read()) { blockers.Add(new DeleteBlockerInfo { TableName = GetString(reader, "TableName"), RowCount = GetInt32(reader, "LinkCount") }); } } } return blockers; } private static async Task> LoadDeleteBlockersAsync(SqlConnection connection, SqlTransaction transaction, IEnumerable cardIds, CancellationToken cancellationToken = default) { var aggregated = new Dictionary(StringComparer.OrdinalIgnoreCase); foreach (var cardId in cardIds) { foreach (var blocker in await LoadDeleteBlockersAsync(connection, transaction, cardId, cancellationToken).ConfigureAwait(false)) { int currentCount; if (!aggregated.TryGetValue(blocker.TableName, out currentCount)) { currentCount = 0; } aggregated[blocker.TableName] = currentCount + blocker.RowCount; } } return aggregated .OrderBy(delegate(KeyValuePair blocker) { return blocker.Key; }) .Select(delegate(KeyValuePair blocker) { return new DeleteBlockerInfo { TableName = blocker.Key, RowCount = blocker.Value }; }) .ToList(); } private static Task> LoadDeleteBlockersAsync(SqlConnection connection, SqlTransaction transaction, int cardId, CancellationToken cancellationToken = default) { const string sql = @" SELECT blocker.TableName, blocker.LinkCount FROM ( SELECT N'EKZMKDH' AS TableName, COUNT(*) AS LinkCount FROM dbo.EKZMKDH child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZMK = @CardId UNION ALL SELECT N'EKZMKEKZK', COUNT(*) FROM dbo.EKZMKEKZK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZMK = @CardId UNION ALL SELECT N'EKZMKND', COUNT(*) FROM dbo.EKZMKND child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZMK = @CardId UNION ALL SELECT N'FRPTMK', COUNT(*) FROM dbo.FRPTMK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZMK = @CardId UNION ALL SELECT N'KSPELEKZMK', COUNT(*) FROM dbo.KSPELEKZMK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.IDEKZMK = @CardId ) blocker WHERE blocker.LinkCount > 0 ORDER BY blocker.TableName;"; return connection.QueryAsync( transaction, sql, delegate(SqlDataReader reader) { return new DeleteBlockerInfo { TableName = GetString(reader, "TableName"), RowCount = GetInt32(reader, "LinkCount") }; }, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId; }, cancellationToken); } private static Task> LoadDeleteBlockersAsync(SqlConnection connection, SqlTransaction transaction, string documentNumber, CancellationToken cancellationToken = default) { const string sql = @" SELECT blocker.TableName, blocker.LinkCount FROM ( SELECT N'EKZMKDH' AS TableName, COUNT(*) AS LinkCount FROM dbo.EKZMKDH child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber UNION ALL SELECT N'EKZMKEKZK', COUNT(*) FROM dbo.EKZMKEKZK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber UNION ALL SELECT N'EKZMKND', COUNT(*) FROM dbo.EKZMKND child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber UNION ALL SELECT N'FRPTMK', COUNT(*) FROM dbo.FRPTMK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber UNION ALL SELECT N'KSPELEKZMK', COUNT(*) FROM dbo.KSPELEKZMK child JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK WHERE parent.NNZVPV = @DocumentNumber ) blocker WHERE blocker.LinkCount > 0 ORDER BY blocker.TableName;"; return connection.QueryAsync( transaction, sql, delegate(SqlDataReader reader) { return new DeleteBlockerInfo { TableName = GetString(reader, "TableName"), RowCount = GetInt32(reader, "LinkCount") }; }, delegate(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber; }, cancellationToken); } private static InstrumentIdentityInfo LoadInstrumentIdentity(SqlConnection connection, SqlTransaction transaction, int instrumentId) { const string sql = @" SELECT tips.TP AS InstrumentType, sizeInfo.DPZN AS RangeText, sizeInfo.NNGSRS AS RegistryNumber, z.NNZV AS SerialNumber FROM dbo.EKZ z LEFT JOIN dbo.TPRZ sizeInfo ON sizeInfo.IDTPRZ = z.IDTPRZ LEFT JOIN dbo.TIPS tips ON tips.IDTIPS = sizeInfo.IDTIPS WHERE z.IDEKZ = @InstrumentId;"; using (var command = new SqlCommand(sql, connection, transaction)) { command.Parameters.Add("@InstrumentId", SqlDbType.Int).Value = instrumentId; using (var reader = command.ExecuteReader()) { if (!reader.Read()) { return null; } return new InstrumentIdentityInfo { DuplicateKey = PsvDocumentLine.BuildDuplicateKey( GetString(reader, "InstrumentType"), GetString(reader, "RangeText"), GetString(reader, "RegistryNumber"), GetString(reader, "SerialNumber")) }; } } } private static int LoadVerificationTypeId(SqlConnection connection, SqlTransaction transaction) { const string sql = @" SELECT TOP (1) IDSPVDMK FROM dbo.SPVDMK WHERE OBVDMK = N'Рџ' OR NMVDMK = N'Поверка' ORDER BY CASE WHEN OBVDMK = N'Рџ' THEN 0 ELSE 1 END, IDSPVDMK;"; using (var command = new SqlCommand(sql, connection, transaction)) { var result = command.ExecuteScalar(); if (result == null || result == DBNull.Value) { throw new InvalidOperationException("Р’ справочнике SPVDMK РЅРµ найден РІРёРґ РњРљ 'Поверка'."); } return Convert.ToInt32(result); } } private static EkzMkTemplate LoadTemplate(SqlConnection connection, SqlTransaction transaction, int instrumentId) { const string sql = @" DECLARE @TypeSizeId int; SELECT @TypeSizeId = IDTPRZ FROM dbo.EKZ WHERE IDEKZ = @InstrumentId; WITH TemplateCandidates AS ( SELECT * FROM ( SELECT TOP (1) 1 AS Priority, m.IDSPMU, m.IDGRSI, m.IDKSPRL, m.IDSPVDMC, m.IDFRPD, m.IDSPMPOB, m.IDPRSN, m.IDSPKMMK, m.IDSPVDKL, m.IDPRSNVD, m.PRMK, m.STMK, m.STMKDP, m.NCSRMK, m.idprsnsd, m.idprsnpr, m.idprsnvy, m.idsptsmp, m.idspssmp, m.NRVRMNDmp, m.NRVRMmp, m.VRMKFK, m.IDKSP, m.DPZNmp, m.HRTCmp, m.IDSPVDSBMK, m.IDEKZETL, CAST(N'История РїСЂРёР±РѕСЂР°' AS nvarchar(60)) AS SourceDescription FROM dbo.EKZMK m WHERE m.IDEKZ = @InstrumentId ORDER BY ISNULL(m.DTPRM, CONVERT(datetime, '19000101', 112)) DESC, m.IDEKZMK DESC ) instrumentTemplate UNION ALL SELECT * FROM ( SELECT TOP (1) 2 AS Priority, m.IDSPMU, m.IDGRSI, m.IDKSPRL, m.IDSPVDMC, m.IDFRPD, m.IDSPMPOB, m.IDPRSN, m.IDSPKMMK, m.IDSPVDKL, m.IDPRSNVD, m.PRMK, m.STMK, m.STMKDP, m.NCSRMK, m.idprsnsd, m.idprsnpr, m.idprsnvy, m.idsptsmp, m.idspssmp, m.NRVRMNDmp, m.NRVRMmp, m.VRMKFK, m.IDKSP, m.DPZNmp, m.HRTCmp, m.IDSPVDSBMK, m.IDEKZETL, CAST(N'Шаблон РїРѕ типоразмеру' AS nvarchar(60)) AS SourceDescription FROM dbo.EKZMK m JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ WHERE z.IDTPRZ = @TypeSizeId ORDER BY ISNULL(m.DTPRM, CONVERT(datetime, '19000101', 112)) DESC, m.IDEKZMK DESC ) typeTemplate ) SELECT TOP (1) * FROM TemplateCandidates ORDER BY Priority;"; using (var command = new SqlCommand(sql, connection, transaction)) { command.Parameters.Add("@InstrumentId", SqlDbType.Int).Value = instrumentId; using (var reader = command.ExecuteReader()) { if (reader.Read()) { return new EkzMkTemplate { IdSpmu = GetNullableInt32(reader, "IDSPMU"), IdGrsi = GetNullableInt32(reader, "IDGRSI"), IdKsprl = GetNullableInt32(reader, "IDKSPRL"), IdSpvdmc = GetNullableInt32(reader, "IDSPVDMC"), IdFrpd = GetInt32(reader, "IDFRPD"), IdSpmpob = GetNullableInt32(reader, "IDSPMPOB"), IdPrsn = GetNullableInt32(reader, "IDPRSN"), IdSpkmmk = GetNullableInt32(reader, "IDSPKMMK"), IdSpvdkl = GetNullableInt32(reader, "IDSPVDKL"), IdPrsnvd = GetNullableInt32(reader, "IDPRSNVD"), Prmk = GetInt32(reader, "PRMK"), Stmk = GetNullableDecimal(reader, "STMK"), Stmkdp = GetNullableDecimal(reader, "STMKDP"), NcSrmk = GetNullableDecimal(reader, "NCSRMK"), IdPrsnsd = GetNullableInt32(reader, "idprsnsd"), IdPrsnpr = GetNullableInt32(reader, "idprsnpr"), IdPrsnvy = GetNullableInt32(reader, "idprsnvy"), IdSptsmp = GetNullableInt32(reader, "idsptsmp"), IdSpssmp = GetNullableInt32(reader, "idspssmp"), Nrvrmndmp = GetNullableDecimal(reader, "NRVRMNDmp"), Nrvrmmp = GetNullableDecimal(reader, "NRVRMmp"), Vrmkfk = GetNullableDecimal(reader, "VRMKFK"), IdKsp = GetNullableInt32(reader, "IDKSP"), Dpznmp = GetString(reader, "DPZNmp"), Hrtcmp = GetString(reader, "HRTCmp"), IdSpvdsbmk = GetNullableInt32(reader, "IDSPVDSBMK"), IdEkzetl = GetNullableInt32(reader, "IDEKZETL"), SourceDescription = GetString(reader, "SourceDescription") }; } } } return LoadFallbackTemplate(connection, transaction, instrumentId); } private static EkzMkTemplate LoadFallbackTemplate(SqlConnection connection, SqlTransaction transaction, int instrumentId) { const string sql = @" WITH DefaultLab AS ( SELECT CASE WHEN COUNT(DISTINCT m.IDFRPD) = 1 THEN MIN(m.IDFRPD) ELSE NULL END AS DefaultIdFrpd FROM dbo.EKZMK m ) SELECT TOP (1) COALESCE(periodByInstrument.IDGRSI, periodByType.IDGRSI) AS IDGRSI, COALESCE(periodByInstrument.IDSPVDMC, periodByType.IDSPVDMC) AS IDSPVDMC, defaultLab.DefaultIdFrpd AS IDFRPD, tprz.IDSPKMMK, COALESCE(periodByInstrument.PRMK, periodByType.PRMK, tips.PRMKGR) AS PRMK, tprz.DPZN AS DPZNmp, tprz.HRTC AS HRTCmp, CAST( CASE WHEN COALESCE(periodByInstrument.PRMK, periodByType.PRMK) IS NOT NULL THEN N'Период РёР· TPRMCP' WHEN tips.PRMKGR IS NOT NULL THEN N'Регистрационный период РёР· TIPS' ELSE N'' END AS nvarchar(60)) AS SourceDescription FROM dbo.EKZ z JOIN dbo.TPRZ tprz ON tprz.IDTPRZ = z.IDTPRZ JOIN dbo.TIPS tips ON tips.IDTIPS = tprz.IDTIPS CROSS JOIN DefaultLab defaultLab OUTER APPLY ( SELECT TOP (1) t.IDGRSI, t.IDSPVDMC, t.PRMK FROM dbo.EKZMCP e JOIN dbo.TPRMCP t ON t.IDTPRMCP = e.IDTPRMCP WHERE e.IDEKZ = z.IDEKZ ORDER BY e.IDEKZMCP DESC, t.IDTPRMCP DESC ) periodByInstrument OUTER APPLY ( SELECT TOP (1) t.IDGRSI, t.IDSPVDMC, t.PRMK FROM dbo.TPRMCP t WHERE t.IDTPRZ = z.IDTPRZ ORDER BY t.IDTPRMCP DESC ) periodByType WHERE z.IDEKZ = @InstrumentId AND defaultLab.DefaultIdFrpd IS NOT NULL AND COALESCE(periodByInstrument.PRMK, periodByType.PRMK, tips.PRMKGR) IS NOT NULL;"; using (var command = new SqlCommand(sql, connection, transaction)) { command.Parameters.Add("@InstrumentId", SqlDbType.Int).Value = instrumentId; using (var reader = command.ExecuteReader()) { if (!reader.Read()) { return null; } return new EkzMkTemplate { IdSpmu = null, IdGrsi = GetNullableInt32(reader, "IDGRSI"), IdKsprl = null, IdSpvdmc = GetNullableInt32(reader, "IDSPVDMC"), IdFrpd = GetInt32(reader, "IDFRPD"), IdSpmpob = null, IdPrsn = null, IdSpkmmk = GetNullableInt32(reader, "IDSPKMMK"), IdSpvdkl = null, IdPrsnvd = null, Prmk = GetInt32(reader, "PRMK"), Stmk = null, Stmkdp = null, NcSrmk = null, IdPrsnsd = null, IdPrsnpr = null, IdPrsnvy = null, IdSptsmp = null, IdSpssmp = null, Nrvrmndmp = null, Nrvrmmp = null, Vrmkfk = null, IdKsp = null, Dpznmp = GetString(reader, "DPZNmp"), Hrtcmp = GetString(reader, "HRTCmp"), IdSpvdsbmk = null, IdEkzetl = null, SourceDescription = GetString(reader, "SourceDescription") }; } } } private static string NormalizeDocumentNumber(string value) { if (string.IsNullOrWhiteSpace(value)) { return null; } return value.Trim(); } private static void ConfigureCommandTimeout(SqlCommand command) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; } private static SpoiDirectoryItem NormalizeSpoiItem(SpoiDirectoryItem item) { if (item == null) { throw new ArgumentNullException("item"); } var code = NormalizeRequiredSpoiValue( item.Code, "РљРѕРґ ОИ РЅРµ заполнен.", SpoiDirectoryRules.CodeMaxLength, "РљРѕРґ ОИ превышает допустимую длину."); var name = NormalizeRequiredSpoiValue( item.Name, "Область измерений РЅРµ заполнена.", SpoiDirectoryRules.NameMaxLength, "Область измерений превышает допустимую длину."); return new SpoiDirectoryItem { Id = item.Id, Code = code, Name = name }; } private static void EnsureSpoiCodeIsUnique(SqlConnection connection, string code, int? excludeId) { const string sql = @" SELECT TOP (1) IDSPOI FROM dbo.SPOI WHERE KDOI = @Code AND (@ExcludeId IS NULL OR IDSPOI <> @ExcludeId);"; using (var command = new SqlCommand(sql, connection)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@Code", SqlDbType.VarChar, SpoiDirectoryRules.CodeMaxLength).Value = code; command.Parameters.Add("@ExcludeId", SqlDbType.Int).Value = (object)excludeId ?? DBNull.Value; var existingId = command.ExecuteScalar(); if (existingId != null && existingId != DBNull.Value) { throw CreateSpoiDuplicateCodeException(code, null); } } } private static void EnsureSpoiNameIsUnique(SqlConnection connection, string name, int? excludeId) { const string sql = @" SELECT TOP (1) IDSPOI FROM dbo.SPOI WHERE NMOI = @Name AND (@ExcludeId IS NULL OR IDSPOI <> @ExcludeId);"; using (var command = new SqlCommand(sql, connection)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@Name", SqlDbType.VarChar, SpoiDirectoryRules.NameMaxLength).Value = name; command.Parameters.Add("@ExcludeId", SqlDbType.Int).Value = (object)excludeId ?? DBNull.Value; var existingId = command.ExecuteScalar(); if (existingId != null && existingId != DBNull.Value) { throw CreateSpoiDuplicateNameException(name, null); } } } private static InvalidOperationException CreateSpoiDuplicateCodeException(string code, Exception innerException) { return new InvalidOperationException( string.Format("РљРѕРґ ОИ \"{0}\" СѓР¶Рµ существует РІ справочнике.", code), innerException); } private static InvalidOperationException CreateSpoiDuplicateNameException(string name, Exception innerException) { return new InvalidOperationException( string.Format("Область измерений \"{0}\" СѓР¶Рµ существует РІ справочнике.", name), innerException); } private static List LoadSpoiDeleteBlockers(SqlConnection connection, int id) { const string sql = @" SELECT blocker.TableName, blocker.LinkCount FROM ( SELECT N'FRATGR' AS TableName, COUNT(*) AS LinkCount FROM dbo.FRATGR WHERE IDSPOI = @Id UNION ALL SELECT N'PRATGR', COUNT(*) FROM dbo.PRATGR WHERE IDSPOI = @Id UNION ALL SELECT N'PRSTOI', COUNT(*) FROM dbo.PRSTOI WHERE IDSPOI = @Id UNION ALL SELECT N'TIPS', COUNT(*) FROM dbo.TIPS WHERE IDSPOI = @Id ) blocker WHERE blocker.LinkCount > 0 ORDER BY blocker.TableName;"; var blockers = new List(); using (var command = new SqlCommand(sql, connection)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@Id", SqlDbType.Int).Value = id; using (var reader = command.ExecuteReader()) { while (reader.Read()) { blockers.Add(new DeleteBlockerInfo { TableName = GetString(reader, "TableName"), RowCount = GetInt32(reader, "LinkCount") }); } } } return blockers; } private static string CreateSpoiDeleteBlockedMessage(IEnumerable blockers) { var blockerList = blockers == null ? new List() : blockers.Where(delegate(DeleteBlockerInfo blocker) { return blocker != null; }).ToList(); var details = blockerList.Count == 0 ? "FRATGR, PRATGR, PRSTOI, TIPS" : string.Join(", ", blockerList.Select(delegate(DeleteBlockerInfo blocker) { return string.Format("{0}: {1}", blocker.TableName, blocker.RowCount); })); return string.Format( "Запись SPOI РЅРµ может быть удалена, потому что РЅР° неё есть ссылки РІ таблицах: {0}. Подтверждённые ограничения БД: FK_FRATGR_SPOI, FK_PRATGR_SPOI, FK_PRSTOI_SPOI, FK_TIPS_SPOI.", details); } private static string CreateSpoiDeleteBlockedMessage(SqlException ex) { if (ex != null && ex.Message.IndexOf("FK_FRATGR_SPOI", StringComparison.OrdinalIgnoreCase) >= 0) { return "Запись SPOI РЅРµ может быть удалена, потому что РЅР° неё есть ссылки РІ таблице FRATGR. Ограничение БД: FK_FRATGR_SPOI (dbo.FRATGR.IDSPOI -> dbo.SPOI.IDSPOI)."; } if (ex != null && ex.Message.IndexOf("FK_PRATGR_SPOI", StringComparison.OrdinalIgnoreCase) >= 0) { return "Запись SPOI РЅРµ может быть удалена, потому что РЅР° неё есть ссылки РІ таблице PRATGR. Ограничение БД: FK_PRATGR_SPOI (dbo.PRATGR.IDSPOI -> dbo.SPOI.IDSPOI)."; } if (ex != null && ex.Message.IndexOf("FK_PRSTOI_SPOI", StringComparison.OrdinalIgnoreCase) >= 0) { return "Запись SPOI РЅРµ может быть удалена, потому что РЅР° неё есть ссылки РІ таблице PRSTOI. Ограничение БД: FK_PRSTOI_SPOI (dbo.PRSTOI.IDSPOI -> dbo.SPOI.IDSPOI)."; } if (ex != null && ex.Message.IndexOf("FK_TIPS_SPOI", StringComparison.OrdinalIgnoreCase) >= 0) { return "Запись SPOI РЅРµ может быть удалена, потому что РЅР° неё есть ссылки РІ таблице TIPS. Ограничение БД: FK_TIPS_SPOI (dbo.TIPS.IDSPOI -> dbo.SPOI.IDSPOI)."; } return "Запись SPOI РЅРµ может быть удалена РёР·-Р·Р° ограничения ссылочной целостности РІ БД."; } private static bool IsSpoiDuplicateCodeViolation(SqlException ex) { return ex != null && (ex.Number == 2601 || ex.Number == 2627) && ex.Message.IndexOf("XAK2SPOI", StringComparison.OrdinalIgnoreCase) >= 0; } private static bool IsSpoiDuplicateNameViolation(SqlException ex) { return ex != null && (ex.Number == 2601 || ex.Number == 2627) && ex.Message.IndexOf("XAK1SPOI", StringComparison.OrdinalIgnoreCase) >= 0; } private static string NormalizeRequiredSpoiValue(string value, string emptyErrorMessage, int maxLength, string tooLongErrorMessage) { if (string.IsNullOrWhiteSpace(value)) { throw new InvalidOperationException(emptyErrorMessage); } var normalizedValue = value.Trim(); if (normalizedValue.Length > maxLength) { throw new InvalidOperationException(tooLongErrorMessage); } return normalizedValue; } private static SpnmtpDirectoryItem NormalizeSpnmtpItem(SpnmtpDirectoryItem item) { if (item == null) { throw new ArgumentNullException("item"); } var name = NormalizeRequiredSpnmtpValue( item.Name, "Наименование типа СИ РЅРµ заполнено.", SpnmtpDirectoryRules.NameMaxLength, "Наименование типа СИ превышает допустимую длину."); var specialName = NormalizeOptionalSpnmtpValue( item.SpecialName, SpnmtpDirectoryRules.SpecialNameMaxLength, "Специальное наименование типа превышает допустимую длину."); return new SpnmtpDirectoryItem { Id = item.Id, Name = name, SpecialName = specialName }; } private static void EnsureSpnmtpNameIsUnique(SqlConnection connection, string name, int? excludeId) { const string sql = @" SELECT TOP (1) IDSPNMTP FROM dbo.SPNMTP WHERE NMTP = @Name AND (@ExcludeId IS NULL OR IDSPNMTP <> @ExcludeId);"; using (var command = new SqlCommand(sql, connection)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@Name", SqlDbType.NVarChar, SpnmtpDirectoryRules.NameMaxLength).Value = name; command.Parameters.Add("@ExcludeId", SqlDbType.Int).Value = (object)excludeId ?? DBNull.Value; var existingId = command.ExecuteScalar(); if (existingId != null && existingId != DBNull.Value) { throw CreateSpnmtpDuplicateNameException(name, null); } } } private static InvalidOperationException CreateSpnmtpDuplicateNameException(string name, Exception innerException) { return new InvalidOperationException( string.Format("Наименование типа СИ \"{0}\" СѓР¶Рµ существует РІ справочнике.", name), innerException); } private static List LoadSpnmtpDeleteBlockers(SqlConnection connection, int id) { const string sql = @" SELECT blocker.TableName, blocker.LinkCount FROM ( SELECT N'TIPS' AS TableName, COUNT(*) AS LinkCount FROM dbo.TIPS WHERE IDSPNMTP = @Id ) blocker WHERE blocker.LinkCount > 0 ORDER BY blocker.TableName;"; var blockers = new List(); using (var command = new SqlCommand(sql, connection)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@Id", SqlDbType.Int).Value = id; using (var reader = command.ExecuteReader()) { while (reader.Read()) { blockers.Add(new DeleteBlockerInfo { TableName = GetString(reader, "TableName"), RowCount = GetInt32(reader, "LinkCount") }); } } } return blockers; } private static string CreateSpnmtpDeleteBlockedMessage(IEnumerable blockers) { var blockerList = blockers == null ? new List() : blockers.Where(delegate(DeleteBlockerInfo blocker) { return blocker != null; }).ToList(); var details = blockerList.Count == 0 ? "TIPS" : string.Join(", ", blockerList.Select(delegate(DeleteBlockerInfo blocker) { return string.Format("{0}: {1}", blocker.TableName, blocker.RowCount); })); return string.Format( "Запись SPNMTP РЅРµ может быть удалена, потому что РЅР° неё есть ссылки РІ таблицах: {0}. Подтверждённое ограничение БД: FK_TIPS_SPNMTP (dbo.TIPS.IDSPNMTP -> dbo.SPNMTP.IDSPNMTP).", details); } private static string CreateSpnmtpDeleteBlockedMessage(SqlException ex) { if (ex != null && ex.Message.IndexOf("FK_TIPS_SPNMTP", StringComparison.OrdinalIgnoreCase) >= 0) { return "Запись SPNMTP РЅРµ может быть удалена, потому что РЅР° неё есть ссылки РІ таблице TIPS. Ограничение БД: FK_TIPS_SPNMTP (dbo.TIPS.IDSPNMTP -> dbo.SPNMTP.IDSPNMTP)."; } return "Запись SPNMTP РЅРµ может быть удалена РёР·-Р·Р° ограничения ссылочной целостности РІ БД."; } private static bool IsSpnmtpDuplicateNameViolation(SqlException ex) { return ex != null && (ex.Number == 2601 || ex.Number == 2627) && ex.Message.IndexOf("XAK1SPNMTP", StringComparison.OrdinalIgnoreCase) >= 0; } private static string NormalizeRequiredSpnmtpValue(string value, string emptyErrorMessage, int maxLength, string tooLongErrorMessage) { if (string.IsNullOrWhiteSpace(value)) { throw new InvalidOperationException(emptyErrorMessage); } var normalizedValue = value.Trim(); if (normalizedValue.Length > maxLength) { throw new InvalidOperationException(tooLongErrorMessage); } return normalizedValue; } private static string NormalizeOptionalSpnmtpValue(string value, int maxLength, string tooLongErrorMessage) { if (string.IsNullOrWhiteSpace(value)) { return null; } var normalizedValue = value.Trim(); if (normalizedValue.Length > maxLength) { throw new InvalidOperationException(tooLongErrorMessage); } return normalizedValue; } private static int UpdateDocumentHeader(SqlConnection connection, SqlTransaction transaction, string currentDocumentNumber, DocumentEditorResult document) { const string sql = @" UPDATE dbo.EKZMK SET NNZVPV = @NewDocumentNumber, DTPRM = @AcceptedOn, DTVDM = @IssuedOn WHERE NNZVPV = @CurrentDocumentNumber; SELECT @@ROWCOUNT;"; using (var command = new SqlCommand(sql, connection, transaction)) { command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds; command.Parameters.Add("@NewDocumentNumber", SqlDbType.NVarChar, 60).Value = document.DocumentNumber; command.Parameters.Add("@AcceptedOn", SqlDbType.DateTime).Value = document.AcceptedOn; command.Parameters.Add("@IssuedOn", SqlDbType.DateTime).Value = (object)document.IssuedOn ?? DBNull.Value; command.Parameters.Add("@CurrentDocumentNumber", SqlDbType.NVarChar, 60).Value = currentDocumentNumber; return Convert.ToInt32(command.ExecuteScalar()); } } private sealed class DeleteBlockerInfo { public int RowCount { get; set; } public string TableName { get; set; } } private sealed class InstrumentIdentityInfo { public string DuplicateKey { get; set; } } } }