diff --git a/ClosePsv.docx b/ClosePsv.docx
index eab67f3..7495ee3 100644
Binary files a/ClosePsv.docx and b/ClosePsv.docx differ
diff --git a/OpenPsv.docx b/OpenPsv.docx
index 3cfd7b9..f70b740 100644
Binary files a/OpenPsv.docx and b/OpenPsv.docx differ
diff --git a/XLAB/App.xaml b/XLAB/App.xaml
index c673361..b8cf07b 100644
--- a/XLAB/App.xaml
+++ b/XLAB/App.xaml
@@ -17,6 +17,10 @@
+
+
+
+
@@ -118,6 +122,166 @@
+
-
-
-
diff --git a/XLAB/SpnmtpDirectoryWindow.xaml.cs b/XLAB/SpnmtpDirectoryWindow.xaml.cs
index d3872df..abdd53f 100644
--- a/XLAB/SpnmtpDirectoryWindow.xaml.cs
+++ b/XLAB/SpnmtpDirectoryWindow.xaml.cs
@@ -1,4 +1,6 @@
using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
namespace XLAB
{
@@ -13,6 +15,16 @@ namespace XLAB
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();
diff --git a/XLAB/SpoiDirectoryWindow.xaml b/XLAB/SpoiDirectoryWindow.xaml
index f6eb22f..42212d6 100644
--- a/XLAB/SpoiDirectoryWindow.xaml
+++ b/XLAB/SpoiDirectoryWindow.xaml
@@ -44,6 +44,22 @@
CanUserAddRows="False"
IsReadOnly="True"
HeadersVisibility="Column">
+
+
+
+
+
+
+
+
+
+
-
-
-
diff --git a/XLAB/SpoiDirectoryWindow.xaml.cs b/XLAB/SpoiDirectoryWindow.xaml.cs
index 8a85b41..4a6d28c 100644
--- a/XLAB/SpoiDirectoryWindow.xaml.cs
+++ b/XLAB/SpoiDirectoryWindow.xaml.cs
@@ -1,4 +1,6 @@
using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Input;
namespace XLAB
{
@@ -13,6 +15,16 @@ namespace XLAB
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();
diff --git a/XLAB2/MainWindow.xaml b/XLAB2/MainWindow.xaml
index c9e11bd..883461c 100644
--- a/XLAB2/MainWindow.xaml
+++ b/XLAB2/MainWindow.xaml
@@ -358,7 +358,7 @@
Margin="12,0,0,0"
VerticalAlignment="Center"
Foreground="DimGray"
- Text="Поиск по наименованию, типу, диапазону, госреестру или зав. №" />
+ Text="Поиск по наименованию, типу, диапазону, характеристикам, госреестру или зав. №" />
+
diff --git a/XLAB2/MainWindowViewModel.cs b/XLAB2/MainWindowViewModel.cs
index bcc16e1..ec5ff42 100644
--- a/XLAB2/MainWindowViewModel.cs
+++ b/XLAB2/MainWindowViewModel.cs
@@ -1786,6 +1786,7 @@ namespace XLAB2
return Contains(group.InstrumentName, GroupFilterText)
|| Contains(group.InstrumentType, GroupFilterText)
|| Contains(group.RangeText, GroupFilterText)
+ || Contains(group.AccuracyText, GroupFilterText)
|| Contains(group.RegistryNumber, GroupFilterText)
|| Contains(group.SerialNumbersText, GroupFilterText);
}
@@ -1860,6 +1861,7 @@ namespace XLAB2
&& right != null
&& string.Equals(left.InstrumentType ?? string.Empty, right.InstrumentType ?? string.Empty, StringComparison.OrdinalIgnoreCase)
&& string.Equals(left.RangeText ?? string.Empty, right.RangeText ?? string.Empty, StringComparison.OrdinalIgnoreCase)
+ && string.Equals(left.AccuracyText ?? string.Empty, right.AccuracyText ?? string.Empty, StringComparison.OrdinalIgnoreCase)
&& string.Equals(left.RegistryNumber ?? string.Empty, right.RegistryNumber ?? string.Empty, StringComparison.OrdinalIgnoreCase);
}
@@ -2268,16 +2270,15 @@ namespace XLAB2
_pendingLinesByDocumentKey[pendingKey] = pendingLines;
}
- var serialNumber = string.IsNullOrWhiteSpace(result.SerialNumber) ? string.Empty : result.SerialNumber.Trim();
- if (string.IsNullOrWhiteSpace(serialNumber))
- {
- _dialogService.ShowWarning("Введите заводской номер.");
- return;
- }
+ var serialNumbers = (result.SerialNumbers ?? Array.Empty())
+ .Where(delegate(string value) { return !string.IsNullOrWhiteSpace(value); })
+ .Select(delegate(string value) { return value.Trim(); })
+ .Distinct(StringComparer.OrdinalIgnoreCase)
+ .ToList();
- if (serialNumber.Length > EkzDirectoryRules.SerialNumberMaxLength)
+ if (serialNumbers.Count == 0)
{
- _dialogService.ShowWarning(string.Format("Заводской номер не должен превышать {0} символов.", EkzDirectoryRules.SerialNumberMaxLength));
+ _dialogService.ShowWarning("Введите хотя бы один заводской номер.");
return;
}
@@ -2287,11 +2288,34 @@ namespace XLAB2
return;
}
- var candidateLine = CreatePendingTypeLine(result.TypeItem, serialNumber);
+ var validSerialNumbers = new List();
+ var skippedInvalidLengthCount = 0;
+
+ foreach (var serialNumber in serialNumbers)
+ {
+ if (serialNumber.Length > EkzDirectoryRules.SerialNumberMaxLength)
+ {
+ skippedInvalidLengthCount++;
+ continue;
+ }
+
+ validSerialNumbers.Add(serialNumber);
+ }
+
+ if (validSerialNumbers.Count == 0)
+ {
+ _dialogService.ShowWarning(string.Format("Каждый заводской номер должен содержать не более {0} символов.", EkzDirectoryRules.SerialNumberMaxLength));
+ return;
+ }
+
+ var candidateLines = validSerialNumbers
+ .Select(delegate(string serialNumber) { return CreatePendingTypeLine(result.TypeItem, serialNumber); })
+ .ToList();
+
List openDocumentConflicts;
try
{
- openDocumentConflicts = FindOpenDocumentConflicts(new[] { candidateLine });
+ openDocumentConflicts = FindOpenDocumentConflicts(candidateLines);
}
catch (Exception ex)
{
@@ -2299,36 +2323,88 @@ namespace XLAB2
return;
}
- if (openDocumentConflicts.Count > 0)
+ var openConflictKeys = new HashSet(
+ openDocumentConflicts.Select(delegate(OpenDocumentConflictInfo conflict) { return conflict.OpenDocumentConflictKey; }),
+ StringComparer.OrdinalIgnoreCase);
+
+ var duplicateKeys = new HashSet(DocumentLines.Select(delegate(PsvDocumentLine line) { return line.DuplicateKey; }), StringComparer.OrdinalIgnoreCase);
+ var addedCount = 0;
+ var skippedDuplicateCount = 0;
+ var skippedOpenDocumentCount = 0;
+
+ foreach (var serialNumber in validSerialNumbers)
{
- _dialogService.ShowWarning(BuildOpenDocumentConflictMessage(openDocumentConflicts));
- return;
+ if (openConflictKeys.Contains(PsvDocumentLine.BuildOpenDocumentConflictKey(result.TypeItem.TypeSizeId, serialNumber)))
+ {
+ skippedOpenDocumentCount++;
+ continue;
+ }
+
+ var duplicateKey = PsvDocumentLine.BuildDuplicateKey(
+ result.TypeItem.InstrumentType,
+ result.TypeItem.RangeText,
+ result.TypeItem.RegistryNumber,
+ serialNumber);
+
+ if (duplicateKeys.Contains(duplicateKey))
+ {
+ skippedDuplicateCount++;
+ continue;
+ }
+
+ pendingLines.Add(CreatePendingTypeLine(result.TypeItem, serialNumber));
+ duplicateKeys.Add(duplicateKey);
+ addedCount++;
}
- var duplicateKey = PsvDocumentLine.BuildDuplicateKey(
- result.TypeItem.InstrumentType,
- result.TypeItem.RangeText,
- result.TypeItem.RegistryNumber,
- serialNumber);
-
- if (DocumentLines.Any(delegate(PsvDocumentLine line)
+ if (addedCount == 0 && skippedDuplicateCount > 0 && skippedOpenDocumentCount == 0 && skippedInvalidLengthCount == 0)
{
- return string.Equals(line.DuplicateKey, duplicateKey, StringComparison.OrdinalIgnoreCase);
- }))
- {
- _dialogService.ShowWarning("Такой прибор уже есть в ПСВ.");
+ _dialogService.ShowWarning("Такие приборы уже есть в ПСВ.");
return;
}
- pendingLines.Add(candidateLine);
-
if (SelectedDocument.IsDraft)
{
UpdateDocumentSummaryFromLines(SelectedDocument, pendingLines);
}
LoadSelectedDocumentAsync();
- _dialogService.ShowInfo("Прибор по типу добавлен в ПСВ.");
+
+ var messages = new List();
+ if (addedCount > 0)
+ {
+ messages.Add(string.Format("Добавлено приборов по типу: {0}.", addedCount));
+ }
+
+ if (skippedDuplicateCount > 0)
+ {
+ messages.Add(string.Format("Исключено дублей: {0}.", skippedDuplicateCount));
+ }
+
+ if (skippedInvalidLengthCount > 0)
+ {
+ messages.Add(string.Format("Пропущено из-за длины зав. № более {0} символов: {1}.", EkzDirectoryRules.SerialNumberMaxLength, skippedInvalidLengthCount));
+ }
+
+ if (skippedOpenDocumentCount > 0)
+ {
+ messages.Add(string.Format("Пропущено из-за других открытых ПСВ: {0}.", skippedOpenDocumentCount));
+ messages.Add(BuildOpenDocumentConflictMessage(openDocumentConflicts));
+ }
+
+ if (messages.Count > 0)
+ {
+ var message = string.Join(" ", messages.ToArray());
+ if (addedCount == 0)
+ {
+ _dialogService.ShowWarning(message);
+ }
+ else
+ {
+ _dialogService.ShowInfo(message);
+ }
+ }
+
RaiseCommandStates();
OnPropertyChanged("IsCustomerEditable");
}
@@ -2395,22 +2471,26 @@ namespace XLAB2
{
InstrumentType = line.InstrumentType ?? string.Empty,
RangeText = line.RangeText ?? string.Empty,
+ AccuracyText = line.AccuracyText ?? string.Empty,
RegistryNumber = line.RegistryNumber ?? string.Empty
})
.OrderBy(group => group.Key.InstrumentType)
.ThenBy(group => group.Key.RegistryNumber)
.ThenBy(group => group.Key.RangeText)
+ .ThenBy(group => group.Key.AccuracyText)
.Select(group => new PsvDocumentGroupSummary
{
InstrumentName = BuildInstrumentNamesText(group),
InstrumentType = group.Key.InstrumentType,
RangeText = group.Key.RangeText,
+ AccuracyText = group.Key.AccuracyText,
RegistryNumber = group.Key.RegistryNumber,
SerialNumbersText = BuildSerialNumbersText(group),
IsBatchSelected = checkedGroups.Any(delegate(PsvDocumentGroupSummary previous)
{
return string.Equals(previous.InstrumentType ?? string.Empty, group.Key.InstrumentType, StringComparison.OrdinalIgnoreCase)
&& string.Equals(previous.RangeText ?? string.Empty, group.Key.RangeText, StringComparison.OrdinalIgnoreCase)
+ && string.Equals(previous.AccuracyText ?? string.Empty, group.Key.AccuracyText, StringComparison.OrdinalIgnoreCase)
&& string.Equals(previous.RegistryNumber ?? string.Empty, group.Key.RegistryNumber, StringComparison.OrdinalIgnoreCase);
}),
InVerificationCount = group.Count(line => !line.IsPassed.HasValue),
diff --git a/XLAB2/PsvModels.cs b/XLAB2/PsvModels.cs
index cac05c6..0f8f97c 100644
--- a/XLAB2/PsvModels.cs
+++ b/XLAB2/PsvModels.cs
@@ -370,6 +370,8 @@ namespace XLAB2
public string RangeText { get; set; }
+ public string AccuracyText { get; set; }
+
public string RegistryNumber { get; set; }
public string SerialNumbersText { get; set; }
@@ -393,6 +395,7 @@ namespace XLAB2
return line != null
&& string.Equals(InstrumentType ?? string.Empty, line.InstrumentType ?? string.Empty, StringComparison.OrdinalIgnoreCase)
&& string.Equals(RangeText ?? string.Empty, line.RangeText ?? string.Empty, StringComparison.OrdinalIgnoreCase)
+ && string.Equals(AccuracyText ?? string.Empty, line.AccuracyText ?? string.Empty, StringComparison.OrdinalIgnoreCase)
&& string.Equals(RegistryNumber ?? string.Empty, line.RegistryNumber ?? string.Empty, StringComparison.OrdinalIgnoreCase);
}
}
@@ -527,7 +530,7 @@ namespace XLAB2
{
public AvailableInstrumentItem TypeItem { get; set; }
- public string SerialNumber { get; set; }
+ public IReadOnlyList SerialNumbers { get; set; }
}
public sealed class VerificationEditSeed
diff --git a/XLAB2/SelectInstrumentTypeWindow.xaml b/XLAB2/SelectInstrumentTypeWindow.xaml
index 5ba12e0..8e77fee 100644
--- a/XLAB2/SelectInstrumentTypeWindow.xaml
+++ b/XLAB2/SelectInstrumentTypeWindow.xaml
@@ -61,14 +61,17 @@
-
-
+ Margin="0,10,0,0">
+
+
+
instrumentTypes)
@@ -65,12 +65,12 @@ namespace XLAB2
}
}
- public string SerialNumber
+ public string SerialNumbersText
{
- get { return _serialNumber; }
+ get { return _serialNumbersText; }
set
{
- if (SetProperty(ref _serialNumber, value))
+ if (SetProperty(ref _serialNumbersText, value))
{
((RelayCommand)ConfirmCommand).RaiseCanExecuteChanged();
UpdateStatus();
@@ -86,12 +86,13 @@ namespace XLAB2
public InstrumentTypeSelectionResult GetResult()
{
+ var serialNumbers = ParseSerialNumbers(SerialNumbersText);
return SelectedType == null
? null
: new InstrumentTypeSelectionResult
{
TypeItem = SelectedType,
- SerialNumber = string.IsNullOrWhiteSpace(SerialNumber) ? string.Empty : SerialNumber.Trim()
+ SerialNumbers = serialNumbers
};
}
@@ -103,7 +104,7 @@ namespace XLAB2
private bool CanConfirm(object parameter)
{
return SelectedType != null
- && !string.IsNullOrWhiteSpace(SerialNumber);
+ && ParseSerialNumbers(SerialNumbersText).Count > 0;
}
private void Confirm(object parameter)
@@ -138,6 +139,30 @@ namespace XLAB2
&& source.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0;
}
+ private static List ParseSerialNumbers(string value)
+ {
+ var serialNumbers = new List();
+ var unique = new HashSet(StringComparer.OrdinalIgnoreCase);
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return serialNumbers;
+ }
+
+ var separators = new[] { '\r', '\n', '\t', ',', ';' };
+ foreach (var token in value.Split(separators, StringSplitOptions.RemoveEmptyEntries))
+ {
+ var serialNumber = token.Trim();
+ if (serialNumber.Length == 0 || !unique.Add(serialNumber))
+ {
+ continue;
+ }
+
+ serialNumbers.Add(serialNumber);
+ }
+
+ return serialNumbers;
+ }
+
private void RaiseCloseRequested(bool? dialogResult)
{
var handler = CloseRequested;
@@ -150,12 +175,13 @@ namespace XLAB2
private void UpdateStatus()
{
var visibleCount = InstrumentTypesView.Cast