edit
This commit is contained in:
70
XLAB/FrpdDirectoryDialogService.cs
Normal file
70
XLAB/FrpdDirectoryDialogService.cs
Normal file
@@ -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<FrpdDirectoryItem> existingItems, FrpdDirectoryService service);
|
||||||
|
|
||||||
|
FrpdvdDirectoryItem ShowFrpdvdEditDialog(FrpdvdDirectoryItem seed, bool isNew, IReadOnlyList<FrpdvdDirectoryItem> 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<FrpdDirectoryItem> 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<FrpdvdDirectoryItem> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
XLAB/FrpdDirectoryModels.cs
Normal file
45
XLAB/FrpdDirectoryModels.cs
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
556
XLAB/FrpdDirectoryService.cs
Normal file
556
XLAB/FrpdDirectoryService.cs
Normal file
@@ -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<FrpdDirectoryItem> 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<FrpdDirectoryItem>();
|
||||||
|
|
||||||
|
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<DirectoryLookupItem> 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<FrpdvdDirectoryItem> 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<FrpdvdDirectoryItem>();
|
||||||
|
|
||||||
|
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<DirectoryLookupItem> 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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
119
XLAB/FrpdDirectoryWindow.xaml
Normal file
119
XLAB/FrpdDirectoryWindow.xaml
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<Window x:Class="XLAB.FrpdDirectoryWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
Title="Организации и подразделения"
|
||||||
|
Height="820"
|
||||||
|
Width="1280"
|
||||||
|
MinHeight="680"
|
||||||
|
MinWidth="1040"
|
||||||
|
Loaded="Window_Loaded"
|
||||||
|
WindowStartupLocation="CenterOwner">
|
||||||
|
<Grid Margin="12">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="2.2*" />
|
||||||
|
<RowDefinition Height="1.5*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<DockPanel Grid.Row="0"
|
||||||
|
Margin="0,0,0,12">
|
||||||
|
<Button DockPanel.Dock="Right"
|
||||||
|
Width="110"
|
||||||
|
Margin="12,0,0,0"
|
||||||
|
Command="{Binding RefreshCommand}"
|
||||||
|
Content="Обновить" />
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock Margin="0,0,8,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="Поиск по FRPD" />
|
||||||
|
<TextBox Width="360"
|
||||||
|
Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</StackPanel>
|
||||||
|
</DockPanel>
|
||||||
|
|
||||||
|
<GroupBox Grid.Row="1"
|
||||||
|
Header="Организации и подразделения (FRPD)">
|
||||||
|
<DataGrid ItemsSource="{Binding FrpdItems}"
|
||||||
|
SelectedItem="{Binding SelectedFrpd, Mode=TwoWay}"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
CanUserAddRows="False"
|
||||||
|
IsReadOnly="True"
|
||||||
|
HeadersVisibility="Column">
|
||||||
|
<DataGrid.ContextMenu>
|
||||||
|
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||||
|
<MenuItem Header="Добавить"
|
||||||
|
Command="{Binding AddFrpdCommand}" />
|
||||||
|
<MenuItem Header="Изменить"
|
||||||
|
Command="{Binding EditFrpdCommand}" />
|
||||||
|
<MenuItem Header="Удалить"
|
||||||
|
Command="{Binding DeleteFrpdCommand}" />
|
||||||
|
</ContextMenu>
|
||||||
|
</DataGrid.ContextMenu>
|
||||||
|
<DataGrid.RowStyle>
|
||||||
|
<Style TargetType="DataGridRow">
|
||||||
|
<EventSetter Event="PreviewMouseRightButtonDown"
|
||||||
|
Handler="DataGridRow_PreviewMouseRightButtonDown" />
|
||||||
|
</Style>
|
||||||
|
</DataGrid.RowStyle>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="ID" Width="80" Binding="{Binding Id}" />
|
||||||
|
<DataGridTextColumn Header="Организация/подразделение" Width="*" Binding="{Binding Name}" />
|
||||||
|
<DataGridTextColumn Header="Родительская запись" Width="240" Binding="{Binding ParentName}" />
|
||||||
|
<DataGridTextColumn Header="Локальный код" Width="150" Binding="{Binding LocalCode}" />
|
||||||
|
<DataGridTextColumn Header="GUID" Width="220" Binding="{Binding Guid}" />
|
||||||
|
<DataGridTextColumn Header="Дата создания" Width="120" Binding="{Binding CreatedOn, StringFormat=d}" />
|
||||||
|
<DataGridTextColumn Header="Дата ликвидации" Width="130" Binding="{Binding LiquidatedOn, StringFormat=d}" />
|
||||||
|
<DataGridTextColumn Header="Виды деятельности" Width="260" Binding="{Binding ActivityNames}" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
|
<GroupBox Grid.Row="2"
|
||||||
|
Margin="0,12,0,0"
|
||||||
|
Header="Виды деятельности организации/подразделения (FRPDVD)">
|
||||||
|
<DataGrid ItemsSource="{Binding FrpdvdItems}"
|
||||||
|
SelectedItem="{Binding SelectedFrpdvd, Mode=TwoWay}"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
CanUserAddRows="False"
|
||||||
|
IsReadOnly="True"
|
||||||
|
HeadersVisibility="Column">
|
||||||
|
<DataGrid.ContextMenu>
|
||||||
|
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||||
|
<MenuItem Header="Добавить"
|
||||||
|
Command="{Binding AddFrpdvdCommand}" />
|
||||||
|
<MenuItem Header="Изменить"
|
||||||
|
Command="{Binding EditFrpdvdCommand}" />
|
||||||
|
<MenuItem Header="Удалить"
|
||||||
|
Command="{Binding DeleteFrpdvdCommand}" />
|
||||||
|
</ContextMenu>
|
||||||
|
</DataGrid.ContextMenu>
|
||||||
|
<DataGrid.RowStyle>
|
||||||
|
<Style TargetType="DataGridRow">
|
||||||
|
<EventSetter Event="PreviewMouseRightButtonDown"
|
||||||
|
Handler="DataGridRow_PreviewMouseRightButtonDown" />
|
||||||
|
</Style>
|
||||||
|
</DataGrid.RowStyle>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="ID" Width="100" Binding="{Binding Id}" />
|
||||||
|
<DataGridTextColumn Header="Вид деятельности" Width="*" Binding="{Binding ActivityName}" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="3"
|
||||||
|
Margin="0,8,0,0"
|
||||||
|
Foreground="DimGray"
|
||||||
|
Text="{Binding StatusText}" />
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="4"
|
||||||
|
Margin="0,12,0,0"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
HorizontalAlignment="Right">
|
||||||
|
<Button Width="90"
|
||||||
|
IsCancel="True"
|
||||||
|
Content="Закрыть" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
33
XLAB/FrpdDirectoryWindow.xaml.cs
Normal file
33
XLAB/FrpdDirectoryWindow.xaml.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
public partial class FrpdDirectoryWindow : Window
|
||||||
|
{
|
||||||
|
private readonly FrpdDirectoryWindowViewModel _viewModel;
|
||||||
|
|
||||||
|
public FrpdDirectoryWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
_viewModel = new FrpdDirectoryWindowViewModel(new FrpdDirectoryService(), new FrpdDirectoryDialogService(this));
|
||||||
|
DataContext = _viewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DataGridRow_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
var row = sender as DataGridRow;
|
||||||
|
if (row != null)
|
||||||
|
{
|
||||||
|
row.IsSelected = true;
|
||||||
|
row.Focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
await _viewModel.InitializeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
476
XLAB/FrpdDirectoryWindowViewModel.cs
Normal file
476
XLAB/FrpdDirectoryWindowViewModel.cs
Normal file
@@ -0,0 +1,476 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
internal sealed class FrpdDirectoryWindowViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
private readonly IFrpdDirectoryDialogService _dialogService;
|
||||||
|
private readonly FrpdDirectoryService _service;
|
||||||
|
private List<FrpdDirectoryItem> _frpdCache;
|
||||||
|
private bool _isBusy;
|
||||||
|
private string _searchText;
|
||||||
|
private FrpdDirectoryItem _selectedFrpd;
|
||||||
|
private FrpdvdDirectoryItem _selectedFrpdvd;
|
||||||
|
private string _statusText;
|
||||||
|
|
||||||
|
public FrpdDirectoryWindowViewModel(FrpdDirectoryService service, IFrpdDirectoryDialogService dialogService)
|
||||||
|
{
|
||||||
|
_service = service;
|
||||||
|
_dialogService = dialogService;
|
||||||
|
_frpdCache = new List<FrpdDirectoryItem>();
|
||||||
|
|
||||||
|
FrpdItems = new ObservableCollection<FrpdDirectoryItem>();
|
||||||
|
FrpdvdItems = new ObservableCollection<FrpdvdDirectoryItem>();
|
||||||
|
|
||||||
|
AddFrpdCommand = new RelayCommand(delegate { AddFrpdAsync(); }, delegate { return !IsBusy; });
|
||||||
|
EditFrpdCommand = new RelayCommand(delegate { EditFrpdAsync(); }, delegate { return !IsBusy && SelectedFrpd != null; });
|
||||||
|
DeleteFrpdCommand = new RelayCommand(delegate { DeleteFrpdAsync(); }, delegate { return !IsBusy && SelectedFrpd != null; });
|
||||||
|
AddFrpdvdCommand = new RelayCommand(delegate { AddFrpdvdAsync(); }, delegate { return !IsBusy && SelectedFrpd != null; });
|
||||||
|
EditFrpdvdCommand = new RelayCommand(delegate { EditFrpdvdAsync(); }, delegate { return !IsBusy && SelectedFrpdvd != null; });
|
||||||
|
DeleteFrpdvdCommand = new RelayCommand(delegate { DeleteFrpdvdAsync(); }, delegate { return !IsBusy && SelectedFrpdvd != null; });
|
||||||
|
RefreshCommand = new RelayCommand(delegate { RefreshAsync(); }, delegate { return !IsBusy; });
|
||||||
|
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICommand AddFrpdCommand { get; private set; }
|
||||||
|
public ICommand AddFrpdvdCommand { get; private set; }
|
||||||
|
public ICommand DeleteFrpdCommand { get; private set; }
|
||||||
|
public ICommand DeleteFrpdvdCommand { get; private set; }
|
||||||
|
public ICommand EditFrpdCommand { get; private set; }
|
||||||
|
public ICommand EditFrpdvdCommand { get; private set; }
|
||||||
|
public ObservableCollection<FrpdDirectoryItem> FrpdItems { get; private set; }
|
||||||
|
public ObservableCollection<FrpdvdDirectoryItem> FrpdvdItems { get; private set; }
|
||||||
|
public ICommand RefreshCommand { get; private set; }
|
||||||
|
|
||||||
|
public bool IsBusy
|
||||||
|
{
|
||||||
|
get { return _isBusy; }
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _isBusy, value))
|
||||||
|
{
|
||||||
|
RaiseCommandStates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SearchText
|
||||||
|
{
|
||||||
|
get { return _searchText; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _searchText, value))
|
||||||
|
{
|
||||||
|
ApplySearchFilter();
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrpdDirectoryItem SelectedFrpd
|
||||||
|
{
|
||||||
|
get { return _selectedFrpd; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _selectedFrpd, value))
|
||||||
|
{
|
||||||
|
RaiseCommandStates();
|
||||||
|
LoadFrpdvdForSelection();
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrpdvdDirectoryItem SelectedFrpdvd
|
||||||
|
{
|
||||||
|
get { return _selectedFrpdvd; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _selectedFrpdvd, value))
|
||||||
|
{
|
||||||
|
RaiseCommandStates();
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StatusText
|
||||||
|
{
|
||||||
|
get { return _statusText; }
|
||||||
|
private set { SetProperty(ref _statusText, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
await ExecuteBusyOperationAsync(async delegate { await RefreshFrpdCoreAsync(null, null); });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddFrpdAsync()
|
||||||
|
{
|
||||||
|
var result = _dialogService.ShowFrpdEditDialog(new FrpdDirectoryItem(), true, _frpdCache.ToList(), _service);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
var createdId = await Task.Run(delegate { return _service.AddFrpdItem(result); });
|
||||||
|
await RefreshFrpdCoreAsync(createdId, null);
|
||||||
|
_dialogService.ShowInfo("Запись FRPD добавлена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddFrpdvdAsync()
|
||||||
|
{
|
||||||
|
if (SelectedFrpd == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = _dialogService.ShowFrpdvdEditDialog(new FrpdvdDirectoryItem { FrpdId = SelectedFrpd.Id }, true, FrpdvdItems.ToList(), _service);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
var createdId = await Task.Run(delegate { return _service.AddFrpdvdItem(result); });
|
||||||
|
await RefreshFrpdCoreAsync(result.FrpdId, createdId);
|
||||||
|
_dialogService.ShowInfo("Запись FRPDVD добавлена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyFrpdFilter(int? preferredId)
|
||||||
|
{
|
||||||
|
var filteredItems = _frpdCache.Where(delegate(FrpdDirectoryItem item) { return MatchesSearch(item); }).ToList();
|
||||||
|
FrpdItems.Clear();
|
||||||
|
foreach (var item in filteredItems)
|
||||||
|
{
|
||||||
|
FrpdItems.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedFrpd = preferredId.HasValue
|
||||||
|
? FrpdItems.FirstOrDefault(delegate(FrpdDirectoryItem item) { return item.Id == preferredId.Value; })
|
||||||
|
: FrpdItems.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplySearchFilter()
|
||||||
|
{
|
||||||
|
if (!IsBusy)
|
||||||
|
{
|
||||||
|
ApplyFrpdFilter(SelectedFrpd == null ? (int?)null : SelectedFrpd.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FrpdDirectoryItem CloneFrpd(FrpdDirectoryItem source)
|
||||||
|
{
|
||||||
|
return new FrpdDirectoryItem
|
||||||
|
{
|
||||||
|
CreatedOn = source.CreatedOn,
|
||||||
|
Guid = source.Guid,
|
||||||
|
Id = source.Id,
|
||||||
|
LiquidatedOn = source.LiquidatedOn,
|
||||||
|
LocalCode = source.LocalCode,
|
||||||
|
Name = source.Name,
|
||||||
|
ParentId = source.ParentId,
|
||||||
|
ParentName = source.ParentName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FrpdvdDirectoryItem CloneFrpdvd(FrpdvdDirectoryItem source)
|
||||||
|
{
|
||||||
|
return new FrpdvdDirectoryItem
|
||||||
|
{
|
||||||
|
ActivityId = source.ActivityId,
|
||||||
|
ActivityName = source.ActivityName,
|
||||||
|
FrpdId = source.FrpdId,
|
||||||
|
Id = source.Id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeleteFrpdAsync()
|
||||||
|
{
|
||||||
|
if (SelectedFrpd == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selected = SelectedFrpd;
|
||||||
|
if (!_dialogService.Confirm(string.Format("Удалить организацию/подразделение \"{0}\"?", selected.Name)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
var result = await Task.Run(delegate { return _service.DeleteFrpdItem(selected.Id); });
|
||||||
|
if (!result.IsDeleted)
|
||||||
|
{
|
||||||
|
_dialogService.ShowWarning(result.WarningMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await RefreshFrpdCoreAsync(null, null);
|
||||||
|
_dialogService.ShowInfo("Запись FRPD удалена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeleteFrpdvdAsync()
|
||||||
|
{
|
||||||
|
if (SelectedFrpdvd == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selected = SelectedFrpdvd;
|
||||||
|
if (!_dialogService.Confirm(string.Format("Удалить вид деятельности \"{0}\"?", selected.ActivityName)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
var result = await Task.Run(delegate { return _service.DeleteFrpdvdItem(selected.Id); });
|
||||||
|
if (!result.IsDeleted)
|
||||||
|
{
|
||||||
|
_dialogService.ShowWarning(result.WarningMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await RefreshFrpdCoreAsync(selected.FrpdId, null);
|
||||||
|
_dialogService.ShowInfo("Запись FRPDVD удалена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteBusyOperationAsync(Func<Task> operation)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IsBusy = true;
|
||||||
|
await operation();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_dialogService.ShowError(ex.Message);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteMutationOperationAsync(Func<Task> operation)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IsBusy = true;
|
||||||
|
await operation();
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
_dialogService.ShowWarning(ex.Message);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_dialogService.ShowError(ex.Message);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EditFrpdAsync()
|
||||||
|
{
|
||||||
|
if (SelectedFrpd == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = _dialogService.ShowFrpdEditDialog(CloneFrpd(SelectedFrpd), false, _frpdCache.ToList(), _service);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
await Task.Run(delegate { _service.UpdateFrpdItem(result); });
|
||||||
|
await RefreshFrpdCoreAsync(result.Id, SelectedFrpdvd == null ? (int?)null : SelectedFrpdvd.Id);
|
||||||
|
_dialogService.ShowInfo("Запись FRPD обновлена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EditFrpdvdAsync()
|
||||||
|
{
|
||||||
|
if (SelectedFrpdvd == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = _dialogService.ShowFrpdvdEditDialog(CloneFrpdvd(SelectedFrpdvd), false, FrpdvdItems.ToList(), _service);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
await Task.Run(delegate { _service.UpdateFrpdvdItem(result); });
|
||||||
|
await RefreshFrpdCoreAsync(result.FrpdId, result.Id);
|
||||||
|
_dialogService.ShowInfo("Запись FRPDVD обновлена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private string[] GetSearchTokens()
|
||||||
|
{
|
||||||
|
return (SearchText ?? string.Empty)
|
||||||
|
.Split(new[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(delegate(string token) { return token.Trim().ToUpperInvariant(); })
|
||||||
|
.Where(delegate(string token) { return token.Length > 0; })
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadFrpdvdForSelection()
|
||||||
|
{
|
||||||
|
if (!IsBusy)
|
||||||
|
{
|
||||||
|
RunBusyOperation(async delegate
|
||||||
|
{
|
||||||
|
if (SelectedFrpd == null)
|
||||||
|
{
|
||||||
|
FrpdvdItems.Clear();
|
||||||
|
SelectedFrpdvd = null;
|
||||||
|
UpdateStatus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await RefreshFrpdvdCoreAsync(SelectedFrpd.Id, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool MatchesSearch(FrpdDirectoryItem item)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokens = GetSearchTokens();
|
||||||
|
if (tokens.Length == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var haystack = string.Join(
|
||||||
|
" ",
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
item.Id.ToString(),
|
||||||
|
item.Name,
|
||||||
|
item.ParentName,
|
||||||
|
item.LocalCode,
|
||||||
|
item.Guid,
|
||||||
|
item.ActivityNames
|
||||||
|
}
|
||||||
|
.Where(delegate(string value) { return !string.IsNullOrWhiteSpace(value); }))
|
||||||
|
.ToUpperInvariant();
|
||||||
|
return tokens.All(delegate(string token) { return haystack.IndexOf(token, StringComparison.Ordinal) >= 0; });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RefreshFrpdCoreAsync(int? frpdIdToSelect, int? frpdvdIdToSelect)
|
||||||
|
{
|
||||||
|
var currentFrpdId = SelectedFrpd == null ? (int?)null : SelectedFrpd.Id;
|
||||||
|
_frpdCache = (await Task.Run(delegate { return _service.LoadFrpdItems(); })).ToList();
|
||||||
|
|
||||||
|
ApplyFrpdFilter(frpdIdToSelect.HasValue ? frpdIdToSelect : currentFrpdId);
|
||||||
|
if (SelectedFrpd == null)
|
||||||
|
{
|
||||||
|
FrpdvdItems.Clear();
|
||||||
|
SelectedFrpdvd = null;
|
||||||
|
UpdateStatus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await RefreshFrpdvdCoreAsync(SelectedFrpd.Id, frpdvdIdToSelect);
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RefreshFrpdvdCoreAsync(int frpdId, int? frpdvdIdToSelect)
|
||||||
|
{
|
||||||
|
var items = await Task.Run(delegate { return _service.LoadFrpdvdItems(frpdId); });
|
||||||
|
FrpdvdItems.Clear();
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
FrpdvdItems.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedFrpdvd = frpdvdIdToSelect.HasValue
|
||||||
|
? FrpdvdItems.FirstOrDefault(delegate(FrpdvdDirectoryItem item) { return item.Id == frpdvdIdToSelect.Value; })
|
||||||
|
: FrpdvdItems.FirstOrDefault();
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaiseCommandStates()
|
||||||
|
{
|
||||||
|
((RelayCommand)AddFrpdCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)EditFrpdCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)DeleteFrpdCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)AddFrpdvdCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)EditFrpdvdCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)DeleteFrpdvdCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)RefreshCommand).RaiseCanExecuteChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshAsync()
|
||||||
|
{
|
||||||
|
RunBusyOperation(async delegate { await RefreshFrpdCoreAsync(SelectedFrpd == null ? (int?)null : SelectedFrpd.Id, SelectedFrpdvd == null ? (int?)null : SelectedFrpdvd.Id); });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void RunBusyOperation(Func<Task> operation)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ExecuteBusyOperationAsync(operation);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
_dialogService.ShowError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void RunMutationOperation(Func<Task> operation)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ExecuteMutationOperationAsync(operation);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
_dialogService.ShowError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateStatus()
|
||||||
|
{
|
||||||
|
var searchText = string.IsNullOrWhiteSpace(SearchText) ? null : SearchText.Trim();
|
||||||
|
StatusText = string.Format(
|
||||||
|
"{0}FRPD: {1}/{2}. FRPDVD: {3}.",
|
||||||
|
string.IsNullOrWhiteSpace(searchText) ? string.Empty : string.Format("Поиск: \"{0}\". ", searchText),
|
||||||
|
FrpdItems.Count,
|
||||||
|
_frpdCache.Count,
|
||||||
|
FrpdvdItems.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
XLAB/FrpdEditWindow.xaml
Normal file
57
XLAB/FrpdEditWindow.xaml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<Window x:Class="XLAB.FrpdEditWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
Title="{Binding Title}"
|
||||||
|
Height="360"
|
||||||
|
Width="680"
|
||||||
|
MinHeight="340"
|
||||||
|
MinWidth="620"
|
||||||
|
WindowStartupLocation="CenterOwner">
|
||||||
|
<Grid Margin="16">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid Grid.Row="0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="220" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Родительская запись" />
|
||||||
|
<ComboBox Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding ParentItems}" SelectedValue="{Binding ParentId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Организация/подразделение" />
|
||||||
|
<TextBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,8" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Локальный код" />
|
||||||
|
<TextBox Grid.Row="2" Grid.Column="1" Margin="0,0,0,8" Text="{Binding LocalCode, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="3" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="GUID подразделения" />
|
||||||
|
<TextBox Grid.Row="3" Grid.Column="1" Margin="0,0,0,8" Text="{Binding Guid, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="4" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Дата создания" />
|
||||||
|
<DatePicker Grid.Row="4" Grid.Column="1" Margin="0,0,0,8" SelectedDate="{Binding CreatedOn, Mode=TwoWay}" SelectedDateFormat="Short" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="5" Grid.Column="0" Margin="0,0,12,0" VerticalAlignment="Center" Text="Дата ликвидации" />
|
||||||
|
<DatePicker Grid.Row="5" Grid.Column="1" SelectedDate="{Binding LiquidatedOn, Mode=TwoWay}" SelectedDateFormat="Short" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Margin="0,12,0,0" Foreground="Firebrick" Text="{Binding ValidationMessage}" />
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="2" Margin="0,12,0,0" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
|
<Button Width="100" Margin="0,0,8,0" IsDefault="True" Command="{Binding ConfirmCommand}" Content="Сохранить" />
|
||||||
|
<Button Width="90" Command="{Binding CancelCommand}" Content="Отмена" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
20
XLAB/FrpdEditWindow.xaml.cs
Normal file
20
XLAB/FrpdEditWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
public partial class FrpdEditWindow : Window
|
||||||
|
{
|
||||||
|
internal FrpdEditWindow(FrpdEditWindowViewModel viewModel)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContext = viewModel;
|
||||||
|
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||||
|
{
|
||||||
|
DialogResult = dialogResult;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
168
XLAB/FrpdEditWindowViewModel.cs
Normal file
168
XLAB/FrpdEditWindowViewModel.cs
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
internal sealed class FrpdEditWindowViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
private readonly IReadOnlyList<FrpdDirectoryItem> _existingItems;
|
||||||
|
private string _guid;
|
||||||
|
private string _localCode;
|
||||||
|
private string _name;
|
||||||
|
private int _parentId;
|
||||||
|
private string _validationMessage;
|
||||||
|
|
||||||
|
public FrpdEditWindowViewModel(FrpdDirectoryItem seed, bool isNew, IReadOnlyList<FrpdDirectoryItem> existingItems, FrpdDirectoryService service)
|
||||||
|
{
|
||||||
|
var source = seed ?? new FrpdDirectoryItem();
|
||||||
|
_existingItems = existingItems ?? Array.Empty<FrpdDirectoryItem>();
|
||||||
|
Id = source.Id;
|
||||||
|
IsNew = isNew;
|
||||||
|
|
||||||
|
ParentItems = new[] { new DirectoryLookupItem { Id = 0, Name = string.Empty } }
|
||||||
|
.Concat((service.LoadFrpdReferences() ?? Array.Empty<DirectoryLookupItem>()).Where(delegate(DirectoryLookupItem item) { return item.Id != Id; }))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
ParentId = source.ParentId.HasValue ? source.ParentId.Value : 0;
|
||||||
|
Name = source.Name ?? string.Empty;
|
||||||
|
LocalCode = source.LocalCode ?? string.Empty;
|
||||||
|
Guid = source.Guid ?? string.Empty;
|
||||||
|
CreatedOn = source.CreatedOn;
|
||||||
|
LiquidatedOn = source.LiquidatedOn;
|
||||||
|
|
||||||
|
ConfirmCommand = new RelayCommand(Confirm);
|
||||||
|
CancelCommand = new RelayCommand(Cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<bool?> CloseRequested;
|
||||||
|
|
||||||
|
public ICommand CancelCommand { get; private set; }
|
||||||
|
public ICommand ConfirmCommand { get; private set; }
|
||||||
|
public DateTime? CreatedOn { get; set; }
|
||||||
|
|
||||||
|
public string Guid
|
||||||
|
{
|
||||||
|
get { return _guid; }
|
||||||
|
set { SetProperty(ref _guid, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Id { get; private set; }
|
||||||
|
public bool IsNew { get; private set; }
|
||||||
|
public DateTime? LiquidatedOn { get; set; }
|
||||||
|
|
||||||
|
public string LocalCode
|
||||||
|
{
|
||||||
|
get { return _localCode; }
|
||||||
|
set { SetProperty(ref _localCode, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return _name; }
|
||||||
|
set { SetProperty(ref _name, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ParentId
|
||||||
|
{
|
||||||
|
get { return _parentId; }
|
||||||
|
set { SetProperty(ref _parentId, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<DirectoryLookupItem> ParentItems { get; private set; }
|
||||||
|
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get { return IsNew ? "Новая организация/подразделение" : "Редактирование организации/подразделения"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ValidationMessage
|
||||||
|
{
|
||||||
|
get { return _validationMessage; }
|
||||||
|
private set { SetProperty(ref _validationMessage, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrpdDirectoryItem ToResult()
|
||||||
|
{
|
||||||
|
return new FrpdDirectoryItem
|
||||||
|
{
|
||||||
|
CreatedOn = CreatedOn,
|
||||||
|
Guid = string.IsNullOrWhiteSpace(Guid) ? null : Guid.Trim(),
|
||||||
|
Id = Id,
|
||||||
|
LiquidatedOn = LiquidatedOn,
|
||||||
|
LocalCode = string.IsNullOrWhiteSpace(LocalCode) ? null : LocalCode.Trim(),
|
||||||
|
Name = string.IsNullOrWhiteSpace(Name) ? string.Empty : Name.Trim(),
|
||||||
|
ParentId = ParentId > 0 ? (int?)ParentId : null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel(object parameter)
|
||||||
|
{
|
||||||
|
RaiseCloseRequested(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Confirm(object parameter)
|
||||||
|
{
|
||||||
|
var normalizedName = string.IsNullOrWhiteSpace(Name) ? string.Empty : Name.Trim();
|
||||||
|
var normalizedLocalCode = string.IsNullOrWhiteSpace(LocalCode) ? null : LocalCode.Trim();
|
||||||
|
var normalizedGuid = string.IsNullOrWhiteSpace(Guid) ? null : Guid.Trim();
|
||||||
|
|
||||||
|
if (normalizedName.Length == 0)
|
||||||
|
{
|
||||||
|
ValidationMessage = "Укажите организацию/подразделение.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedName.Length > FrpdDirectoryRules.NameMaxLength)
|
||||||
|
{
|
||||||
|
ValidationMessage = string.Format("Организация/подразделение не должна превышать {0} символов.", FrpdDirectoryRules.NameMaxLength);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedLocalCode != null && normalizedLocalCode.Length > FrpdDirectoryRules.LocalCodeMaxLength)
|
||||||
|
{
|
||||||
|
ValidationMessage = string.Format("Локальный код не должен превышать {0} символов.", FrpdDirectoryRules.LocalCodeMaxLength);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedGuid != null && normalizedGuid.Length > FrpdDirectoryRules.GuidMaxLength)
|
||||||
|
{
|
||||||
|
ValidationMessage = string.Format("GUID подразделения не должен превышать {0} символов.", FrpdDirectoryRules.GuidMaxLength);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ParentId == Id && Id > 0)
|
||||||
|
{
|
||||||
|
ValidationMessage = "Нельзя выбрать эту же запись как родительскую.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var duplicateGuid = _existingItems.FirstOrDefault(delegate(FrpdDirectoryItem item)
|
||||||
|
{
|
||||||
|
return item != null
|
||||||
|
&& item.Id != Id
|
||||||
|
&& !string.IsNullOrWhiteSpace(item.Guid)
|
||||||
|
&& normalizedGuid != null
|
||||||
|
&& string.Equals(item.Guid.Trim(), normalizedGuid, StringComparison.OrdinalIgnoreCase);
|
||||||
|
});
|
||||||
|
if (duplicateGuid != null)
|
||||||
|
{
|
||||||
|
ValidationMessage = string.Format("GUID подразделения \"{0}\" уже существует в справочнике.", normalizedGuid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidationMessage = string.Empty;
|
||||||
|
RaiseCloseRequested(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaiseCloseRequested(bool? dialogResult)
|
||||||
|
{
|
||||||
|
var handler = CloseRequested;
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
handler(this, dialogResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
XLAB/FrpdvdEditWindow.xaml
Normal file
32
XLAB/FrpdvdEditWindow.xaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<Window x:Class="XLAB.FrpdvdEditWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
Title="{Binding Title}"
|
||||||
|
Height="210"
|
||||||
|
Width="560"
|
||||||
|
MinHeight="200"
|
||||||
|
MinWidth="520"
|
||||||
|
ResizeMode="NoResize"
|
||||||
|
WindowStartupLocation="CenterOwner">
|
||||||
|
<Grid Margin="16">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="170" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Вид деятельности" />
|
||||||
|
<ComboBox Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding ActivityItems}" SelectedValue="{Binding ActivityId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Grid.ColumnSpan="2" Margin="0,8,0,0" Foreground="Firebrick" Text="{Binding ValidationMessage}" />
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="2" Grid.ColumnSpan="2" Margin="0,12,0,0" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
|
<Button Width="100" Margin="0,0,8,0" IsDefault="True" Command="{Binding ConfirmCommand}" Content="Сохранить" />
|
||||||
|
<Button Width="90" Command="{Binding CancelCommand}" Content="Отмена" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
20
XLAB/FrpdvdEditWindow.xaml.cs
Normal file
20
XLAB/FrpdvdEditWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
public partial class FrpdvdEditWindow : Window
|
||||||
|
{
|
||||||
|
internal FrpdvdEditWindow(FrpdvdEditWindowViewModel viewModel)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContext = viewModel;
|
||||||
|
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||||
|
{
|
||||||
|
DialogResult = dialogResult;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
103
XLAB/FrpdvdEditWindowViewModel.cs
Normal file
103
XLAB/FrpdvdEditWindowViewModel.cs
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
internal sealed class FrpdvdEditWindowViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
private readonly IReadOnlyList<FrpdvdDirectoryItem> _existingItems;
|
||||||
|
private int _activityId;
|
||||||
|
private string _validationMessage;
|
||||||
|
|
||||||
|
public FrpdvdEditWindowViewModel(FrpdvdDirectoryItem seed, bool isNew, IReadOnlyList<FrpdvdDirectoryItem> existingItems, FrpdDirectoryService service)
|
||||||
|
{
|
||||||
|
var source = seed ?? new FrpdvdDirectoryItem();
|
||||||
|
_existingItems = existingItems ?? Array.Empty<FrpdvdDirectoryItem>();
|
||||||
|
Id = source.Id;
|
||||||
|
FrpdId = source.FrpdId;
|
||||||
|
IsNew = isNew;
|
||||||
|
|
||||||
|
ActivityItems = service.LoadSpvddoReferences();
|
||||||
|
ActivityId = source.ActivityId;
|
||||||
|
|
||||||
|
ConfirmCommand = new RelayCommand(Confirm);
|
||||||
|
CancelCommand = new RelayCommand(Cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<bool?> CloseRequested;
|
||||||
|
|
||||||
|
public int ActivityId
|
||||||
|
{
|
||||||
|
get { return _activityId; }
|
||||||
|
set { SetProperty(ref _activityId, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<DirectoryLookupItem> ActivityItems { get; private set; }
|
||||||
|
public ICommand CancelCommand { get; private set; }
|
||||||
|
public ICommand ConfirmCommand { get; private set; }
|
||||||
|
public int FrpdId { get; private set; }
|
||||||
|
public int Id { get; private set; }
|
||||||
|
public bool IsNew { get; private set; }
|
||||||
|
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get { return IsNew ? "Новый вид деятельности организации" : "Редактирование вида деятельности организации"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ValidationMessage
|
||||||
|
{
|
||||||
|
get { return _validationMessage; }
|
||||||
|
private set { SetProperty(ref _validationMessage, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public FrpdvdDirectoryItem ToResult()
|
||||||
|
{
|
||||||
|
return new FrpdvdDirectoryItem
|
||||||
|
{
|
||||||
|
ActivityId = ActivityId,
|
||||||
|
FrpdId = FrpdId,
|
||||||
|
Id = Id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel(object parameter)
|
||||||
|
{
|
||||||
|
RaiseCloseRequested(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Confirm(object parameter)
|
||||||
|
{
|
||||||
|
if (ActivityId <= 0)
|
||||||
|
{
|
||||||
|
ValidationMessage = "Укажите вид деятельности организации.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var duplicate = _existingItems.FirstOrDefault(delegate(FrpdvdDirectoryItem item)
|
||||||
|
{
|
||||||
|
return item != null
|
||||||
|
&& item.Id != Id
|
||||||
|
&& item.ActivityId == ActivityId;
|
||||||
|
});
|
||||||
|
if (duplicate != null)
|
||||||
|
{
|
||||||
|
ValidationMessage = "Выбранный вид деятельности уже существует у этой организации/подразделения.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidationMessage = string.Empty;
|
||||||
|
RaiseCloseRequested(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaiseCloseRequested(bool? dialogResult)
|
||||||
|
{
|
||||||
|
var handler = CloseRequested;
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
handler(this, dialogResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,13 +17,17 @@
|
|||||||
<Menu Grid.Row="0"
|
<Menu Grid.Row="0"
|
||||||
Margin="0,0,0,12">
|
Margin="0,0,0,12">
|
||||||
<MenuItem Header="Справочники">
|
<MenuItem Header="Справочники">
|
||||||
<MenuItem Header="Типоразмеры СИ"
|
|
||||||
Click="TypeSizeDirectoryMenuItem_Click" />
|
|
||||||
<MenuItem Header="Области измерений"
|
<MenuItem Header="Области измерений"
|
||||||
Click="SpoiDirectoryMenuItem_Click" />
|
Click="SpoiDirectoryMenuItem_Click" />
|
||||||
<MenuItem Header="Наименования типов СИ"
|
<MenuItem Header="Наименования типов СИ"
|
||||||
Click="SpnmtpDirectoryMenuItem_Click" />
|
Click="SpnmtpDirectoryMenuItem_Click" />
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
<MenuItem Header="Организации и подразделения"
|
||||||
|
Click="FrpdDirectoryMenuItem_Click" />
|
||||||
|
<MenuItem Header="Персоны"
|
||||||
|
Click="PrsnDirectoryMenuItem_Click" />
|
||||||
|
<MenuItem Header="Типоразмеры СИ"
|
||||||
|
Click="TypeSizeDirectoryMenuItem_Click" />
|
||||||
</Menu>
|
</Menu>
|
||||||
|
|
||||||
<Grid Grid.Row="1">
|
<Grid Grid.Row="1">
|
||||||
|
|||||||
@@ -45,6 +45,20 @@ namespace XLAB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void FrpdDirectoryMenuItem_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var window = new FrpdDirectoryWindow();
|
||||||
|
window.Owner = this;
|
||||||
|
window.ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void PrsnDirectoryMenuItem_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var window = new PrsnDirectoryWindow();
|
||||||
|
window.Owner = this;
|
||||||
|
window.ShowDialog();
|
||||||
|
}
|
||||||
|
|
||||||
private void SpnmtpDirectoryMenuItem_Click(object sender, RoutedEventArgs e)
|
private void SpnmtpDirectoryMenuItem_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var window = new SpnmtpDirectoryWindow();
|
var window = new SpnmtpDirectoryWindow();
|
||||||
|
|||||||
53
XLAB/PrdspvEditWindow.xaml
Normal file
53
XLAB/PrdspvEditWindow.xaml
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
<Window x:Class="XLAB.PrdspvEditWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
Title="{Binding Title}"
|
||||||
|
Height="280"
|
||||||
|
Width="640"
|
||||||
|
MinHeight="260"
|
||||||
|
MinWidth="600"
|
||||||
|
WindowStartupLocation="CenterOwner">
|
||||||
|
<Grid Margin="16">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="180" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Вид клейма" />
|
||||||
|
<ComboBox Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding StampTypeItems}" SelectedValue="{Binding StampTypeId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Шифр клейма" />
|
||||||
|
<TextBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,8" Text="{Binding StampCode, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<Grid Grid.Row="2" Grid.ColumnSpan="2">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="180" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Дата получения" />
|
||||||
|
<DatePicker Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" SelectedDate="{Binding ReceivedOn, Mode=TwoWay}" SelectedDateFormat="Short" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,0,12,0" VerticalAlignment="Top" Text="Доп. сведения" />
|
||||||
|
<TextBox Grid.Row="1" Grid.Column="1" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" Text="{Binding Notes, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<DockPanel Grid.Row="3" Grid.ColumnSpan="2" Margin="0,12,0,0">
|
||||||
|
<TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" Foreground="Firebrick" Text="{Binding ValidationMessage}" />
|
||||||
|
<StackPanel DockPanel.Dock="Right" Orientation="Horizontal">
|
||||||
|
<Button Width="100" Margin="0,0,8,0" IsDefault="True" Command="{Binding ConfirmCommand}" Content="Сохранить" />
|
||||||
|
<Button Width="90" Command="{Binding CancelCommand}" Content="Отмена" />
|
||||||
|
</StackPanel>
|
||||||
|
</DockPanel>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
20
XLAB/PrdspvEditWindow.xaml.cs
Normal file
20
XLAB/PrdspvEditWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
public partial class PrdspvEditWindow : Window
|
||||||
|
{
|
||||||
|
internal PrdspvEditWindow(PrdspvEditWindowViewModel viewModel)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContext = viewModel;
|
||||||
|
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||||
|
{
|
||||||
|
DialogResult = dialogResult;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
157
XLAB/PrdspvEditWindowViewModel.cs
Normal file
157
XLAB/PrdspvEditWindowViewModel.cs
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
internal sealed class PrdspvEditWindowViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
private readonly IReadOnlyList<PrdspvDirectoryItem> _existingItems;
|
||||||
|
private string _notes;
|
||||||
|
private int _stampTypeId;
|
||||||
|
private string _stampCode;
|
||||||
|
private string _validationMessage;
|
||||||
|
|
||||||
|
public PrdspvEditWindowViewModel(PrdspvDirectoryItem seed, bool isNew, IReadOnlyList<PrdspvDirectoryItem> existingItems, PrsnDirectoryService service)
|
||||||
|
{
|
||||||
|
var source = seed ?? new PrdspvDirectoryItem();
|
||||||
|
_existingItems = existingItems ?? Array.Empty<PrdspvDirectoryItem>();
|
||||||
|
Id = source.Id;
|
||||||
|
EmploymentId = source.EmploymentId;
|
||||||
|
IsNew = isNew;
|
||||||
|
|
||||||
|
StampTypeItems = service.LoadSpvdmkReferences();
|
||||||
|
StampTypeId = source.StampTypeId;
|
||||||
|
StampCode = source.StampCode ?? string.Empty;
|
||||||
|
ReceivedOn = source.ReceivedOn;
|
||||||
|
Notes = source.Notes ?? string.Empty;
|
||||||
|
|
||||||
|
ConfirmCommand = new RelayCommand(Confirm);
|
||||||
|
CancelCommand = new RelayCommand(Cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<bool?> CloseRequested;
|
||||||
|
|
||||||
|
public ICommand CancelCommand { get; private set; }
|
||||||
|
public ICommand ConfirmCommand { get; private set; }
|
||||||
|
public int EmploymentId { get; private set; }
|
||||||
|
public int Id { get; private set; }
|
||||||
|
public bool IsNew { get; private set; }
|
||||||
|
|
||||||
|
public string Notes
|
||||||
|
{
|
||||||
|
get { return _notes; }
|
||||||
|
set { SetProperty(ref _notes, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime? ReceivedOn { get; set; }
|
||||||
|
|
||||||
|
public string StampCode
|
||||||
|
{
|
||||||
|
get { return _stampCode; }
|
||||||
|
set { SetProperty(ref _stampCode, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int StampTypeId
|
||||||
|
{
|
||||||
|
get { return _stampTypeId; }
|
||||||
|
set { SetProperty(ref _stampTypeId, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<DirectoryLookupItem> StampTypeItems { get; private set; }
|
||||||
|
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get { return IsNew ? "Новое клеймо" : "Редактирование клейма"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ValidationMessage
|
||||||
|
{
|
||||||
|
get { return _validationMessage; }
|
||||||
|
private set { SetProperty(ref _validationMessage, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrdspvDirectoryItem ToResult()
|
||||||
|
{
|
||||||
|
return new PrdspvDirectoryItem
|
||||||
|
{
|
||||||
|
EmploymentId = EmploymentId,
|
||||||
|
Id = Id,
|
||||||
|
Notes = NormalizeNullable(Notes),
|
||||||
|
ReceivedOn = ReceivedOn,
|
||||||
|
StampCode = NormalizeRequired(StampCode),
|
||||||
|
StampTypeId = StampTypeId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel(object parameter)
|
||||||
|
{
|
||||||
|
RaiseCloseRequested(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Confirm(object parameter)
|
||||||
|
{
|
||||||
|
var normalizedStampCode = NormalizeRequired(StampCode);
|
||||||
|
var normalizedNotes = NormalizeNullable(Notes);
|
||||||
|
|
||||||
|
if (StampTypeId <= 0)
|
||||||
|
{
|
||||||
|
ValidationMessage = "Укажите вид клейма.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedStampCode.Length == 0)
|
||||||
|
{
|
||||||
|
ValidationMessage = "Укажите шифр клейма.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedStampCode.Length > PrdspvDirectoryRules.StampCodeMaxLength)
|
||||||
|
{
|
||||||
|
ValidationMessage = string.Format("Шифр клейма не должен превышать {0} символов.", PrdspvDirectoryRules.StampCodeMaxLength);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedNotes != null && normalizedNotes.Length > PrdspvDirectoryRules.NotesMaxLength)
|
||||||
|
{
|
||||||
|
ValidationMessage = string.Format("Дополнительные сведения не должны превышать {0} символов.", PrdspvDirectoryRules.NotesMaxLength);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var duplicate = _existingItems.FirstOrDefault(delegate(PrdspvDirectoryItem item)
|
||||||
|
{
|
||||||
|
return item != null
|
||||||
|
&& item.Id != Id
|
||||||
|
&& item.StampTypeId == StampTypeId;
|
||||||
|
});
|
||||||
|
if (duplicate != null)
|
||||||
|
{
|
||||||
|
ValidationMessage = "Выбранный вид клейма уже существует у этого сотрудника.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidationMessage = string.Empty;
|
||||||
|
RaiseCloseRequested(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string NormalizeNullable(string value)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string NormalizeRequired(string value)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaiseCloseRequested(bool? dialogResult)
|
||||||
|
{
|
||||||
|
var handler = CloseRequested;
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
handler(this, dialogResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
91
XLAB/PrfrEditWindow.xaml
Normal file
91
XLAB/PrfrEditWindow.xaml
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
<Window x:Class="XLAB.PrfrEditWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
Title="{Binding Title}"
|
||||||
|
Height="620"
|
||||||
|
Width="860"
|
||||||
|
MinHeight="560"
|
||||||
|
MinWidth="780"
|
||||||
|
WindowStartupLocation="CenterOwner">
|
||||||
|
<Grid Margin="16">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<ScrollViewer Grid.Row="0"
|
||||||
|
VerticalScrollBarVisibility="Auto">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="220" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="220" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Организация/подразделение" />
|
||||||
|
<ComboBox Grid.Row="0" Grid.Column="1" Margin="0,0,16,8" ItemsSource="{Binding OrganizationItems}" SelectedValue="{Binding OrganizationId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="2" Margin="0,0,12,8" VerticalAlignment="Center" Text="Должность" />
|
||||||
|
<ComboBox Grid.Row="0" Grid.Column="3" Margin="0,0,0,8" ItemsSource="{Binding PositionItems}" SelectedValue="{Binding PositionId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Дата приёма" />
|
||||||
|
<DatePicker Grid.Row="1" Grid.Column="1" Margin="0,0,16,8" SelectedDate="{Binding HireDate, Mode=TwoWay}" SelectedDateFormat="Short" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="2" Margin="0,0,12,8" VerticalAlignment="Center" Text="Дата увольнения" />
|
||||||
|
<DatePicker Grid.Row="1" Grid.Column="3" Margin="0,0,0,8" SelectedDate="{Binding DismissalDate, Mode=TwoWay}" SelectedDateFormat="Short" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Дата вступления в должность" />
|
||||||
|
<DatePicker Grid.Row="2" Grid.Column="1" Margin="0,0,16,8" SelectedDate="{Binding PositionStartDate, Mode=TwoWay}" SelectedDateFormat="Short" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="2" Grid.Column="2" Margin="0,0,12,8" VerticalAlignment="Center" Text="План повышения квалификации" />
|
||||||
|
<DatePicker Grid.Row="2" Grid.Column="3" Margin="0,0,0,8" SelectedDate="{Binding QualificationPlanDate, Mode=TwoWay}" SelectedDateFormat="Short" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="3" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Начало последнего отпуска" />
|
||||||
|
<DatePicker Grid.Row="3" Grid.Column="1" Margin="0,0,16,8" SelectedDate="{Binding LastVacationStartDate, Mode=TwoWay}" SelectedDateFormat="Short" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="3" Grid.Column="2" Margin="0,0,12,8" VerticalAlignment="Center" Text="Окончание последнего отпуска" />
|
||||||
|
<DatePicker Grid.Row="3" Grid.Column="3" Margin="0,0,0,8" SelectedDate="{Binding LastVacationEndDate, Mode=TwoWay}" SelectedDateFormat="Short" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="4" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Начало будущего отпуска" />
|
||||||
|
<DatePicker Grid.Row="4" Grid.Column="1" Margin="0,0,16,8" SelectedDate="{Binding NextVacationStartDate, Mode=TwoWay}" SelectedDateFormat="Short" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="4" Grid.Column="2" Margin="0,0,12,8" VerticalAlignment="Center" Text="Окончание будущего отпуска" />
|
||||||
|
<DatePicker Grid.Row="4" Grid.Column="3" Margin="0,0,0,8" SelectedDate="{Binding NextVacationEndDate, Mode=TwoWay}" SelectedDateFormat="Short" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="5" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Табельный номер" />
|
||||||
|
<TextBox Grid.Row="5" Grid.Column="1" Margin="0,0,16,8" Text="{Binding PersonnelNumber, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="5" Grid.Column="2" Margin="0,0,12,8" VerticalAlignment="Center" Text="GUID сотрудника" />
|
||||||
|
<TextBox Grid.Row="5" Grid.Column="3" Margin="0,0,0,8" Text="{Binding Guid, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="6" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="PIN сотрудника (хэш)" />
|
||||||
|
<TextBox Grid.Row="6" Grid.Column="1" Margin="0,0,16,8" Text="{Binding PinHash, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="6" Grid.Column="2" Margin="0,0,12,8" VerticalAlignment="Center" Text="Дата изменения PIN" />
|
||||||
|
<TextBox Grid.Row="6" Grid.Column="3" Margin="0,0,0,8" Text="{Binding PinChangedAtText, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="7" Grid.Column="0" Margin="0,0,12,0" VerticalAlignment="Center" Text="Аутентификация PIN" />
|
||||||
|
<CheckBox Grid.Row="7" Grid.Column="1" IsThreeState="True" IsChecked="{Binding IsPinAuth}" VerticalAlignment="Center" />
|
||||||
|
</Grid>
|
||||||
|
</ScrollViewer>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Margin="0,12,0,0" Foreground="Firebrick" Text="{Binding ValidationMessage}" />
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="2" Margin="0,12,0,0" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
|
<Button Width="100" Margin="0,0,8,0" IsDefault="True" Command="{Binding ConfirmCommand}" Content="Сохранить" />
|
||||||
|
<Button Width="90" Command="{Binding CancelCommand}" Content="Отмена" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
20
XLAB/PrfrEditWindow.xaml.cs
Normal file
20
XLAB/PrfrEditWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
public partial class PrfrEditWindow : Window
|
||||||
|
{
|
||||||
|
internal PrfrEditWindow(PrfrEditWindowViewModel viewModel)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContext = viewModel;
|
||||||
|
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||||
|
{
|
||||||
|
DialogResult = dialogResult;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
243
XLAB/PrfrEditWindowViewModel.cs
Normal file
243
XLAB/PrfrEditWindowViewModel.cs
Normal file
@@ -0,0 +1,243 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
internal sealed class PrfrEditWindowViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
private readonly IReadOnlyList<PrfrDirectoryItem> _existingItems;
|
||||||
|
private string _guid;
|
||||||
|
private bool? _isPinAuth;
|
||||||
|
private int _organizationId;
|
||||||
|
private string _personnelNumber;
|
||||||
|
private string _pinChangedAtText;
|
||||||
|
private string _pinHash;
|
||||||
|
private int _positionId;
|
||||||
|
private string _validationMessage;
|
||||||
|
|
||||||
|
public PrfrEditWindowViewModel(PrfrDirectoryItem seed, bool isNew, IReadOnlyList<PrfrDirectoryItem> existingItems, PrsnDirectoryService service)
|
||||||
|
{
|
||||||
|
var source = seed ?? new PrfrDirectoryItem();
|
||||||
|
_existingItems = existingItems ?? Array.Empty<PrfrDirectoryItem>();
|
||||||
|
EmploymentId = source.EmploymentId;
|
||||||
|
PersonId = source.PersonId;
|
||||||
|
IsNew = isNew;
|
||||||
|
|
||||||
|
OrganizationItems = service.LoadFrpdReferences();
|
||||||
|
PositionItems = new[] { new DirectoryLookupItem { Id = 0, Name = string.Empty } }
|
||||||
|
.Concat(service.LoadSpdlReferences() ?? Array.Empty<DirectoryLookupItem>())
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
OrganizationId = source.OrganizationId;
|
||||||
|
PositionId = source.PositionId.HasValue ? source.PositionId.Value : 0;
|
||||||
|
HireDate = source.HireDate;
|
||||||
|
DismissalDate = source.DismissalDate;
|
||||||
|
PositionStartDate = source.PositionStartDate;
|
||||||
|
QualificationPlanDate = source.QualificationPlanDate;
|
||||||
|
LastVacationStartDate = source.LastVacationStartDate;
|
||||||
|
LastVacationEndDate = source.LastVacationEndDate;
|
||||||
|
NextVacationStartDate = source.NextVacationStartDate;
|
||||||
|
NextVacationEndDate = source.NextVacationEndDate;
|
||||||
|
PersonnelNumber = source.PersonnelNumber ?? string.Empty;
|
||||||
|
Guid = source.Guid ?? string.Empty;
|
||||||
|
PinHash = source.PinHash ?? string.Empty;
|
||||||
|
PinChangedAtText = source.PinChangedAt.HasValue ? source.PinChangedAt.Value.ToString("dd.MM.yyyy HH:mm") : string.Empty;
|
||||||
|
IsPinAuth = source.IsPinAuth;
|
||||||
|
|
||||||
|
ConfirmCommand = new RelayCommand(Confirm);
|
||||||
|
CancelCommand = new RelayCommand(Cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<bool?> CloseRequested;
|
||||||
|
|
||||||
|
public ICommand CancelCommand { get; private set; }
|
||||||
|
public ICommand ConfirmCommand { get; private set; }
|
||||||
|
public DateTime? DismissalDate { get; set; }
|
||||||
|
public int EmploymentId { get; private set; }
|
||||||
|
|
||||||
|
public string Guid
|
||||||
|
{
|
||||||
|
get { return _guid; }
|
||||||
|
set { SetProperty(ref _guid, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime? HireDate { get; set; }
|
||||||
|
|
||||||
|
public bool? IsPinAuth
|
||||||
|
{
|
||||||
|
get { return _isPinAuth; }
|
||||||
|
set { SetProperty(ref _isPinAuth, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsNew { get; private set; }
|
||||||
|
public DateTime? LastVacationEndDate { get; set; }
|
||||||
|
public DateTime? LastVacationStartDate { get; set; }
|
||||||
|
public DateTime? NextVacationEndDate { get; set; }
|
||||||
|
public DateTime? NextVacationStartDate { get; set; }
|
||||||
|
|
||||||
|
public int OrganizationId
|
||||||
|
{
|
||||||
|
get { return _organizationId; }
|
||||||
|
set { SetProperty(ref _organizationId, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<DirectoryLookupItem> OrganizationItems { get; private set; }
|
||||||
|
|
||||||
|
public int PersonId { get; private set; }
|
||||||
|
|
||||||
|
public string PersonnelNumber
|
||||||
|
{
|
||||||
|
get { return _personnelNumber; }
|
||||||
|
set { SetProperty(ref _personnelNumber, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PinChangedAtText
|
||||||
|
{
|
||||||
|
get { return _pinChangedAtText; }
|
||||||
|
set { SetProperty(ref _pinChangedAtText, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PinHash
|
||||||
|
{
|
||||||
|
get { return _pinHash; }
|
||||||
|
set { SetProperty(ref _pinHash, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int PositionId
|
||||||
|
{
|
||||||
|
get { return _positionId; }
|
||||||
|
set { SetProperty(ref _positionId, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<DirectoryLookupItem> PositionItems { get; private set; }
|
||||||
|
public DateTime? PositionStartDate { get; set; }
|
||||||
|
public DateTime? QualificationPlanDate { get; set; }
|
||||||
|
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get { return IsNew ? "Новая запись персонала в организации" : "Редактирование записи персонала в организации"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ValidationMessage
|
||||||
|
{
|
||||||
|
get { return _validationMessage; }
|
||||||
|
private set { SetProperty(ref _validationMessage, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrfrDirectoryItem ToResult()
|
||||||
|
{
|
||||||
|
return new PrfrDirectoryItem
|
||||||
|
{
|
||||||
|
DismissalDate = DismissalDate,
|
||||||
|
EmploymentId = EmploymentId,
|
||||||
|
Guid = NormalizeNullable(Guid),
|
||||||
|
HireDate = HireDate,
|
||||||
|
IsPinAuth = IsPinAuth,
|
||||||
|
LastVacationEndDate = LastVacationEndDate,
|
||||||
|
LastVacationStartDate = LastVacationStartDate,
|
||||||
|
NextVacationEndDate = NextVacationEndDate,
|
||||||
|
NextVacationStartDate = NextVacationStartDate,
|
||||||
|
OrganizationId = OrganizationId,
|
||||||
|
PersonId = PersonId,
|
||||||
|
PersonnelNumber = NormalizeNullable(PersonnelNumber),
|
||||||
|
PinChangedAt = ParseNullableDateTime(PinChangedAtText),
|
||||||
|
PinHash = NormalizeNullable(PinHash),
|
||||||
|
PositionId = PositionId > 0 ? (int?)PositionId : null,
|
||||||
|
PositionStartDate = PositionStartDate,
|
||||||
|
QualificationPlanDate = QualificationPlanDate
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel(object parameter)
|
||||||
|
{
|
||||||
|
RaiseCloseRequested(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Confirm(object parameter)
|
||||||
|
{
|
||||||
|
var normalizedPersonnelNumber = NormalizeNullable(PersonnelNumber);
|
||||||
|
var normalizedGuid = NormalizeNullable(Guid);
|
||||||
|
DateTime? pinChangedAt;
|
||||||
|
|
||||||
|
if (OrganizationId <= 0)
|
||||||
|
{
|
||||||
|
ValidationMessage = "Укажите организацию/подразделение.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedPersonnelNumber != null && normalizedPersonnelNumber.Length > PrfrDirectoryRules.PersonnelNumberMaxLength)
|
||||||
|
{
|
||||||
|
ValidationMessage = string.Format("Табельный номер не должен превышать {0} символов.", PrfrDirectoryRules.PersonnelNumberMaxLength);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedGuid != null && normalizedGuid.Length > PrfrDirectoryRules.GuidMaxLength)
|
||||||
|
{
|
||||||
|
ValidationMessage = string.Format("GUID сотрудника не должен превышать {0} символов.", PrfrDirectoryRules.GuidMaxLength);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!TryParseNullableDateTime(PinChangedAtText, out pinChangedAt))
|
||||||
|
{
|
||||||
|
ValidationMessage = "Дата/время изменения PIN указаны в неверном формате.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var duplicate = _existingItems.FirstOrDefault(delegate(PrfrDirectoryItem item)
|
||||||
|
{
|
||||||
|
return item != null
|
||||||
|
&& item.EmploymentId != EmploymentId
|
||||||
|
&& item.OrganizationId == OrganizationId;
|
||||||
|
});
|
||||||
|
if (duplicate != null)
|
||||||
|
{
|
||||||
|
ValidationMessage = "Такая связка персоны и организации уже существует в справочнике.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidationMessage = string.Empty;
|
||||||
|
RaiseCloseRequested(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string NormalizeNullable(string value)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DateTime? ParseNullableDateTime(string value)
|
||||||
|
{
|
||||||
|
DateTime? result;
|
||||||
|
return TryParseNullableDateTime(value, out result) ? result : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryParseNullableDateTime(string value, out DateTime? result)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
result = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime parsedValue;
|
||||||
|
if (DateTime.TryParse(value.Trim(), out parsedValue))
|
||||||
|
{
|
||||||
|
result = parsedValue;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaiseCloseRequested(bool? dialogResult)
|
||||||
|
{
|
||||||
|
var handler = CloseRequested;
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
handler(this, dialogResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
XLAB/PrfrvdEditWindow.xaml
Normal file
32
XLAB/PrfrvdEditWindow.xaml
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<Window x:Class="XLAB.PrfrvdEditWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
Title="{Binding Title}"
|
||||||
|
Height="210"
|
||||||
|
Width="560"
|
||||||
|
MinHeight="200"
|
||||||
|
MinWidth="520"
|
||||||
|
ResizeMode="NoResize"
|
||||||
|
WindowStartupLocation="CenterOwner">
|
||||||
|
<Grid Margin="16">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="170" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Вид деятельности" />
|
||||||
|
<ComboBox Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" ItemsSource="{Binding ActivityItems}" SelectedValue="{Binding ActivityId}" SelectedValuePath="Id" DisplayMemberPath="Name" IsTextSearchEnabled="True" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Grid.ColumnSpan="2" Margin="0,8,0,0" Foreground="Firebrick" Text="{Binding ValidationMessage}" />
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="2" Grid.ColumnSpan="2" Margin="0,12,0,0" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
|
<Button Width="100" Margin="0,0,8,0" IsDefault="True" Command="{Binding ConfirmCommand}" Content="Сохранить" />
|
||||||
|
<Button Width="90" Command="{Binding CancelCommand}" Content="Отмена" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
20
XLAB/PrfrvdEditWindow.xaml.cs
Normal file
20
XLAB/PrfrvdEditWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
public partial class PrfrvdEditWindow : Window
|
||||||
|
{
|
||||||
|
internal PrfrvdEditWindow(PrfrvdEditWindowViewModel viewModel)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContext = viewModel;
|
||||||
|
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||||
|
{
|
||||||
|
DialogResult = dialogResult;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
103
XLAB/PrfrvdEditWindowViewModel.cs
Normal file
103
XLAB/PrfrvdEditWindowViewModel.cs
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
internal sealed class PrfrvdEditWindowViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
private readonly IReadOnlyList<PrfrvdDirectoryItem> _existingItems;
|
||||||
|
private int _activityId;
|
||||||
|
private string _validationMessage;
|
||||||
|
|
||||||
|
public PrfrvdEditWindowViewModel(PrfrvdDirectoryItem seed, bool isNew, IReadOnlyList<PrfrvdDirectoryItem> existingItems, PrsnDirectoryService service)
|
||||||
|
{
|
||||||
|
var source = seed ?? new PrfrvdDirectoryItem();
|
||||||
|
_existingItems = existingItems ?? Array.Empty<PrfrvdDirectoryItem>();
|
||||||
|
Id = source.Id;
|
||||||
|
EmploymentId = source.EmploymentId;
|
||||||
|
IsNew = isNew;
|
||||||
|
|
||||||
|
ActivityItems = service.LoadSpvdprReferences();
|
||||||
|
ActivityId = source.ActivityId;
|
||||||
|
|
||||||
|
ConfirmCommand = new RelayCommand(Confirm);
|
||||||
|
CancelCommand = new RelayCommand(Cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<bool?> CloseRequested;
|
||||||
|
|
||||||
|
public int ActivityId
|
||||||
|
{
|
||||||
|
get { return _activityId; }
|
||||||
|
set { SetProperty(ref _activityId, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<DirectoryLookupItem> ActivityItems { get; private set; }
|
||||||
|
public ICommand CancelCommand { get; private set; }
|
||||||
|
public ICommand ConfirmCommand { get; private set; }
|
||||||
|
public int EmploymentId { get; private set; }
|
||||||
|
public int Id { get; private set; }
|
||||||
|
public bool IsNew { get; private set; }
|
||||||
|
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get { return IsNew ? "Новый вид деятельности персоны" : "Редактирование вида деятельности персоны"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ValidationMessage
|
||||||
|
{
|
||||||
|
get { return _validationMessage; }
|
||||||
|
private set { SetProperty(ref _validationMessage, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrfrvdDirectoryItem ToResult()
|
||||||
|
{
|
||||||
|
return new PrfrvdDirectoryItem
|
||||||
|
{
|
||||||
|
ActivityId = ActivityId,
|
||||||
|
EmploymentId = EmploymentId,
|
||||||
|
Id = Id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel(object parameter)
|
||||||
|
{
|
||||||
|
RaiseCloseRequested(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Confirm(object parameter)
|
||||||
|
{
|
||||||
|
if (ActivityId <= 0)
|
||||||
|
{
|
||||||
|
ValidationMessage = "Укажите вид деятельности персонала.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var duplicate = _existingItems.FirstOrDefault(delegate(PrfrvdDirectoryItem item)
|
||||||
|
{
|
||||||
|
return item != null
|
||||||
|
&& item.Id != Id
|
||||||
|
&& item.ActivityId == ActivityId;
|
||||||
|
});
|
||||||
|
if (duplicate != null)
|
||||||
|
{
|
||||||
|
ValidationMessage = "Выбранный вид деятельности уже существует у этой записи персонала.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidationMessage = string.Empty;
|
||||||
|
RaiseCloseRequested(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaiseCloseRequested(bool? dialogResult)
|
||||||
|
{
|
||||||
|
var handler = CloseRequested;
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
handler(this, dialogResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
94
XLAB/PrsnDirectoryDialogService.cs
Normal file
94
XLAB/PrsnDirectoryDialogService.cs
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
internal interface IPrsnDirectoryDialogService
|
||||||
|
{
|
||||||
|
bool Confirm(string message);
|
||||||
|
|
||||||
|
PrdspvDirectoryItem ShowPrdspvEditDialog(PrdspvDirectoryItem seed, bool isNew, IReadOnlyList<PrdspvDirectoryItem> existingItems, PrsnDirectoryService service);
|
||||||
|
|
||||||
|
PrfrDirectoryItem ShowPrfrEditDialog(PrfrDirectoryItem seed, bool isNew, IReadOnlyList<PrfrDirectoryItem> existingItems, PrsnDirectoryService service);
|
||||||
|
|
||||||
|
PrfrvdDirectoryItem ShowPrfrvdEditDialog(PrfrvdDirectoryItem seed, bool isNew, IReadOnlyList<PrfrvdDirectoryItem> existingItems, PrsnDirectoryService service);
|
||||||
|
|
||||||
|
PrsnDirectoryItem ShowPrsnEditDialog(PrsnDirectoryItem seed, bool isNew, IReadOnlyList<PrsnDirectoryItem> existingItems);
|
||||||
|
|
||||||
|
void ShowError(string message);
|
||||||
|
|
||||||
|
void ShowInfo(string message);
|
||||||
|
|
||||||
|
void ShowWarning(string message);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal sealed class PrsnDirectoryDialogService : IPrsnDirectoryDialogService
|
||||||
|
{
|
||||||
|
private readonly Window _owner;
|
||||||
|
|
||||||
|
public PrsnDirectoryDialogService(Window owner)
|
||||||
|
{
|
||||||
|
_owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Confirm(string message)
|
||||||
|
{
|
||||||
|
return MessageBox.Show(_owner, message, "ПСВ", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrdspvDirectoryItem ShowPrdspvEditDialog(PrdspvDirectoryItem seed, bool isNew, IReadOnlyList<PrdspvDirectoryItem> existingItems, PrsnDirectoryService service)
|
||||||
|
{
|
||||||
|
var viewModel = new PrdspvEditWindowViewModel(seed, isNew, existingItems, service);
|
||||||
|
var window = new PrdspvEditWindow(viewModel);
|
||||||
|
window.Owner = _owner;
|
||||||
|
|
||||||
|
var result = window.ShowDialog();
|
||||||
|
return result.HasValue && result.Value ? viewModel.ToResult() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrfrDirectoryItem ShowPrfrEditDialog(PrfrDirectoryItem seed, bool isNew, IReadOnlyList<PrfrDirectoryItem> existingItems, PrsnDirectoryService service)
|
||||||
|
{
|
||||||
|
var viewModel = new PrfrEditWindowViewModel(seed, isNew, existingItems, service);
|
||||||
|
var window = new PrfrEditWindow(viewModel);
|
||||||
|
window.Owner = _owner;
|
||||||
|
|
||||||
|
var result = window.ShowDialog();
|
||||||
|
return result.HasValue && result.Value ? viewModel.ToResult() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrfrvdDirectoryItem ShowPrfrvdEditDialog(PrfrvdDirectoryItem seed, bool isNew, IReadOnlyList<PrfrvdDirectoryItem> existingItems, PrsnDirectoryService service)
|
||||||
|
{
|
||||||
|
var viewModel = new PrfrvdEditWindowViewModel(seed, isNew, existingItems, service);
|
||||||
|
var window = new PrfrvdEditWindow(viewModel);
|
||||||
|
window.Owner = _owner;
|
||||||
|
|
||||||
|
var result = window.ShowDialog();
|
||||||
|
return result.HasValue && result.Value ? viewModel.ToResult() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrsnDirectoryItem ShowPrsnEditDialog(PrsnDirectoryItem seed, bool isNew, IReadOnlyList<PrsnDirectoryItem> existingItems)
|
||||||
|
{
|
||||||
|
var viewModel = new PrsnEditWindowViewModel(seed, isNew, existingItems);
|
||||||
|
var window = new PrsnEditWindow(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
147
XLAB/PrsnDirectoryModels.cs
Normal file
147
XLAB/PrsnDirectoryModels.cs
Normal file
@@ -0,0 +1,147 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
public sealed class PrdspvDirectoryItem
|
||||||
|
{
|
||||||
|
public int EmploymentId { get; set; }
|
||||||
|
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public string Notes { get; set; }
|
||||||
|
|
||||||
|
public DateTime? ReceivedOn { get; set; }
|
||||||
|
|
||||||
|
public string StampCode { get; set; }
|
||||||
|
|
||||||
|
public int StampTypeId { get; set; }
|
||||||
|
|
||||||
|
public string StampTypeName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class PrfrDirectoryItem
|
||||||
|
{
|
||||||
|
public string ActivityNames { get; set; }
|
||||||
|
|
||||||
|
public DateTime? DismissalDate { get; set; }
|
||||||
|
|
||||||
|
public int EmploymentId { get; set; }
|
||||||
|
|
||||||
|
public int Id
|
||||||
|
{
|
||||||
|
get { return EmploymentId; }
|
||||||
|
set { EmploymentId = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Guid { get; set; }
|
||||||
|
|
||||||
|
public DateTime? HireDate { get; set; }
|
||||||
|
|
||||||
|
public bool? IsPinAuth { get; set; }
|
||||||
|
|
||||||
|
public DateTime? LastVacationEndDate { get; set; }
|
||||||
|
|
||||||
|
public DateTime? LastVacationStartDate { get; set; }
|
||||||
|
|
||||||
|
public DateTime? NextVacationEndDate { get; set; }
|
||||||
|
|
||||||
|
public DateTime? NextVacationStartDate { get; set; }
|
||||||
|
|
||||||
|
public int OrganizationId { get; set; }
|
||||||
|
|
||||||
|
public string OrganizationName { get; set; }
|
||||||
|
|
||||||
|
public int PersonId { get; set; }
|
||||||
|
|
||||||
|
public string PersonnelNumber { get; set; }
|
||||||
|
|
||||||
|
public DateTime? PinChangedAt { get; set; }
|
||||||
|
|
||||||
|
public string PinHash { get; set; }
|
||||||
|
|
||||||
|
public int? PositionId { get; set; }
|
||||||
|
|
||||||
|
public string PositionName { get; set; }
|
||||||
|
|
||||||
|
public DateTime? PositionStartDate { get; set; }
|
||||||
|
|
||||||
|
public DateTime? QualificationPlanDate { get; set; }
|
||||||
|
|
||||||
|
public string StampNames { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class PrfrvdDirectoryItem
|
||||||
|
{
|
||||||
|
public int ActivityId { get; set; }
|
||||||
|
|
||||||
|
public string ActivityName { get; set; }
|
||||||
|
|
||||||
|
public int EmploymentId { get; set; }
|
||||||
|
|
||||||
|
public int Id { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class PrsnDirectoryItem
|
||||||
|
{
|
||||||
|
public string ActivityNames { get; set; }
|
||||||
|
|
||||||
|
public string Email { get; set; }
|
||||||
|
|
||||||
|
public string ExternalId { get; set; }
|
||||||
|
|
||||||
|
public string FirstName { get; set; }
|
||||||
|
|
||||||
|
public string FullName { get; set; }
|
||||||
|
|
||||||
|
public string Guid { get; set; }
|
||||||
|
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
public string LastName { get; set; }
|
||||||
|
|
||||||
|
public string Notes { get; set; }
|
||||||
|
|
||||||
|
public string OrganizationNames { get; set; }
|
||||||
|
|
||||||
|
public string Patronymic { get; set; }
|
||||||
|
|
||||||
|
public string Phone { get; set; }
|
||||||
|
|
||||||
|
public string StampNames { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class PrdspvDirectoryRules
|
||||||
|
{
|
||||||
|
public const int NotesMaxLength = 200;
|
||||||
|
|
||||||
|
public const int StampCodeMaxLength = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class PrfrDirectoryRules
|
||||||
|
{
|
||||||
|
public const int GuidMaxLength = 50;
|
||||||
|
|
||||||
|
public const int PersonnelNumberMaxLength = 25;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class PrsnDirectoryRules
|
||||||
|
{
|
||||||
|
public const int EmailMaxLength = 50;
|
||||||
|
|
||||||
|
public const int ExternalIdMaxLength = 50;
|
||||||
|
|
||||||
|
public const int FirstNameMaxLength = 25;
|
||||||
|
|
||||||
|
public const int FullNameMaxLength = 35;
|
||||||
|
|
||||||
|
public const int GuidMaxLength = 50;
|
||||||
|
|
||||||
|
public const int LastNameMaxLength = 30;
|
||||||
|
|
||||||
|
public const int NotesMaxLength = 2000;
|
||||||
|
|
||||||
|
public const int PatronymicMaxLength = 25;
|
||||||
|
|
||||||
|
public const int PhoneMaxLength = 50;
|
||||||
|
}
|
||||||
|
}
|
||||||
1345
XLAB/PrsnDirectoryService.cs
Normal file
1345
XLAB/PrsnDirectoryService.cs
Normal file
File diff suppressed because it is too large
Load Diff
199
XLAB/PrsnDirectoryWindow.xaml
Normal file
199
XLAB/PrsnDirectoryWindow.xaml
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
<Window x:Class="XLAB.PrsnDirectoryWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
Title="Персоны"
|
||||||
|
Height="940"
|
||||||
|
Width="1500"
|
||||||
|
MinHeight="780"
|
||||||
|
MinWidth="1240"
|
||||||
|
Loaded="Window_Loaded"
|
||||||
|
WindowStartupLocation="CenterOwner">
|
||||||
|
<Grid Margin="12">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="2.1*" />
|
||||||
|
<RowDefinition Height="1.8*" />
|
||||||
|
<RowDefinition Height="1.8*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<DockPanel Grid.Row="0"
|
||||||
|
Margin="0,0,0,12">
|
||||||
|
<Button DockPanel.Dock="Right"
|
||||||
|
Width="110"
|
||||||
|
Margin="12,0,0,0"
|
||||||
|
Command="{Binding RefreshCommand}"
|
||||||
|
Content="Обновить" />
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock Margin="0,0,8,0"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
Text="Поиск по PRSN" />
|
||||||
|
<TextBox Width="360"
|
||||||
|
Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</StackPanel>
|
||||||
|
</DockPanel>
|
||||||
|
|
||||||
|
<GroupBox Grid.Row="1"
|
||||||
|
Header="Персоны (PRSN)">
|
||||||
|
<DataGrid ItemsSource="{Binding PrsnItems}"
|
||||||
|
SelectedItem="{Binding SelectedPrsn, Mode=TwoWay}"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
CanUserAddRows="False"
|
||||||
|
IsReadOnly="True"
|
||||||
|
HeadersVisibility="Column">
|
||||||
|
<DataGrid.ContextMenu>
|
||||||
|
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||||
|
<MenuItem Header="Добавить"
|
||||||
|
Command="{Binding AddPrsnCommand}" />
|
||||||
|
<MenuItem Header="Изменить"
|
||||||
|
Command="{Binding EditPrsnCommand}" />
|
||||||
|
<MenuItem Header="Удалить"
|
||||||
|
Command="{Binding DeletePrsnCommand}" />
|
||||||
|
</ContextMenu>
|
||||||
|
</DataGrid.ContextMenu>
|
||||||
|
<DataGrid.RowStyle>
|
||||||
|
<Style TargetType="DataGridRow">
|
||||||
|
<EventSetter Event="PreviewMouseRightButtonDown"
|
||||||
|
Handler="DataGridRow_PreviewMouseRightButtonDown" />
|
||||||
|
</Style>
|
||||||
|
</DataGrid.RowStyle>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="ID" Width="80" Binding="{Binding Id}" />
|
||||||
|
<DataGridTextColumn Header="ФИО" Width="240" Binding="{Binding FullName}" />
|
||||||
|
<DataGridTextColumn Header="Телефон" Width="140" Binding="{Binding Phone}" />
|
||||||
|
<DataGridTextColumn Header="E-mail" Width="180" Binding="{Binding Email}" />
|
||||||
|
<DataGridTextColumn Header="Организации" Width="220" Binding="{Binding OrganizationNames}" />
|
||||||
|
<DataGridTextColumn Header="Виды деятельности" Width="220" Binding="{Binding ActivityNames}" />
|
||||||
|
<DataGridTextColumn Header="Клейма" Width="260" Binding="{Binding StampNames}" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
|
<GroupBox Grid.Row="2"
|
||||||
|
Margin="0,12,0,0"
|
||||||
|
Header="Персонал организации/подразделения (PRFR)">
|
||||||
|
<DataGrid ItemsSource="{Binding PrfrItems}"
|
||||||
|
SelectedItem="{Binding SelectedPrfr, Mode=TwoWay}"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
CanUserAddRows="False"
|
||||||
|
IsReadOnly="True"
|
||||||
|
HeadersVisibility="Column">
|
||||||
|
<DataGrid.ContextMenu>
|
||||||
|
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||||
|
<MenuItem Header="Добавить"
|
||||||
|
Command="{Binding AddPrfrCommand}" />
|
||||||
|
<MenuItem Header="Изменить"
|
||||||
|
Command="{Binding EditPrfrCommand}" />
|
||||||
|
<MenuItem Header="Удалить"
|
||||||
|
Command="{Binding DeletePrfrCommand}" />
|
||||||
|
</ContextMenu>
|
||||||
|
</DataGrid.ContextMenu>
|
||||||
|
<DataGrid.RowStyle>
|
||||||
|
<Style TargetType="DataGridRow">
|
||||||
|
<EventSetter Event="PreviewMouseRightButtonDown"
|
||||||
|
Handler="DataGridRow_PreviewMouseRightButtonDown" />
|
||||||
|
</Style>
|
||||||
|
</DataGrid.RowStyle>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="ID" Width="80" Binding="{Binding EmploymentId}" />
|
||||||
|
<DataGridTextColumn Header="Организация" Width="*" Binding="{Binding OrganizationName}" />
|
||||||
|
<DataGridTextColumn Header="Должность" Width="220" Binding="{Binding PositionName}" />
|
||||||
|
<DataGridTextColumn Header="Дата приёма" Width="120" Binding="{Binding HireDate, StringFormat=d}" />
|
||||||
|
<DataGridTextColumn Header="Дата увольнения" Width="130" Binding="{Binding DismissalDate, StringFormat=d}" />
|
||||||
|
<DataGridTextColumn Header="Таб. №" Width="110" Binding="{Binding PersonnelNumber}" />
|
||||||
|
<DataGridTextColumn Header="Виды деятельности" Width="220" Binding="{Binding ActivityNames}" />
|
||||||
|
<DataGridTextColumn Header="Клейма" Width="240" Binding="{Binding StampNames}" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
|
<Grid Grid.Row="3"
|
||||||
|
Margin="0,12,0,0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="12" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<GroupBox Grid.Column="0"
|
||||||
|
Header="Вид деятельности персоны (PRFRVD)">
|
||||||
|
<DataGrid ItemsSource="{Binding PrfrvdItems}"
|
||||||
|
SelectedItem="{Binding SelectedPrfrvd, Mode=TwoWay}"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
CanUserAddRows="False"
|
||||||
|
IsReadOnly="True"
|
||||||
|
HeadersVisibility="Column">
|
||||||
|
<DataGrid.ContextMenu>
|
||||||
|
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||||
|
<MenuItem Header="Добавить"
|
||||||
|
Command="{Binding AddPrfrvdCommand}" />
|
||||||
|
<MenuItem Header="Изменить"
|
||||||
|
Command="{Binding EditPrfrvdCommand}" />
|
||||||
|
<MenuItem Header="Удалить"
|
||||||
|
Command="{Binding DeletePrfrvdCommand}" />
|
||||||
|
</ContextMenu>
|
||||||
|
</DataGrid.ContextMenu>
|
||||||
|
<DataGrid.RowStyle>
|
||||||
|
<Style TargetType="DataGridRow">
|
||||||
|
<EventSetter Event="PreviewMouseRightButtonDown"
|
||||||
|
Handler="DataGridRow_PreviewMouseRightButtonDown" />
|
||||||
|
</Style>
|
||||||
|
</DataGrid.RowStyle>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="ID" Width="90" Binding="{Binding Id}" />
|
||||||
|
<DataGridTextColumn Header="Вид деятельности" Width="*" Binding="{Binding ActivityName}" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</GroupBox>
|
||||||
|
|
||||||
|
<GroupBox Grid.Column="2"
|
||||||
|
Header="Дополнительные сведения о поверителе/калибровщике (PRDSPV)">
|
||||||
|
<DataGrid ItemsSource="{Binding PrdspvItems}"
|
||||||
|
SelectedItem="{Binding SelectedPrdspv, Mode=TwoWay}"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
CanUserAddRows="False"
|
||||||
|
IsReadOnly="True"
|
||||||
|
HeadersVisibility="Column">
|
||||||
|
<DataGrid.ContextMenu>
|
||||||
|
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||||
|
<MenuItem Header="Добавить"
|
||||||
|
Command="{Binding AddPrdspvCommand}" />
|
||||||
|
<MenuItem Header="Изменить"
|
||||||
|
Command="{Binding EditPrdspvCommand}" />
|
||||||
|
<MenuItem Header="Удалить"
|
||||||
|
Command="{Binding DeletePrdspvCommand}" />
|
||||||
|
</ContextMenu>
|
||||||
|
</DataGrid.ContextMenu>
|
||||||
|
<DataGrid.RowStyle>
|
||||||
|
<Style TargetType="DataGridRow">
|
||||||
|
<EventSetter Event="PreviewMouseRightButtonDown"
|
||||||
|
Handler="DataGridRow_PreviewMouseRightButtonDown" />
|
||||||
|
</Style>
|
||||||
|
</DataGrid.RowStyle>
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="ID" Width="90" Binding="{Binding Id}" />
|
||||||
|
<DataGridTextColumn Header="Вид клейма" Width="180" Binding="{Binding StampTypeName}" />
|
||||||
|
<DataGridTextColumn Header="Шифр клейма" Width="140" Binding="{Binding StampCode}" />
|
||||||
|
<DataGridTextColumn Header="Дата получения" Width="130" Binding="{Binding ReceivedOn, StringFormat=d}" />
|
||||||
|
<DataGridTextColumn Header="Доп. сведения" Width="*" Binding="{Binding Notes}" />
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</GroupBox>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="4"
|
||||||
|
Margin="0,8,0,0"
|
||||||
|
Foreground="DimGray"
|
||||||
|
Text="{Binding StatusText}" />
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="5"
|
||||||
|
Margin="0,12,0,0"
|
||||||
|
Orientation="Horizontal"
|
||||||
|
HorizontalAlignment="Right">
|
||||||
|
<Button Width="90"
|
||||||
|
IsCancel="True"
|
||||||
|
Content="Закрыть" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
33
XLAB/PrsnDirectoryWindow.xaml.cs
Normal file
33
XLAB/PrsnDirectoryWindow.xaml.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
public partial class PrsnDirectoryWindow : Window
|
||||||
|
{
|
||||||
|
private readonly PrsnDirectoryWindowViewModel _viewModel;
|
||||||
|
|
||||||
|
public PrsnDirectoryWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
_viewModel = new PrsnDirectoryWindowViewModel(new PrsnDirectoryService(), new PrsnDirectoryDialogService(this));
|
||||||
|
DataContext = _viewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DataGridRow_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
var row = sender as DataGridRow;
|
||||||
|
if (row != null)
|
||||||
|
{
|
||||||
|
row.IsSelected = true;
|
||||||
|
row.Focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
await _viewModel.InitializeAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
790
XLAB/PrsnDirectoryWindowViewModel.cs
Normal file
790
XLAB/PrsnDirectoryWindowViewModel.cs
Normal file
@@ -0,0 +1,790 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
internal sealed class PrsnDirectoryWindowViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
private readonly IPrsnDirectoryDialogService _dialogService;
|
||||||
|
private readonly PrsnDirectoryService _service;
|
||||||
|
private bool _isBusy;
|
||||||
|
private List<PrsnDirectoryItem> _prsnCache;
|
||||||
|
private string _searchText;
|
||||||
|
private PrdspvDirectoryItem _selectedPrdspv;
|
||||||
|
private PrfrDirectoryItem _selectedPrfr;
|
||||||
|
private PrfrvdDirectoryItem _selectedPrfrvd;
|
||||||
|
private PrsnDirectoryItem _selectedPrsn;
|
||||||
|
private string _statusText;
|
||||||
|
|
||||||
|
public PrsnDirectoryWindowViewModel(PrsnDirectoryService service, IPrsnDirectoryDialogService dialogService)
|
||||||
|
{
|
||||||
|
_service = service;
|
||||||
|
_dialogService = dialogService;
|
||||||
|
_prsnCache = new List<PrsnDirectoryItem>();
|
||||||
|
|
||||||
|
PrsnItems = new ObservableCollection<PrsnDirectoryItem>();
|
||||||
|
PrfrItems = new ObservableCollection<PrfrDirectoryItem>();
|
||||||
|
PrfrvdItems = new ObservableCollection<PrfrvdDirectoryItem>();
|
||||||
|
PrdspvItems = new ObservableCollection<PrdspvDirectoryItem>();
|
||||||
|
|
||||||
|
AddPrsnCommand = new RelayCommand(delegate { AddPrsnAsync(); }, delegate { return !IsBusy; });
|
||||||
|
EditPrsnCommand = new RelayCommand(delegate { EditPrsnAsync(); }, delegate { return !IsBusy && SelectedPrsn != null; });
|
||||||
|
DeletePrsnCommand = new RelayCommand(delegate { DeletePrsnAsync(); }, delegate { return !IsBusy && SelectedPrsn != null; });
|
||||||
|
AddPrfrCommand = new RelayCommand(delegate { AddPrfrAsync(); }, delegate { return !IsBusy && SelectedPrsn != null; });
|
||||||
|
EditPrfrCommand = new RelayCommand(delegate { EditPrfrAsync(); }, delegate { return !IsBusy && SelectedPrfr != null; });
|
||||||
|
DeletePrfrCommand = new RelayCommand(delegate { DeletePrfrAsync(); }, delegate { return !IsBusy && SelectedPrfr != null; });
|
||||||
|
AddPrfrvdCommand = new RelayCommand(delegate { AddPrfrvdAsync(); }, delegate { return !IsBusy && SelectedPrfr != null; });
|
||||||
|
EditPrfrvdCommand = new RelayCommand(delegate { EditPrfrvdAsync(); }, delegate { return !IsBusy && SelectedPrfrvd != null; });
|
||||||
|
DeletePrfrvdCommand = new RelayCommand(delegate { DeletePrfrvdAsync(); }, delegate { return !IsBusy && SelectedPrfrvd != null; });
|
||||||
|
AddPrdspvCommand = new RelayCommand(delegate { AddPrdspvAsync(); }, delegate { return !IsBusy && SelectedPrfr != null; });
|
||||||
|
EditPrdspvCommand = new RelayCommand(delegate { EditPrdspvAsync(); }, delegate { return !IsBusy && SelectedPrdspv != null; });
|
||||||
|
DeletePrdspvCommand = new RelayCommand(delegate { DeletePrdspvAsync(); }, delegate { return !IsBusy && SelectedPrdspv != null; });
|
||||||
|
RefreshCommand = new RelayCommand(delegate { RefreshAsync(); }, delegate { return !IsBusy; });
|
||||||
|
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICommand AddPrdspvCommand { get; private set; }
|
||||||
|
public ICommand AddPrfrCommand { get; private set; }
|
||||||
|
public ICommand AddPrfrvdCommand { get; private set; }
|
||||||
|
public ICommand AddPrsnCommand { get; private set; }
|
||||||
|
public ICommand DeletePrdspvCommand { get; private set; }
|
||||||
|
public ICommand DeletePrfrCommand { get; private set; }
|
||||||
|
public ICommand DeletePrfrvdCommand { get; private set; }
|
||||||
|
public ICommand DeletePrsnCommand { get; private set; }
|
||||||
|
public ICommand EditPrdspvCommand { get; private set; }
|
||||||
|
public ICommand EditPrfrCommand { get; private set; }
|
||||||
|
public ICommand EditPrfrvdCommand { get; private set; }
|
||||||
|
public ICommand EditPrsnCommand { get; private set; }
|
||||||
|
public ObservableCollection<PrdspvDirectoryItem> PrdspvItems { get; private set; }
|
||||||
|
public ObservableCollection<PrfrDirectoryItem> PrfrItems { get; private set; }
|
||||||
|
public ObservableCollection<PrfrvdDirectoryItem> PrfrvdItems { get; private set; }
|
||||||
|
public ObservableCollection<PrsnDirectoryItem> PrsnItems { get; private set; }
|
||||||
|
public ICommand RefreshCommand { get; private set; }
|
||||||
|
|
||||||
|
public bool IsBusy
|
||||||
|
{
|
||||||
|
get { return _isBusy; }
|
||||||
|
private set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _isBusy, value))
|
||||||
|
{
|
||||||
|
RaiseCommandStates();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SearchText
|
||||||
|
{
|
||||||
|
get { return _searchText; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _searchText, value))
|
||||||
|
{
|
||||||
|
ApplySearchFilter();
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrdspvDirectoryItem SelectedPrdspv
|
||||||
|
{
|
||||||
|
get { return _selectedPrdspv; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _selectedPrdspv, value))
|
||||||
|
{
|
||||||
|
RaiseCommandStates();
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrfrDirectoryItem SelectedPrfr
|
||||||
|
{
|
||||||
|
get { return _selectedPrfr; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _selectedPrfr, value))
|
||||||
|
{
|
||||||
|
RaiseCommandStates();
|
||||||
|
LoadLeafTablesForSelection();
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrfrvdDirectoryItem SelectedPrfrvd
|
||||||
|
{
|
||||||
|
get { return _selectedPrfrvd; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _selectedPrfrvd, value))
|
||||||
|
{
|
||||||
|
RaiseCommandStates();
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrsnDirectoryItem SelectedPrsn
|
||||||
|
{
|
||||||
|
get { return _selectedPrsn; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _selectedPrsn, value))
|
||||||
|
{
|
||||||
|
RaiseCommandStates();
|
||||||
|
LoadPrfrForSelection();
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string StatusText
|
||||||
|
{
|
||||||
|
get { return _statusText; }
|
||||||
|
private set { SetProperty(ref _statusText, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task InitializeAsync()
|
||||||
|
{
|
||||||
|
await ExecuteBusyOperationAsync(async delegate { await RefreshPrsnCoreAsync(null, null, null, null); });
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddPrdspvAsync()
|
||||||
|
{
|
||||||
|
if (SelectedPrfr == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = _dialogService.ShowPrdspvEditDialog(new PrdspvDirectoryItem { EmploymentId = SelectedPrfr.EmploymentId }, true, PrdspvItems.ToList(), _service);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
var createdId = await Task.Run(delegate { return _service.AddPrdspvItem(result); });
|
||||||
|
await RefreshPrsnCoreAsync(SelectedPrsn == null ? (int?)null : SelectedPrsn.Id, result.EmploymentId, SelectedPrfrvd == null ? (int?)null : SelectedPrfrvd.Id, createdId);
|
||||||
|
_dialogService.ShowInfo("Запись PRDSPV добавлена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddPrfrAsync()
|
||||||
|
{
|
||||||
|
if (SelectedPrsn == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = _dialogService.ShowPrfrEditDialog(new PrfrDirectoryItem { PersonId = SelectedPrsn.Id }, true, PrfrItems.ToList(), _service);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
var createdId = await Task.Run(delegate { return _service.AddPrfrItem(result); });
|
||||||
|
await RefreshPrsnCoreAsync(result.PersonId, createdId, null, null);
|
||||||
|
_dialogService.ShowInfo("Запись PRFR добавлена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddPrfrvdAsync()
|
||||||
|
{
|
||||||
|
if (SelectedPrfr == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = _dialogService.ShowPrfrvdEditDialog(new PrfrvdDirectoryItem { EmploymentId = SelectedPrfr.EmploymentId }, true, PrfrvdItems.ToList(), _service);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
var createdId = await Task.Run(delegate { return _service.AddPrfrvdItem(result); });
|
||||||
|
await RefreshPrsnCoreAsync(SelectedPrsn == null ? (int?)null : SelectedPrsn.Id, result.EmploymentId, createdId, SelectedPrdspv == null ? (int?)null : SelectedPrdspv.Id);
|
||||||
|
_dialogService.ShowInfo("Запись PRFRVD добавлена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddPrsnAsync()
|
||||||
|
{
|
||||||
|
var result = _dialogService.ShowPrsnEditDialog(new PrsnDirectoryItem(), true, _prsnCache.ToList());
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
var createdId = await Task.Run(delegate { return _service.AddPrsnItem(result); });
|
||||||
|
await RefreshPrsnCoreAsync(createdId, null, null, null);
|
||||||
|
_dialogService.ShowInfo("Запись PRSN добавлена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyPrsnFilter(int? preferredId)
|
||||||
|
{
|
||||||
|
var filteredItems = _prsnCache.Where(delegate(PrsnDirectoryItem item) { return MatchesSearch(item); }).ToList();
|
||||||
|
PrsnItems.Clear();
|
||||||
|
foreach (var item in filteredItems)
|
||||||
|
{
|
||||||
|
PrsnItems.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedPrsn = preferredId.HasValue
|
||||||
|
? PrsnItems.FirstOrDefault(delegate(PrsnDirectoryItem item) { return item.Id == preferredId.Value; })
|
||||||
|
: PrsnItems.FirstOrDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplySearchFilter()
|
||||||
|
{
|
||||||
|
if (!IsBusy)
|
||||||
|
{
|
||||||
|
ApplyPrsnFilter(SelectedPrsn == null ? (int?)null : SelectedPrsn.Id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PrdspvDirectoryItem ClonePrdspv(PrdspvDirectoryItem source)
|
||||||
|
{
|
||||||
|
return new PrdspvDirectoryItem
|
||||||
|
{
|
||||||
|
EmploymentId = source.EmploymentId,
|
||||||
|
Id = source.Id,
|
||||||
|
Notes = source.Notes,
|
||||||
|
ReceivedOn = source.ReceivedOn,
|
||||||
|
StampCode = source.StampCode,
|
||||||
|
StampTypeId = source.StampTypeId,
|
||||||
|
StampTypeName = source.StampTypeName
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PrfrDirectoryItem ClonePrfr(PrfrDirectoryItem source)
|
||||||
|
{
|
||||||
|
return new PrfrDirectoryItem
|
||||||
|
{
|
||||||
|
DismissalDate = source.DismissalDate,
|
||||||
|
EmploymentId = source.EmploymentId,
|
||||||
|
Guid = source.Guid,
|
||||||
|
HireDate = source.HireDate,
|
||||||
|
IsPinAuth = source.IsPinAuth,
|
||||||
|
LastVacationEndDate = source.LastVacationEndDate,
|
||||||
|
LastVacationStartDate = source.LastVacationStartDate,
|
||||||
|
NextVacationEndDate = source.NextVacationEndDate,
|
||||||
|
NextVacationStartDate = source.NextVacationStartDate,
|
||||||
|
OrganizationId = source.OrganizationId,
|
||||||
|
OrganizationName = source.OrganizationName,
|
||||||
|
PersonId = source.PersonId,
|
||||||
|
PersonnelNumber = source.PersonnelNumber,
|
||||||
|
PinChangedAt = source.PinChangedAt,
|
||||||
|
PinHash = source.PinHash,
|
||||||
|
PositionId = source.PositionId,
|
||||||
|
PositionName = source.PositionName,
|
||||||
|
PositionStartDate = source.PositionStartDate,
|
||||||
|
QualificationPlanDate = source.QualificationPlanDate
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PrfrvdDirectoryItem ClonePrfrvd(PrfrvdDirectoryItem source)
|
||||||
|
{
|
||||||
|
return new PrfrvdDirectoryItem
|
||||||
|
{
|
||||||
|
ActivityId = source.ActivityId,
|
||||||
|
ActivityName = source.ActivityName,
|
||||||
|
EmploymentId = source.EmploymentId,
|
||||||
|
Id = source.Id
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private static PrsnDirectoryItem ClonePrsn(PrsnDirectoryItem source)
|
||||||
|
{
|
||||||
|
return new PrsnDirectoryItem
|
||||||
|
{
|
||||||
|
Email = source.Email,
|
||||||
|
ExternalId = source.ExternalId,
|
||||||
|
FirstName = source.FirstName,
|
||||||
|
FullName = source.FullName,
|
||||||
|
Guid = source.Guid,
|
||||||
|
Id = source.Id,
|
||||||
|
LastName = source.LastName,
|
||||||
|
Notes = source.Notes,
|
||||||
|
Patronymic = source.Patronymic,
|
||||||
|
Phone = source.Phone
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeletePrdspvAsync()
|
||||||
|
{
|
||||||
|
if (SelectedPrdspv == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selected = SelectedPrdspv;
|
||||||
|
if (!_dialogService.Confirm(string.Format("Удалить клеймо \"{0}\"?", selected.StampCode)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
var result = await Task.Run(delegate { return _service.DeletePrdspvItem(selected.Id); });
|
||||||
|
if (!result.IsDeleted)
|
||||||
|
{
|
||||||
|
_dialogService.ShowWarning(result.WarningMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await RefreshPrsnCoreAsync(SelectedPrsn == null ? (int?)null : SelectedPrsn.Id, selected.EmploymentId, SelectedPrfrvd == null ? (int?)null : SelectedPrfrvd.Id, null);
|
||||||
|
_dialogService.ShowInfo("Запись PRDSPV удалена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeletePrfrAsync()
|
||||||
|
{
|
||||||
|
if (SelectedPrfr == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selected = SelectedPrfr;
|
||||||
|
if (!_dialogService.Confirm(string.Format("Удалить запись персонала в организации \"{0}\"?", selected.OrganizationName)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
var result = await Task.Run(delegate { return _service.DeletePrfrItem(selected.EmploymentId); });
|
||||||
|
if (!result.IsDeleted)
|
||||||
|
{
|
||||||
|
_dialogService.ShowWarning(result.WarningMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await RefreshPrsnCoreAsync(selected.PersonId, null, null, null);
|
||||||
|
_dialogService.ShowInfo("Запись PRFR удалена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeletePrfrvdAsync()
|
||||||
|
{
|
||||||
|
if (SelectedPrfrvd == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selected = SelectedPrfrvd;
|
||||||
|
if (!_dialogService.Confirm(string.Format("Удалить вид деятельности \"{0}\"?", selected.ActivityName)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
var result = await Task.Run(delegate { return _service.DeletePrfrvdItem(selected.Id); });
|
||||||
|
if (!result.IsDeleted)
|
||||||
|
{
|
||||||
|
_dialogService.ShowWarning(result.WarningMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await RefreshPrsnCoreAsync(SelectedPrsn == null ? (int?)null : SelectedPrsn.Id, selected.EmploymentId, null, SelectedPrdspv == null ? (int?)null : SelectedPrdspv.Id);
|
||||||
|
_dialogService.ShowInfo("Запись PRFRVD удалена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeletePrsnAsync()
|
||||||
|
{
|
||||||
|
if (SelectedPrsn == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selected = SelectedPrsn;
|
||||||
|
if (!_dialogService.Confirm(string.Format("Удалить персону \"{0}\"?", selected.FullName)))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
var result = await Task.Run(delegate { return _service.DeletePrsnItem(selected.Id); });
|
||||||
|
if (!result.IsDeleted)
|
||||||
|
{
|
||||||
|
_dialogService.ShowWarning(result.WarningMessage);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await RefreshPrsnCoreAsync(null, null, null, null);
|
||||||
|
_dialogService.ShowInfo("Запись PRSN удалена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteBusyOperationAsync(Func<Task> operation)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IsBusy = true;
|
||||||
|
await operation();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_dialogService.ShowError(ex.Message);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteMutationOperationAsync(Func<Task> operation)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IsBusy = true;
|
||||||
|
await operation();
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException ex)
|
||||||
|
{
|
||||||
|
_dialogService.ShowWarning(ex.Message);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_dialogService.ShowError(ex.Message);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EditPrdspvAsync()
|
||||||
|
{
|
||||||
|
if (SelectedPrdspv == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = _dialogService.ShowPrdspvEditDialog(ClonePrdspv(SelectedPrdspv), false, PrdspvItems.ToList(), _service);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
await Task.Run(delegate { _service.UpdatePrdspvItem(result); });
|
||||||
|
await RefreshPrsnCoreAsync(SelectedPrsn == null ? (int?)null : SelectedPrsn.Id, result.EmploymentId, SelectedPrfrvd == null ? (int?)null : SelectedPrfrvd.Id, result.Id);
|
||||||
|
_dialogService.ShowInfo("Запись PRDSPV обновлена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EditPrfrAsync()
|
||||||
|
{
|
||||||
|
if (SelectedPrfr == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = _dialogService.ShowPrfrEditDialog(ClonePrfr(SelectedPrfr), false, PrfrItems.ToList(), _service);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
await Task.Run(delegate { _service.UpdatePrfrItem(result); });
|
||||||
|
await RefreshPrsnCoreAsync(result.PersonId, result.EmploymentId, SelectedPrfrvd == null ? (int?)null : SelectedPrfrvd.Id, SelectedPrdspv == null ? (int?)null : SelectedPrdspv.Id);
|
||||||
|
_dialogService.ShowInfo("Запись PRFR обновлена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EditPrfrvdAsync()
|
||||||
|
{
|
||||||
|
if (SelectedPrfrvd == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = _dialogService.ShowPrfrvdEditDialog(ClonePrfrvd(SelectedPrfrvd), false, PrfrvdItems.ToList(), _service);
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
await Task.Run(delegate { _service.UpdatePrfrvdItem(result); });
|
||||||
|
await RefreshPrsnCoreAsync(SelectedPrsn == null ? (int?)null : SelectedPrsn.Id, result.EmploymentId, result.Id, SelectedPrdspv == null ? (int?)null : SelectedPrdspv.Id);
|
||||||
|
_dialogService.ShowInfo("Запись PRFRVD обновлена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EditPrsnAsync()
|
||||||
|
{
|
||||||
|
if (SelectedPrsn == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var result = _dialogService.ShowPrsnEditDialog(ClonePrsn(SelectedPrsn), false, _prsnCache.ToList());
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RunMutationOperation(async delegate
|
||||||
|
{
|
||||||
|
await Task.Run(delegate { _service.UpdatePrsnItem(result); });
|
||||||
|
await RefreshPrsnCoreAsync(result.Id, SelectedPrfr == null ? (int?)null : SelectedPrfr.EmploymentId, SelectedPrfrvd == null ? (int?)null : SelectedPrfrvd.Id, SelectedPrdspv == null ? (int?)null : SelectedPrdspv.Id);
|
||||||
|
_dialogService.ShowInfo("Запись PRSN обновлена.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private string[] GetSearchTokens()
|
||||||
|
{
|
||||||
|
return (SearchText ?? string.Empty)
|
||||||
|
.Split(new[] { ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
|
.Select(delegate(string token) { return token.Trim().ToUpperInvariant(); })
|
||||||
|
.Where(delegate(string token) { return token.Length > 0; })
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadLeafTablesForSelection()
|
||||||
|
{
|
||||||
|
if (!IsBusy)
|
||||||
|
{
|
||||||
|
RunBusyOperation(async delegate
|
||||||
|
{
|
||||||
|
if (SelectedPrfr == null)
|
||||||
|
{
|
||||||
|
PrfrvdItems.Clear();
|
||||||
|
PrdspvItems.Clear();
|
||||||
|
SelectedPrfrvd = null;
|
||||||
|
SelectedPrdspv = null;
|
||||||
|
UpdateStatus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await RefreshLeafTablesCoreAsync(SelectedPrfr.EmploymentId, null, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadPrfrForSelection()
|
||||||
|
{
|
||||||
|
if (!IsBusy)
|
||||||
|
{
|
||||||
|
RunBusyOperation(async delegate
|
||||||
|
{
|
||||||
|
if (SelectedPrsn == null)
|
||||||
|
{
|
||||||
|
PrfrItems.Clear();
|
||||||
|
PrfrvdItems.Clear();
|
||||||
|
PrdspvItems.Clear();
|
||||||
|
SelectedPrfr = null;
|
||||||
|
SelectedPrfrvd = null;
|
||||||
|
SelectedPrdspv = null;
|
||||||
|
UpdateStatus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await RefreshPrfrCoreAsync(SelectedPrsn.Id, null, null, null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool MatchesSearch(PrsnDirectoryItem item)
|
||||||
|
{
|
||||||
|
if (item == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tokens = GetSearchTokens();
|
||||||
|
if (tokens.Length == 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var haystack = string.Join(
|
||||||
|
" ",
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
item.Id.ToString(),
|
||||||
|
item.FullName,
|
||||||
|
item.LastName,
|
||||||
|
item.FirstName,
|
||||||
|
item.Patronymic,
|
||||||
|
item.Phone,
|
||||||
|
item.Email,
|
||||||
|
item.ExternalId,
|
||||||
|
item.Guid,
|
||||||
|
item.OrganizationNames,
|
||||||
|
item.ActivityNames,
|
||||||
|
item.StampNames,
|
||||||
|
item.Notes
|
||||||
|
}
|
||||||
|
.Where(delegate(string value) { return !string.IsNullOrWhiteSpace(value); }))
|
||||||
|
.ToUpperInvariant();
|
||||||
|
return tokens.All(delegate(string token) { return haystack.IndexOf(token, StringComparison.Ordinal) >= 0; });
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RefreshLeafTablesCoreAsync(int employmentId, int? prfrvdIdToSelect, int? prdspvIdToSelect)
|
||||||
|
{
|
||||||
|
var prfrvdTask = Task.Run(delegate { return _service.LoadPrfrvdItems(employmentId); });
|
||||||
|
var prdspvTask = Task.Run(delegate { return _service.LoadPrdspvItems(employmentId); });
|
||||||
|
await Task.WhenAll(prfrvdTask, prdspvTask);
|
||||||
|
|
||||||
|
PrfrvdItems.Clear();
|
||||||
|
foreach (var item in prfrvdTask.Result)
|
||||||
|
{
|
||||||
|
PrfrvdItems.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrdspvItems.Clear();
|
||||||
|
foreach (var item in prdspvTask.Result)
|
||||||
|
{
|
||||||
|
PrdspvItems.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedPrfrvd = prfrvdIdToSelect.HasValue
|
||||||
|
? PrfrvdItems.FirstOrDefault(delegate(PrfrvdDirectoryItem item) { return item.Id == prfrvdIdToSelect.Value; })
|
||||||
|
: PrfrvdItems.FirstOrDefault();
|
||||||
|
SelectedPrdspv = prdspvIdToSelect.HasValue
|
||||||
|
? PrdspvItems.FirstOrDefault(delegate(PrdspvDirectoryItem item) { return item.Id == prdspvIdToSelect.Value; })
|
||||||
|
: PrdspvItems.FirstOrDefault();
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RefreshPrfrCoreAsync(int personId, int? prfrIdToSelect, int? prfrvdIdToSelect, int? prdspvIdToSelect)
|
||||||
|
{
|
||||||
|
var items = await Task.Run(delegate { return _service.LoadPrfrItems(personId); });
|
||||||
|
PrfrItems.Clear();
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
PrfrItems.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
SelectedPrfr = prfrIdToSelect.HasValue
|
||||||
|
? PrfrItems.FirstOrDefault(delegate(PrfrDirectoryItem item) { return item.EmploymentId == prfrIdToSelect.Value; })
|
||||||
|
: PrfrItems.FirstOrDefault();
|
||||||
|
if (SelectedPrfr == null)
|
||||||
|
{
|
||||||
|
PrfrvdItems.Clear();
|
||||||
|
PrdspvItems.Clear();
|
||||||
|
SelectedPrfrvd = null;
|
||||||
|
SelectedPrdspv = null;
|
||||||
|
UpdateStatus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await RefreshLeafTablesCoreAsync(SelectedPrfr.EmploymentId, prfrvdIdToSelect, prdspvIdToSelect);
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task RefreshPrsnCoreAsync(int? prsnIdToSelect, int? prfrIdToSelect, int? prfrvdIdToSelect, int? prdspvIdToSelect)
|
||||||
|
{
|
||||||
|
var currentPrsnId = SelectedPrsn == null ? (int?)null : SelectedPrsn.Id;
|
||||||
|
_prsnCache = (await Task.Run(delegate { return _service.LoadPrsnItems(); })).ToList();
|
||||||
|
|
||||||
|
ApplyPrsnFilter(prsnIdToSelect.HasValue ? prsnIdToSelect : currentPrsnId);
|
||||||
|
if (SelectedPrsn == null)
|
||||||
|
{
|
||||||
|
PrfrItems.Clear();
|
||||||
|
PrfrvdItems.Clear();
|
||||||
|
PrdspvItems.Clear();
|
||||||
|
SelectedPrfr = null;
|
||||||
|
SelectedPrfrvd = null;
|
||||||
|
SelectedPrdspv = null;
|
||||||
|
UpdateStatus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await RefreshPrfrCoreAsync(SelectedPrsn.Id, prfrIdToSelect, prfrvdIdToSelect, prdspvIdToSelect);
|
||||||
|
UpdateStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaiseCommandStates()
|
||||||
|
{
|
||||||
|
((RelayCommand)AddPrsnCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)EditPrsnCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)DeletePrsnCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)AddPrfrCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)EditPrfrCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)DeletePrfrCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)AddPrfrvdCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)EditPrfrvdCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)DeletePrfrvdCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)AddPrdspvCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)EditPrdspvCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)DeletePrdspvCommand).RaiseCanExecuteChanged();
|
||||||
|
((RelayCommand)RefreshCommand).RaiseCanExecuteChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshAsync()
|
||||||
|
{
|
||||||
|
RunBusyOperation(async delegate
|
||||||
|
{
|
||||||
|
await RefreshPrsnCoreAsync(
|
||||||
|
SelectedPrsn == null ? (int?)null : SelectedPrsn.Id,
|
||||||
|
SelectedPrfr == null ? (int?)null : SelectedPrfr.EmploymentId,
|
||||||
|
SelectedPrfrvd == null ? (int?)null : SelectedPrfrvd.Id,
|
||||||
|
SelectedPrdspv == null ? (int?)null : SelectedPrdspv.Id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void RunBusyOperation(Func<Task> operation)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ExecuteBusyOperationAsync(operation);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
_dialogService.ShowError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void RunMutationOperation(Func<Task> operation)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await ExecuteMutationOperationAsync(operation);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
IsBusy = false;
|
||||||
|
_dialogService.ShowError(ex.Message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateStatus()
|
||||||
|
{
|
||||||
|
var searchText = string.IsNullOrWhiteSpace(SearchText) ? null : SearchText.Trim();
|
||||||
|
StatusText = string.Format(
|
||||||
|
"{0}PRSN: {1}/{2}. PRFR: {3}. PRFRVD: {4}. PRDSPV: {5}.",
|
||||||
|
string.IsNullOrWhiteSpace(searchText) ? string.Empty : string.Format("Поиск: \"{0}\". ", searchText),
|
||||||
|
PrsnItems.Count,
|
||||||
|
_prsnCache.Count,
|
||||||
|
PrfrItems.Count,
|
||||||
|
PrfrvdItems.Count,
|
||||||
|
PrdspvItems.Count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
69
XLAB/PrsnEditWindow.xaml
Normal file
69
XLAB/PrsnEditWindow.xaml
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
<Window x:Class="XLAB.PrsnEditWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
Title="{Binding Title}"
|
||||||
|
Height="470"
|
||||||
|
Width="720"
|
||||||
|
MinHeight="440"
|
||||||
|
MinWidth="660"
|
||||||
|
WindowStartupLocation="CenterOwner">
|
||||||
|
<Grid Margin="16">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid Grid.Row="0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="180" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="0" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="ФИО" />
|
||||||
|
<TextBox Grid.Row="0" Grid.Column="1" Margin="0,0,0,8" Text="{Binding FullName, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Фамилия" />
|
||||||
|
<TextBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,8" Text="{Binding LastName, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="2" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Имя" />
|
||||||
|
<TextBox Grid.Row="2" Grid.Column="1" Margin="0,0,0,8" Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="3" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Отчество" />
|
||||||
|
<TextBox Grid.Row="3" Grid.Column="1" Margin="0,0,0,8" Text="{Binding Patronymic, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="4" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="Телефон" />
|
||||||
|
<TextBox Grid.Row="4" Grid.Column="1" Margin="0,0,0,8" Text="{Binding Phone, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="5" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="E-mail" />
|
||||||
|
<TextBox Grid.Row="5" Grid.Column="1" Margin="0,0,0,8" Text="{Binding Email, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="6" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Center" Text="GUID персоны" />
|
||||||
|
<TextBox Grid.Row="6" Grid.Column="1" Margin="0,0,0,8" Text="{Binding Guid, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="7" Grid.Column="0" Margin="0,0,12,8" VerticalAlignment="Top" Text="Доп. сведения" />
|
||||||
|
<TextBox Grid.Row="7" Grid.Column="1" Margin="0,0,0,8" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" Text="{Binding Notes, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="8" Grid.Column="0" Margin="0,0,12,0" VerticalAlignment="Center" Text="Доп. идентификатор" />
|
||||||
|
<TextBox Grid.Row="8" Grid.Column="1" Text="{Binding ExternalId, UpdateSourceTrigger=PropertyChanged}" />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1" Margin="0,12,0,0" Foreground="Firebrick" Text="{Binding ValidationMessage}" />
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="2" Margin="0,12,0,0" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
|
<Button Width="100" Margin="0,0,8,0" IsDefault="True" Command="{Binding ConfirmCommand}" Content="Сохранить" />
|
||||||
|
<Button Width="90" Command="{Binding CancelCommand}" Content="Отмена" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
20
XLAB/PrsnEditWindow.xaml.cs
Normal file
20
XLAB/PrsnEditWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
public partial class PrsnEditWindow : Window
|
||||||
|
{
|
||||||
|
internal PrsnEditWindow(PrsnEditWindowViewModel viewModel)
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContext = viewModel;
|
||||||
|
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||||
|
{
|
||||||
|
DialogResult = dialogResult;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
237
XLAB/PrsnEditWindowViewModel.cs
Normal file
237
XLAB/PrsnEditWindowViewModel.cs
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Input;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
internal sealed class PrsnEditWindowViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
private readonly IReadOnlyList<PrsnDirectoryItem> _existingItems;
|
||||||
|
private string _email;
|
||||||
|
private string _externalId;
|
||||||
|
private string _firstName;
|
||||||
|
private string _fullName;
|
||||||
|
private string _guid;
|
||||||
|
private string _lastName;
|
||||||
|
private string _notes;
|
||||||
|
private string _patronymic;
|
||||||
|
private string _phone;
|
||||||
|
private string _validationMessage;
|
||||||
|
|
||||||
|
public PrsnEditWindowViewModel(PrsnDirectoryItem seed, bool isNew, IReadOnlyList<PrsnDirectoryItem> existingItems)
|
||||||
|
{
|
||||||
|
var source = seed ?? new PrsnDirectoryItem();
|
||||||
|
_existingItems = existingItems ?? Array.Empty<PrsnDirectoryItem>();
|
||||||
|
Id = source.Id;
|
||||||
|
IsNew = isNew;
|
||||||
|
|
||||||
|
FullName = source.FullName ?? string.Empty;
|
||||||
|
LastName = source.LastName ?? string.Empty;
|
||||||
|
FirstName = source.FirstName ?? string.Empty;
|
||||||
|
Patronymic = source.Patronymic ?? string.Empty;
|
||||||
|
Phone = source.Phone ?? string.Empty;
|
||||||
|
Email = source.Email ?? string.Empty;
|
||||||
|
Notes = source.Notes ?? string.Empty;
|
||||||
|
Guid = source.Guid ?? string.Empty;
|
||||||
|
ExternalId = source.ExternalId ?? string.Empty;
|
||||||
|
|
||||||
|
ConfirmCommand = new RelayCommand(Confirm);
|
||||||
|
CancelCommand = new RelayCommand(Cancel);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<bool?> CloseRequested;
|
||||||
|
|
||||||
|
public ICommand CancelCommand { get; private set; }
|
||||||
|
public ICommand ConfirmCommand { get; private set; }
|
||||||
|
|
||||||
|
public string Email
|
||||||
|
{
|
||||||
|
get { return _email; }
|
||||||
|
set { SetProperty(ref _email, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ExternalId
|
||||||
|
{
|
||||||
|
get { return _externalId; }
|
||||||
|
set { SetProperty(ref _externalId, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FirstName
|
||||||
|
{
|
||||||
|
get { return _firstName; }
|
||||||
|
set { SetProperty(ref _firstName, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FullName
|
||||||
|
{
|
||||||
|
get { return _fullName; }
|
||||||
|
set { SetProperty(ref _fullName, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Guid
|
||||||
|
{
|
||||||
|
get { return _guid; }
|
||||||
|
set { SetProperty(ref _guid, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Id { get; private set; }
|
||||||
|
public bool IsNew { get; private set; }
|
||||||
|
|
||||||
|
public string LastName
|
||||||
|
{
|
||||||
|
get { return _lastName; }
|
||||||
|
set { SetProperty(ref _lastName, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Notes
|
||||||
|
{
|
||||||
|
get { return _notes; }
|
||||||
|
set { SetProperty(ref _notes, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Patronymic
|
||||||
|
{
|
||||||
|
get { return _patronymic; }
|
||||||
|
set { SetProperty(ref _patronymic, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Phone
|
||||||
|
{
|
||||||
|
get { return _phone; }
|
||||||
|
set { SetProperty(ref _phone, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get { return IsNew ? "Новая персона" : "Редактирование персоны"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ValidationMessage
|
||||||
|
{
|
||||||
|
get { return _validationMessage; }
|
||||||
|
private set { SetProperty(ref _validationMessage, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public PrsnDirectoryItem ToResult()
|
||||||
|
{
|
||||||
|
return new PrsnDirectoryItem
|
||||||
|
{
|
||||||
|
Email = NormalizeNullable(Email),
|
||||||
|
ExternalId = NormalizeNullable(ExternalId),
|
||||||
|
FirstName = NormalizeNullable(FirstName),
|
||||||
|
FullName = NormalizeRequired(FullName),
|
||||||
|
Guid = NormalizeNullable(Guid),
|
||||||
|
Id = Id,
|
||||||
|
LastName = NormalizeNullable(LastName),
|
||||||
|
Notes = NormalizeNullable(Notes),
|
||||||
|
Patronymic = NormalizeNullable(Patronymic),
|
||||||
|
Phone = NormalizeNullable(Phone)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel(object parameter)
|
||||||
|
{
|
||||||
|
RaiseCloseRequested(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Confirm(object parameter)
|
||||||
|
{
|
||||||
|
var normalizedFullName = NormalizeRequired(FullName);
|
||||||
|
var normalizedLastName = NormalizeNullable(LastName);
|
||||||
|
var normalizedFirstName = NormalizeNullable(FirstName);
|
||||||
|
var normalizedPatronymic = NormalizeNullable(Patronymic);
|
||||||
|
var normalizedPhone = NormalizeNullable(Phone);
|
||||||
|
var normalizedEmail = NormalizeNullable(Email);
|
||||||
|
var normalizedNotes = NormalizeNullable(Notes);
|
||||||
|
var normalizedGuid = NormalizeNullable(Guid);
|
||||||
|
var normalizedExternalId = NormalizeNullable(ExternalId);
|
||||||
|
|
||||||
|
if (normalizedFullName.Length == 0)
|
||||||
|
{
|
||||||
|
ValidationMessage = "Укажите ФИО.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (normalizedFullName.Length > PrsnDirectoryRules.FullNameMaxLength)
|
||||||
|
{
|
||||||
|
ValidationMessage = string.Format("ФИО не должно превышать {0} символов.", PrsnDirectoryRules.FullNameMaxLength);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ValidateMaxLength(normalizedLastName, PrsnDirectoryRules.LastNameMaxLength, "Фамилия")
|
||||||
|
|| !ValidateMaxLength(normalizedFirstName, PrsnDirectoryRules.FirstNameMaxLength, "Имя")
|
||||||
|
|| !ValidateMaxLength(normalizedPatronymic, PrsnDirectoryRules.PatronymicMaxLength, "Отчество")
|
||||||
|
|| !ValidateMaxLength(normalizedPhone, PrsnDirectoryRules.PhoneMaxLength, "Телефон")
|
||||||
|
|| !ValidateMaxLength(normalizedEmail, PrsnDirectoryRules.EmailMaxLength, "E-mail")
|
||||||
|
|| !ValidateMaxLength(normalizedGuid, PrsnDirectoryRules.GuidMaxLength, "GUID персоны")
|
||||||
|
|| !ValidateMaxLength(normalizedExternalId, PrsnDirectoryRules.ExternalIdMaxLength, "Дополнительный идентификатор персоны")
|
||||||
|
|| !ValidateMaxLength(normalizedNotes, PrsnDirectoryRules.NotesMaxLength, "Дополнительные сведения о персоне"))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var duplicate = _existingItems.FirstOrDefault(delegate(PrsnDirectoryItem item)
|
||||||
|
{
|
||||||
|
return item != null
|
||||||
|
&& item.Id != Id
|
||||||
|
&& string.Equals(NormalizeRequired(item.FullName), normalizedFullName, StringComparison.OrdinalIgnoreCase)
|
||||||
|
&& string.Equals(NormalizeNullable(item.ExternalId) ?? string.Empty, normalizedExternalId ?? string.Empty, StringComparison.OrdinalIgnoreCase);
|
||||||
|
});
|
||||||
|
if (duplicate != null)
|
||||||
|
{
|
||||||
|
ValidationMessage = normalizedExternalId == null
|
||||||
|
? string.Format("Персона \"{0}\" без дополнительного идентификатора уже существует в справочнике.", normalizedFullName)
|
||||||
|
: string.Format("Персона \"{0}\" с дополнительным идентификатором \"{1}\" уже существует в справочнике.", normalizedFullName, normalizedExternalId);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var duplicateGuid = _existingItems.FirstOrDefault(delegate(PrsnDirectoryItem item)
|
||||||
|
{
|
||||||
|
return item != null
|
||||||
|
&& item.Id != Id
|
||||||
|
&& !string.IsNullOrWhiteSpace(item.Guid)
|
||||||
|
&& normalizedGuid != null
|
||||||
|
&& string.Equals(item.Guid.Trim(), normalizedGuid, StringComparison.OrdinalIgnoreCase);
|
||||||
|
});
|
||||||
|
if (duplicateGuid != null)
|
||||||
|
{
|
||||||
|
ValidationMessage = string.Format("GUID персоны \"{0}\" уже существует в справочнике.", normalizedGuid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ValidationMessage = string.Empty;
|
||||||
|
RaiseCloseRequested(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private string NormalizeNullable(string value)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string NormalizeRequired(string value)
|
||||||
|
{
|
||||||
|
return string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RaiseCloseRequested(bool? dialogResult)
|
||||||
|
{
|
||||||
|
var handler = CloseRequested;
|
||||||
|
if (handler != null)
|
||||||
|
{
|
||||||
|
handler(this, dialogResult);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ValidateMaxLength(string value, int maxLength, string fieldName)
|
||||||
|
{
|
||||||
|
if (value != null && value.Length > maxLength)
|
||||||
|
{
|
||||||
|
ValidationMessage = string.Format("{0} не должно превышать {1} символов.", fieldName, maxLength);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
237
XLAB/ReferenceDirectorySqlHelpers.cs
Normal file
237
XLAB/ReferenceDirectorySqlHelpers.cs
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Configuration;
|
||||||
|
using System.Data;
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace XLAB
|
||||||
|
{
|
||||||
|
internal sealed class DeleteBlockerInfo
|
||||||
|
{
|
||||||
|
public int RowCount { get; set; }
|
||||||
|
|
||||||
|
public string TableName { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static class ReferenceDirectorySqlHelpers
|
||||||
|
{
|
||||||
|
public static SqlConnection CreateConnection()
|
||||||
|
{
|
||||||
|
var connectionString = ConfigurationManager.ConnectionStrings["AsumsSql"];
|
||||||
|
if (connectionString == null || string.IsNullOrWhiteSpace(connectionString.ConnectionString))
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("В App.config не найдено подключение AsumsSql.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new SqlConnection(connectionString.ConnectionString);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IReadOnlyList<DirectoryLookupItem> LoadLookupItems(string sql)
|
||||||
|
{
|
||||||
|
var items = new List<DirectoryLookupItem>();
|
||||||
|
|
||||||
|
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 DirectoryLookupItem
|
||||||
|
{
|
||||||
|
Id = GetInt32(reader, "Id"),
|
||||||
|
Name = GetString(reader, "Name")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<DeleteBlockerInfo> LoadDeleteBlockersFromForeignKeys(SqlConnection connection, string parentTableName, int id, IEnumerable<string> excludedChildTables = null)
|
||||||
|
{
|
||||||
|
var excluded = new HashSet<string>(excludedChildTables ?? Enumerable.Empty<string>(), StringComparer.OrdinalIgnoreCase);
|
||||||
|
var metadata = LoadForeignKeyMetadata(connection, parentTableName)
|
||||||
|
.Where(delegate(ForeignKeyMetadata item) { return !excluded.Contains(item.TableName); })
|
||||||
|
.GroupBy(delegate(ForeignKeyMetadata item) { return item.SchemaName + "." + item.TableName; })
|
||||||
|
.Select(delegate(IGrouping<string, ForeignKeyMetadata> group)
|
||||||
|
{
|
||||||
|
var first = group.First();
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
first.SchemaName,
|
||||||
|
first.TableName,
|
||||||
|
Columns = group.Select(delegate(ForeignKeyMetadata item) { return item.ColumnName; }).Distinct(StringComparer.OrdinalIgnoreCase).ToList()
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var blockers = new List<DeleteBlockerInfo>();
|
||||||
|
foreach (var item in metadata)
|
||||||
|
{
|
||||||
|
var whereClause = string.Join(" OR ", item.Columns.Select(delegate(string columnName)
|
||||||
|
{
|
||||||
|
return string.Format("[{0}] = @Id", EscapeIdentifier(columnName));
|
||||||
|
}));
|
||||||
|
var sql = string.Format(
|
||||||
|
"SELECT COUNT(*) FROM [{0}].[{1}] WHERE {2};",
|
||||||
|
EscapeIdentifier(item.SchemaName),
|
||||||
|
EscapeIdentifier(item.TableName),
|
||||||
|
whereClause);
|
||||||
|
|
||||||
|
using (var command = new SqlCommand(sql, connection))
|
||||||
|
{
|
||||||
|
command.CommandTimeout = 60;
|
||||||
|
command.Parameters.Add("@Id", SqlDbType.Int).Value = id;
|
||||||
|
var rowCount = Convert.ToInt32(command.ExecuteScalar());
|
||||||
|
if (rowCount > 0)
|
||||||
|
{
|
||||||
|
blockers.Add(new DeleteBlockerInfo
|
||||||
|
{
|
||||||
|
TableName = item.TableName,
|
||||||
|
RowCount = rowCount
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return blockers.OrderBy(delegate(DeleteBlockerInfo blocker) { return blocker.TableName; }).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string CreateDeleteBlockedMessage(string tableName, IEnumerable<DeleteBlockerInfo> blockers)
|
||||||
|
{
|
||||||
|
var details = string.Join(", ", (blockers ?? Enumerable.Empty<DeleteBlockerInfo>())
|
||||||
|
.OrderBy(delegate(DeleteBlockerInfo blocker) { return blocker.TableName; })
|
||||||
|
.Select(delegate(DeleteBlockerInfo blocker) { return string.Format("{0}: {1}", blocker.TableName, blocker.RowCount); }));
|
||||||
|
|
||||||
|
return string.Format(
|
||||||
|
"Запись {0} не может быть удалена, потому что на неё есть ссылки в таблицах: {1}.",
|
||||||
|
tableName,
|
||||||
|
string.IsNullOrWhiteSpace(details) ? "связанные данные" : details);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string CreateDeleteBlockedMessage(string tableName, SqlException ex)
|
||||||
|
{
|
||||||
|
var suffix = ex == null || string.IsNullOrWhiteSpace(ex.Message)
|
||||||
|
? string.Empty
|
||||||
|
: " " + ex.Message.Trim();
|
||||||
|
|
||||||
|
return string.Format(
|
||||||
|
"Запись {0} не может быть удалена из-за ограничений ссылочной целостности в БД.{1}",
|
||||||
|
tableName,
|
||||||
|
suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsDuplicateViolation(SqlException ex, string indexName)
|
||||||
|
{
|
||||||
|
return ex != null
|
||||||
|
&& (ex.Number == 2601 || ex.Number == 2627)
|
||||||
|
&& ex.Message.IndexOf(indexName, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int GetInt32(SqlDataReader reader, string columnName)
|
||||||
|
{
|
||||||
|
return reader.GetInt32(reader.GetOrdinal(columnName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int? GetNullableInt32(SqlDataReader reader, string columnName)
|
||||||
|
{
|
||||||
|
var ordinal = reader.GetOrdinal(columnName);
|
||||||
|
return reader.IsDBNull(ordinal) ? (int?)null : reader.GetInt32(ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetString(SqlDataReader reader, string columnName)
|
||||||
|
{
|
||||||
|
var ordinal = reader.GetOrdinal(columnName);
|
||||||
|
return reader.IsDBNull(ordinal) ? string.Empty : Convert.ToString(reader.GetValue(ordinal));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DateTime? GetNullableDateTime(SqlDataReader reader, string columnName)
|
||||||
|
{
|
||||||
|
var ordinal = reader.GetOrdinal(columnName);
|
||||||
|
return reader.IsDBNull(ordinal) ? (DateTime?)null : reader.GetDateTime(ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool? GetNullableBoolean(SqlDataReader reader, string columnName)
|
||||||
|
{
|
||||||
|
var ordinal = reader.GetOrdinal(columnName);
|
||||||
|
return reader.IsDBNull(ordinal) ? (bool?)null : reader.GetBoolean(ordinal);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AddNullableIntParameter(SqlCommand command, string name, int? value)
|
||||||
|
{
|
||||||
|
command.Parameters.Add(name, SqlDbType.Int).Value = (object)value ?? DBNull.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AddNullableStringParameter(SqlCommand command, string name, SqlDbType dbType, int size, string value)
|
||||||
|
{
|
||||||
|
command.Parameters.Add(name, dbType, size).Value = (object)value ?? DBNull.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AddNullableDateTimeParameter(SqlCommand command, string name, DateTime? value)
|
||||||
|
{
|
||||||
|
command.Parameters.Add(name, SqlDbType.DateTime).Value = (object)value ?? DBNull.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AddNullableTextParameter(SqlCommand command, string name, string value)
|
||||||
|
{
|
||||||
|
command.Parameters.Add(name, SqlDbType.VarChar, -1).Value = (object)value ?? DBNull.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IReadOnlyList<ForeignKeyMetadata> LoadForeignKeyMetadata(SqlConnection connection, string parentTableName)
|
||||||
|
{
|
||||||
|
const string sql = @"
|
||||||
|
SELECT
|
||||||
|
OBJECT_SCHEMA_NAME(fk.parent_object_id) AS SchemaName,
|
||||||
|
OBJECT_NAME(fk.parent_object_id) AS TableName,
|
||||||
|
childColumn.name AS ColumnName
|
||||||
|
FROM sys.foreign_keys fk
|
||||||
|
JOIN sys.foreign_key_columns fkc ON fkc.constraint_object_id = fk.object_id
|
||||||
|
JOIN sys.columns childColumn ON childColumn.object_id = fkc.parent_object_id AND childColumn.column_id = fkc.parent_column_id
|
||||||
|
WHERE OBJECT_NAME(fk.referenced_object_id) = @ParentTableName
|
||||||
|
ORDER BY TableName, ColumnName;";
|
||||||
|
|
||||||
|
var result = new List<ForeignKeyMetadata>();
|
||||||
|
|
||||||
|
using (var command = new SqlCommand(sql, connection))
|
||||||
|
{
|
||||||
|
command.CommandTimeout = 60;
|
||||||
|
command.Parameters.Add("@ParentTableName", SqlDbType.VarChar, 128).Value = parentTableName;
|
||||||
|
|
||||||
|
using (var reader = command.ExecuteReader())
|
||||||
|
{
|
||||||
|
while (reader.Read())
|
||||||
|
{
|
||||||
|
result.Add(new ForeignKeyMetadata
|
||||||
|
{
|
||||||
|
SchemaName = GetString(reader, "SchemaName"),
|
||||||
|
TableName = GetString(reader, "TableName"),
|
||||||
|
ColumnName = GetString(reader, "ColumnName")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string EscapeIdentifier(string identifier)
|
||||||
|
{
|
||||||
|
return (identifier ?? string.Empty).Replace("]", "]]");
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class ForeignKeyMetadata
|
||||||
|
{
|
||||||
|
public string ColumnName { get; set; }
|
||||||
|
|
||||||
|
public string SchemaName { get; set; }
|
||||||
|
|
||||||
|
public string TableName { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -78,6 +78,9 @@
|
|||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="CloneVerificationWindowViewModel.cs" />
|
<Compile Include="CloneVerificationWindowViewModel.cs" />
|
||||||
<Compile Include="DialogService.cs" />
|
<Compile Include="DialogService.cs" />
|
||||||
|
<Compile Include="FrpdDirectoryDialogService.cs" />
|
||||||
|
<Compile Include="FrpdDirectoryModels.cs" />
|
||||||
|
<Compile Include="FrpdDirectoryService.cs" />
|
||||||
<Page Include="MainWindow.xaml">
|
<Page Include="MainWindow.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
@@ -90,6 +93,34 @@
|
|||||||
<Compile Include="MvvmInfrastructure.cs" />
|
<Compile Include="MvvmInfrastructure.cs" />
|
||||||
<Compile Include="PsvDataService.cs" />
|
<Compile Include="PsvDataService.cs" />
|
||||||
<Compile Include="PsvModels.cs" />
|
<Compile Include="PsvModels.cs" />
|
||||||
|
<Compile Include="ReferenceDirectorySqlHelpers.cs" />
|
||||||
|
<Page Include="FrpdDirectoryWindow.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="FrpdDirectoryWindow.xaml.cs">
|
||||||
|
<DependentUpon>FrpdDirectoryWindow.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="FrpdDirectoryWindowViewModel.cs" />
|
||||||
|
<Page Include="FrpdEditWindow.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="FrpdEditWindow.xaml.cs">
|
||||||
|
<DependentUpon>FrpdEditWindow.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="FrpdEditWindowViewModel.cs" />
|
||||||
|
<Page Include="FrpdvdEditWindow.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="FrpdvdEditWindow.xaml.cs">
|
||||||
|
<DependentUpon>FrpdvdEditWindow.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="FrpdvdEditWindowViewModel.cs" />
|
||||||
<Page Include="SelectInstrumentsWindow.xaml">
|
<Page Include="SelectInstrumentsWindow.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
@@ -183,6 +214,54 @@
|
|||||||
<SubType>Code</SubType>
|
<SubType>Code</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="SpnmtpEditWindowViewModel.cs" />
|
<Compile Include="SpnmtpEditWindowViewModel.cs" />
|
||||||
|
<Compile Include="PrsnDirectoryDialogService.cs" />
|
||||||
|
<Compile Include="PrsnDirectoryModels.cs" />
|
||||||
|
<Compile Include="PrsnDirectoryService.cs" />
|
||||||
|
<Page Include="PrsnDirectoryWindow.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="PrsnDirectoryWindow.xaml.cs">
|
||||||
|
<DependentUpon>PrsnDirectoryWindow.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="PrsnDirectoryWindowViewModel.cs" />
|
||||||
|
<Page Include="PrsnEditWindow.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="PrsnEditWindow.xaml.cs">
|
||||||
|
<DependentUpon>PrsnEditWindow.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="PrsnEditWindowViewModel.cs" />
|
||||||
|
<Page Include="PrfrEditWindow.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="PrfrEditWindow.xaml.cs">
|
||||||
|
<DependentUpon>PrfrEditWindow.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="PrfrEditWindowViewModel.cs" />
|
||||||
|
<Page Include="PrfrvdEditWindow.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="PrfrvdEditWindow.xaml.cs">
|
||||||
|
<DependentUpon>PrfrvdEditWindow.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="PrfrvdEditWindowViewModel.cs" />
|
||||||
|
<Page Include="PrdspvEditWindow.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
</Page>
|
||||||
|
<Compile Include="PrdspvEditWindow.xaml.cs">
|
||||||
|
<DependentUpon>PrdspvEditWindow.xaml</DependentUpon>
|
||||||
|
<SubType>Code</SubType>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="PrdspvEditWindowViewModel.cs" />
|
||||||
<Page Include="TprmcpEditWindow.xaml">
|
<Page Include="TprmcpEditWindow.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
|
|||||||
Reference in New Issue
Block a user