This commit is contained in:
Курнат Андрей
2026-03-13 19:12:50 +03:00
parent d6cea24aa9
commit 9df4de1ba1
5 changed files with 812 additions and 104 deletions

View File

@@ -192,15 +192,33 @@
SelectedItem="{Binding SelectedDocumentGroup, Mode=TwoWay}"
AutoGenerateColumns="False"
CanUserAddRows="False"
IsReadOnly="True"
IsReadOnly="False"
HeadersVisibility="Column">
<DataGrid.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Выбрать по заводским номерам"
<MenuItem Header="Добавить по заводским номерам"
Command="{Binding OpenInstrumentPickerCommand}" />
<MenuItem Header="Удалить"
Command="{Binding DeleteSelectedGroupsCommand}" />
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<EventSetter Event="PreviewMouseRightButtonDown"
Handler="DocumentGroupRow_PreviewMouseRightButtonDown" />
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Выбр."
Width="52">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Center"
VerticalAlignment="Center"
IsChecked="{Binding IsBatchSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Тип"
Width="180"
Binding="{Binding InstrumentType}" />
@@ -268,6 +286,16 @@
</Style>
</DataGrid.RowStyle>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Выбр."
Width="52">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Center"
VerticalAlignment="Center"
IsChecked="{Binding IsBatchSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Зав. №"
Width="120"
Binding="{Binding SerialNumber}" />

View File

@@ -35,6 +35,16 @@ namespace XLAB
}
}
private void DocumentGroupRow_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();

View File

