From 13e451acf5c6429309d599454f61f8aa2f690862 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D1=83=D1=80=D0=BD=D0=B0=D1=82=20=D0=90=D0=BD=D0=B4?= =?UTF-8?q?=D1=80=D0=B5=D0=B9?= Date: Sat, 14 Mar 2026 14:31:52 +0300 Subject: [PATCH] edit --- XLAB/DialogService.cs | 12 ++ XLAB/MainWindow.xaml | 27 ++- XLAB/MainWindow.xaml.cs | 7 + XLAB/PsvDataService.cs | 240 ++++++++++++++++++++++ XLAB/PsvModels.cs | 16 ++ XLAB/SpnmtpDirectoryWindow.xaml | 86 ++++++++ XLAB/SpnmtpDirectoryWindow.xaml.cs | 21 ++ XLAB/SpnmtpDirectoryWindowViewModel.cs | 272 +++++++++++++++++++++++++ XLAB/SpnmtpEditWindow.xaml | 64 ++++++ XLAB/SpnmtpEditWindow.xaml.cs | 20 ++ XLAB/SpnmtpEditWindowViewModel.cs | 127 ++++++++++++ XLAB/XLAB.csproj | 18 ++ 12 files changed, 904 insertions(+), 6 deletions(-) create mode 100644 XLAB/SpnmtpDirectoryWindow.xaml create mode 100644 XLAB/SpnmtpDirectoryWindow.xaml.cs create mode 100644 XLAB/SpnmtpDirectoryWindowViewModel.cs create mode 100644 XLAB/SpnmtpEditWindow.xaml create mode 100644 XLAB/SpnmtpEditWindow.xaml.cs create mode 100644 XLAB/SpnmtpEditWindowViewModel.cs diff --git a/XLAB/DialogService.cs b/XLAB/DialogService.cs index 3c94889..58d7027 100644 --- a/XLAB/DialogService.cs +++ b/XLAB/DialogService.cs @@ -13,6 +13,8 @@ namespace XLAB IReadOnlyList ShowCloneVerificationDialog(CloneVerificationSeed seed); + SpnmtpDirectoryItem ShowSpnmtpEditDialog(SpnmtpDirectoryItem seed, bool isNew, IReadOnlyList existingItems); + VerificationEditResult ShowVerificationDialog( VerificationEditSeed seed, IReadOnlyList verifiers, @@ -76,6 +78,16 @@ namespace XLAB return result.HasValue && result.Value ? viewModel.GetSerialNumbers() : null; } + public SpnmtpDirectoryItem ShowSpnmtpEditDialog(SpnmtpDirectoryItem seed, bool isNew, IReadOnlyList existingItems) + { + var viewModel = new SpnmtpEditWindowViewModel(seed, isNew, existingItems); + var window = new SpnmtpEditWindow(viewModel); + window.Owner = _owner; + + var result = window.ShowDialog(); + return result.HasValue && result.Value ? viewModel.ToResult() : null; + } + public VerificationEditResult ShowVerificationDialog( VerificationEditSeed seed, IReadOnlyList verifiers, diff --git a/XLAB/MainWindow.xaml b/XLAB/MainWindow.xaml index b670fc7..b55d865 100644 --- a/XLAB/MainWindow.xaml +++ b/XLAB/MainWindow.xaml @@ -9,13 +9,27 @@ WindowState="Maximized" Loaded="Window_Loaded"> - - - - - + + + + - + + + + + + + + + + + + + + @@ -322,4 +336,5 @@ + diff --git a/XLAB/MainWindow.xaml.cs b/XLAB/MainWindow.xaml.cs index 20c7621..13c53af 100644 --- a/XLAB/MainWindow.xaml.cs +++ b/XLAB/MainWindow.xaml.cs @@ -45,6 +45,13 @@ namespace XLAB } } + private void SpnmtpDirectoryMenuItem_Click(object sender, RoutedEventArgs e) + { + var window = new SpnmtpDirectoryWindow(); + window.Owner = this; + window.ShowDialog(); + } + private async void Window_Loaded(object sender, RoutedEventArgs e) { await _viewModel.InitializeAsync(); diff --git a/XLAB/PsvDataService.cs b/XLAB/PsvDataService.cs index ae6bc6f..dd3b267 100644 --- a/XLAB/PsvDataService.cs +++ b/XLAB/PsvDataService.cs @@ -146,6 +146,153 @@ ORDER BY fr.NMFRD, v.IDVDODVDD;"; return forms; } + public IReadOnlyList LoadSpnmtpItems() + { + const string sql = @" +SELECT + s.IDSPNMTP AS Id, + s.NMTP AS Name, + s.NMTPSP AS SpecialName +FROM dbo.SPNMTP s +ORDER BY s.NMTP, s.IDSPNMTP;"; + + var items = new List(); + + using (var connection = CreateConnection()) + using (var command = new SqlCommand(sql, connection)) + { + connection.Open(); + command.CommandTimeout = 60; + + 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 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 = 60; + 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 = 60; + 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 void 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()) + using (var command = new SqlCommand(sql, connection)) + { + connection.Open(); + command.CommandTimeout = 60; + command.Parameters.Add("@Id", SqlDbType.Int).Value = id; + + if (Convert.ToInt32(command.ExecuteScalar()) == 0) + { + throw new InvalidOperationException("Запись SPNMTP для удаления не найдена."); + } + } + } + catch (SqlException ex) when (ex.Number == 547) + { + throw new InvalidOperationException("Запись справочника используется в связанных данных и не может быть удалена.", ex); + } + } + public IReadOnlyList LoadDocuments() { const string sql = @" @@ -2136,6 +2283,99 @@ WHERE z.IDEKZ = @InstrumentId return value.Trim(); } + 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 = 60; + 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 bool IsSpnmtpDuplicateNameViolation(SqlException ex) + { + return ex != null + && (ex.Number == 2601 || ex.Number == 2627) + && ex.Message.IndexOf("XAK1SPNMTP", StringComparison.OrdinalIgnoreCase) >= 0; + } + + private static string NormalizeRequiredSpnmtpValue(string value, string emptyErrorMessage, int maxLength, string tooLongErrorMessage) + { + if (string.IsNullOrWhiteSpace(value)) + { + throw new InvalidOperationException(emptyErrorMessage); + } + + var normalizedValue = value.Trim(); + if (normalizedValue.Length > maxLength) + { + throw new InvalidOperationException(tooLongErrorMessage); + } + + return normalizedValue; + } + + private static string NormalizeOptionalSpnmtpValue(string value, int maxLength, string tooLongErrorMessage) + { + if (string.IsNullOrWhiteSpace(value)) + { + return null; + } + + var normalizedValue = value.Trim(); + if (normalizedValue.Length > maxLength) + { + throw new InvalidOperationException(tooLongErrorMessage); + } + + return normalizedValue; + } + private static int UpdateDocumentHeader(SqlConnection connection, SqlTransaction transaction, string currentDocumentNumber, DocumentEditorResult document) { const string sql = @" diff --git a/XLAB/PsvModels.cs b/XLAB/PsvModels.cs index f25e804..4b44a72 100644 --- a/XLAB/PsvModels.cs +++ b/XLAB/PsvModels.cs @@ -344,6 +344,22 @@ namespace XLAB } } + public sealed class SpnmtpDirectoryItem + { + public int Id { get; set; } + + public string Name { get; set; } + + public string SpecialName { get; set; } + } + + internal static class SpnmtpDirectoryRules + { + public const int NameMaxLength = 150; + + public const int SpecialNameMaxLength = 150; + } + public sealed class DocumentFormReference { public int DocumentFormId { get; set; } diff --git a/XLAB/SpnmtpDirectoryWindow.xaml b/XLAB/SpnmtpDirectoryWindow.xaml new file mode 100644 index 0000000..c24b87b --- /dev/null +++ b/XLAB/SpnmtpDirectoryWindow.xaml @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + +