From 70b704b964f1f167b4c3486abba03275c3038218 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 22:27:20 +0300 Subject: [PATCH] edit --- XLAB/FrpdDirectoryDialogService.cs | 70 ++ XLAB/FrpdDirectoryModels.cs | 45 + XLAB/FrpdDirectoryService.cs | 556 +++++++++++ XLAB/FrpdDirectoryWindow.xaml | 119 +++ XLAB/FrpdDirectoryWindow.xaml.cs | 33 + XLAB/FrpdDirectoryWindowViewModel.cs | 476 +++++++++ XLAB/FrpdEditWindow.xaml | 57 ++ XLAB/FrpdEditWindow.xaml.cs | 20 + XLAB/FrpdEditWindowViewModel.cs | 168 ++++ XLAB/FrpdvdEditWindow.xaml | 32 + XLAB/FrpdvdEditWindow.xaml.cs | 20 + XLAB/FrpdvdEditWindowViewModel.cs | 103 ++ XLAB/MainWindow.xaml | 590 +++++------ XLAB/MainWindow.xaml.cs | 14 + XLAB/PrdspvEditWindow.xaml | 53 + XLAB/PrdspvEditWindow.xaml.cs | 20 + XLAB/PrdspvEditWindowViewModel.cs | 157 +++ XLAB/PrfrEditWindow.xaml | 91 ++ XLAB/PrfrEditWindow.xaml.cs | 20 + XLAB/PrfrEditWindowViewModel.cs | 243 +++++ XLAB/PrfrvdEditWindow.xaml | 32 + XLAB/PrfrvdEditWindow.xaml.cs | 20 + XLAB/PrfrvdEditWindowViewModel.cs | 103 ++ XLAB/PrsnDirectoryDialogService.cs | 94 ++ XLAB/PrsnDirectoryModels.cs | 147 +++ XLAB/PrsnDirectoryService.cs | 1345 ++++++++++++++++++++++++++ XLAB/PrsnDirectoryWindow.xaml | 199 ++++ XLAB/PrsnDirectoryWindow.xaml.cs | 33 + XLAB/PrsnDirectoryWindowViewModel.cs | 790 +++++++++++++++ XLAB/PrsnEditWindow.xaml | 69 ++ XLAB/PrsnEditWindow.xaml.cs | 20 + XLAB/PrsnEditWindowViewModel.cs | 237 +++++ XLAB/ReferenceDirectorySqlHelpers.cs | 237 +++++ XLAB/XLAB.csproj | 79 ++ 34 files changed, 5999 insertions(+), 293 deletions(-) create mode 100644 XLAB/FrpdDirectoryDialogService.cs create mode 100644 XLAB/FrpdDirectoryModels.cs create mode 100644 XLAB/FrpdDirectoryService.cs create mode 100644 XLAB/FrpdDirectoryWindow.xaml create mode 100644 XLAB/FrpdDirectoryWindow.xaml.cs create mode 100644 XLAB/FrpdDirectoryWindowViewModel.cs create mode 100644 XLAB/FrpdEditWindow.xaml create mode 100644 XLAB/FrpdEditWindow.xaml.cs create mode 100644 XLAB/FrpdEditWindowViewModel.cs create mode 100644 XLAB/FrpdvdEditWindow.xaml create mode 100644 XLAB/FrpdvdEditWindow.xaml.cs create mode 100644 XLAB/FrpdvdEditWindowViewModel.cs create mode 100644 XLAB/PrdspvEditWindow.xaml create mode 100644 XLAB/PrdspvEditWindow.xaml.cs create mode 100644 XLAB/PrdspvEditWindowViewModel.cs create mode 100644 XLAB/PrfrEditWindow.xaml create mode 100644 XLAB/PrfrEditWindow.xaml.cs create mode 100644 XLAB/PrfrEditWindowViewModel.cs create mode 100644 XLAB/PrfrvdEditWindow.xaml create mode 100644 XLAB/PrfrvdEditWindow.xaml.cs create mode 100644 XLAB/PrfrvdEditWindowViewModel.cs create mode 100644 XLAB/PrsnDirectoryDialogService.cs create mode 100644 XLAB/PrsnDirectoryModels.cs create mode 100644 XLAB/PrsnDirectoryService.cs create mode 100644 XLAB/PrsnDirectoryWindow.xaml create mode 100644 XLAB/PrsnDirectoryWindow.xaml.cs create mode 100644 XLAB/PrsnDirectoryWindowViewModel.cs create mode 100644 XLAB/PrsnEditWindow.xaml create mode 100644 XLAB/PrsnEditWindow.xaml.cs create mode 100644 XLAB/PrsnEditWindowViewModel.cs create mode 100644 XLAB/ReferenceDirectorySqlHelpers.cs diff --git a/XLAB/FrpdDirectoryDialogService.cs b/XLAB/FrpdDirectoryDialogService.cs new file mode 100644 index 0000000..b3b3d27 --- /dev/null +++ b/XLAB/FrpdDirectoryDialogService.cs @@ -0,0 +1,70 @@ +using System.Collections.Generic; +using System.Windows; + +namespace XLAB +{ + internal interface IFrpdDirectoryDialogService + { + bool Confirm(string message); + + FrpdDirectoryItem ShowFrpdEditDialog(FrpdDirectoryItem seed, bool isNew, IReadOnlyList existingItems, FrpdDirectoryService service); + + FrpdvdDirectoryItem ShowFrpdvdEditDialog(FrpdvdDirectoryItem seed, bool isNew, IReadOnlyList existingItems, FrpdDirectoryService service); + + void ShowError(string message); + + void ShowInfo(string message); + + void ShowWarning(string message); + } + + internal sealed class FrpdDirectoryDialogService : IFrpdDirectoryDialogService + { + private readonly Window _owner; + + public FrpdDirectoryDialogService(Window owner) + { + _owner = owner; + } + + public bool Confirm(string message) + { + return MessageBox.Show(_owner, message, "ПСВ", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes; + } + + public FrpdDirectoryItem ShowFrpdEditDialog(FrpdDirectoryItem seed, bool isNew, IReadOnlyList existingItems, FrpdDirectoryService service) + { + var viewModel = new FrpdEditWindowViewModel(seed, isNew, existingItems, service); + var window = new FrpdEditWindow(viewModel); + window.Owner = _owner; + + var result = window.ShowDialog(); + return result.HasValue && result.Value ? viewModel.ToResult() : null; + } + + public FrpdvdDirectoryItem ShowFrpdvdEditDialog(FrpdvdDirectoryItem seed, bool isNew, IReadOnlyList existingItems, FrpdDirectoryService service) + { + var viewModel = new FrpdvdEditWindowViewModel(seed, isNew, existingItems, service); + var window = new FrpdvdEditWindow(viewModel); + window.Owner = _owner; + + var result = window.ShowDialog(); + return result.HasValue && result.Value ? viewModel.ToResult() : null; + } + + public void ShowError(string message) + { + MessageBox.Show(_owner, message, "ПСВ", MessageBoxButton.OK, MessageBoxImage.Error); + } + + public void ShowInfo(string message) + { + MessageBox.Show(_owner, message, "ПСВ", MessageBoxButton.OK, MessageBoxImage.Information); + } + + public void ShowWarning(string message) + { + MessageBox.Show(_owner, message, "ПСВ", MessageBoxButton.OK, MessageBoxImage.Warning); + } + } +} diff --git a/XLAB/FrpdDirectoryModels.cs b/XLAB/FrpdDirectoryModels.cs new file mode 100644 index 0000000..b9654b8 --- /dev/null +++ b/XLAB/FrpdDirectoryModels.cs @@ -0,0 +1,45 @@ +using System; + +namespace XLAB +{ + public sealed class FrpdDirectoryItem + { + public string ActivityNames { get; set; } + + public DateTime? CreatedOn { get; set; } + + public string Guid { get; set; } + + public int Id { get; set; } + + public DateTime? LiquidatedOn { get; set; } + + public string LocalCode { get; set; } + + public string Name { get; set; } + + public int? ParentId { get; set; } + + public string ParentName { get; set; } + } + + public sealed class FrpdvdDirectoryItem + { + public string ActivityName { get; set; } + + public int ActivityId { get; set; } + + public int FrpdId { get; set; } + + public int Id { get; set; } + } + + internal static class FrpdDirectoryRules + { + public const int GuidMaxLength = 50; + + public const int LocalCodeMaxLength = 20; + + public const int NameMaxLength = 80; + } +} diff --git a/XLAB/FrpdDirectoryService.cs b/XLAB/FrpdDirectoryService.cs new file mode 100644 index 0000000..7fe3dba --- /dev/null +++ b/XLAB/FrpdDirectoryService.cs @@ -0,0 +1,556 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Linq; + +namespace XLAB +{ + internal sealed class FrpdDirectoryService + { + public int AddFrpdItem(FrpdDirectoryItem item) + { + var normalizedItem = NormalizeFrpdItem(item); + + const string sql = @" +INSERT INTO dbo.FRPD +( + IDFRPDR, + NMFRPD, + KDFRPDLC, + FRPDGUID, + DTSZFRPD, + DTLKFRPD +) +VALUES +( + @ParentId, + @Name, + @LocalCode, + @Guid, + @CreatedOn, + @LiquidatedOn +); + +SELECT CAST(SCOPE_IDENTITY() AS int);"; + + using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) + using (var command = new SqlCommand(sql, connection)) + { + connection.Open(); + EnsureFrpdGuidIsUnique(connection, normalizedItem.Guid, null); + + command.CommandTimeout = 60; + ReferenceDirectorySqlHelpers.AddNullableIntParameter(command, "@ParentId", normalizedItem.ParentId); + command.Parameters.Add("@Name", SqlDbType.VarChar, FrpdDirectoryRules.NameMaxLength).Value = normalizedItem.Name; + ReferenceDirectorySqlHelpers.AddNullableStringParameter(command, "@LocalCode", SqlDbType.VarChar, FrpdDirectoryRules.LocalCodeMaxLength, normalizedItem.LocalCode); + ReferenceDirectorySqlHelpers.AddNullableStringParameter(command, "@Guid", SqlDbType.VarChar, FrpdDirectoryRules.GuidMaxLength, normalizedItem.Guid); + ReferenceDirectorySqlHelpers.AddNullableDateTimeParameter(command, "@CreatedOn", normalizedItem.CreatedOn); + ReferenceDirectorySqlHelpers.AddNullableDateTimeParameter(command, "@LiquidatedOn", normalizedItem.LiquidatedOn); + + try + { + return Convert.ToInt32(command.ExecuteScalar()); + } + catch (SqlException ex) when (ReferenceDirectorySqlHelpers.IsDuplicateViolation(ex, "IX_FRPD_FRPDGUID")) + { + throw CreateFrpdDuplicateGuidException(normalizedItem.Guid); + } + } + } + + public int AddFrpdvdItem(FrpdvdDirectoryItem item) + { + var normalizedItem = NormalizeFrpdvdItem(item); + + const string sql = @" +INSERT INTO dbo.FRPDVD +( + IDFRPD, + IDSPVDDO +) +VALUES +( + @FrpdId, + @ActivityId +); + +SELECT CAST(SCOPE_IDENTITY() AS int);"; + + using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) + using (var command = new SqlCommand(sql, connection)) + { + connection.Open(); + EnsureFrpdvdIsUnique(connection, normalizedItem.FrpdId, normalizedItem.ActivityId, null); + + command.CommandTimeout = 60; + command.Parameters.Add("@FrpdId", SqlDbType.Int).Value = normalizedItem.FrpdId; + command.Parameters.Add("@ActivityId", SqlDbType.Int).Value = normalizedItem.ActivityId; + + try + { + return Convert.ToInt32(command.ExecuteScalar()); + } + catch (SqlException ex) when (ReferenceDirectorySqlHelpers.IsDuplicateViolation(ex, "XAK1FRPDVD")) + { + throw CreateFrpdvdDuplicateException(); + } + } + } + + public DirectoryDeleteResult DeleteFrpdItem(int id) + { + if (id <= 0) + { + throw new InvalidOperationException("Не выбрана запись FRPD для удаления."); + } + + const string sql = @" +DELETE FROM dbo.FRPD +WHERE IDFRPD = @Id; + +SELECT @@ROWCOUNT;"; + + try + { + using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) + { + connection.Open(); + var blockers = ReferenceDirectorySqlHelpers.LoadDeleteBlockersFromForeignKeys(connection, "FRPD", id); + if (blockers.Count > 0) + { + return new DirectoryDeleteResult + { + IsDeleted = false, + WarningMessage = ReferenceDirectorySqlHelpers.CreateDeleteBlockedMessage("FRPD", blockers) + }; + } + + using (var command = new SqlCommand(sql, connection)) + { + command.CommandTimeout = 60; + command.Parameters.Add("@Id", SqlDbType.Int).Value = id; + if (Convert.ToInt32(command.ExecuteScalar()) == 0) + { + throw new InvalidOperationException("Запись FRPD для удаления не найдена."); + } + } + + return new DirectoryDeleteResult + { + IsDeleted = true + }; + } + } + catch (SqlException ex) when (ex.Number == 547) + { + return new DirectoryDeleteResult + { + IsDeleted = false, + WarningMessage = ReferenceDirectorySqlHelpers.CreateDeleteBlockedMessage("FRPD", ex) + }; + } + } + + public DirectoryDeleteResult DeleteFrpdvdItem(int id) + { + if (id <= 0) + { + throw new InvalidOperationException("Не выбрана запись FRPDVD для удаления."); + } + + const string sql = @" +DELETE FROM dbo.FRPDVD +WHERE IDFRPDVD = @Id; + +SELECT @@ROWCOUNT;"; + + try + { + using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) + { + connection.Open(); + var blockers = ReferenceDirectorySqlHelpers.LoadDeleteBlockersFromForeignKeys(connection, "FRPDVD", id); + if (blockers.Count > 0) + { + return new DirectoryDeleteResult + { + IsDeleted = false, + WarningMessage = ReferenceDirectorySqlHelpers.CreateDeleteBlockedMessage("FRPDVD", blockers) + }; + } + + using (var command = new SqlCommand(sql, connection)) + { + command.CommandTimeout = 60; + command.Parameters.Add("@Id", SqlDbType.Int).Value = id; + if (Convert.ToInt32(command.ExecuteScalar()) == 0) + { + throw new InvalidOperationException("Запись FRPDVD для удаления не найдена."); + } + } + + return new DirectoryDeleteResult + { + IsDeleted = true + }; + } + } + catch (SqlException ex) when (ex.Number == 547) + { + return new DirectoryDeleteResult + { + IsDeleted = false, + WarningMessage = ReferenceDirectorySqlHelpers.CreateDeleteBlockedMessage("FRPDVD", ex) + }; + } + } + + public IReadOnlyList LoadFrpdItems() + { + const string sql = @" +SELECT + fr.IDFRPD AS Id, + fr.IDFRPDR AS ParentId, + parent.NMFRPD AS ParentName, + fr.NMFRPD AS Name, + fr.KDFRPDLC AS LocalCode, + fr.FRPDGUID AS Guid, + fr.DTSZFRPD AS CreatedOn, + fr.DTLKFRPD AS LiquidatedOn, + ISNULL( + STUFF(( + SELECT ', ' + activity.ActivityName + FROM + ( + SELECT DISTINCT sp.NMVDDO AS ActivityName + FROM dbo.FRPDVD link + JOIN dbo.SPVDDO sp ON sp.IDSPVDDO = link.IDSPVDDO + WHERE link.IDFRPD = fr.IDFRPD + ) activity + ORDER BY activity.ActivityName + FOR XML PATH(''), TYPE + ).value('.', 'nvarchar(max)'), 1, 2, ''), + '' + ) AS ActivityNames +FROM dbo.FRPD fr +LEFT JOIN dbo.FRPD parent ON parent.IDFRPD = fr.IDFRPDR +ORDER BY fr.NMFRPD, fr.IDFRPD;"; + + var items = new List(); + + using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) + using (var command = new SqlCommand(sql, connection)) + { + connection.Open(); + command.CommandTimeout = 60; + + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + items.Add(new FrpdDirectoryItem + { + ActivityNames = ReferenceDirectorySqlHelpers.GetString(reader, "ActivityNames"), + CreatedOn = ReferenceDirectorySqlHelpers.GetNullableDateTime(reader, "CreatedOn"), + Guid = ReferenceDirectorySqlHelpers.GetString(reader, "Guid"), + Id = ReferenceDirectorySqlHelpers.GetInt32(reader, "Id"), + LiquidatedOn = ReferenceDirectorySqlHelpers.GetNullableDateTime(reader, "LiquidatedOn"), + LocalCode = ReferenceDirectorySqlHelpers.GetString(reader, "LocalCode"), + Name = ReferenceDirectorySqlHelpers.GetString(reader, "Name"), + ParentId = ReferenceDirectorySqlHelpers.GetNullableInt32(reader, "ParentId"), + ParentName = ReferenceDirectorySqlHelpers.GetString(reader, "ParentName") + }); + } + } + } + + return items; + } + + public IReadOnlyList LoadFrpdReferences() + { + return ReferenceDirectorySqlHelpers.LoadLookupItems(@" +SELECT + fr.IDFRPD AS Id, + fr.NMFRPD AS Name +FROM dbo.FRPD fr +ORDER BY fr.NMFRPD, fr.IDFRPD;"); + } + + public IReadOnlyList LoadFrpdvdItems(int frpdId) + { + const string sql = @" +SELECT + link.IDFRPDVD AS Id, + link.IDFRPD AS FrpdId, + link.IDSPVDDO AS ActivityId, + sp.NMVDDO AS ActivityName +FROM dbo.FRPDVD link +JOIN dbo.SPVDDO sp ON sp.IDSPVDDO = link.IDSPVDDO +WHERE link.IDFRPD = @FrpdId +ORDER BY sp.NMVDDO, link.IDFRPDVD;"; + + var items = new List(); + + using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) + using (var command = new SqlCommand(sql, connection)) + { + connection.Open(); + command.CommandTimeout = 60; + command.Parameters.Add("@FrpdId", SqlDbType.Int).Value = frpdId; + + using (var reader = command.ExecuteReader()) + { + while (reader.Read()) + { + items.Add(new FrpdvdDirectoryItem + { + ActivityId = ReferenceDirectorySqlHelpers.GetInt32(reader, "ActivityId"), + ActivityName = ReferenceDirectorySqlHelpers.GetString(reader, "ActivityName"), + FrpdId = ReferenceDirectorySqlHelpers.GetInt32(reader, "FrpdId"), + Id = ReferenceDirectorySqlHelpers.GetInt32(reader, "Id") + }); + } + } + } + + return items; + } + + public IReadOnlyList LoadSpvddoReferences() + { + return ReferenceDirectorySqlHelpers.LoadLookupItems(@" +SELECT + sp.IDSPVDDO AS Id, + sp.NMVDDO AS Name +FROM dbo.SPVDDO sp +ORDER BY sp.NMVDDO, sp.IDSPVDDO;"); + } + + public void UpdateFrpdItem(FrpdDirectoryItem item) + { + var normalizedItem = NormalizeFrpdItem(item); + if (normalizedItem.Id <= 0) + { + throw new InvalidOperationException("Не выбрана запись FRPD для изменения."); + } + + const string sql = @" +UPDATE dbo.FRPD +SET IDFRPDR = @ParentId, + NMFRPD = @Name, + KDFRPDLC = @LocalCode, + FRPDGUID = @Guid, + DTSZFRPD = @CreatedOn, + DTLKFRPD = @LiquidatedOn +WHERE IDFRPD = @Id; + +SELECT @@ROWCOUNT;"; + + using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) + using (var command = new SqlCommand(sql, connection)) + { + connection.Open(); + EnsureFrpdGuidIsUnique(connection, normalizedItem.Guid, normalizedItem.Id); + + command.CommandTimeout = 60; + command.Parameters.Add("@Id", SqlDbType.Int).Value = normalizedItem.Id; + ReferenceDirectorySqlHelpers.AddNullableIntParameter(command, "@ParentId", normalizedItem.ParentId); + command.Parameters.Add("@Name", SqlDbType.VarChar, FrpdDirectoryRules.NameMaxLength).Value = normalizedItem.Name; + ReferenceDirectorySqlHelpers.AddNullableStringParameter(command, "@LocalCode", SqlDbType.VarChar, FrpdDirectoryRules.LocalCodeMaxLength, normalizedItem.LocalCode); + ReferenceDirectorySqlHelpers.AddNullableStringParameter(command, "@Guid", SqlDbType.VarChar, FrpdDirectoryRules.GuidMaxLength, normalizedItem.Guid); + ReferenceDirectorySqlHelpers.AddNullableDateTimeParameter(command, "@CreatedOn", normalizedItem.CreatedOn); + ReferenceDirectorySqlHelpers.AddNullableDateTimeParameter(command, "@LiquidatedOn", normalizedItem.LiquidatedOn); + + try + { + if (Convert.ToInt32(command.ExecuteScalar()) == 0) + { + throw new InvalidOperationException("Запись FRPD для изменения не найдена."); + } + } + catch (SqlException ex) when (ReferenceDirectorySqlHelpers.IsDuplicateViolation(ex, "IX_FRPD_FRPDGUID")) + { + throw CreateFrpdDuplicateGuidException(normalizedItem.Guid); + } + } + } + + public void UpdateFrpdvdItem(FrpdvdDirectoryItem item) + { + var normalizedItem = NormalizeFrpdvdItem(item); + if (normalizedItem.Id <= 0) + { + throw new InvalidOperationException("Не выбрана запись FRPDVD для изменения."); + } + + const string sql = @" +UPDATE dbo.FRPDVD +SET IDSPVDDO = @ActivityId +WHERE IDFRPDVD = @Id; + +SELECT @@ROWCOUNT;"; + + using (var connection = ReferenceDirectorySqlHelpers.CreateConnection()) + using (var command = new SqlCommand(sql, connection)) + { + connection.Open(); + EnsureFrpdvdIsUnique(connection, normalizedItem.FrpdId, normalizedItem.ActivityId, normalizedItem.Id); + + command.CommandTimeout = 60; + command.Parameters.Add("@Id", SqlDbType.Int).Value = normalizedItem.Id; + command.Parameters.Add("@ActivityId", SqlDbType.Int).Value = normalizedItem.ActivityId; + + try + { + if (Convert.ToInt32(command.ExecuteScalar()) == 0) + { + throw new InvalidOperationException("Запись FRPDVD для изменения не найдена."); + } + } + catch (SqlException ex) when (ReferenceDirectorySqlHelpers.IsDuplicateViolation(ex, "XAK1FRPDVD")) + { + throw CreateFrpdvdDuplicateException(); + } + } + } + + private static InvalidOperationException CreateFrpdDuplicateGuidException(string guid) + { + return new InvalidOperationException(string.Format("GUID подразделения \"{0}\" уже существует в справочнике.", guid)); + } + + private static InvalidOperationException CreateFrpdvdDuplicateException() + { + return new InvalidOperationException("Выбранный вид деятельности уже существует у этой организации/подразделения."); + } + + private static void EnsureFrpdGuidIsUnique(SqlConnection connection, string guid, int? excludeId) + { + if (string.IsNullOrWhiteSpace(guid)) + { + return; + } + + const string sql = @" +SELECT COUNT(1) +FROM dbo.FRPD +WHERE FRPDGUID = @Guid + AND (@ExcludeId IS NULL OR IDFRPD <> @ExcludeId);"; + + using (var command = new SqlCommand(sql, connection)) + { + command.CommandTimeout = 60; + command.Parameters.Add("@Guid", SqlDbType.VarChar, FrpdDirectoryRules.GuidMaxLength).Value = guid; + ReferenceDirectorySqlHelpers.AddNullableIntParameter(command, "@ExcludeId", excludeId); + if (Convert.ToInt32(command.ExecuteScalar()) > 0) + { + throw CreateFrpdDuplicateGuidException(guid); + } + } + } + + private static void EnsureFrpdvdIsUnique(SqlConnection connection, int frpdId, int activityId, int? excludeId) + { + const string sql = @" +SELECT COUNT(1) +FROM dbo.FRPDVD +WHERE IDFRPD = @FrpdId + AND IDSPVDDO = @ActivityId + AND (@ExcludeId IS NULL OR IDFRPDVD <> @ExcludeId);"; + + using (var command = new SqlCommand(sql, connection)) + { + command.CommandTimeout = 60; + command.Parameters.Add("@FrpdId", SqlDbType.Int).Value = frpdId; + command.Parameters.Add("@ActivityId", SqlDbType.Int).Value = activityId; + ReferenceDirectorySqlHelpers.AddNullableIntParameter(command, "@ExcludeId", excludeId); + if (Convert.ToInt32(command.ExecuteScalar()) > 0) + { + throw CreateFrpdvdDuplicateException(); + } + } + } + + private static string NormalizeRequired(string value, int maxLength, string fieldDisplayName) + { + var normalizedValue = string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim(); + if (normalizedValue.Length == 0) + { + throw new InvalidOperationException(string.Format("Укажите {0}.", fieldDisplayName)); + } + + if (normalizedValue.Length > maxLength) + { + throw new InvalidOperationException(string.Format("{0} не должно превышать {1} символов.", fieldDisplayName, maxLength)); + } + + return normalizedValue; + } + + private static string NormalizeNullable(string value, int maxLength, string fieldDisplayName) + { + var normalizedValue = string.IsNullOrWhiteSpace(value) ? null : value.Trim(); + if (normalizedValue != null && normalizedValue.Length > maxLength) + { + throw new InvalidOperationException(string.Format("{0} не должно превышать {1} символов.", fieldDisplayName, maxLength)); + } + + return normalizedValue; + } + + private static FrpdDirectoryItem NormalizeFrpdItem(FrpdDirectoryItem item) + { + if (item == null) + { + throw new InvalidOperationException("Не передана запись FRPD."); + } + + var normalizedItem = new FrpdDirectoryItem + { + CreatedOn = item.CreatedOn, + Guid = NormalizeNullable(item.Guid, FrpdDirectoryRules.GuidMaxLength, "GUID подразделения"), + Id = item.Id, + LiquidatedOn = item.LiquidatedOn, + LocalCode = NormalizeNullable(item.LocalCode, FrpdDirectoryRules.LocalCodeMaxLength, "Локальный код организации/подразделения"), + Name = NormalizeRequired(item.Name, FrpdDirectoryRules.NameMaxLength, "организацию/подразделение"), + ParentId = item.ParentId.HasValue && item.ParentId.Value > 0 ? item.ParentId : null + }; + + if (normalizedItem.Id > 0 + && normalizedItem.ParentId.HasValue + && normalizedItem.ParentId.Value == normalizedItem.Id) + { + throw new InvalidOperationException("Организация/подразделение не может ссылаться на себя как на родительскую запись."); + } + + return normalizedItem; + } + + private static FrpdvdDirectoryItem NormalizeFrpdvdItem(FrpdvdDirectoryItem item) + { + if (item == null) + { + throw new InvalidOperationException("Не передана запись FRPDVD."); + } + + if (item.FrpdId <= 0) + { + throw new InvalidOperationException("Не выбрана организация/подразделение для вида деятельности."); + } + + if (item.ActivityId <= 0) + { + throw new InvalidOperationException("Укажите вид деятельности организации."); + } + + return new FrpdvdDirectoryItem + { + ActivityId = item.ActivityId, + FrpdId = item.FrpdId, + Id = item.Id + }; + } + } +} diff --git a/XLAB/FrpdDirectoryWindow.xaml b/XLAB/FrpdDirectoryWindow.xaml new file mode 100644 index 0000000..4d5c806 --- /dev/null +++ b/XLAB/FrpdDirectoryWindow.xaml @@ -0,0 +1,119 @@ + + + + + + + + + + + +