@@ -49,6 +49,7 @@ namespace XLAB
AddDocumentCommand = new RelayCommand(delegate { AddDocument(); }, delegate { return !IsBusy; });
DeleteDocumentCommand = new RelayCommand(delegate { DeleteDocumentAsync(); }, delegate { return !IsBusy && SelectedDocument != null; });
DeleteSelectedGroupsCommand = new RelayCommand(delegate { DeleteSelectedGroupsAsync(); }, delegate { return CanDeleteSelectedGroups(); });
MarkLinePassedCommand = new RelayCommand(delegate { EditLineVerificationAsync(true); }, delegate { return CanEditSelectedLineVerification(); });
MarkLineRejectedCommand = new RelayCommand(delegate { EditLineVerificationAsync(false); }, delegate { return CanEditSelectedLineVerification(); });
OpenInstrumentPickerCommand = new RelayCommand(delegate { OpenInstrumentPickerAsync(); }, delegate { return !IsBusy && SelectedDocument != null && SelectedDocument.CustomerId.HasValue; });
@@ -100,6 +101,8 @@ namespace XLAB
public ICommand DeleteDocumentCommand { get; private set; }
public ICommand DeleteSelectedGroupsCommand { get; private set; }
public string GroupDetailFilterText
{
get { return _groupDetailFilterText; }
@@ -312,18 +315,27 @@ namespace XLAB
return GetPendingLines(SelectedDocument).Count > 0;
}
private bool CanEditSelectedLineVerification()
private bool CanDeleteSelectedGroups()
{
return !IsBusy
&& SelectedDocumentLine != null
&& !HasVerificationData(SelectedDocumentLine);
&& SelectedDocument != null
&& GetDeleteTargetGroups().Count > 0;
}
private bool CanEditSelectedLineVerification()
{
var targetLines = GetVerificationTargetLines();
return !IsBusy
&& targetLines.Count > 0
&& targetLines.All(delegate(PsvDocumentLine line) { return !HasVerificationData(line); });
}
private bool CanResetSelectedLineVerification()
{
var targetLines = GetVerificationTargetLines();
return !IsBusy
&& SelectedDocumentLine != null
&& HasVerificationData(SelectedDocumentLine);
&& targetLines.Count > 0
&& targetLines.All(HasVerificationData);
}
private static bool HasVerificationData(PsvDocumentLine line)
@@ -340,11 +352,131 @@ namespace XLAB
|| !string.IsNullOrWhiteSpace(line.RejectionReason));
}
private List<PsvDocumentLine> GetCheckedDocumentLines()
{
return DocumentLinesView.Cast<object>()
.OfType<PsvDocumentLine>()
.Where(delegate(PsvDocumentLine line) { return line.IsBatchSelected; })
.ToList();
}
private List<PsvDocumentGroupSummary> GetCheckedDocumentGroups()
{
return DocumentGroupSummaries
.Where(delegate(PsvDocumentGroupSummary group) { return group.IsBatchSelected; })
.ToList();
}
private List<PsvDocumentGroupSummary> GetDeleteTargetGroups()
{
var checkedGroups = GetCheckedDocumentGroups();
if (checkedGroups.Count > 0)
{
return checkedGroups;
}
return SelectedDocumentGroup == null
? new List<PsvDocumentGroupSummary>()
: new List<PsvDocumentGroupSummary> { SelectedDocumentGroup };
}
private List<PsvDocumentLine> GetVerificationTargetLines()
{
var checkedLines = GetCheckedDocumentLines();
if (checkedLines.Count > 0)
{
return checkedLines;
}
return SelectedDocumentLine == null
? new List<PsvDocumentLine>()
: new List<PsvDocumentLine> { SelectedDocumentLine };
}
private void ClearCollections<T>(ObservableCollection<T> collection)
{
collection.Clear();
}
private void ClearDocumentLines()
{
foreach (var line in DocumentLines.ToList())
{
UnsubscribeFromDocumentLine(line);
}
ClearCollections(DocumentLines);
}
private void ClearDocumentGroups()
{
foreach (var group in DocumentGroupSummaries.ToList())
{
UnsubscribeFromDocumentGroup(group);
}
ClearCollections(DocumentGroupSummaries);
}
private void SubscribeToDocumentLine(PsvDocumentLine line)
{
if (line == null)
{
return;
}
line.PropertyChanged -= DocumentLine_PropertyChanged;
line.PropertyChanged += DocumentLine_PropertyChanged;
}
private void SubscribeToDocumentGroup(PsvDocumentGroupSummary group)
{
if (group == null)
{
return;
}
group.PropertyChanged -= DocumentGroup_PropertyChanged;
group.PropertyChanged += DocumentGroup_PropertyChanged;
}
private void UnsubscribeFromDocumentLine(PsvDocumentLine line)
{
if (line == null)
{
return;
}
line.PropertyChanged -= DocumentLine_PropertyChanged;
}
private void UnsubscribeFromDocumentGroup(PsvDocumentGroupSummary group)
{
if (group == null)
{
return;
}
group.PropertyChanged -= DocumentGroup_PropertyChanged;
}
private void DocumentLine_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (string.Equals(e.PropertyName, "IsBatchSelected", StringComparison.Ordinal))
{
UpdateLineStatus();
RaiseCommandStates();
}
}
private void DocumentGroup_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (string.Equals(e.PropertyName, "IsBatchSelected", StringComparison.Ordinal))
{
RaiseCommandStates();
}
}
private void ClearHeader()
{
DocumentNumberEditor = string.Empty;
@@ -415,7 +547,7 @@ namespace XLAB
};
}
private void ApplyVerificationResultToLine(PsvDocumentLine line, VerificationEditResult result)
private static void ApplyVerificationResultCore(PsvDocumentLine line, VerificationEditResult result)
{
if (line == null || result == null)
{
@@ -432,11 +564,15 @@ namespace XLAB
line.VerificationDocumentNumber = result.VerificationDocumentNumber;
line.VerificationDocumentDate = result.VerificationDate;
line.RejectionReason = result.IsPassed ? string.Empty : result.RejectionReason;
}
private void ApplyVerificationResultToLine(PsvDocumentLine line, VerificationEditResult result)
{
ApplyVerificationResultCore(line, result);
RefreshAfterLineVerificationChanged(line);
}
private void ClearVerificationFromLine(PsvDocumentLine line)
private static void ClearVerificationFromLineCore(PsvDocumentLine line)
{
if (line == null)
{
@@ -453,22 +589,26 @@ namespace XLAB
line.VerificationDocumentNumber = string.Empty;
line.VerificationDocumentDate = null;
line.RejectionReason = string.Empty;
}
private void ClearVerificationFromLine(PsvDocumentLine line)
{
ClearVerificationFromLineCore(line);
RefreshAfterLineVerificationChanged(line);
}
private void EditLineVerificationAsync(bool isPassed)
{
var line = SelectedDocumentLine;
if (line == null)
var targetLines = GetVerificationTargetLines();
if (targetLines.Count == 0)
{
return;
}
EditLineVerificationCoreAsync(line, isPassed);
EditLineVerificationCoreAsync(targetLines, isPassed);
}
private async void EditLineVerificationCoreAsync(PsvDocumentLine line, bool isPassed)
private async void EditLineVerificationCoreAsync(IReadOnlyList<PsvDocumentLine> targetLines, bool isPassed)
{
IReadOnlyList<DocumentFormReference> documentForms;
IReadOnlyList<PersonReference> verifiers;
@@ -489,22 +629,41 @@ namespace XLAB
IsBusy = false;
}
var seed = CreateVerificationSeed(line, isPassed, documentForms);
var seed = CreateVerificationSeed(targetLines[0], isPassed, documentForms);
var result = _dialogService.ShowVerificationDialog(seed, verifiers, documentForms);
if (result == null)
{
return;
}
if (line.IsPendingInsert)
var pendingLines = targetLines.Where(delegate(PsvDocumentLine line) { return line.IsPendingInsert; }).ToList();
var persistedCardIds = targetLines.Where(delegate(PsvDocumentLine line) { return !line.IsPendingInsert; })
.Select(delegate(PsvDocumentLine line) { return line.CardId; })
.Distinct()
.ToList();
if (persistedCardIds.Count == 0)
{
ApplyVerificationResultToLine(line, result);
foreach (var pendingLine in pendingLines)
{
ApplyVerificationResultCore(pendingLine, result);
pendingLine.IsBatchSelected = false;
}
RefreshAfterLineVerificationChanged(targetLines[0]);
return;
}
RunBusyOperation(async delegate
{
await Task.Run(delegate { _service.SaveLineVerification(line.CardId, result); });
await Task.Run(delegate { _service.SaveLineVerification(persistedCardIds, result); });
foreach (var pendingLine in pendingLines)
{
ApplyVerificationResultCore(pendingLine, result);
pendingLine.IsBatchSelected = false;
}
await ReloadSelectedDocumentLinesAsync();
});
}
@@ -516,25 +675,45 @@ namespace XLAB
SelectedDocumentGroup = FindMatchingGroup(previousGroup) ?? DocumentGroupSummaries.FirstOrDefault();
RefreshDocumentLinesView();
SelectedDocumentLine = line;
RaiseCommandStates();
}
private void ResetSelectedLineVerificationAsync()
{
var line = SelectedDocumentLine;
if (line == null)
var targetLines = GetVerificationTargetLines();
if (targetLines.Count == 0)
{
return;
}
if (line.IsPendingInsert)
var pendingLines = targetLines.Where(delegate(PsvDocumentLine line) { return line.IsPendingInsert; }).ToList();
var persistedCardIds = targetLines.Where(delegate(PsvDocumentLine line) { return !line.IsPendingInsert; })
.Select(delegate(PsvDocumentLine line) { return line.CardId; })
.Distinct()
.ToList();
if (persistedCardIds.Count == 0)
{
ClearVerificationFromLine(line);
foreach (var pendingLine in pendingLines)
{
ClearVerificationFromLineCore(pendingLine);
pendingLine.IsBatchSelected = false;
}
RefreshAfterLineVerificationChanged(targetLines[0]);
return;
}
RunBusyOperation(async delegate
{
await Task.Run(delegate { _service.ResetLineVerification(line.CardId); });
await Task.Run(delegate { _service.ResetLineVerification(persistedCardIds); });
foreach (var pendingLine in pendingLines)
{
ClearVerificationFromLineCore(pendingLine);
pendingLine.IsBatchSelected = false;
}
await ReloadSelectedDocumentLinesAsync();
});
}
@@ -582,6 +761,132 @@ namespace XLAB
DocumentStatusText = string.Format("Документов: {0}.", Documents.Count);
}
private void DeleteSelectedGroupsAsync()
{
if (SelectedDocument == null)
{
return;
}
var targetGroups = GetDeleteTargetGroups();
if (targetGroups.Count == 0)
{
return;
}
var targetLines = DocumentLines
.Where(delegate(PsvDocumentLine line)
{
return targetGroups.Any(delegate(PsvDocumentGroupSummary group) { return group.Matches(line); });
})
.ToList();
if (targetLines.Count == 0)
{
_dialogService.ShowWarning("Для удаления не найдено строк выбранных групп.");
return;
}
if (!_dialogService.Confirm(string.Format(
"Удалить из ПСВ \"{0}\" групп: {1}, строк приборов: {2}?",
SelectedDocument.DocumentNumber,
targetGroups.Count,
targetLines.Count)))
{
return;
}
var selectedDocument = SelectedDocument;
var selectedDocumentKey = selectedDocument.DocumentKey;
var selectedDocumentNumber = selectedDocument.DocumentNumber;
RunBusyOperation(async delegate
{
var pendingLines = GetPendingLines(selectedDocument);
var pendingLinesToRemove = pendingLines
.Where(delegate(PsvDocumentLine line)
{
return line.IsPendingInsert
&& targetGroups.Any(delegate(PsvDocumentGroupSummary group) { return group.Matches(line); });
})
.ToList();
var persistedCardIds = targetLines
.Where(delegate(PsvDocumentLine line) { return !line.IsPendingInsert; })
.Select(delegate(PsvDocumentLine line) { return line.CardId; })
.Distinct()
.ToList();
foreach (var pendingLine in pendingLinesToRemove)
{
pendingLines.Remove(pendingLine);
}
var deletedPendingCount = pendingLinesToRemove.Count;
var deletedResult = new DocumentGroupDeleteResult();
if (persistedCardIds.Count > 0)
{
deletedResult = await Task.Run(delegate
{
return _service.DeleteDocumentGroups(selectedDocumentNumber, persistedCardIds);
});
}
var remainingPendingCount = pendingLines.Count;
var remainingPersistedCount = DocumentLines.Count(delegate(PsvDocumentLine line) { return !line.IsPendingInsert; }) - persistedCardIds.Count;
if (selectedDocument.IsDraft)
{
UpdateDocumentSummaryFromLines(selectedDocument, pendingLines);
ApplyDocumentLines(pendingLines, SelectedDocumentGroup);
DocumentsView.Refresh();
DocumentStatusText = string.Format("Документов: {0}.", Documents.Count);
}
else if (remainingPersistedCount == 0 && remainingPendingCount > 0)
{
if (!_draftDocuments.Any(delegate(PsvDocumentSummary draft) { return draft.DocumentKey == selectedDocumentKey; }))
{
_draftDocuments.Add(selectedDocument);
}
selectedDocument.IsDraft = true;
UpdateDocumentSummaryFromLines(selectedDocument, pendingLines);
await RefreshDocumentsCoreAsync(selectedDocumentKey, selectedDocumentNumber);
}
else
{
await RefreshDocumentsCoreAsync(selectedDocumentKey, selectedDocumentNumber);
}
var messages = new List<string>();
if (deletedPendingCount > 0)
{
messages.Add(string.Format("Удалено черновых строк: {0}.", deletedPendingCount));
}
if (deletedResult.DeletedEkzMkFctvlCount > 0)
{
messages.Add(string.Format("Удалено строк EKZMKFCTVL: {0}.", deletedResult.DeletedEkzMkFctvlCount));
}
if (deletedResult.DeletedEkzMkCount > 0)
{
messages.Add(string.Format("Удалено строк EKZMK: {0}.", deletedResult.DeletedEkzMkCount));
}
if (deletedResult.DeletedDmsCount > 0)
{
messages.Add(string.Format("Удалено связанных DMS: {0}.", deletedResult.DeletedDmsCount));
}
if (messages.Count > 0)
{
_dialogService.ShowInfo(string.Join(" ", messages.ToArray()));
}
});
}
private bool DocumentExistsInCollections(string documentNumber, string excludeDocumentKey)
{
return Documents.Any(delegate(PsvDocumentSummary document)
@@ -591,6 +896,20 @@ namespace XLAB
});
}
private static void UpdateDocumentSummaryFromLines(PsvDocumentSummary document, IEnumerable<PsvDocumentLine> lines)
{
if (document == null)
{
return;
}
var materializedLines = lines == null ? new List<PsvDocumentLine>() : lines.ToList();
document.ItemCount = materializedLines.Count;
document.PassedCount = materializedLines.Count(delegate(PsvDocumentLine line) { return line.IsPassed == true; });
document.FailedCount = materializedLines.Count(delegate(PsvDocumentLine line) { return line.IsPassed == false; });
document.IssuedCount = materializedLines.Count(delegate(PsvDocumentLine line) { return line.IssuedOn.HasValue; });
}
private async Task ExecuteBusyOperationAsync(Func<Task> operation)
{
if (IsBusy)
@@ -671,12 +990,19 @@ namespace XLAB
return DocumentGroupSummaries.FirstOrDefault(delegate(PsvDocumentGroupSummary current)
{
return string.Equals(current.InstrumentType ?? string.Empty, group.InstrumentType ?? string.Empty, StringComparison.OrdinalIgnoreCase)
&& string.Equals(current.RangeText ?? string.Empty, group.RangeText ?? string.Empty, StringComparison.OrdinalIgnoreCase)
&& string.Equals(current.RegistryNumber ?? string.Empty, group.RegistryNumber ?? string.Empty, StringComparison.OrdinalIgnoreCase);
return AreSameGroup(current, group);
});
}
private static bool AreSameGroup(PsvDocumentGroupSummary left, PsvDocumentGroupSummary right)
{
return left != null
&& 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.RegistryNumber ?? string.Empty, right.RegistryNumber ?? string.Empty, StringComparison.OrdinalIgnoreCase);
}
private void FillHeaderFromSelection()
{
if (SelectedDocument == null)
@@ -731,8 +1057,8 @@ namespace XLAB
{
if (SelectedDocument == null)
{
ClearCollections(DocumentLines);
ClearCollections(DocumentGroupSummaries);
ClearDocumentLines();
ClearDocumentGroups();
SelectedDocumentGroup = null;
SelectedDocumentLine = null;
LineStatusText = "Документ не выбран.";
@@ -753,8 +1079,8 @@ namespace XLAB
{
if (SelectedDocument == null)
{
ClearCollections(DocumentLines);
ClearCollections(DocumentGroupSummaries);
ClearDocumentLines();
ClearDocumentGroups();
SelectedDocumentGroup = null;
SelectedDocumentLine = null;
return;
@@ -894,9 +1220,10 @@ namespace XLAB
private void ApplyDocumentLines(IEnumerable<PsvDocumentLine> lines, PsvDocumentGroupSummary previousGroup)
{
var previousLine = SelectedDocumentLine;
ClearCollections(DocumentLines);
ClearDocumentLines();
foreach (var line in lines)
{
SubscribeToDocumentLine(line);
DocumentLines.Add(line);
}
@@ -916,12 +1243,14 @@ namespace XLAB
&& string.Equals(line.DuplicateKey, previousLine.DuplicateKey, StringComparison.OrdinalIgnoreCase);
});
RefreshDocumentLinesView();
RaiseCommandStates();
}
private void RaiseCommandStates()
{
((RelayCommand)AddDocumentCommand).RaiseCanExecuteChanged();
((RelayCommand)DeleteDocumentCommand).RaiseCanExecuteChanged();
((RelayCommand)DeleteSelectedGroupsCommand).RaiseCanExecuteChanged();
((RelayCommand)MarkLinePassedCommand).RaiseCanExecuteChanged();
((RelayCommand)MarkLineRejectedCommand).RaiseCanExecuteChanged();
((RelayCommand)OpenInstrumentPickerCommand).RaiseCanExecuteChanged();
@@ -932,7 +1261,11 @@ namespace XLAB
private void RebuildDocumentGroupSummaries(IEnumerable<PsvDocumentLine> lines)
{
ClearCollections(DocumentGroupSummaries);
var checkedGroups = DocumentGroupSummaries
.Where(delegate(PsvDocumentGroupSummary group) { return group.IsBatchSelected; })
.ToList();
ClearDocumentGroups();
var groups = lines.GroupBy(line => new
{
@@ -948,6 +1281,12 @@ namespace XLAB
InstrumentType = group.Key.InstrumentType,
RangeText = group.Key.RangeText,
RegistryNumber = group.Key.RegistryNumber,
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.RegistryNumber ?? string.Empty, group.Key.RegistryNumber, StringComparison.OrdinalIgnoreCase);
}),
InVerificationCount = group.Count(line => !line.IsPassed.HasValue),
VerifiedCount = group.Count(line => line.IsPassed.HasValue),
GoodCount = group.Count(line => line.IsPassed == true),
@@ -956,6 +1295,7 @@ namespace XLAB
foreach (var group in groups)
{
SubscribeToDocumentGroup(group);
DocumentGroupSummaries.Add(group);
}
}
@@ -964,6 +1304,7 @@ namespace XLAB
{
DocumentLinesView.Refresh();
UpdateLineStatus();
RaiseCommandStates();
}
private void RefreshDocumentsAsync(string documentKeyToSelect, string documentNumberToSelect)

View File

@@ -330,7 +330,7 @@ SELECT
CASE
WHEN instrumentTemplate.LastDocumentNumber IS NOT NULL
OR typeTemplate.LastDocumentNumber IS NOT NULL
OR periodTemplate.PeriodMonths IS NOT NULL
OR COALESCE(periodByInstrument.PRMK, periodByType.PRMK) IS NOT NULL
THEN CAST(1 AS bit)
ELSE CAST(0 AS bit)
END AS HasTemplate,
@@ -339,6 +339,7 @@ SELECT
CASE
WHEN instrumentTemplate.LastDocumentNumber IS NOT NULL THEN N'История прибора'
WHEN typeTemplate.LastDocumentNumber IS NOT NULL THEN N'Шаблон по типоразмеру'
WHEN COALESCE(periodByInstrument.PRMK, periodByType.PRMK) IS NOT NULL THEN N'Период из TPRMCP'
ELSE N''
END AS TemplateSource
FROM dbo.EKZ z
@@ -369,21 +370,20 @@ OUTER APPLY
OUTER APPLY
(
SELECT TOP (1)
COALESCE(periodByInstrument.PRMK, periodByType.PRMK) AS PeriodMonths
FROM
(
SELECT t.PRMK
t.PRMK
FROM dbo.EKZMCP e
JOIN dbo.TPRMCP t ON t.IDTPRMCP = e.IDTPRMCP
WHERE e.IDEKZ = z.IDEKZ
ORDER BY e.IDEKZMCP DESC, t.IDTPRMCP DESC
) periodByInstrument
FULL JOIN
OUTER APPLY
(
SELECT t.PRMK
SELECT TOP (1)
t.PRMK
FROM dbo.TPRMCP t
WHERE t.IDTPRZ = z.IDTPRZ
) periodByType ON 1 = 0
) periodTemplate
ORDER BY t.IDTPRMCP DESC
) periodByType
WHERE z.IDFRPDV = @CustomerId
ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, z.NNZV;";
@@ -488,6 +488,76 @@ ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, z.NNZV;";
}
}
public void ResetLineVerification(IEnumerable<int> cardIds)
{
var normalizedCardIds = NormalizeCardIds(
cardIds,
"Не выбрана строка EKZMK для отмены поверки.",
"Не выбрано ни одной строки EKZMK для отмены поверки.");
using (var connection = CreateConnection())
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
foreach (var cardId in normalizedCardIds)
{
ClearLineVerificationCore(connection, transaction, cardId);
DeleteVerificationDocuments(connection, transaction, cardId);
}
transaction.Commit();
}
}
}
public void SaveLineVerification(IEnumerable<int> cardIds, VerificationEditResult result)
{
if (result == null)
{
throw new ArgumentNullException("result");
}
var normalizedCardIds = NormalizeCardIds(
cardIds,
"Не выбрана строка EKZMK для сохранения результата поверки.",
"Не выбрано ни одной строки EKZMK для сохранения результата поверки.");
using (var connection = CreateConnection())
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
foreach (var cardId in normalizedCardIds)
{
SaveLineVerificationCore(connection, transaction, cardId, result);
DeleteVerificationDocuments(connection, transaction, cardId);
if (!string.IsNullOrWhiteSpace(result.VerificationDocumentNumber))
{
if (result.DocumentFormId <= 0 || result.DocumentLinkTypeId <= 0)
{
throw new InvalidOperationException("Для документа поверки не определена форма или связь с объектом.");
}
InsertVerificationDocument(
connection,
transaction,
cardId,
result.DocumentLinkTypeId,
result.DocumentFormId,
result.VerificationDocumentNumber,
result.VerificationDate);
}
}
transaction.Commit();
}
}
}
public DocumentSaveResult SaveDocument(string currentDocumentNumber, DocumentEditorResult document, IEnumerable<PsvDocumentLine> pendingLines)
{
if (document == null)
@@ -656,6 +726,87 @@ ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, z.NNZV;";
}
}
public DocumentGroupDeleteResult DeleteDocumentGroups(string documentNumber, IEnumerable<int> cardIds)
{
if (string.IsNullOrWhiteSpace(documentNumber))
{
throw new InvalidOperationException("Не выбран документ для удаления групп.");
}
var normalizedCardIds = NormalizeCardIds(
cardIds,
"Рсписке удаляемых строк есть некорректный IDEKZMK.",
"Не выбрано ни одной строки EKZMK для удаления.");
using (var connection = CreateConnection())
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
var blockers = LoadDeleteBlockers(connection, transaction, normalizedCardIds);
if (blockers.Count > 0)
{
var details = string.Join(", ", blockers.Select(delegate(DeleteBlockerInfo blocker)
{
return string.Format("{0}: {1}", blocker.TableName, blocker.RowCount);
}));
throw new InvalidOperationException(
string.Format(
"Выбранные строки EKZMK не могут быть удалены, потому что на них есть ссылки в таблицах: {0}. По вашему правилу приложение не трогает эти таблицы.",
details));
}
var deletedEkzMkFctvlCount = 0;
var deletedDmsCount = 0;
var deletedEkzMkCount = 0;
foreach (var cardId in normalizedCardIds)
{
deletedEkzMkFctvlCount += DeleteLineEkzMkFctvl(connection, transaction, documentNumber, cardId);
deletedDmsCount += DeleteLineDms(connection, transaction, documentNumber, cardId);
deletedEkzMkCount += DeleteLineEkzMk(connection, transaction, documentNumber, cardId);
}
if (deletedEkzMkCount == 0)
{
throw new InvalidOperationException("Строки EKZMK для выбранных групп не найдены.");
}
transaction.Commit();
return new DocumentGroupDeleteResult
{
DeletedEkzMkFctvlCount = deletedEkzMkFctvlCount,
DeletedEkzMkCount = deletedEkzMkCount,
DeletedDmsCount = deletedDmsCount
};
}
}
}
private static List<int> NormalizeCardIds(IEnumerable<int> cardIds, string invalidCardMessage, string emptyListMessage)
{
if (cardIds == null)
{
throw new InvalidOperationException(emptyListMessage);
}
var normalizedCardIds = cardIds.Distinct().ToList();
if (normalizedCardIds.Count == 0)
{
throw new InvalidOperationException(emptyListMessage);
}
if (normalizedCardIds.Any(delegate(int cardId) { return cardId <= 0; }))
{
throw new InvalidOperationException(invalidCardMessage);
}
return normalizedCardIds;
}
private static SqlConnection CreateConnection()
{
var connectionString = ConfigurationManager.ConnectionStrings["AsumsSql"];
@@ -789,6 +940,63 @@ SELECT @@ROWCOUNT;";
}
}
private static int DeleteLineDms(SqlConnection connection, SqlTransaction transaction, string documentNumber, int cardId)
{
const string sql = @"
DELETE d
FROM dbo.DMS d
JOIN dbo.VDODVDD vdd ON vdd.IDVDODVDD = d.IDVDODVDD
JOIN dbo.EKZMK m ON m.IDEKZMK = d.IDOD
WHERE m.NNZVPV = @DocumentNumber
AND m.IDEKZMK = @CardId
AND vdd.IDSPVDOD = 2;
SELECT @@ROWCOUNT;";
using (var command = new SqlCommand(sql, connection, transaction))
{
command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber;
command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId;
return Convert.ToInt32(command.ExecuteScalar());
}
}
private static int DeleteLineEkzMk(SqlConnection connection, SqlTransaction transaction, string documentNumber, int cardId)
{
const string sql = @"
DELETE FROM dbo.EKZMK
WHERE NNZVPV = @DocumentNumber
AND IDEKZMK = @CardId;
SELECT @@ROWCOUNT;";
using (var command = new SqlCommand(sql, connection, transaction))
{
command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber;
command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId;
return Convert.ToInt32(command.ExecuteScalar());
}
}
private static int DeleteLineEkzMkFctvl(SqlConnection connection, SqlTransaction transaction, string documentNumber, int cardId)
{
const string sql = @"
DELETE child
FROM dbo.EKZMKFCTVL child
JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK
WHERE parent.NNZVPV = @DocumentNumber
AND parent.IDEKZMK = @CardId;
SELECT @@ROWCOUNT;";
using (var command = new SqlCommand(sql, connection, transaction))
{
command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber;
command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId;
return Convert.ToInt32(command.ExecuteScalar());
}
}
private static int DeleteDocumentDms(SqlConnection connection, SqlTransaction transaction, string documentNumber)
{
const string sql = @"
@@ -1100,6 +1308,101 @@ WHERE m.NNZVPV = @DocumentNumber;";
return keys;
}
private static List<DeleteBlockerInfo> LoadDeleteBlockers(SqlConnection connection, SqlTransaction transaction, IEnumerable<int> cardIds)
{
var aggregated = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
foreach (var cardId in cardIds)
{
foreach (var blocker in LoadDeleteBlockers(connection, transaction, cardId))
{
int currentCount;
if (!aggregated.TryGetValue(blocker.TableName, out currentCount))
{
currentCount = 0;
}
aggregated[blocker.TableName] = currentCount + blocker.RowCount;
}
}
return aggregated
.OrderBy(delegate(KeyValuePair<string, int> blocker) { return blocker.Key; })
.Select(delegate(KeyValuePair<string, int> blocker)
{
return new DeleteBlockerInfo
{
TableName = blocker.Key,
RowCount = blocker.Value
};
})
.ToList();
}
private static List<DeleteBlockerInfo> LoadDeleteBlockers(SqlConnection connection, SqlTransaction transaction, int cardId)
{
const string sql = @"
SELECT blocker.TableName, blocker.LinkCount
FROM
(
SELECT N'EKZMKDH' AS TableName, COUNT(*) AS LinkCount
FROM dbo.EKZMKDH child
JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK
WHERE parent.IDEKZMK = @CardId
UNION ALL
SELECT N'EKZMKEKZK', COUNT(*)
FROM dbo.EKZMKEKZK child
JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK
WHERE parent.IDEKZMK = @CardId
UNION ALL
SELECT N'EKZMKND', COUNT(*)
FROM dbo.EKZMKND child
JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK
WHERE parent.IDEKZMK = @CardId
UNION ALL
SELECT N'FRPTMK', COUNT(*)
FROM dbo.FRPTMK child
JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK
WHERE parent.IDEKZMK = @CardId
UNION ALL
SELECT N'KSPELEKZMK', COUNT(*)
FROM dbo.KSPELEKZMK child
JOIN dbo.EKZMK parent ON parent.IDEKZMK = child.IDEKZMK
WHERE parent.IDEKZMK = @CardId
) blocker
WHERE blocker.LinkCount > 0
ORDER BY blocker.TableName;";
var blockers = new List<DeleteBlockerInfo>();
using (var command = new SqlCommand(sql, connection, transaction))
{
command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId;
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
blockers.Add(new DeleteBlockerInfo
{
TableName = GetString(reader, "TableName"),
RowCount = GetInt32(reader, "LinkCount")
});
}
}
}
return blockers;
}
private static List<DeleteBlockerInfo> LoadDeleteBlockers(SqlConnection connection, SqlTransaction transaction, string documentNumber)
{
const string sql = @"
@@ -1315,11 +1618,8 @@ ORDER BY Priority;";
using (var reader = command.ExecuteReader())
{
if (!reader.Read())
if (reader.Read())
{
return null;
}
return new EkzMkTemplate
{
IdSpmu = GetNullableInt32(reader, "IDSPMU"),
@@ -1355,6 +1655,9 @@ ORDER BY Priority;";
}
}
return LoadFallbackTemplate(connection, transaction, instrumentId);
}
private static EkzMkTemplate LoadFallbackTemplate(SqlConnection connection, SqlTransaction transaction, int instrumentId)
{
const string sql = @"
@@ -1365,11 +1668,11 @@ WITH DefaultLab AS
FROM dbo.EKZMK m
)
SELECT TOP (1)
periodInfo.IDGRSI,
periodInfo.IDSPVDMC,
COALESCE(periodByInstrument.IDGRSI, periodByType.IDGRSI) AS IDGRSI,
COALESCE(periodByInstrument.IDSPVDMC, periodByType.IDSPVDMC) AS IDSPVDMC,
defaultLab.DefaultIdFrpd AS IDFRPD,
tprz.IDSPKMMK,
periodInfo.PRMK,
COALESCE(periodByInstrument.PRMK, periodByType.PRMK) AS PRMK,
tprz.DPZN AS DPZNmp,
tprz.HRTC AS HRTCmp,
CAST(N'Период из TPRMCP' AS nvarchar(60)) AS SourceDescription
@@ -1379,26 +1682,27 @@ CROSS JOIN DefaultLab defaultLab
OUTER APPLY
(
SELECT TOP (1)
COALESCE(periodByInstrument.IDGRSI, periodByType.IDGRSI) AS IDGRSI,
COALESCE(periodByInstrument.IDSPVDMC, periodByType.IDSPVDMC) AS IDSPVDMC,
COALESCE(periodByInstrument.PRMK, periodByType.PRMK) AS PRMK
FROM
(
SELECT t.IDGRSI, t.IDSPVDMC, t.PRMK
t.IDGRSI,
t.IDSPVDMC,
t.PRMK
FROM dbo.EKZMCP e
JOIN dbo.TPRMCP t ON t.IDTPRMCP = e.IDTPRMCP
WHERE e.IDEKZ = z.IDEKZ
ORDER BY e.IDEKZMCP DESC, t.IDTPRMCP DESC
) periodByInstrument
FULL JOIN
OUTER APPLY
(
SELECT t.IDGRSI, t.IDSPVDMC, t.PRMK
SELECT TOP (1)
t.IDGRSI,
t.IDSPVDMC,
t.PRMK
FROM dbo.TPRMCP t
WHERE t.IDTPRZ = z.IDTPRZ
) periodByType ON 1 = 0
) periodInfo
ORDER BY t.IDTPRMCP DESC
) periodByType
WHERE z.IDEKZ = @InstrumentId
AND defaultLab.DefaultIdFrpd IS NOT NULL
AND periodInfo.PRMK IS NOT NULL;";
AND COALESCE(periodByInstrument.PRMK, periodByType.PRMK) IS NOT NULL;";
using (var command = new SqlCommand(sql, connection, transaction))
{

View File

@@ -125,8 +125,10 @@ namespace XLAB
}
}
public sealed class PsvDocumentLine
public sealed class PsvDocumentLine : ObservableObject
{
private bool _isBatchSelected;
public int CardId { get; set; }
public int InstrumentId { get; set; }
@@ -181,6 +183,12 @@ namespace XLAB
public bool IsPendingInsert { get; set; }
public bool IsBatchSelected
{
get { return _isBatchSelected; }
set { SetProperty(ref _isBatchSelected, value); }
}
public string DuplicateKey
{
get
@@ -235,8 +243,10 @@ namespace XLAB
}
}
public sealed class PsvDocumentGroupSummary
public sealed class PsvDocumentGroupSummary : ObservableObject
{
private bool _isBatchSelected;
public string InstrumentType { get; set; }
public string RangeText { get; set; }
@@ -251,6 +261,12 @@ namespace XLAB
public int RejectedCount { get; set; }
public bool IsBatchSelected
{
get { return _isBatchSelected; }
set { SetProperty(ref _isBatchSelected, value); }
}
public bool Matches(PsvDocumentLine line)
{
return line != null
@@ -385,6 +401,15 @@ namespace XLAB
public int DeletedDmsCount { get; set; }
}
internal sealed class DocumentGroupDeleteResult
{
public int DeletedEkzMkFctvlCount { get; set; }
public int DeletedEkzMkCount { get; set; }
public int DeletedDmsCount { get; set; }
}
internal sealed class DocumentSaveResult
{
public string DocumentNumber { get; set; }