Files
XLAB/XLAB2/PsvDataService.cs
Курнат Андрей d46172beb9 edit
2026-03-24 22:31:05 +03:00

4450 lines
189 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
{
private const int EkzMkCompletenessMaxLength = 600;
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<bool> 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<CustomerReference> 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<CustomerReference>();
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<IReadOnlyList<CustomerReference>> 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<IReadOnlyList<CustomerReference>>(delegate(Task<List<CustomerReference>> task)
{
return task.Result;
}, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
public IReadOnlyList<PersonReference> 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<PersonReference>();
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<IReadOnlyList<PersonReference>> 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<IReadOnlyList<PersonReference>>(delegate(Task<List<PersonReference>> task)
{
return task.Result;
}, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
public IReadOnlyList<DocumentFormReference> 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<DocumentFormReference>();
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<IReadOnlyList<DocumentFormReference>> 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<IReadOnlyList<DocumentFormReference>>(delegate(Task<List<DocumentFormReference>> task)
{
return task.Result;
}, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
public IReadOnlyList<SpoiDirectoryItem> 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<SpoiDirectoryItem>();
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<IReadOnlyList<SpoiDirectoryItem>> 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<IReadOnlyList<SpoiDirectoryItem>>(delegate(Task<List<SpoiDirectoryItem>> 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<SpnmtpDirectoryItem> 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<SpnmtpDirectoryItem>();
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<IReadOnlyList<SpnmtpDirectoryItem>> 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<IReadOnlyList<SpnmtpDirectoryItem>>(delegate(Task<List<SpnmtpDirectoryItem>> 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<PsvDocumentSummary> 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<PsvDocumentSummary>();
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
});
}
}
var serialNumbersByDocument = LoadDocumentSerialNumbers(connection, loadClosedDocumentsForCurrentYear, currentYearStart, nextYearStart);
foreach (var document in documents)
{
if (serialNumbersByDocument.TryGetValue(document.DocumentNumber, out var serialNumbersText))
{
document.SerialNumbersText = serialNumbersText;
}
}
}
return documents;
}
public async Task<IReadOnlyList<PsvDocumentSummary>> 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);
var documents = new List<PsvDocumentSummary>();
await using (var connection = await SqlServerConnectionFactory.Current.OpenConnectionAsync(cancellationToken).ConfigureAwait(false))
using (var command = new SqlCommand(sql, connection))
{
ConfigureCommandTimeout(command);
if (loadClosedDocumentsForCurrentYear)
{
command.Parameters.Add("@IssuedFrom", SqlDbType.DateTime).Value = currentYearStart;
command.Parameters.Add("@IssuedTo", SqlDbType.DateTime).Value = nextYearStart;
}
using (var reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false))
{
while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
{
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
});
}
}
var serialNumbersByDocument = await LoadDocumentSerialNumbersAsync(connection, loadClosedDocumentsForCurrentYear, currentYearStart, nextYearStart, cancellationToken).ConfigureAwait(false);
foreach (var document in documents)
{
if (serialNumbersByDocument.TryGetValue(document.DocumentNumber, out var serialNumbersText))
{
document.SerialNumbersText = serialNumbersText;
}
}
}
return documents;
}
private Dictionary<string, string> LoadDocumentSerialNumbers(SqlConnection connection, bool loadClosedDocumentsForCurrentYear, DateTime currentYearStart, DateTime nextYearStart)
{
var sql = @"
WITH filteredDocuments AS
(
SELECT m.NNZVPV
FROM dbo.EKZMK m
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") + @"
)
SELECT
m.NNZVPV AS DocumentNumber,
z.NNZV AS SerialNumber
FROM dbo.EKZMK m
JOIN filteredDocuments documents ON documents.NNZVPV = m.NNZVPV
JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ
WHERE NULLIF(LTRIM(RTRIM(z.NNZV)), N'') IS NOT NULL
ORDER BY m.NNZVPV, z.NNZV;";
var serialNumbersByDocument = new Dictionary<string, SortedSet<string>>(StringComparer.OrdinalIgnoreCase);
using (var command = new SqlCommand(sql, connection))
{
ConfigureCommandTimeout(command);
if (loadClosedDocumentsForCurrentYear)
{
command.Parameters.Add("@IssuedFrom", SqlDbType.DateTime).Value = currentYearStart;
command.Parameters.Add("@IssuedTo", SqlDbType.DateTime).Value = nextYearStart;
}
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
var documentNumber = GetString(reader, "DocumentNumber");
var serialNumber = GetString(reader, "SerialNumber");
if (string.IsNullOrWhiteSpace(documentNumber) || string.IsNullOrWhiteSpace(serialNumber))
{
continue;
}
if (!serialNumbersByDocument.TryGetValue(documentNumber, out var serialNumbers))
{
serialNumbers = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
serialNumbersByDocument[documentNumber] = serialNumbers;
}
serialNumbers.Add(serialNumber.Trim());
}
}
}
return serialNumbersByDocument.ToDictionary(pair => pair.Key, pair => string.Join(", ", pair.Value), StringComparer.OrdinalIgnoreCase);
}
private async Task<Dictionary<string, string>> LoadDocumentSerialNumbersAsync(SqlConnection connection, bool loadClosedDocumentsForCurrentYear, DateTime currentYearStart, DateTime nextYearStart, CancellationToken cancellationToken)
{
var sql = @"
WITH filteredDocuments AS
(
SELECT m.NNZVPV
FROM dbo.EKZMK m
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") + @"
)
SELECT
m.NNZVPV AS DocumentNumber,
z.NNZV AS SerialNumber
FROM dbo.EKZMK m
JOIN filteredDocuments documents ON documents.NNZVPV = m.NNZVPV
JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ
WHERE NULLIF(LTRIM(RTRIM(z.NNZV)), N'') IS NOT NULL
ORDER BY m.NNZVPV, z.NNZV;";
var serialNumbersByDocument = new Dictionary<string, SortedSet<string>>(StringComparer.OrdinalIgnoreCase);
using (var command = new SqlCommand(sql, connection))
{
ConfigureCommandTimeout(command);
if (loadClosedDocumentsForCurrentYear)
{
command.Parameters.Add("@IssuedFrom", SqlDbType.DateTime).Value = currentYearStart;
command.Parameters.Add("@IssuedTo", SqlDbType.DateTime).Value = nextYearStart;
}
using (var reader = await command.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false))
{
while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
{
var documentNumber = GetString(reader, "DocumentNumber");
var serialNumber = GetString(reader, "SerialNumber");
if (string.IsNullOrWhiteSpace(documentNumber) || string.IsNullOrWhiteSpace(serialNumber))
{
continue;
}
if (!serialNumbersByDocument.TryGetValue(documentNumber, out var serialNumbers))
{
serialNumbers = new SortedSet<string>(StringComparer.OrdinalIgnoreCase);
serialNumbersByDocument[documentNumber] = serialNumbers;
}
serialNumbers.Add(serialNumber.Trim());
}
}
}
return serialNumbersByDocument.ToDictionary(pair => pair.Key, pair => string.Join(", ", pair.Value), StringComparer.OrdinalIgnoreCase);
}
public IReadOnlyList<PsvDocumentLine> 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<PsvDocumentLine>();
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<IReadOnlyList<PsvDocumentLine>> 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<AvailableInstrumentItem> 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<AvailableInstrumentItem>();
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<IReadOnlyList<AvailableInstrumentItem>> 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<IReadOnlyList<AvailableInstrumentItem>>(delegate(Task<List<AvailableInstrumentItem>> task)
{
return task.Result;
}, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
public IReadOnlyList<AvailableInstrumentItem> 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<AvailableInstrumentItem>();
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<IReadOnlyList<AvailableInstrumentItem>> 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<IReadOnlyList<AvailableInstrumentItem>>(delegate(Task<List<AvailableInstrumentItem>> task)
{
return task.Result;
}, cancellationToken, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
public IReadOnlyList<OpenDocumentConflictInfo> FindOpenDocumentConflicts(int customerId, string currentDocumentNumber, IEnumerable<PsvDocumentLine> candidateLines)
{
if (customerId <= 0 || candidateLines == null)
{
return new List<OpenDocumentConflictInfo>();
}
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<int> 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<int> 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<int> 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<int> 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<PsvDocumentLine> documentLines)
{
if (document == null)
{
throw new ArgumentNullException("document");
}
var normalizedNumber = NormalizeDocumentNumber(document.DocumentNumber);
if (normalizedNumber == null)
{
throw new InvalidOperationException("Номер ПСВ не заполнен.");
}
document.DocumentNumber = normalizedNumber;
var materializedDocumentLines = documentLines == null
? new List<PsvDocumentLine>()
: documentLines
.Where(delegate(PsvDocumentLine line) { return line != null; })
.ToList();
var distinctPendingLines = materializedDocumentLines
.Where(IsPendingLineReadyForSave)
.GroupBy(GetPendingLineSaveKey, StringComparer.OrdinalIgnoreCase)
.Select(delegate(IGrouping<string, PsvDocumentLine> group) { return group.First(); })
.ToList();
var persistedLines = materializedDocumentLines
.Where(delegate(PsvDocumentLine line) { return !line.IsPendingInsert && line.CardId > 0; })
.GroupBy(delegate(PsvDocumentLine line) { return line.CardId; })
.Select(delegate(IGrouping<int, PsvDocumentLine> 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 updatedCompletenessCount = UpdateDocumentLineCompleteness(connection, transaction, normalizedNumber, persistedLines);
if (updatedCompletenessCount > updatedEkzMkCount)
{
updatedEkzMkCount = updatedCompletenessCount;
}
}
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;
}
var effectiveVerificationTypeId = template.IdSpvdmk;
if (!effectiveVerificationTypeId.HasValue || effectiveVerificationTypeId.Value <= 0)
{
if (!verificationTypeLoaded)
{
verificationTypeId = LoadVerificationTypeId(connection, transaction);
verificationTypeLoaded = true;
}
effectiveVerificationTypeId = verificationTypeId;
}
var cardId = InsertEkzMk(connection, transaction, effectiveVerificationTypeId.Value, 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<DocumentDeleteResult> 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<int> 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<DocumentGroupDeleteResult> DeleteDocumentGroupsAsync(string documentNumber, IEnumerable<int> 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.IsPendingInsert
&& (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 (serialNumber.Length > EkzDirectoryRules.SerialNumberMaxLength)
{
throw new InvalidOperationException(string.Format("Заводской номер не должен превышать {0} символов.", EkzDirectoryRules.SerialNumberMaxLength));
}
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<int> NormalizeCardIds(IEnumerable<int> 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 LTRIM(RTRIM(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.NVarChar, EkzDirectoryRules.SerialNumberMaxLength).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.NVarChar, EkzDirectoryRules.SerialNumberMaxLength).Value = serialNumber;
command.Parameters.Add("@GuidEkz", SqlDbType.UniqueIdentifier).Value = Guid.NewGuid();
return Convert.ToInt32(command.ExecuteScalar());
}
}
private static string BuildOpenDocumentConflictMessage(IEnumerable<OpenDocumentConflictInfo> conflicts)
{
var materializedConflicts = conflicts == null
? new List<OpenDocumentConflictInfo>()
: 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<string, OpenDocumentConflictInfo> 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<OpenDocumentConflictInfo> LoadOpenDocumentConflicts(
SqlConnection connection,
SqlTransaction transaction,
int customerId,
string currentDocumentNumber,
IEnumerable<PsvDocumentLine> candidateLines)
{
var normalizedCandidates = candidateLines == null
? new List<PsvDocumentLine>()
: 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<string, PsvDocumentLine> group) { return group.First(); })
.ToList();
if (customerId <= 0 || normalizedCandidates.Count == 0)
{
return new List<OpenDocumentConflictInfo>();
}
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<OpenDocumentConflictInfo>();
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.NVarChar, EkzDirectoryRules.SerialNumberMaxLength).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<string, OpenDocumentConflictInfo> 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<List<OpenDocumentConflictInfo>> LoadOpenDocumentConflictsAsync(
SqlConnection connection,
SqlTransaction transaction,
int customerId,
string currentDocumentNumber,
IEnumerable<PsvDocumentLine> candidateLines,
CancellationToken cancellationToken = default)
{
var normalizedCandidates = candidateLines == null
? new List<PsvDocumentLine>()
: 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<string, PsvDocumentLine> group) { return group.First(); })
.ToList();
if (customerId <= 0 || normalizedCandidates.Count == 0)
{
return new List<OpenDocumentConflictInfo>();
}
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<OpenDocumentConflictInfo>();
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.NVarChar, EkzDirectoryRules.SerialNumberMaxLength).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<string, OpenDocumentConflictInfo> 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<int>(
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<int>(
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<int> 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<int>(
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<int> 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<int>(
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<int> 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<int>(
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<int> 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<int>(
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<int> 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<int>(
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<int> 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<int>(
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<bool> 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<int>(
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,
@DSEKZMK,
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("@DSEKZMK", SqlDbType.NVarChar, EkzMkCompletenessMaxLength).Value = pendingLine == null
? DBNull.Value
: (object)NormalizeOptionalCompleteness(pendingLine.Notes) ?? DBNull.Value;
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<string> 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<string>(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<DeleteBlockerInfo> LoadDeleteBlockers(SqlConnection connection, SqlTransaction transaction, IEnumerable<int> cardIds)
{
var aggregated = new Dictionary<string, int>(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<string, int> blocker) { return blocker.Key; })
.Select(delegate(KeyValuePair<string, int> blocker)
{
return new DeleteBlockerInfo
{
TableName = blocker.Key,
RowCount = blocker.Value
};
})
.ToList();
}
private static List<DeleteBlockerInfo> 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<DeleteBlockerInfo>();
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<DeleteBlockerInfo> 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<DeleteBlockerInfo>();
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<List<DeleteBlockerInfo>> LoadDeleteBlockersAsync(SqlConnection connection, SqlTransaction transaction, IEnumerable<int> cardIds, CancellationToken cancellationToken = default)
{
var aggregated = new Dictionary<string, int>(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<string, int> blocker) { return blocker.Key; })
.Select(delegate(KeyValuePair<string, int> blocker)
{
return new DeleteBlockerInfo
{
TableName = blocker.Key,
RowCount = blocker.Value
};
})
.ToList();
}
private static Task<List<DeleteBlockerInfo>> 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<List<DeleteBlockerInfo>> 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 UPPER(LTRIM(RTRIM(ISNULL(OBVDMK, N'')))) = N'П'
OR UPPER(LTRIM(RTRIM(ISNULL(NMVDMK, N'')))) = N'ПОВЕРКА'
OR UPPER(LTRIM(RTRIM(ISNULL(NMVDMK, N'')))) LIKE N'ПОВЕРК%'
OR UPPER(LTRIM(RTRIM(ISNULL(NMVDMK, N'')))) LIKE N'%ПОВЕРК%'
ORDER BY CASE
WHEN UPPER(LTRIM(RTRIM(ISNULL(OBVDMK, N'')))) = N'П' THEN 0
WHEN UPPER(LTRIM(RTRIM(ISNULL(NMVDMK, N'')))) = N'ПОВЕРКА' THEN 1
WHEN UPPER(LTRIM(RTRIM(ISNULL(NMVDMK, N'')))) LIKE N'ПОВЕРК%' THEN 2
ELSE 3
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.IDSPVDMK,
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.IDSPVDMK,
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"),
IdSpvdmk = GetNullableInt32(reader, "IDSPVDMK"),
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,
IdSpvdmk = 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<DeleteBlockerInfo> 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<DeleteBlockerInfo>();
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<DeleteBlockerInfo> blockers)
{
var blockerList = blockers == null
? new List<DeleteBlockerInfo>()
: 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<DeleteBlockerInfo> 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<DeleteBlockerInfo>();
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<DeleteBlockerInfo> blockers)
{
var blockerList = blockers == null
? new List<DeleteBlockerInfo>()
: 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 UpdateDocumentLineCompleteness(
SqlConnection connection,
SqlTransaction transaction,
string documentNumber,
IEnumerable<PsvDocumentLine> persistedLines)
{
var materializedLines = persistedLines == null
? new List<PsvDocumentLine>()
: persistedLines
.Where(delegate(PsvDocumentLine line) { return line != null && line.CardId > 0; })
.GroupBy(delegate(PsvDocumentLine line) { return line.CardId; })
.Select(delegate(IGrouping<int, PsvDocumentLine> group) { return group.First(); })
.ToList();
var updatedCount = 0;
foreach (var line in materializedLines)
{
updatedCount += UpdateDocumentLineCompletenessCore(
connection,
transaction,
documentNumber,
line.CardId,
NormalizeOptionalCompleteness(line.Notes));
}
return updatedCount;
}
private static int UpdateDocumentLineCompletenessCore(
SqlConnection connection,
SqlTransaction transaction,
string documentNumber,
int cardId,
string completeness)
{
const string sql = @"
UPDATE dbo.EKZMK
SET DSEKZMK = @Completeness
WHERE NNZVPV = @DocumentNumber
AND IDEKZMK = @CardId;
SELECT @@ROWCOUNT;";
using (var command = new SqlCommand(sql, connection, transaction))
{
command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds;
command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber;
command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId;
command.Parameters.Add("@Completeness", SqlDbType.NVarChar, EkzMkCompletenessMaxLength).Value = (object)completeness ?? DBNull.Value;
return Convert.ToInt32(command.ExecuteScalar());
}
}
private static string NormalizeOptionalCompleteness(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return null;
}
var normalizedValue = value.Trim();
if (normalizedValue.Length > EkzMkCompletenessMaxLength)
{
throw new InvalidOperationException(string.Format("Комплектность не должна превышать {0} символов.", EkzMkCompletenessMaxLength));
}
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; }
}
}
}