diff --git a/XLAB.slnx b/XLAB.slnx
index a0b3985..5b5d087 100644
--- a/XLAB.slnx
+++ b/XLAB.slnx
@@ -1,4 +1,4 @@
-
-
+
+
diff --git a/XLAB/DialogService.cs b/XLAB/DialogService.cs
index 91e40e7..18b2a15 100644
--- a/XLAB/DialogService.cs
+++ b/XLAB/DialogService.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using System.Windows;
namespace XLAB
@@ -6,6 +7,13 @@ namespace XLAB
{
DocumentEditorResult ShowCreateDocumentDialog(DocumentEditorResult seed);
+ IReadOnlyList ShowInstrumentPickerDialog(string customerName, IReadOnlyList instruments);
+
+ VerificationEditResult ShowVerificationDialog(
+ VerificationEditSeed seed,
+ IReadOnlyList verifiers,
+ IReadOnlyList documentForms);
+
bool Confirm(string message);
void ShowError(string message);
@@ -34,6 +42,29 @@ namespace XLAB
return result.HasValue && result.Value ? viewModel.ToResult() : null;
}
+ public IReadOnlyList ShowInstrumentPickerDialog(string customerName, IReadOnlyList instruments)
+ {
+ var viewModel = new SelectInstrumentsWindowViewModel(customerName, instruments);
+ var window = new SelectInstrumentsWindow(viewModel);
+ window.Owner = _owner;
+
+ var result = window.ShowDialog();
+ return result.HasValue && result.Value ? viewModel.GetSelectedItems() : null;
+ }
+
+ public VerificationEditResult ShowVerificationDialog(
+ VerificationEditSeed seed,
+ IReadOnlyList verifiers,
+ IReadOnlyList documentForms)
+ {
+ var viewModel = new VerificationEditWindowViewModel(seed, verifiers, documentForms);
+ var window = new VerificationEditWindow(viewModel);
+ window.Owner = _owner;
+
+ var result = window.ShowDialog();
+ return result.HasValue && result.Value ? viewModel.ToResult() : null;
+ }
+
public bool Confirm(string message)
{
return MessageBox.Show(_owner, message, "ПСВ", MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes;
diff --git a/XLAB/MainWindow.xaml b/XLAB/MainWindow.xaml
index 7f0c807..8e70539 100644
--- a/XLAB/MainWindow.xaml
+++ b/XLAB/MainWindow.xaml
@@ -157,12 +157,15 @@
Margin="0,0,8,6"
VerticalAlignment="Center"
Text="Заказчик" />
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
_draftDocuments;
private readonly IDialogService _dialogService;
+ private readonly Dictionary> _pendingLinesByDocumentKey;
private readonly PsvDataService _service;
private string _documentFilterText;
private string _documentNumberEditor;
private string _documentStatusText;
private string _groupDetailFilterText;
- private string _headerCustomerName;
private string _headerDepartmentName;
private DateTime? _headerIssuedOn;
private DateTime? _headerReceivedOn;
private bool _isBusy;
private string _lineStatusText;
+ private int? _selectedCustomerId;
private PsvDocumentSummary _selectedDocument;
private PsvDocumentGroupSummary _selectedDocumentGroup;
+ private PsvDocumentLine _selectedDocumentLine;
public MainWindowViewModel(PsvDataService service, IDialogService dialogService)
{
_service = service;
_dialogService = dialogService;
_draftDocuments = new List();
+ _pendingLinesByDocumentKey = new Dictionary>(StringComparer.OrdinalIgnoreCase);
+ Customers = new ObservableCollection();
Documents = new ObservableCollection();
DocumentLines = new ObservableCollection();
DocumentGroupSummaries = new ObservableCollection();
@@ -45,8 +49,12 @@ namespace XLAB
AddDocumentCommand = new RelayCommand(delegate { AddDocument(); }, delegate { return !IsBusy; });
DeleteDocumentCommand = new RelayCommand(delegate { DeleteDocumentAsync(); }, delegate { return !IsBusy && SelectedDocument != null; });
- RefreshDocumentsCommand = new RelayCommand(delegate { RefreshDocumentsAsync(null); }, delegate { return !IsBusy; });
- SaveDocumentHeaderCommand = new RelayCommand(delegate { SaveDocumentHeaderAsync(); }, delegate { return !IsBusy && SelectedDocument != null && !SelectedDocument.IsDraft; });
+ 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; });
+ RefreshDocumentsCommand = new RelayCommand(delegate { RefreshDocumentsAsync(null, null); }, delegate { return !IsBusy; });
+ ResetLineVerificationCommand = new RelayCommand(delegate { ResetSelectedLineVerificationAsync(); }, delegate { return CanResetSelectedLineVerification(); });
+ SaveDocumentHeaderCommand = new RelayCommand(delegate { SaveDocumentAsync(); }, delegate { return CanSaveDocument(); });
DocumentStatusText = "Готово.";
LineStatusText = "Документ не выбран.";
@@ -54,6 +62,8 @@ namespace XLAB
public ICommand AddDocumentCommand { get; private set; }
+ public ObservableCollection Customers { get; private set; }
+
public string DocumentFilterText
{
get { return _documentFilterText; }
@@ -66,24 +76,24 @@ namespace XLAB
}
}
+ public ObservableCollection DocumentLines { get; private set; }
+
+ public ICollectionView DocumentLinesView { get; private set; }
+
public string DocumentNumberEditor
{
get { return _documentNumberEditor; }
set { SetProperty(ref _documentNumberEditor, value); }
}
+ public ObservableCollection DocumentGroupSummaries { get; private set; }
+
public string DocumentStatusText
{
get { return _documentStatusText; }
private set { SetProperty(ref _documentStatusText, value); }
}
- public ObservableCollection DocumentLines { get; private set; }
-
- public ObservableCollection DocumentGroupSummaries { get; private set; }
-
- public ICollectionView DocumentLinesView { get; private set; }
-
public ObservableCollection Documents { get; private set; }
public ICollectionView DocumentsView { get; private set; }
@@ -102,12 +112,6 @@ namespace XLAB
}
}
- public string HeaderCustomerName
- {
- get { return _headerCustomerName; }
- private set { SetProperty(ref _headerCustomerName, value); }
- }
-
public string HeaderDepartmentName
{
get { return _headerDepartmentName; }
@@ -134,20 +138,54 @@ namespace XLAB
if (SetProperty(ref _isBusy, value))
{
RaiseCommandStates();
+ OnPropertyChanged("IsCustomerEditable");
}
}
}
+ public bool IsCustomerEditable
+ {
+ get
+ {
+ return !IsBusy
+ && SelectedDocument != null
+ && SelectedDocument.IsDraft
+ && GetPendingLines(SelectedDocument).Count == 0;
+ }
+ }
+
public string LineStatusText
{
get { return _lineStatusText; }
private set { SetProperty(ref _lineStatusText, value); }
}
+ public ICommand MarkLinePassedCommand { get; private set; }
+
+ public ICommand MarkLineRejectedCommand { get; private set; }
+
+ public ICommand OpenInstrumentPickerCommand { get; private set; }
+
public ICommand RefreshDocumentsCommand { get; private set; }
+ public ICommand ResetLineVerificationCommand { get; private set; }
+
public ICommand SaveDocumentHeaderCommand { get; private set; }
+ public int? SelectedCustomerId
+ {
+ get { return _selectedCustomerId; }
+ set
+ {
+ if (!SetProperty(ref _selectedCustomerId, value))
+ {
+ return;
+ }
+
+ ApplySelectedCustomer();
+ }
+ }
+
public PsvDocumentSummary SelectedDocument
{
get { return _selectedDocument; }
@@ -157,6 +195,7 @@ namespace XLAB
{
FillHeaderFromSelection();
RaiseCommandStates();
+ OnPropertyChanged("IsCustomerEditable");
LoadSelectedDocumentAsync();
}
}
@@ -174,18 +213,29 @@ namespace XLAB
}
}
+ public PsvDocumentLine SelectedDocumentLine
+ {
+ get { return _selectedDocumentLine; }
+ set
+ {
+ if (SetProperty(ref _selectedDocumentLine, value))
+ {
+ RaiseCommandStates();
+ }
+ }
+ }
+
public async Task InitializeAsync()
{
- await RefreshDocumentsCoreAsync(null);
+ await ExecuteBusyOperationAsync(async delegate
+ {
+ await LoadCustomersCoreAsync();
+ await RefreshDocumentsCoreAsync(null, null);
+ });
}
private void AddDocument()
{
- if (IsBusy)
- {
- return;
- }
-
var request = _dialogService.ShowCreateDocumentDialog(new DocumentEditorResult
{
AcceptedOn = DateTime.Today,
@@ -198,19 +248,13 @@ namespace XLAB
return;
}
- request.DocumentNumber = request.DocumentNumber == null ? string.Empty : request.DocumentNumber.Trim();
- request.IssuedOn = null;
-
if (string.IsNullOrWhiteSpace(request.DocumentNumber))
{
_dialogService.ShowWarning("Введите номер ПСВ.");
return;
}
- if (Documents.Any(delegate(PsvDocumentSummary document)
- {
- return string.Equals(document.DocumentNumber, request.DocumentNumber, StringComparison.OrdinalIgnoreCase);
- }))
+ if (DocumentExistsInCollections(request.DocumentNumber, null))
{
_dialogService.ShowWarning("ПСВ с таким номером уже есть в списке.");
return;
@@ -218,10 +262,12 @@ namespace XLAB
var draft = new PsvDocumentSummary
{
- DocumentNumber = request.DocumentNumber,
+ DocumentKey = Guid.NewGuid().ToString("N"),
+ DocumentNumber = request.DocumentNumber.Trim(),
AcceptedOn = request.AcceptedOn,
IssuedOn = null,
- CustomerName = "Черновик текущего сеанса",
+ CustomerName = string.Empty,
+ CustomerId = null,
DepartmentName = string.Empty,
ItemCount = 0,
IssuedCount = 0,
@@ -237,6 +283,63 @@ namespace XLAB
DocumentStatusText = string.Format("Документов: {0}.", Documents.Count);
}
+ private void ApplySelectedCustomer()
+ {
+ if (SelectedDocument == null || !SelectedDocument.IsDraft)
+ {
+ return;
+ }
+
+ SelectedDocument.CustomerId = SelectedCustomerId;
+ var customer = Customers.FirstOrDefault(delegate(CustomerReference item) { return item.CustomerId == SelectedCustomerId; });
+ SelectedDocument.CustomerName = customer == null ? string.Empty : customer.CustomerName;
+ DocumentsView.Refresh();
+ RaiseCommandStates();
+ }
+
+ private bool CanSaveDocument()
+ {
+ if (IsBusy || SelectedDocument == null)
+ {
+ return false;
+ }
+
+ if (!SelectedDocument.IsDraft)
+ {
+ return true;
+ }
+
+ return GetPendingLines(SelectedDocument).Count > 0;
+ }
+
+ private bool CanEditSelectedLineVerification()
+ {
+ return !IsBusy
+ && SelectedDocumentLine != null
+ && !HasVerificationData(SelectedDocumentLine);
+ }
+
+ private bool CanResetSelectedLineVerification()
+ {
+ return !IsBusy
+ && SelectedDocumentLine != null
+ && HasVerificationData(SelectedDocumentLine);
+ }
+
+ private static bool HasVerificationData(PsvDocumentLine line)
+ {
+ return line != null
+ && (line.IsPassed.HasValue
+ || line.VerificationPerformedOn.HasValue
+ || line.VerifierId.HasValue
+ || !string.IsNullOrWhiteSpace(line.StickerNumber)
+ || line.VerificationDocumentFormId.HasValue
+ || line.VerificationDocumentLinkTypeId.HasValue
+ || !string.IsNullOrWhiteSpace(line.VerificationDocumentNumber)
+ || line.VerificationDocumentDate.HasValue
+ || !string.IsNullOrWhiteSpace(line.RejectionReason));
+ }
+
private void ClearCollections(ObservableCollection collection)
{
collection.Clear();
@@ -247,8 +350,193 @@ namespace XLAB
DocumentNumberEditor = string.Empty;
HeaderReceivedOn = null;
HeaderIssuedOn = null;
- HeaderCustomerName = string.Empty;
HeaderDepartmentName = string.Empty;
+ SelectedCustomerId = null;
+ }
+
+ private VerificationEditSeed CreateVerificationSeed(PsvDocumentLine line, bool isPassed, IReadOnlyList documentForms)
+ {
+ var selectedForm = documentForms == null
+ ? null
+ : documentForms.FirstOrDefault(delegate(DocumentFormReference item)
+ {
+ return item.DocumentFormId == line.VerificationDocumentFormId;
+ });
+
+ return new VerificationEditSeed
+ {
+ DocumentForm = selectedForm,
+ IsPassed = isPassed,
+ RejectionReason = isPassed ? string.Empty : line.RejectionReason,
+ StickerNumber = isPassed ? line.StickerNumber : string.Empty,
+ VerificationDate = line.VerificationPerformedOn ?? line.VerificationDocumentDate ?? DateTime.Today,
+ VerificationDocumentNumber = line.VerificationDocumentNumber,
+ VerifierId = line.VerifierId
+ };
+ }
+
+ private bool Contains(string source, string filter)
+ {
+ return !string.IsNullOrWhiteSpace(source)
+ && source.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0;
+ }
+
+ private PsvDocumentLine CreatePendingLine(AvailableInstrumentItem item)
+ {
+ return new PsvDocumentLine
+ {
+ CardId = 0,
+ InstrumentId = item.InstrumentId,
+ SerialNumber = item.SerialNumber,
+ InventoryNumber = item.InventoryNumber,
+ CustomerName = item.CustomerName,
+ InstrumentType = item.InstrumentType,
+ InstrumentName = item.InstrumentName,
+ MeasurementArea = item.MeasurementArea,
+ RangeText = item.RangeText,
+ RegistryNumber = item.RegistryNumber,
+ AccuracyText = item.AccuracyText,
+ VerificationType = string.Empty,
+ PeriodMonths = 0,
+ AcceptedOn = HeaderReceivedOn,
+ IssuedOn = null,
+ IsPassed = null,
+ VerificationPerformedOn = null,
+ VerifierId = null,
+ VerifierName = string.Empty,
+ StickerNumber = string.Empty,
+ VerificationDocumentFormId = null,
+ VerificationDocumentLinkTypeId = null,
+ VerificationDocumentNumber = string.Empty,
+ VerificationDocumentDate = null,
+ RejectionReason = string.Empty,
+ Notes = string.Empty,
+ IsPendingInsert = true
+ };
+ }
+
+ private void ApplyVerificationResultToLine(PsvDocumentLine line, VerificationEditResult result)
+ {
+ if (line == null || result == null)
+ {
+ return;
+ }
+
+ line.IsPassed = result.IsPassed;
+ line.VerificationPerformedOn = result.VerificationDate;
+ line.VerifierId = result.VerifierId;
+ line.VerifierName = result.VerifierName;
+ line.StickerNumber = result.IsPassed ? result.StickerNumber : string.Empty;
+ line.VerificationDocumentFormId = string.IsNullOrWhiteSpace(result.VerificationDocumentNumber) ? (int?)null : result.DocumentFormId;
+ line.VerificationDocumentLinkTypeId = string.IsNullOrWhiteSpace(result.VerificationDocumentNumber) ? (int?)null : result.DocumentLinkTypeId;
+ line.VerificationDocumentNumber = result.VerificationDocumentNumber;
+ line.VerificationDocumentDate = result.VerificationDate;
+ line.RejectionReason = result.IsPassed ? string.Empty : result.RejectionReason;
+
+ RefreshAfterLineVerificationChanged(line);
+ }
+
+ private void ClearVerificationFromLine(PsvDocumentLine line)
+ {
+ if (line == null)
+ {
+ return;
+ }
+
+ line.IsPassed = null;
+ line.VerificationPerformedOn = null;
+ line.VerifierId = null;
+ line.VerifierName = string.Empty;
+ line.StickerNumber = string.Empty;
+ line.VerificationDocumentFormId = null;
+ line.VerificationDocumentLinkTypeId = null;
+ line.VerificationDocumentNumber = string.Empty;
+ line.VerificationDocumentDate = null;
+ line.RejectionReason = string.Empty;
+
+ RefreshAfterLineVerificationChanged(line);
+ }
+
+ private void EditLineVerificationAsync(bool isPassed)
+ {
+ var line = SelectedDocumentLine;
+ if (line == null)
+ {
+ return;
+ }
+
+ EditLineVerificationCoreAsync(line, isPassed);
+ }
+
+ private async void EditLineVerificationCoreAsync(PsvDocumentLine line, bool isPassed)
+ {
+ IReadOnlyList documentForms;
+ IReadOnlyList verifiers;
+
+ try
+ {
+ IsBusy = true;
+ verifiers = await Task.Run(delegate { return _service.LoadVerifiers(); });
+ documentForms = await Task.Run(delegate { return _service.LoadVerificationDocumentForms(isPassed); });
+ }
+ catch (Exception ex)
+ {
+ _dialogService.ShowError(ex.Message);
+ return;
+ }
+ finally
+ {
+ IsBusy = false;
+ }
+
+ var seed = CreateVerificationSeed(line, isPassed, documentForms);
+ var result = _dialogService.ShowVerificationDialog(seed, verifiers, documentForms);
+ if (result == null)
+ {
+ return;
+ }
+
+ if (line.IsPendingInsert)
+ {
+ ApplyVerificationResultToLine(line, result);
+ return;
+ }
+
+ RunBusyOperation(async delegate
+ {
+ await Task.Run(delegate { _service.SaveLineVerification(line.CardId, result); });
+ await ReloadSelectedDocumentLinesAsync();
+ });
+ }
+
+ private void RefreshAfterLineVerificationChanged(PsvDocumentLine line)
+ {
+ var previousGroup = SelectedDocumentGroup;
+ RebuildDocumentGroupSummaries(DocumentLines);
+ SelectedDocumentGroup = FindMatchingGroup(previousGroup) ?? DocumentGroupSummaries.FirstOrDefault();
+ RefreshDocumentLinesView();
+ SelectedDocumentLine = line;
+ }
+
+ private void ResetSelectedLineVerificationAsync()
+ {
+ var line = SelectedDocumentLine;
+ if (line == null)
+ {
+ return;
+ }
+
+ if (line.IsPendingInsert)
+ {
+ ClearVerificationFromLine(line);
+ return;
+ }
+
+ RunBusyOperation(async delegate
+ {
+ await Task.Run(delegate { _service.ResetLineVerification(line.CardId); });
+ await ReloadSelectedDocumentLinesAsync();
+ });
}
private void DeleteDocumentAsync()
@@ -270,10 +558,11 @@ namespace XLAB
return;
}
- ExecuteBusyOperationAsync(async delegate
+ RunBusyOperation(async delegate
{
var result = await Task.Run(delegate { return _service.DeleteDocument(selectedDocument.DocumentNumber); });
- await RefreshDocumentsCoreAsync(null);
+ _pendingLinesByDocumentKey.Remove(selectedDocument.DocumentKey);
+ await RefreshDocumentsCoreAsync(null, null);
_dialogService.ShowInfo(
string.Format(
"Удалено строк EKZMKFCTVL: {0}. Удалено строк EKZMK: {1}. Удалено связанных DMS: {2}.",
@@ -285,32 +574,24 @@ namespace XLAB
private void DeleteDraftDocument(PsvDocumentSummary draft)
{
- _draftDocuments.RemoveAll(delegate(PsvDocumentSummary item)
- {
- return string.Equals(item.DocumentNumber, draft.DocumentNumber, StringComparison.OrdinalIgnoreCase);
- });
-
+ _draftDocuments.RemoveAll(delegate(PsvDocumentSummary item) { return item.DocumentKey == draft.DocumentKey; });
+ _pendingLinesByDocumentKey.Remove(draft.DocumentKey);
Documents.Remove(draft);
DocumentsView.Refresh();
-
- if (Documents.Count > 0)
- {
- SelectedDocument = Documents[0];
- }
- else
- {
- SelectedDocument = null;
- }
-
+ SelectedDocument = Documents.Count > 0 ? Documents[0] : null;
DocumentStatusText = string.Format("Документов: {0}.", Documents.Count);
}
- private void ExecuteBusyOperationAsync(Func operation)
+ private bool DocumentExistsInCollections(string documentNumber, string excludeDocumentKey)
{
- ExecuteBusyOperationCoreAsync(operation);
+ return Documents.Any(delegate(PsvDocumentSummary document)
+ {
+ return !string.Equals(document.DocumentKey, excludeDocumentKey, StringComparison.OrdinalIgnoreCase)
+ && string.Equals(document.DocumentNumber, documentNumber, StringComparison.OrdinalIgnoreCase);
+ });
}
- private async void ExecuteBusyOperationCoreAsync(Func operation)
+ private async Task ExecuteBusyOperationAsync(Func operation)
{
if (IsBusy)
{
@@ -332,6 +613,11 @@ namespace XLAB
}
}
+ private async void RunBusyOperation(Func operation)
+ {
+ await ExecuteBusyOperationAsync(operation);
+ }
+
private bool FilterDocuments(object item)
{
var document = item as PsvDocumentSummary;
@@ -376,21 +662,6 @@ namespace XLAB
return Contains(line.SerialNumber, GroupDetailFilterText);
}
- private void FillHeaderFromSelection()
- {
- if (SelectedDocument == null)
- {
- ClearHeader();
- return;
- }
-
- DocumentNumberEditor = SelectedDocument.DocumentNumber;
- HeaderReceivedOn = SelectedDocument.AcceptedOn;
- HeaderIssuedOn = SelectedDocument.IssuedOn;
- HeaderCustomerName = SelectedDocument.CustomerName;
- HeaderDepartmentName = SelectedDocument.DepartmentName;
- }
-
private PsvDocumentGroupSummary FindMatchingGroup(PsvDocumentGroupSummary group)
{
if (group == null)
@@ -406,6 +677,34 @@ namespace XLAB
});
}
+ private void FillHeaderFromSelection()
+ {
+ if (SelectedDocument == null)
+ {
+ ClearHeader();
+ return;
+ }
+
+ DocumentNumberEditor = SelectedDocument.DocumentNumber;
+ HeaderReceivedOn = SelectedDocument.AcceptedOn;
+ HeaderIssuedOn = SelectedDocument.IssuedOn;
+ HeaderDepartmentName = SelectedDocument.DepartmentName;
+ SelectedCustomerId = SelectedDocument.CustomerId;
+ }
+
+ private List GetPendingLines(PsvDocumentSummary document)
+ {
+ if (document == null)
+ {
+ return new List();
+ }
+
+ List lines;
+ return _pendingLinesByDocumentKey.TryGetValue(document.DocumentKey, out lines)
+ ? lines
+ : new List();
+ }
+
private void InsertDraftIntoCollection(PsvDocumentSummary draft)
{
var insertIndex = 0;
@@ -418,6 +717,16 @@ namespace XLAB
Documents.Insert(insertIndex, draft);
}
+ private async Task LoadCustomersCoreAsync()
+ {
+ var customers = await Task.Run(delegate { return _service.LoadCustomers(); });
+ ClearCollections(Customers);
+ foreach (var customer in customers)
+ {
+ Customers.Add(customer);
+ }
+ }
+
private async void LoadSelectedDocumentAsync()
{
if (SelectedDocument == null)
@@ -425,41 +734,14 @@ namespace XLAB
ClearCollections(DocumentLines);
ClearCollections(DocumentGroupSummaries);
SelectedDocumentGroup = null;
+ SelectedDocumentLine = null;
LineStatusText = "Документ не выбран.";
return;
}
- if (SelectedDocument.IsDraft)
- {
- ClearCollections(DocumentLines);
- ClearCollections(DocumentGroupSummaries);
- SelectedDocumentGroup = null;
- LineStatusText = "Черновик текущего сеанса. В базе он не сохранён, потому что отдельной таблицы ПСВ нет.";
- return;
- }
-
- await LoadSelectedDocumentCoreAsync();
- }
-
- private async Task LoadSelectedDocumentCoreAsync()
- {
try
{
- LineStatusText = "Загрузка строк документа...";
-
- var previousGroup = SelectedDocumentGroup;
- var documentNumber = SelectedDocument.DocumentNumber;
- var lines = await Task.Run(delegate { return _service.LoadDocumentLines(documentNumber); });
-
- ClearCollections(DocumentLines);
- foreach (var line in lines)
- {
- DocumentLines.Add(line);
- }
-
- RebuildDocumentGroupSummaries(lines);
- SelectedDocumentGroup = FindMatchingGroup(previousGroup) ?? DocumentGroupSummaries.FirstOrDefault();
- RefreshDocumentLinesView();
+ await ReloadSelectedDocumentLinesAsync();
}
catch (Exception ex)
{
@@ -467,70 +749,187 @@ namespace XLAB
}
}
+ private async Task ReloadSelectedDocumentLinesAsync()
+ {
+ if (SelectedDocument == null)
+ {
+ ClearCollections(DocumentLines);
+ ClearCollections(DocumentGroupSummaries);
+ SelectedDocumentGroup = null;
+ SelectedDocumentLine = null;
+ return;
+ }
+
+ if (SelectedDocument.IsDraft)
+ {
+ ApplyDocumentLines(GetPendingLines(SelectedDocument), SelectedDocumentGroup);
+ return;
+ }
+
+ LineStatusText = "Загрузка строк документа...";
+
+ var previousGroup = SelectedDocumentGroup;
+ var documentNumber = SelectedDocument.DocumentNumber;
+ var persistedLines = await Task.Run(delegate { return _service.LoadDocumentLines(documentNumber); });
+ var mergedLines = persistedLines.Concat(GetPendingLines(SelectedDocument)).ToList();
+
+ ApplyDocumentLines(mergedLines, previousGroup);
+ }
+
+ private void OpenInstrumentPickerAsync()
+ {
+ if (SelectedDocument == null)
+ {
+ return;
+ }
+
+ if (!SelectedDocument.CustomerId.HasValue)
+ {
+ _dialogService.ShowWarning("Сначала выберите заказчика в ПСВ.");
+ return;
+ }
+
+ OpenInstrumentPickerCoreAsync(SelectedDocument.CustomerId.Value, SelectedDocument.CustomerName);
+ }
+
+ private async void OpenInstrumentPickerCoreAsync(int customerId, string customerName)
+ {
+ IReadOnlyList instruments;
+
+ try
+ {
+ IsBusy = true;
+ instruments = await Task.Run(delegate { return _service.LoadCustomerInstruments(customerId); });
+ }
+ catch (Exception ex)
+ {
+ _dialogService.ShowError(ex.Message);
+ return;
+ }
+ finally
+ {
+ IsBusy = false;
+ }
+
+ var selectedItems = _dialogService.ShowInstrumentPickerDialog(customerName, instruments);
+ if (selectedItems == null || selectedItems.Count == 0)
+ {
+ return;
+ }
+
+ AddSelectedInstruments(selectedItems);
+ }
+
+ private void AddSelectedInstruments(IReadOnlyList selectedItems)
+ {
+ if (SelectedDocument == null)
+ {
+ return;
+ }
+
+ List pendingLines;
+ if (!_pendingLinesByDocumentKey.TryGetValue(SelectedDocument.DocumentKey, out pendingLines))
+ {
+ pendingLines = new List();
+ _pendingLinesByDocumentKey[SelectedDocument.DocumentKey] = pendingLines;
+ }
+
+ var duplicateKeys = new HashSet(DocumentLines.Select(delegate(PsvDocumentLine line) { return line.DuplicateKey; }), StringComparer.OrdinalIgnoreCase);
+ var addedCount = 0;
+ var skippedDuplicateCount = 0;
+ var skippedWithoutTemplateCount = 0;
+
+ foreach (var item in selectedItems)
+ {
+ if (!item.HasTemplate)
+ {
+ skippedWithoutTemplateCount++;
+ continue;
+ }
+
+ var duplicateKey = PsvDocumentLine.BuildDuplicateKey(item.InstrumentType, item.RangeText, item.RegistryNumber, item.SerialNumber);
+ if (duplicateKeys.Contains(duplicateKey))
+ {
+ skippedDuplicateCount++;
+ continue;
+ }
+
+ pendingLines.Add(CreatePendingLine(item));
+ duplicateKeys.Add(duplicateKey);
+ addedCount++;
+ }
+
+ if (SelectedDocument.IsDraft)
+ {
+ SelectedDocument.ItemCount = pendingLines.Count;
+ }
+
+ LoadSelectedDocumentAsync();
+
+ var messages = new List();
+ if (addedCount > 0)
+ {
+ messages.Add(string.Format("Добавлено приборов: {0}.", addedCount));
+ }
+
+ if (skippedDuplicateCount > 0)
+ {
+ messages.Add(string.Format("Исключено дублей: {0}.", skippedDuplicateCount));
+ }
+
+ if (skippedWithoutTemplateCount > 0)
+ {
+ messages.Add(string.Format("Пропущено без шаблона EKZMK: {0}.", skippedWithoutTemplateCount));
+ }
+
+ if (messages.Count > 0)
+ {
+ _dialogService.ShowInfo(string.Join(" ", messages.ToArray()));
+ }
+
+ RaiseCommandStates();
+ OnPropertyChanged("IsCustomerEditable");
+ }
+
+ private void ApplyDocumentLines(IEnumerable lines, PsvDocumentGroupSummary previousGroup)
+ {
+ var previousLine = SelectedDocumentLine;
+ ClearCollections(DocumentLines);
+ foreach (var line in lines)
+ {
+ DocumentLines.Add(line);
+ }
+
+ RebuildDocumentGroupSummaries(DocumentLines);
+ SelectedDocumentGroup = FindMatchingGroup(previousGroup) ?? DocumentGroupSummaries.FirstOrDefault();
+ SelectedDocumentLine = previousLine == null
+ ? null
+ : DocumentLines.FirstOrDefault(delegate(PsvDocumentLine line)
+ {
+ if (previousLine.CardId > 0 && line.CardId > 0)
+ {
+ return line.CardId == previousLine.CardId;
+ }
+
+ return line.IsPendingInsert
+ && previousLine.IsPendingInsert
+ && string.Equals(line.DuplicateKey, previousLine.DuplicateKey, StringComparison.OrdinalIgnoreCase);
+ });
+ RefreshDocumentLinesView();
+ }
+
private void RaiseCommandStates()
{
((RelayCommand)AddDocumentCommand).RaiseCanExecuteChanged();
((RelayCommand)DeleteDocumentCommand).RaiseCanExecuteChanged();
+ ((RelayCommand)MarkLinePassedCommand).RaiseCanExecuteChanged();
+ ((RelayCommand)MarkLineRejectedCommand).RaiseCanExecuteChanged();
+ ((RelayCommand)OpenInstrumentPickerCommand).RaiseCanExecuteChanged();
((RelayCommand)RefreshDocumentsCommand).RaiseCanExecuteChanged();
+ ((RelayCommand)ResetLineVerificationCommand).RaiseCanExecuteChanged();
((RelayCommand)SaveDocumentHeaderCommand).RaiseCanExecuteChanged();
}
- private void RefreshDocumentLinesView()
- {
- DocumentLinesView.Refresh();
- UpdateLineStatus();
- }
-
- private void RefreshDocumentsAsync(string documentToSelect)
- {
- ExecuteBusyOperationAsync(delegate { return RefreshDocumentsCoreAsync(documentToSelect); });
- }
-
- private async Task RefreshDocumentsCoreAsync(string documentToSelect)
- {
- DocumentStatusText = "Загрузка списка ПСВ...";
-
- var databaseDocuments = await Task.Run(delegate { return _service.LoadDocuments(); });
- var selectedDocumentNumber = documentToSelect ?? (SelectedDocument != null ? SelectedDocument.DocumentNumber : null);
-
- ClearCollections(Documents);
-
- foreach (var draft in _draftDocuments.OrderByDescending(delegate(PsvDocumentSummary item)
- {
- return item.AcceptedOn ?? DateTime.MinValue;
- }))
- {
- Documents.Add(draft);
- }
-
- foreach (var document in databaseDocuments)
- {
- if (_draftDocuments.Any(delegate(PsvDocumentSummary draft)
- {
- return string.Equals(draft.DocumentNumber, document.DocumentNumber, StringComparison.OrdinalIgnoreCase);
- }))
- {
- continue;
- }
-
- Documents.Add(document);
- }
-
- DocumentsView.Refresh();
-
- SelectedDocument = Documents.FirstOrDefault(delegate(PsvDocumentSummary document)
- {
- return string.Equals(document.DocumentNumber, selectedDocumentNumber, StringComparison.OrdinalIgnoreCase);
- });
-
- if (SelectedDocument == null && Documents.Count > 0)
- {
- SelectedDocument = Documents[0];
- }
-
- DocumentStatusText = string.Format("Документов: {0}.", Documents.Count);
- }
-
private void RebuildDocumentGroupSummaries(IEnumerable lines)
{
ClearCollections(DocumentGroupSummaries);
@@ -561,9 +960,70 @@ namespace XLAB
}
}
- private void SaveDocumentHeaderAsync()
+ private void RefreshDocumentLinesView()
{
- ExecuteBusyOperationAsync(async delegate
+ DocumentLinesView.Refresh();
+ UpdateLineStatus();
+ }
+
+ private void RefreshDocumentsAsync(string documentKeyToSelect, string documentNumberToSelect)
+ {
+ RunBusyOperation(delegate { return RefreshDocumentsCoreAsync(documentKeyToSelect, documentNumberToSelect); });
+ }
+
+ private async Task RefreshDocumentsCoreAsync(string documentKeyToSelect, string documentNumberToSelect)
+ {
+ DocumentStatusText = "Загрузка списка ПСВ...";
+
+ var databaseDocuments = await Task.Run(delegate { return _service.LoadDocuments(); });
+ var currentDocumentKey = documentKeyToSelect ?? (SelectedDocument != null ? SelectedDocument.DocumentKey : null);
+ var currentDocumentNumber = documentNumberToSelect ?? (SelectedDocument != null ? SelectedDocument.DocumentNumber : null);
+
+ ClearCollections(Documents);
+
+ foreach (var draft in _draftDocuments.OrderByDescending(delegate(PsvDocumentSummary item) { return item.AcceptedOn ?? DateTime.MinValue; }))
+ {
+ Documents.Add(draft);
+ }
+
+ foreach (var document in databaseDocuments)
+ {
+ if (_draftDocuments.Any(delegate(PsvDocumentSummary draft)
+ {
+ return string.Equals(draft.DocumentNumber, document.DocumentNumber, StringComparison.OrdinalIgnoreCase);
+ }))
+ {
+ continue;
+ }
+
+ Documents.Add(document);
+ }
+
+ DocumentsView.Refresh();
+
+ SelectedDocument = Documents.FirstOrDefault(delegate(PsvDocumentSummary document)
+ {
+ if (!string.IsNullOrWhiteSpace(currentDocumentKey)
+ && string.Equals(document.DocumentKey, currentDocumentKey, StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+
+ return !string.IsNullOrWhiteSpace(currentDocumentNumber)
+ && string.Equals(document.DocumentNumber, currentDocumentNumber, StringComparison.OrdinalIgnoreCase);
+ });
+
+ if (SelectedDocument == null && Documents.Count > 0)
+ {
+ SelectedDocument = Documents[0];
+ }
+
+ DocumentStatusText = string.Format("Документов: {0}.", Documents.Count);
+ }
+
+ private void SaveDocumentAsync()
+ {
+ RunBusyOperation(async delegate
{
if (SelectedDocument == null)
{
@@ -571,28 +1031,75 @@ namespace XLAB
return;
}
- if (SelectedDocument.IsDraft)
- {
- _dialogService.ShowWarning("Черновик нельзя сохранить в базе без строк EKZMK.");
- return;
- }
-
if (!HeaderReceivedOn.HasValue)
{
_dialogService.ShowWarning("Укажите дату приемки.");
return;
}
+ if (string.IsNullOrWhiteSpace(DocumentNumberEditor))
+ {
+ _dialogService.ShowWarning("Введите номер ПСВ.");
+ return;
+ }
+
+ if (SelectedDocument.IsDraft && !SelectedCustomerId.HasValue)
+ {
+ _dialogService.ShowWarning("Для новой ПСВ сначала выберите заказчика.");
+ return;
+ }
+
+ if (DocumentExistsInCollections(DocumentNumberEditor.Trim(), SelectedDocument.DocumentKey)
+ || _service.DocumentNumberExists(DocumentNumberEditor.Trim(), SelectedDocument.IsDraft ? null : SelectedDocument.DocumentNumber))
+ {
+ _dialogService.ShowWarning("ПСВ с таким номером уже существует.");
+ return;
+ }
+
+ var pendingLines = GetPendingLines(SelectedDocument)
+ .Where(delegate(PsvDocumentLine line) { return line.InstrumentId > 0; })
+ .ToList();
+ if (SelectedDocument.IsDraft && pendingLines.Count == 0)
+ {
+ _dialogService.ShowWarning("Черновик нельзя сохранить без строк EKZMK.");
+ return;
+ }
+
var request = new DocumentEditorResult
{
- DocumentNumber = DocumentNumberEditor,
+ DocumentNumber = DocumentNumberEditor.Trim(),
AcceptedOn = HeaderReceivedOn.Value,
IssuedOn = HeaderIssuedOn
};
- await Task.Run(delegate { _service.UpdateDocumentHeader(SelectedDocument.DocumentNumber, request); });
- await RefreshDocumentsCoreAsync(request.DocumentNumber);
- _dialogService.ShowInfo("Реквизиты ПСВ обновлены.");
+ var currentDocumentNumber = SelectedDocument.IsDraft ? null : SelectedDocument.DocumentNumber;
+ var documentKey = SelectedDocument.DocumentKey;
+ var wasDraft = SelectedDocument.IsDraft;
+ var result = await Task.Run(delegate { return _service.SaveDocument(currentDocumentNumber, request, pendingLines); });
+
+ _pendingLinesByDocumentKey.Remove(documentKey);
+ if (wasDraft)
+ {
+ _draftDocuments.RemoveAll(delegate(PsvDocumentSummary draft) { return draft.DocumentKey == documentKey; });
+ }
+
+ await RefreshDocumentsCoreAsync(null, result.DocumentNumber);
+
+ var messages = new List();
+ messages.Add(string.Format("Обновлено строк EKZMK: {0}.", result.UpdatedEkzMkCount));
+ messages.Add(string.Format("Добавлено строк EKZMK: {0}.", result.InsertedEkzMkCount));
+
+ if (result.SkippedDuplicateCount > 0)
+ {
+ messages.Add(string.Format("Исключено дублей: {0}.", result.SkippedDuplicateCount));
+ }
+
+ if (result.SkippedWithoutTemplateCount > 0)
+ {
+ messages.Add(string.Format("Пропущено без шаблона EKZMK: {0}.", result.SkippedWithoutTemplateCount));
+ }
+
+ _dialogService.ShowInfo(string.Join(" ", messages.ToArray()));
});
}
@@ -604,15 +1111,11 @@ namespace XLAB
return;
}
- if (SelectedDocument.IsDraft)
- {
- LineStatusText = "Черновик текущего сеанса. Строки появятся только после создания записей EKZMK.";
- return;
- }
-
if (DocumentGroupSummaries.Count == 0)
{
- LineStatusText = "В документе нет групп приборов.";
+ LineStatusText = SelectedDocument.IsDraft
+ ? "Черновик пуст. Добавьте приборы через контекстное меню таблицы групп."
+ : "В документе нет групп приборов.";
return;
}
@@ -628,18 +1131,14 @@ namespace XLAB
return SelectedDocumentGroup.Matches(line)
&& (string.IsNullOrWhiteSpace(GroupDetailFilterText) || Contains(line.SerialNumber, GroupDetailFilterText));
});
+ var pendingCount = DocumentLines.Count(delegate(PsvDocumentLine line) { return line.IsPendingInsert; });
LineStatusText = string.Format(
- "Групп: {0}. Приборов в выбранной группе: {1}. Отображено по фильтру: {2}.",
+ "Групп: {0}. Приборов в выбранной группе: {1}. Отображено по фильтру: {2}. Не сохранено строк: {3}.",
DocumentGroupSummaries.Count,
groupLineCount,
- filteredCount);
- }
-
- private static bool Contains(string source, string filter)
- {
- return !string.IsNullOrWhiteSpace(source)
- && source.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0;
+ filteredCount,
+ pendingCount);
}
}
}
diff --git a/XLAB/PsvDataService.cs b/XLAB/PsvDataService.cs
index 0208299..e07b9b2 100644
--- a/XLAB/PsvDataService.cs
+++ b/XLAB/PsvDataService.cs
@@ -9,7 +9,142 @@ namespace XLAB
{
internal sealed class PsvDataService
{
- private const string PsvPrefix = "ПСВ";
+ public bool DocumentNumberExists(string documentNumber, string excludeDocumentNumber)
+ {
+ var normalizedNumber = NormalizeDocumentNumber(documentNumber);
+ if (normalizedNumber == null)
+ {
+ return false;
+ }
+
+ using (var connection = CreateConnection())
+ using (var command = new SqlCommand(
+ @"
+SELECT COUNT(1)
+FROM dbo.EKZMK
+WHERE NNZVPV = @DocumentNumber
+ AND (@ExcludeDocumentNumber = N'' OR NNZVPV <> @ExcludeDocumentNumber);",
+ connection))
+ {
+ connection.Open();
+ command.CommandTimeout = 60;
+ command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = normalizedNumber;
+ command.Parameters.Add("@ExcludeDocumentNumber", SqlDbType.NVarChar, 60).Value = excludeDocumentNumber ?? string.Empty;
+ return Convert.ToInt32(command.ExecuteScalar()) > 0;
+ }
+ }
+
+ public IReadOnlyList LoadCustomers()
+ {
+ const string sql = @"
+SELECT
+ z.IDFRPDV AS CustomerId,
+ fr.NMFRPD AS CustomerName
+FROM dbo.EKZ z
+JOIN dbo.FRPD fr ON fr.IDFRPD = z.IDFRPDV
+WHERE z.IDFRPDV IS NOT NULL
+GROUP BY z.IDFRPDV, fr.NMFRPD
+ORDER BY fr.NMFRPD;";
+
+ var customers = new List();
+
+ using (var connection = CreateConnection())
+ using (var command = new SqlCommand(sql, connection))
+ {
+ connection.Open();
+ command.CommandTimeout = 60;
+
+ using (var reader = command.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ customers.Add(new CustomerReference
+ {
+ CustomerId = GetInt32(reader, "CustomerId"),
+ CustomerName = GetString(reader, "CustomerName")
+ });
+ }
+ }
+ }
+
+ return customers;
+ }
+
+ public IReadOnlyList LoadVerifiers()
+ {
+ const string sql = @"
+SELECT
+ p.IDPRSN AS PersonId,
+ p.PRFIO AS FullName
+FROM dbo.PRSN p
+WHERE NULLIF(LTRIM(RTRIM(p.PRFIO)), N'') IS NOT NULL
+ORDER BY p.PRFIO;";
+
+ var verifiers = new List();
+
+ using (var connection = CreateConnection())
+ using (var command = new SqlCommand(sql, connection))
+ {
+ connection.Open();
+ command.CommandTimeout = 60;
+
+ using (var reader = command.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ verifiers.Add(new PersonReference
+ {
+ PersonId = GetInt32(reader, "PersonId"),
+ FullName = GetString(reader, "FullName")
+ });
+ }
+ }
+ }
+
+ return verifiers;
+ }
+
+ public IReadOnlyList LoadVerificationDocumentForms(bool isPassed)
+ {
+ const string sql = @"
+SELECT DISTINCT
+ fr.IDFRDMS AS DocumentFormId,
+ v.IDVDODVDD AS LinkTypeId,
+ sp.NMVDD AS DocumentKindName,
+ fr.NMFRD AS DocumentFormName
+FROM dbo.FRDMS fr
+JOIN dbo.SPVDD sp ON sp.IDSPVDD = fr.IDSPVDD
+JOIN dbo.VDODVDD v ON v.IDSPVDD = fr.IDSPVDD
+WHERE v.IDSPVDOD = 2
+ AND fr.IDSPVDD = @DocumentTypeId
+ORDER BY fr.NMFRD, v.IDVDODVDD;";
+
+ var forms = new List();
+
+ using (var connection = CreateConnection())
+ using (var command = new SqlCommand(sql, connection))
+ {
+ connection.Open();
+ command.CommandTimeout = 60;
+ command.Parameters.Add("@DocumentTypeId", SqlDbType.Int).Value = isPassed ? 6 : 2;
+
+ using (var reader = command.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ forms.Add(new DocumentFormReference
+ {
+ DocumentFormId = GetInt32(reader, "DocumentFormId"),
+ LinkTypeId = GetInt32(reader, "LinkTypeId"),
+ DocumentKindName = GetString(reader, "DocumentKindName"),
+ DocumentFormName = GetString(reader, "DocumentFormName")
+ });
+ }
+ }
+ }
+
+ return forms;
+ }
public IReadOnlyList LoadDocuments()
{
@@ -19,7 +154,8 @@ SELECT
MAX(m.DTPRM) AS AcceptedOn,
MAX(m.DTVDM) AS IssuedOn,
MIN(dep.NMFRPD) AS DepartmentName,
- MIN(ownerOrg.NMFRPD) AS CustomerName,
+ CASE WHEN COUNT(DISTINCT z.IDFRPDV) = 1 THEN MIN(z.IDFRPDV) ELSE NULL END AS CustomerId,
+ CASE WHEN COUNT(DISTINCT z.IDFRPDV) = 1 THEN MIN(ownerOrg.NMFRPD) ELSE N'' END AS CustomerName,
COUNT(*) AS ItemCount,
SUM(CASE WHEN m.DTVDM IS NOT NULL THEN 1 ELSE 0 END) AS IssuedCount,
SUM(CASE WHEN m.GDN = 1 THEN 1 ELSE 0 END) AS PassedCount,
@@ -29,7 +165,6 @@ JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ
LEFT JOIN dbo.FRPD dep ON dep.IDFRPD = m.IDFRPD
LEFT JOIN dbo.FRPD ownerOrg ON ownerOrg.IDFRPD = z.IDFRPDV
WHERE NULLIF(LTRIM(RTRIM(m.NNZVPV)), N'') IS NOT NULL
- AND m.NNZVPV LIKE N'ПСВ%'
GROUP BY m.NNZVPV
HAVING MAX(m.DTVDM) IS NULL
ORDER BY MAX(m.DTPRM) DESC, m.NNZVPV DESC;";
@@ -46,17 +181,21 @@ ORDER BY MAX(m.DTPRM) DESC, m.NNZVPV DESC;";
{
while (reader.Read())
{
+ var documentNumber = GetString(reader, "DocumentNumber");
documents.Add(new PsvDocumentSummary
{
- DocumentNumber = GetString(reader, "DocumentNumber"),
+ DocumentKey = documentNumber,
+ DocumentNumber = documentNumber,
AcceptedOn = GetNullableDateTime(reader, "AcceptedOn"),
IssuedOn = GetNullableDateTime(reader, "IssuedOn"),
DepartmentName = GetString(reader, "DepartmentName"),
+ CustomerId = GetNullableInt32(reader, "CustomerId"),
CustomerName = GetString(reader, "CustomerName"),
ItemCount = GetInt32(reader, "ItemCount"),
IssuedCount = GetInt32(reader, "IssuedCount"),
PassedCount = GetInt32(reader, "PassedCount"),
- FailedCount = GetInt32(reader, "FailedCount")
+ FailedCount = GetInt32(reader, "FailedCount"),
+ IsDraft = false
});
}
}
@@ -85,10 +224,15 @@ SELECT
m.DTPRM AS AcceptedOn,
m.DTVDM AS IssuedOn,
m.GDN AS IsPassed,
+ m.DTMKFK AS VerificationPerformedOn,
+ m.IDPRSN AS VerifierId,
verifier.PRFIO AS VerifierName,
m.NNNKL AS StickerNumber,
+ verificationDocument.IDFRDMS AS VerificationDocumentFormId,
+ verificationDocument.IDVDODVDD AS VerificationDocumentLinkTypeId,
verificationDocument.NNDMS AS VerificationDocumentNumber,
verificationDocument.DTDMS AS VerificationDocumentDate,
+ m.PRCHNPGDN AS RejectionReason,
m.DSEKZMK AS Notes
FROM dbo.EKZMK m
JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ
@@ -102,6 +246,8 @@ LEFT JOIN dbo.PRSN verifier ON verifier.IDPRSN = m.IDPRSN
OUTER APPLY
(
SELECT TOP (1)
+ d.IDFRDMS,
+ d.IDVDODVDD,
d.NND AS NNDMS,
d.DTD AS DTDMS
FROM dbo.DMS d
@@ -147,11 +293,17 @@ ORDER BY areas.NMOI, names.NMTP, tips.TP, z.NNZV;";
AcceptedOn = GetNullableDateTime(reader, "AcceptedOn"),
IssuedOn = GetNullableDateTime(reader, "IssuedOn"),
IsPassed = GetNullableBoolean(reader, "IsPassed"),
+ VerificationPerformedOn = GetNullableDateTime(reader, "VerificationPerformedOn"),
+ VerifierId = GetNullableInt32(reader, "VerifierId"),
VerifierName = GetString(reader, "VerifierName"),
StickerNumber = GetString(reader, "StickerNumber"),
+ VerificationDocumentFormId = GetNullableInt32(reader, "VerificationDocumentFormId"),
+ VerificationDocumentLinkTypeId = GetNullableInt32(reader, "VerificationDocumentLinkTypeId"),
VerificationDocumentNumber = GetString(reader, "VerificationDocumentNumber"),
VerificationDocumentDate = GetNullableDateTime(reader, "VerificationDocumentDate"),
- Notes = GetString(reader, "Notes")
+ RejectionReason = GetString(reader, "RejectionReason"),
+ Notes = GetString(reader, "Notes"),
+ IsPendingInsert = false
});
}
}
@@ -160,57 +312,28 @@ ORDER BY areas.NMOI, names.NMTP, tips.TP, z.NNZV;";
return lines;
}
- public IReadOnlyList SearchAvailableInstruments(string searchText, string currentDocumentNumber, int take)
+ public IReadOnlyList LoadCustomerInstruments(int customerId)
{
const string sql = @"
-WITH FilteredInstruments AS
-(
- SELECT TOP (@Take)
- z.IDEKZ AS InstrumentId,
- z.IDTPRZ AS TypeSizeId,
- z.NNZV AS SerialNumber,
- z.NNIN AS InventoryNumber,
- ownerOrg.NMFRPD AS CustomerName,
- tips.TP AS InstrumentType,
- names.NMTP AS InstrumentName,
- areas.NMOI AS MeasurementArea,
- sizeInfo.DPZN AS RangeText,
- sizeInfo.HRTC AS AccuracyText
- FROM dbo.EKZ z
- LEFT JOIN dbo.FRPD ownerOrg ON ownerOrg.IDFRPD = z.IDFRPDV
- LEFT JOIN dbo.TPRZ sizeInfo ON sizeInfo.IDTPRZ = z.IDTPRZ
- LEFT JOIN dbo.TIPS tips ON tips.IDTIPS = sizeInfo.IDTIPS
- LEFT JOIN dbo.SPNMTP names ON names.IDSPNMTP = tips.IDSPNMTP
- LEFT JOIN dbo.SPOI areas ON areas.IDSPOI = tips.IDSPOI
- WHERE (@Search = N''
- OR z.NNZV LIKE @LikeSearch
- OR ISNULL(z.NNIN, N'') LIKE @LikeSearch
- OR ISNULL(ownerOrg.NMFRPD, N'') LIKE @LikeSearch
- OR ISNULL(tips.TP, N'') LIKE @LikeSearch
- OR ISNULL(names.NMTP, N'') LIKE @LikeSearch
- OR ISNULL(areas.NMOI, N'') LIKE @LikeSearch
- OR ISNULL(sizeInfo.DPZN, N'') LIKE @LikeSearch)
- AND (@CurrentDocumentNumber = N''
- OR NOT EXISTS
- (
- SELECT 1
- FROM dbo.EKZMK existingInDocument
- WHERE existingInDocument.NNZVPV = @CurrentDocumentNumber
- AND existingInDocument.IDEKZ = z.IDEKZ
- ))
- ORDER BY z.IDEKZ DESC
-)
SELECT
- filtered.InstrumentId,
- filtered.TypeSizeId,
- filtered.SerialNumber,
- filtered.InventoryNumber,
- filtered.CustomerName,
- filtered.InstrumentType,
- filtered.InstrumentName,
- filtered.MeasurementArea,
- filtered.RangeText,
- filtered.AccuracyText,
+ z.IDEKZ AS InstrumentId,
+ z.IDTPRZ AS TypeSizeId,
+ z.NNZV AS SerialNumber,
+ z.NNIN AS InventoryNumber,
+ ownerOrg.NMFRPD AS CustomerName,
+ tips.TP AS InstrumentType,
+ names.NMTP AS InstrumentName,
+ areas.NMOI AS MeasurementArea,
+ sizeInfo.NNGSRS AS RegistryNumber,
+ sizeInfo.DPZN AS RangeText,
+ sizeInfo.HRTC AS AccuracyText,
+ CASE
+ WHEN instrumentTemplate.LastDocumentNumber IS NOT NULL
+ OR typeTemplate.LastDocumentNumber IS NOT NULL
+ OR periodTemplate.PeriodMonths IS NOT NULL
+ THEN CAST(1 AS bit)
+ ELSE CAST(0 AS bit)
+ END AS HasTemplate,
COALESCE(instrumentTemplate.LastDocumentNumber, typeTemplate.LastDocumentNumber) AS LastDocumentNumber,
COALESCE(instrumentTemplate.LastAcceptedOn, typeTemplate.LastAcceptedOn) AS LastAcceptedOn,
CASE
@@ -218,14 +341,19 @@ SELECT
WHEN typeTemplate.LastDocumentNumber IS NOT NULL THEN N'Шаблон по типоразмеру'
ELSE N''
END AS TemplateSource
-FROM FilteredInstruments filtered
+FROM dbo.EKZ z
+LEFT JOIN dbo.FRPD ownerOrg ON ownerOrg.IDFRPD = z.IDFRPDV
+LEFT JOIN dbo.TPRZ sizeInfo ON sizeInfo.IDTPRZ = z.IDTPRZ
+LEFT JOIN dbo.TIPS tips ON tips.IDTIPS = sizeInfo.IDTIPS
+LEFT JOIN dbo.SPNMTP names ON names.IDSPNMTP = tips.IDSPNMTP
+LEFT JOIN dbo.SPOI areas ON areas.IDSPOI = tips.IDSPOI
OUTER APPLY
(
SELECT TOP (1)
history.NNZVPV AS LastDocumentNumber,
history.DTPRM AS LastAcceptedOn
FROM dbo.EKZMK history
- WHERE history.IDEKZ = filtered.InstrumentId
+ WHERE history.IDEKZ = z.IDEKZ
ORDER BY ISNULL(history.DTPRM, CONVERT(datetime, '19000101', 112)) DESC, history.IDEKZMK DESC
) instrumentTemplate
OUTER APPLY
@@ -235,16 +363,29 @@ OUTER APPLY
history.DTPRM AS LastAcceptedOn
FROM dbo.EKZMK history
JOIN dbo.EKZ instrumentOfSameType ON instrumentOfSameType.IDEKZ = history.IDEKZ
- WHERE instrumentOfSameType.IDTPRZ = filtered.TypeSizeId
+ WHERE instrumentOfSameType.IDTPRZ = z.IDTPRZ
ORDER BY ISNULL(history.DTPRM, CONVERT(datetime, '19000101', 112)) DESC, history.IDEKZMK DESC
) typeTemplate
-WHERE instrumentTemplate.LastDocumentNumber IS NOT NULL
- OR typeTemplate.LastDocumentNumber IS NOT NULL
-ORDER BY
- CASE WHEN instrumentTemplate.LastDocumentNumber IS NOT NULL THEN 0 ELSE 1 END,
- filtered.CustomerName,
- filtered.InstrumentName,
- filtered.SerialNumber;";
+OUTER APPLY
+(
+ SELECT TOP (1)
+ COALESCE(periodByInstrument.PRMK, periodByType.PRMK) AS PeriodMonths
+ FROM
+ (
+ SELECT t.PRMK
+ FROM dbo.EKZMCP e
+ JOIN dbo.TPRMCP t ON t.IDTPRMCP = e.IDTPRMCP
+ WHERE e.IDEKZ = z.IDEKZ
+ ) periodByInstrument
+ FULL JOIN
+ (
+ SELECT t.PRMK
+ FROM dbo.TPRMCP t
+ WHERE t.IDTPRZ = z.IDTPRZ
+ ) periodByType ON 1 = 0
+) periodTemplate
+WHERE z.IDFRPDV = @CustomerId
+ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, z.NNZV;";
var instruments = new List();
@@ -253,10 +394,7 @@ ORDER BY
{
connection.Open();
command.CommandTimeout = 60;
- command.Parameters.Add("@Take", SqlDbType.Int).Value = Math.Max(1, take);
- command.Parameters.Add("@Search", SqlDbType.NVarChar, 200).Value = searchText ?? string.Empty;
- command.Parameters.Add("@LikeSearch", SqlDbType.NVarChar, 204).Value = "%" + (searchText ?? string.Empty).Trim() + "%";
- command.Parameters.Add("@CurrentDocumentNumber", SqlDbType.NVarChar, 60).Value = currentDocumentNumber ?? string.Empty;
+ command.Parameters.Add("@CustomerId", SqlDbType.Int).Value = customerId;
using (var reader = command.ExecuteReader())
{
@@ -272,8 +410,10 @@ ORDER BY
InstrumentType = GetString(reader, "InstrumentType"),
InstrumentName = GetString(reader, "InstrumentName"),
MeasurementArea = GetString(reader, "MeasurementArea"),
+ RegistryNumber = GetString(reader, "RegistryNumber"),
RangeText = GetString(reader, "RangeText"),
AccuracyText = GetString(reader, "AccuracyText"),
+ HasTemplate = GetBoolean(reader, "HasTemplate"),
LastDocumentNumber = GetString(reader, "LastDocumentNumber"),
LastAcceptedOn = GetNullableDateTime(reader, "LastAcceptedOn"),
TemplateSource = GetString(reader, "TemplateSource")
@@ -285,71 +425,74 @@ ORDER BY
return instruments;
}
- public int AddInstrumentsToDocument(DocumentEditorResult document, IEnumerable instrumentIds)
+ public void ResetLineVerification(int cardId)
{
- if (document == null)
+ if (cardId <= 0)
{
- throw new ArgumentNullException(nameof(document));
+ throw new InvalidOperationException("Не выбрана строка EKZMK для отмены проверки.");
}
- var normalizedNumber = NormalizeDocumentNumber(document.DocumentNumber);
- if (normalizedNumber == null)
- {
- throw new InvalidOperationException("Номер ПСВ не заполнен.");
- }
-
- var added = 0;
-
using (var connection = CreateConnection())
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
- var verificationTypeId = LoadVerificationTypeId(connection, transaction);
+ ClearLineVerificationCore(connection, transaction, cardId);
+ DeleteVerificationDocuments(connection, transaction, cardId);
+ transaction.Commit();
+ }
+ }
+ }
- foreach (var instrumentId in instrumentIds)
+ public void SaveLineVerification(int cardId, VerificationEditResult result)
+ {
+ if (cardId <= 0)
+ {
+ throw new InvalidOperationException("Не выбрана строка EKZMK для сохранения результата поверки.");
+ }
+
+ if (result == null)
+ {
+ throw new ArgumentNullException("result");
+ }
+
+ using (var connection = CreateConnection())
+ {
+ connection.Open();
+
+ using (var transaction = connection.BeginTransaction())
+ {
+ SaveLineVerificationCore(connection, transaction, cardId, result);
+ DeleteVerificationDocuments(connection, transaction, cardId);
+
+ if (!string.IsNullOrWhiteSpace(result.VerificationDocumentNumber))
{
- if (DocumentContainsInstrument(connection, transaction, normalizedNumber, instrumentId))
+ if (result.DocumentFormId <= 0 || result.DocumentLinkTypeId <= 0)
{
- continue;
+ throw new InvalidOperationException("Для документа поверки не определена форма или связь с объектом.");
}
- var template = LoadTemplate(connection, transaction, instrumentId);
- if (template == null)
- {
- throw new InvalidOperationException(
- string.Format("Для прибора IDEKZ={0} не найден подтверждённый шаблон EKZMK.", instrumentId));
- }
-
- InsertEkzMk(connection, transaction, verificationTypeId, document, normalizedNumber, instrumentId, template);
- added++;
+ InsertVerificationDocument(
+ connection,
+ transaction,
+ cardId,
+ result.DocumentLinkTypeId,
+ result.DocumentFormId,
+ result.VerificationDocumentNumber,
+ result.VerificationDate);
}
transaction.Commit();
}
}
-
- return added;
}
- public void UpdateDocumentHeader(string currentDocumentNumber, DocumentEditorResult document)
+ public DocumentSaveResult SaveDocument(string currentDocumentNumber, DocumentEditorResult document, IEnumerable pendingLines)
{
- const string sql = @"
-UPDATE dbo.EKZMK
-SET NNZVPV = @NewDocumentNumber,
- DTPRM = @AcceptedOn,
- DTVDM = @IssuedOn
-WHERE NNZVPV = @CurrentDocumentNumber;";
-
- if (string.IsNullOrWhiteSpace(currentDocumentNumber))
- {
- throw new InvalidOperationException("Не выбран документ для обновления.");
- }
-
if (document == null)
{
- throw new ArgumentNullException(nameof(document));
+ throw new ArgumentNullException("document");
}
var normalizedNumber = NormalizeDocumentNumber(document.DocumentNumber);
@@ -358,16 +501,110 @@ WHERE NNZVPV = @CurrentDocumentNumber;";
throw new InvalidOperationException("Номер ПСВ не заполнен.");
}
+ document.DocumentNumber = normalizedNumber;
+
+ var distinctPendingLines = pendingLines == null
+ ? new List()
+ : pendingLines
+ .Where(delegate(PsvDocumentLine line) { return line != null && line.InstrumentId > 0; })
+ .GroupBy(delegate(PsvDocumentLine line) { return line.InstrumentId; })
+ .Select(delegate(IGrouping group) { return group.First(); })
+ .ToList();
+
using (var connection = CreateConnection())
- using (var command = new SqlCommand(sql, connection))
{
connection.Open();
- command.CommandTimeout = 60;
- command.Parameters.Add("@NewDocumentNumber", SqlDbType.NVarChar, 60).Value = normalizedNumber;
- command.Parameters.Add("@AcceptedOn", SqlDbType.DateTime).Value = document.AcceptedOn;
- command.Parameters.Add("@IssuedOn", SqlDbType.DateTime).Value = (object)document.IssuedOn ?? DBNull.Value;
- command.Parameters.Add("@CurrentDocumentNumber", SqlDbType.NVarChar, 60).Value = currentDocumentNumber;
- command.ExecuteNonQuery();
+
+ using (var transaction = connection.BeginTransaction())
+ {
+ if (DocumentNumberExists(connection, transaction, normalizedNumber, currentDocumentNumber))
+ {
+ throw new InvalidOperationException(string.Format("ПСВ с номером \"{0}\" уже существует.", normalizedNumber));
+ }
+
+ var updatedEkzMkCount = 0;
+ if (!string.IsNullOrWhiteSpace(currentDocumentNumber))
+ {
+ updatedEkzMkCount = UpdateDocumentHeader(connection, transaction, currentDocumentNumber, document);
+ if (updatedEkzMkCount == 0)
+ {
+ throw new InvalidOperationException("Строки EKZMK для выбранного ПСВ не найдены.");
+ }
+ }
+
+ var insertedEkzMkCount = 0;
+ var skippedDuplicateCount = 0;
+ var skippedWithoutTemplateCount = 0;
+ var duplicateKeys = LoadDocumentDuplicateKeys(connection, transaction, normalizedNumber);
+ var verificationTypeId = 0;
+ var verificationTypeLoaded = false;
+
+ foreach (var pendingLine in distinctPendingLines)
+ {
+ var instrumentId = pendingLine.InstrumentId;
+ var instrumentIdentity = LoadInstrumentIdentity(connection, transaction, instrumentId);
+ if (instrumentIdentity == null)
+ {
+ throw new InvalidOperationException(string.Format("Прибор IDEKZ={0} не найден.", instrumentId));
+ }
+
+ if (duplicateKeys.Contains(instrumentIdentity.DuplicateKey))
+ {
+ skippedDuplicateCount++;
+ continue;
+ }
+
+ var template = LoadTemplate(connection, transaction, instrumentId);
+ if (template == null)
+ {
+ skippedWithoutTemplateCount++;
+ continue;
+ }
+
+ if (!verificationTypeLoaded)
+ {
+ verificationTypeId = LoadVerificationTypeId(connection, transaction);
+ verificationTypeLoaded = true;
+ }
+
+ var cardId = InsertEkzMk(connection, transaction, verificationTypeId, document, normalizedNumber, instrumentId, template, pendingLine);
+ if (!string.IsNullOrWhiteSpace(pendingLine.VerificationDocumentNumber))
+ {
+ if (!pendingLine.VerificationDocumentFormId.HasValue || !pendingLine.VerificationDocumentLinkTypeId.HasValue)
+ {
+ throw new InvalidOperationException("Для новой строки EKZMK не определена форма документа поверки.");
+ }
+
+ InsertVerificationDocument(
+ connection,
+ transaction,
+ cardId,
+ pendingLine.VerificationDocumentLinkTypeId.GetValueOrDefault(),
+ pendingLine.VerificationDocumentFormId.GetValueOrDefault(),
+ pendingLine.VerificationDocumentNumber,
+ pendingLine.VerificationDocumentDate ?? pendingLine.VerificationPerformedOn ?? document.AcceptedOn);
+ }
+
+ duplicateKeys.Add(instrumentIdentity.DuplicateKey);
+ insertedEkzMkCount++;
+ }
+
+ if (string.IsNullOrWhiteSpace(currentDocumentNumber) && insertedEkzMkCount == 0)
+ {
+ throw new InvalidOperationException("Черновик нельзя сохранить без строк EKZMK.");
+ }
+
+ transaction.Commit();
+
+ return new DocumentSaveResult
+ {
+ DocumentNumber = normalizedNumber,
+ InsertedEkzMkCount = insertedEkzMkCount,
+ SkippedDuplicateCount = skippedDuplicateCount,
+ SkippedWithoutTemplateCount = skippedWithoutTemplateCount,
+ UpdatedEkzMkCount = updatedEkzMkCount
+ };
+ }
}
}
@@ -378,15 +615,13 @@ WHERE NNZVPV = @CurrentDocumentNumber;";
throw new InvalidOperationException("Не выбран документ для удаления.");
}
- var blockers = new List();
-
using (var connection = CreateConnection())
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
- blockers = LoadDeleteBlockers(connection, transaction, documentNumber);
+ var blockers = LoadDeleteBlockers(connection, transaction, documentNumber);
if (blockers.Count > 0)
{
var details = string.Join(", ", blockers.Select(delegate(DeleteBlockerInfo blocker)
@@ -421,22 +656,6 @@ WHERE NNZVPV = @CurrentDocumentNumber;";
}
}
- private static string NormalizeDocumentNumber(string value)
- {
- if (string.IsNullOrWhiteSpace(value))
- {
- return null;
- }
-
- var trimmed = value.Trim();
- if (trimmed.StartsWith(PsvPrefix, StringComparison.OrdinalIgnoreCase))
- {
- return trimmed;
- }
-
- return trimmed;
- }
-
private static SqlConnection CreateConnection()
{
var connectionString = ConfigurationManager.ConnectionStrings["AsumsSql"];
@@ -448,19 +667,125 @@ WHERE NNZVPV = @CurrentDocumentNumber;";
return new SqlConnection(connectionString.ConnectionString);
}
- private static bool DocumentContainsInstrument(SqlConnection connection, SqlTransaction transaction, string documentNumber, int instrumentId)
+ private static void ClearLineVerificationCore(SqlConnection connection, SqlTransaction transaction, int cardId)
{
const string sql = @"
-SELECT COUNT(1)
-FROM dbo.EKZMK
-WHERE NNZVPV = @DocumentNumber
- AND IDEKZ = @InstrumentId;";
+UPDATE dbo.EKZMK
+SET IDPRSN = NULL,
+ NNNKL = NULL,
+ GDN = NULL,
+ DTMKFK = NULL,
+ PRCHNPGDN = NULL
+WHERE IDEKZMK = @CardId;
+
+SELECT @@ROWCOUNT;";
using (var command = new SqlCommand(sql, connection, transaction))
{
- command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber;
- command.Parameters.Add("@InstrumentId", SqlDbType.Int).Value = instrumentId;
- return Convert.ToInt32(command.ExecuteScalar()) > 0;
+ command.CommandTimeout = 60;
+ command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId;
+ if (Convert.ToInt32(command.ExecuteScalar()) == 0)
+ {
+ throw new InvalidOperationException("Строка EKZMK для изменения результата поверки не найдена.");
+ }
+ }
+ }
+
+ private static void DeleteVerificationDocuments(SqlConnection connection, SqlTransaction transaction, int cardId)
+ {
+ const string sql = @"
+DELETE d
+FROM dbo.DMS d
+JOIN dbo.VDODVDD vdd ON vdd.IDVDODVDD = d.IDVDODVDD
+JOIN dbo.FRDMS frdms ON frdms.IDFRDMS = d.IDFRDMS
+JOIN dbo.SPVDD spvdd ON spvdd.IDSPVDD = frdms.IDSPVDD
+WHERE d.IDOD = @CardId
+ AND vdd.IDSPVDOD = 2
+ AND spvdd.IDSPVDD IN (2, 6, 8);";
+
+ using (var command = new SqlCommand(sql, connection, transaction))
+ {
+ command.CommandTimeout = 60;
+ command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId;
+ command.ExecuteNonQuery();
+ }
+ }
+
+ private static void InsertVerificationDocument(
+ SqlConnection connection,
+ SqlTransaction transaction,
+ int cardId,
+ int linkTypeId,
+ int formId,
+ string documentNumber,
+ DateTime documentDate)
+ {
+ const string sql = @"
+INSERT INTO dbo.DMS
+(
+ IDOD,
+ IDVDODVDD,
+ IDFRDMS,
+ NND,
+ DTD,
+ PTTXDMS,
+ GUIDDMS
+)
+VALUES
+(
+ @CardId,
+ @LinkTypeId,
+ @FormId,
+ @DocumentNumber,
+ @DocumentDate,
+ NULL,
+ @Guid
+);";
+
+ using (var command = new SqlCommand(sql, connection, transaction))
+ {
+ command.CommandTimeout = 60;
+ command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId;
+ command.Parameters.Add("@LinkTypeId", SqlDbType.Int).Value = linkTypeId;
+ command.Parameters.Add("@FormId", SqlDbType.Int).Value = formId;
+ command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber.Trim();
+ command.Parameters.Add("@DocumentDate", SqlDbType.DateTime).Value = documentDate;
+ command.Parameters.Add("@Guid", SqlDbType.UniqueIdentifier).Value = Guid.NewGuid();
+ command.ExecuteNonQuery();
+ }
+ }
+
+ private static void SaveLineVerificationCore(SqlConnection connection, SqlTransaction transaction, int cardId, VerificationEditResult result)
+ {
+ const string sql = @"
+UPDATE dbo.EKZMK
+SET IDPRSN = @VerifierId,
+ NNNKL = @StickerNumber,
+ GDN = @IsPassed,
+ DTMKFK = @VerificationDate,
+ PRCHNPGDN = @RejectionReason
+WHERE IDEKZMK = @CardId;
+
+SELECT @@ROWCOUNT;";
+
+ using (var command = new SqlCommand(sql, connection, transaction))
+ {
+ command.CommandTimeout = 60;
+ command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId;
+ command.Parameters.Add("@VerifierId", SqlDbType.Int).Value = result.VerifierId;
+ command.Parameters.Add("@StickerNumber", SqlDbType.NVarChar, 30).Value = result.IsPassed && !string.IsNullOrWhiteSpace(result.StickerNumber)
+ ? (object)result.StickerNumber.Trim()
+ : DBNull.Value;
+ command.Parameters.Add("@IsPassed", SqlDbType.Bit).Value = result.IsPassed;
+ command.Parameters.Add("@VerificationDate", SqlDbType.DateTime).Value = result.VerificationDate;
+ command.Parameters.Add("@RejectionReason", SqlDbType.NVarChar, 1024).Value = !result.IsPassed && !string.IsNullOrWhiteSpace(result.RejectionReason)
+ ? (object)result.RejectionReason.Trim()
+ : DBNull.Value;
+
+ if (Convert.ToInt32(command.ExecuteScalar()) == 0)
+ {
+ throw new InvalidOperationException("Строка EKZMK для сохранения результата поверки не найдена.");
+ }
}
}
@@ -474,6 +799,21 @@ JOIN dbo.EKZMK m ON m.IDEKZMK = d.IDOD
WHERE m.NNZVPV = @DocumentNumber
AND vdd.IDSPVDOD = 2;
+SELECT @@ROWCOUNT;";
+
+ using (var command = new SqlCommand(sql, connection, transaction))
+ {
+ command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber;
+ return Convert.ToInt32(command.ExecuteScalar());
+ }
+ }
+
+ private static int DeleteDocumentEkzMk(SqlConnection connection, SqlTransaction transaction, string documentNumber)
+ {
+ const string sql = @"
+DELETE FROM dbo.EKZMK
+WHERE NNZVPV = @DocumentNumber;
+
SELECT @@ROWCOUNT;";
using (var command = new SqlCommand(sql, connection, transaction))
@@ -500,21 +840,266 @@ SELECT @@ROWCOUNT;";
}
}
- private static int DeleteDocumentEkzMk(SqlConnection connection, SqlTransaction transaction, string documentNumber)
+ private static bool DocumentNumberExists(SqlConnection connection, SqlTransaction transaction, string documentNumber, string excludeDocumentNumber)
{
const string sql = @"
-DELETE FROM dbo.EKZMK
-WHERE NNZVPV = @DocumentNumber;
-
-SELECT @@ROWCOUNT;";
+SELECT COUNT(1)
+FROM dbo.EKZMK
+WHERE NNZVPV = @DocumentNumber
+ AND (@ExcludeDocumentNumber = N'' OR NNZVPV <> @ExcludeDocumentNumber);";
using (var command = new SqlCommand(sql, connection, transaction))
{
command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber;
+ command.Parameters.Add("@ExcludeDocumentNumber", SqlDbType.NVarChar, 60).Value = excludeDocumentNumber ?? string.Empty;
+ return Convert.ToInt32(command.ExecuteScalar()) > 0;
+ }
+ }
+
+ private static bool GetBoolean(IDataRecord record, string columnName)
+ {
+ return Convert.ToBoolean(record[columnName]);
+ }
+
+ private static int GetInt32(IDataRecord record, string columnName)
+ {
+ return Convert.ToInt32(record[columnName]);
+ }
+
+ private static string GetString(IDataRecord record, string columnName)
+ {
+ return record[columnName] == DBNull.Value ? string.Empty : Convert.ToString(record[columnName]);
+ }
+
+ private static DateTime? GetNullableDateTime(IDataRecord record, string columnName)
+ {
+ return record[columnName] == DBNull.Value ? (DateTime?)null : Convert.ToDateTime(record[columnName]);
+ }
+
+ private static decimal? GetNullableDecimal(IDataRecord record, string columnName)
+ {
+ return record[columnName] == DBNull.Value ? (decimal?)null : Convert.ToDecimal(record[columnName]);
+ }
+
+ private static bool? GetNullableBoolean(IDataRecord record, string columnName)
+ {
+ return record[columnName] == DBNull.Value ? (bool?)null : Convert.ToBoolean(record[columnName]);
+ }
+
+ private static int? GetNullableInt32(IDataRecord record, string columnName)
+ {
+ return record[columnName] == DBNull.Value ? (int?)null : Convert.ToInt32(record[columnName]);
+ }
+
+ private static int InsertEkzMk(
+ SqlConnection connection,
+ SqlTransaction transaction,
+ int verificationTypeId,
+ DocumentEditorResult document,
+ string normalizedNumber,
+ int instrumentId,
+ EkzMkTemplate template,
+ PsvDocumentLine pendingLine)
+ {
+ const string sql = @"
+INSERT INTO dbo.EKZMK
+(
+ IDEKZ,
+ IDSPMU,
+ IDGRSI,
+ IDKSPRL,
+ IDSPVDMK,
+ IDSPVDMC,
+ IDFRPD,
+ IDSPMPOB,
+ IDPRSN,
+ IDSPKMMK,
+ IDEKZRM,
+ IDSPVDKL,
+ IDPRSNVD,
+ IDEKZTO,
+ IDEKZOT,
+ NNZVPV,
+ SHFKL,
+ NNNKL,
+ PRMK,
+ DTMKFK,
+ DTMKPL,
+ DTPRM,
+ DTVDM,
+ GDN,
+ PZMC,
+ STMK,
+ STMKDP,
+ NCSRMK,
+ idprsnsd,
+ idprsnpr,
+ idprsnvy,
+ idsptsmp,
+ idspssmp,
+ GUIDEKZMK,
+ DSEKZMK,
+ DTOTM,
+ DTVZM,
+ IDPRSNOTM,
+ IDPRSNVZM,
+ NRVRMNDmp,
+ NRVRMmp,
+ VRMKFK,
+ IDKSP,
+ DPZNmp,
+ HRTCmp,
+ IDSPVDSBMK,
+ PRCHNPGDN,
+ IDEKZETL
+)
+VALUES
+(
+ @IDEKZ,
+ @IDSPMU,
+ @IDGRSI,
+ @IDKSPRL,
+ @IDSPVDMK,
+ @IDSPVDMC,
+ @IDFRPD,
+ @IDSPMPOB,
+ @IDPRSN,
+ @IDSPKMMK,
+ NULL,
+ @IDSPVDKL,
+ @IDPRSNVD,
+ NULL,
+ NULL,
+ @NNZVPV,
+ @NNNKL,
+ @PRMK,
+ @DTMKFK,
+ NULL,
+ @DTPRM,
+ @DTVDM,
+ @GDN,
+ NULL,
+ @STMK,
+ @STMKDP,
+ @NCSRMK,
+ @idprsnsd,
+ @idprsnpr,
+ @idprsnvy,
+ @idsptsmp,
+ @idspssmp,
+ @GUIDEKZMK,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ @NRVRMNDmp,
+ @NRVRMmp,
+ @VRMKFK,
+ @IDKSP,
+ @DPZNmp,
+ @HRTCmp,
+ @IDSPVDSBMK,
+ @PRCHNPGDN,
+ @IDEKZETL
+);
+
+SELECT CAST(SCOPE_IDENTITY() AS int);";
+
+ using (var command = new SqlCommand(sql, connection, transaction))
+ {
+ command.CommandTimeout = 60;
+
+ command.Parameters.Add("@IDEKZ", SqlDbType.Int).Value = instrumentId;
+ command.Parameters.Add("@IDSPMU", SqlDbType.Int).Value = (object)template.IdSpmu ?? DBNull.Value;
+ command.Parameters.Add("@IDGRSI", SqlDbType.Int).Value = (object)template.IdGrsi ?? DBNull.Value;
+ command.Parameters.Add("@IDKSPRL", SqlDbType.Int).Value = (object)template.IdKsprl ?? DBNull.Value;
+ command.Parameters.Add("@IDSPVDMK", SqlDbType.Int).Value = verificationTypeId;
+ command.Parameters.Add("@IDSPVDMC", SqlDbType.Int).Value = (object)template.IdSpvdmc ?? DBNull.Value;
+ command.Parameters.Add("@IDFRPD", SqlDbType.Int).Value = template.IdFrpd;
+ command.Parameters.Add("@IDSPMPOB", SqlDbType.Int).Value = (object)template.IdSpmpob ?? DBNull.Value;
+ command.Parameters.Add("@IDPRSN", SqlDbType.Int).Value = pendingLine == null ? DBNull.Value : (object)pendingLine.VerifierId ?? DBNull.Value;
+ command.Parameters.Add("@IDSPKMMK", SqlDbType.Int).Value = (object)template.IdSpkmmk ?? DBNull.Value;
+ command.Parameters.Add("@IDSPVDKL", SqlDbType.Int).Value = (object)template.IdSpvdkl ?? DBNull.Value;
+ command.Parameters.Add("@IDPRSNVD", SqlDbType.Int).Value = (object)template.IdPrsnvd ?? DBNull.Value;
+ command.Parameters.Add("@NNZVPV", SqlDbType.NVarChar, 60).Value = normalizedNumber;
+ command.Parameters.Add("@NNNKL", SqlDbType.NVarChar, 30).Value = pendingLine != null && pendingLine.IsPassed == true
+ ? (object)(string.IsNullOrWhiteSpace(pendingLine.StickerNumber) ? null : pendingLine.StickerNumber.Trim())
+ : DBNull.Value;
+ command.Parameters.Add("@PRMK", SqlDbType.Int).Value = template.Prmk;
+ command.Parameters.Add("@DTMKFK", SqlDbType.DateTime).Value = pendingLine == null
+ ? DBNull.Value
+ : (object)(pendingLine.VerificationPerformedOn ?? pendingLine.VerificationDocumentDate) ?? DBNull.Value;
+ command.Parameters.Add("@DTPRM", SqlDbType.DateTime).Value = document.AcceptedOn;
+ command.Parameters.Add("@DTVDM", SqlDbType.DateTime).Value = (object)document.IssuedOn ?? DBNull.Value;
+ command.Parameters.Add("@GDN", SqlDbType.Bit).Value = pendingLine == null ? DBNull.Value : (object)pendingLine.IsPassed ?? DBNull.Value;
+ command.Parameters.Add("@STMK", SqlDbType.Money).Value = (object)template.Stmk ?? DBNull.Value;
+ command.Parameters.Add("@STMKDP", SqlDbType.Money).Value = (object)template.Stmkdp ?? DBNull.Value;
+ command.Parameters.Add("@NCSRMK", SqlDbType.Money).Value = (object)template.NcSrmk ?? DBNull.Value;
+ command.Parameters.Add("@idprsnsd", SqlDbType.Int).Value = (object)template.IdPrsnsd ?? DBNull.Value;
+ command.Parameters.Add("@idprsnpr", SqlDbType.Int).Value = (object)template.IdPrsnpr ?? DBNull.Value;
+ command.Parameters.Add("@idprsnvy", SqlDbType.Int).Value = (object)template.IdPrsnvy ?? DBNull.Value;
+ command.Parameters.Add("@idsptsmp", SqlDbType.Int).Value = (object)template.IdSptsmp ?? DBNull.Value;
+ command.Parameters.Add("@idspssmp", SqlDbType.Int).Value = (object)template.IdSpssmp ?? DBNull.Value;
+ command.Parameters.Add("@GUIDEKZMK", SqlDbType.UniqueIdentifier).Value = Guid.NewGuid();
+ command.Parameters.Add("@NRVRMNDmp", SqlDbType.Decimal).Value = (object)template.Nrvrmndmp ?? DBNull.Value;
+ command.Parameters["@NRVRMNDmp"].Precision = 10;
+ command.Parameters["@NRVRMNDmp"].Scale = 2;
+ command.Parameters.Add("@NRVRMmp", SqlDbType.Decimal).Value = (object)template.Nrvrmmp ?? DBNull.Value;
+ command.Parameters["@NRVRMmp"].Precision = 10;
+ command.Parameters["@NRVRMmp"].Scale = 2;
+ command.Parameters.Add("@VRMKFK", SqlDbType.Decimal).Value = (object)template.Vrmkfk ?? DBNull.Value;
+ command.Parameters["@VRMKFK"].Precision = 10;
+ command.Parameters["@VRMKFK"].Scale = 2;
+ command.Parameters.Add("@IDKSP", SqlDbType.Int).Value = (object)template.IdKsp ?? DBNull.Value;
+ command.Parameters.Add("@DPZNmp", SqlDbType.NVarChar, 100).Value = (object)template.Dpznmp ?? DBNull.Value;
+ command.Parameters.Add("@HRTCmp", SqlDbType.NVarChar, 80).Value = (object)template.Hrtcmp ?? DBNull.Value;
+ command.Parameters.Add("@IDSPVDSBMK", SqlDbType.Int).Value = (object)template.IdSpvdsbmk ?? DBNull.Value;
+ command.Parameters.Add("@PRCHNPGDN", SqlDbType.NVarChar, 1024).Value = pendingLine != null && pendingLine.IsPassed == false
+ ? (object)(string.IsNullOrWhiteSpace(pendingLine.RejectionReason) ? null : pendingLine.RejectionReason.Trim())
+ : DBNull.Value;
+ command.Parameters.Add("@IDEKZETL", SqlDbType.Int).Value = (object)template.IdEkzetl ?? DBNull.Value;
+
return Convert.ToInt32(command.ExecuteScalar());
}
}
+ private static HashSet LoadDocumentDuplicateKeys(SqlConnection connection, SqlTransaction transaction, string documentNumber)
+ {
+ const string sql = @"
+SELECT DISTINCT
+ tips.TP AS InstrumentType,
+ sizeInfo.DPZN AS RangeText,
+ sizeInfo.NNGSRS AS RegistryNumber,
+ z.NNZV AS SerialNumber
+FROM dbo.EKZMK m
+JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ
+LEFT JOIN dbo.TPRZ sizeInfo ON sizeInfo.IDTPRZ = z.IDTPRZ
+LEFT JOIN dbo.TIPS tips ON tips.IDTIPS = sizeInfo.IDTIPS
+WHERE m.NNZVPV = @DocumentNumber;";
+
+ var keys = new HashSet(StringComparer.OrdinalIgnoreCase);
+
+ using (var command = new SqlCommand(sql, connection, transaction))
+ {
+ command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber;
+
+ using (var reader = command.ExecuteReader())
+ {
+ while (reader.Read())
+ {
+ keys.Add(PsvDocumentLine.BuildDuplicateKey(
+ GetString(reader, "InstrumentType"),
+ GetString(reader, "RangeText"),
+ GetString(reader, "RegistryNumber"),
+ GetString(reader, "SerialNumber")));
+ }
+ }
+ }
+
+ return keys;
+ }
+
private static List LoadDeleteBlockers(SqlConnection connection, SqlTransaction transaction, string documentNumber)
{
const string sql = @"
@@ -579,6 +1164,42 @@ ORDER BY blocker.TableName;";
return blockers;
}
+ private static InstrumentIdentityInfo LoadInstrumentIdentity(SqlConnection connection, SqlTransaction transaction, int instrumentId)
+ {
+ const string sql = @"
+SELECT
+ tips.TP AS InstrumentType,
+ sizeInfo.DPZN AS RangeText,
+ sizeInfo.NNGSRS AS RegistryNumber,
+ z.NNZV AS SerialNumber
+FROM dbo.EKZ z
+LEFT JOIN dbo.TPRZ sizeInfo ON sizeInfo.IDTPRZ = z.IDTPRZ
+LEFT JOIN dbo.TIPS tips ON tips.IDTIPS = sizeInfo.IDTIPS
+WHERE z.IDEKZ = @InstrumentId;";
+
+ using (var command = new SqlCommand(sql, connection, transaction))
+ {
+ command.Parameters.Add("@InstrumentId", SqlDbType.Int).Value = instrumentId;
+
+ using (var reader = command.ExecuteReader())
+ {
+ if (!reader.Read())
+ {
+ return null;
+ }
+
+ return new InstrumentIdentityInfo
+ {
+ DuplicateKey = PsvDocumentLine.BuildDuplicateKey(
+ GetString(reader, "InstrumentType"),
+ GetString(reader, "RangeText"),
+ GetString(reader, "RegistryNumber"),
+ GetString(reader, "SerialNumber"))
+ };
+ }
+ }
+ }
+
private static int LoadVerificationTypeId(SqlConnection connection, SqlTransaction transaction)
{
const string sql = @"
@@ -734,202 +1355,139 @@ ORDER BY Priority;";
}
}
- private static void InsertEkzMk(
- SqlConnection connection,
- SqlTransaction transaction,
- int verificationTypeId,
- DocumentEditorResult document,
- string normalizedNumber,
- int instrumentId,
- EkzMkTemplate template)
+ private static EkzMkTemplate LoadFallbackTemplate(SqlConnection connection, SqlTransaction transaction, int instrumentId)
{
const string sql = @"
-INSERT INTO dbo.EKZMK
+WITH DefaultLab AS
(
- IDEKZ,
- IDSPMU,
- IDGRSI,
- IDKSPRL,
- IDSPVDMK,
- IDSPVDMC,
- IDFRPD,
- IDSPMPOB,
- IDPRSN,
- IDSPKMMK,
- IDEKZRM,
- IDSPVDKL,
- IDPRSNVD,
- IDEKZTO,
- IDEKZOT,
- NNZVPV,
- SHFKL,
- NNNKL,
- PRMK,
- DTMKFK,
- DTMKPL,
- DTPRM,
- DTVDM,
- GDN,
- PZMC,
- STMK,
- STMKDP,
- NCSRMK,
- idprsnsd,
- idprsnpr,
- idprsnvy,
- idsptsmp,
- idspssmp,
- GUIDEKZMK,
- DSEKZMK,
- DTOTM,
- DTVZM,
- IDPRSNOTM,
- IDPRSNVZM,
- NRVRMNDmp,
- NRVRMmp,
- VRMKFK,
- IDKSP,
- DPZNmp,
- HRTCmp,
- IDSPVDSBMK,
- PRCHNPGDN,
- IDEKZETL
+ SELECT
+ CASE WHEN COUNT(DISTINCT m.IDFRPD) = 1 THEN MIN(m.IDFRPD) ELSE NULL END AS DefaultIdFrpd
+ FROM dbo.EKZMK m
)
-VALUES
+SELECT TOP (1)
+ periodInfo.IDGRSI,
+ periodInfo.IDSPVDMC,
+ defaultLab.DefaultIdFrpd AS IDFRPD,
+ tprz.IDSPKMMK,
+ periodInfo.PRMK,
+ tprz.DPZN AS DPZNmp,
+ tprz.HRTC AS HRTCmp,
+ CAST(N'Период из TPRMCP' AS nvarchar(60)) AS SourceDescription
+FROM dbo.EKZ z
+JOIN dbo.TPRZ tprz ON tprz.IDTPRZ = z.IDTPRZ
+CROSS JOIN DefaultLab defaultLab
+OUTER APPLY
(
- @IDEKZ,
- @IDSPMU,
- @IDGRSI,
- @IDKSPRL,
- @IDSPVDMK,
- @IDSPVDMC,
- @IDFRPD,
- @IDSPMPOB,
- @IDPRSN,
- @IDSPKMMK,
- NULL,
- @IDSPVDKL,
- @IDPRSNVD,
- NULL,
- NULL,
- @NNZVPV,
- NULL,
- NULL,
- @PRMK,
- NULL,
- NULL,
- @DTPRM,
- @DTVDM,
- NULL,
- NULL,
- @STMK,
- @STMKDP,
- @NCSRMK,
- @idprsnsd,
- @idprsnpr,
- @idprsnvy,
- @idsptsmp,
- @idspssmp,
- @GUIDEKZMK,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- @NRVRMNDmp,
- @NRVRMmp,
- @VRMKFK,
- @IDKSP,
- @DPZNmp,
- @HRTCmp,
- @IDSPVDSBMK,
- NULL,
- @IDEKZETL
-);";
+ 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
+ FROM dbo.EKZMCP e
+ JOIN dbo.TPRMCP t ON t.IDTPRMCP = e.IDTPRMCP
+ WHERE e.IDEKZ = z.IDEKZ
+ ) periodByInstrument
+ FULL JOIN
+ (
+ SELECT t.IDGRSI, t.IDSPVDMC, t.PRMK
+ FROM dbo.TPRMCP t
+ WHERE t.IDTPRZ = z.IDTPRZ
+ ) periodByType ON 1 = 0
+) periodInfo
+WHERE z.IDEKZ = @InstrumentId
+ AND defaultLab.DefaultIdFrpd IS NOT NULL
+ AND periodInfo.PRMK IS NOT NULL;";
+
+ using (var command = new SqlCommand(sql, connection, transaction))
+ {
+ command.Parameters.Add("@InstrumentId", SqlDbType.Int).Value = instrumentId;
+
+ using (var reader = command.ExecuteReader())
+ {
+ if (!reader.Read())
+ {
+ return null;
+ }
+
+ return new EkzMkTemplate
+ {
+ IdSpmu = null,
+ IdGrsi = GetNullableInt32(reader, "IDGRSI"),
+ IdKsprl = null,
+ IdSpvdmc = GetNullableInt32(reader, "IDSPVDMC"),
+ IdFrpd = GetInt32(reader, "IDFRPD"),
+ IdSpmpob = null,
+ IdPrsn = null,
+ IdSpkmmk = GetNullableInt32(reader, "IDSPKMMK"),
+ IdSpvdkl = null,
+ IdPrsnvd = null,
+ Prmk = GetInt32(reader, "PRMK"),
+ Stmk = null,
+ Stmkdp = null,
+ NcSrmk = null,
+ IdPrsnsd = null,
+ IdPrsnpr = null,
+ IdPrsnvy = null,
+ IdSptsmp = null,
+ IdSpssmp = null,
+ Nrvrmndmp = null,
+ Nrvrmmp = null,
+ Vrmkfk = null,
+ IdKsp = null,
+ Dpznmp = GetString(reader, "DPZNmp"),
+ Hrtcmp = GetString(reader, "HRTCmp"),
+ IdSpvdsbmk = null,
+ IdEkzetl = null,
+ SourceDescription = GetString(reader, "SourceDescription")
+ };
+ }
+ }
+ }
+
+ private static string NormalizeDocumentNumber(string value)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return null;
+ }
+
+ return value.Trim();
+ }
+
+ private static int UpdateDocumentHeader(SqlConnection connection, SqlTransaction transaction, string currentDocumentNumber, DocumentEditorResult document)
+ {
+ const string sql = @"
+UPDATE dbo.EKZMK
+SET NNZVPV = @NewDocumentNumber,
+ DTPRM = @AcceptedOn,
+ DTVDM = @IssuedOn
+WHERE NNZVPV = @CurrentDocumentNumber;
+
+SELECT @@ROWCOUNT;";
using (var command = new SqlCommand(sql, connection, transaction))
{
command.CommandTimeout = 60;
-
- command.Parameters.Add("@IDEKZ", SqlDbType.Int).Value = instrumentId;
- command.Parameters.Add("@IDSPMU", SqlDbType.Int).Value = (object)template.IdSpmu ?? DBNull.Value;
- command.Parameters.Add("@IDGRSI", SqlDbType.Int).Value = (object)template.IdGrsi ?? DBNull.Value;
- command.Parameters.Add("@IDKSPRL", SqlDbType.Int).Value = (object)template.IdKsprl ?? DBNull.Value;
- command.Parameters.Add("@IDSPVDMK", SqlDbType.Int).Value = verificationTypeId;
- command.Parameters.Add("@IDSPVDMC", SqlDbType.Int).Value = (object)template.IdSpvdmc ?? DBNull.Value;
- command.Parameters.Add("@IDFRPD", SqlDbType.Int).Value = template.IdFrpd;
- command.Parameters.Add("@IDSPMPOB", SqlDbType.Int).Value = (object)template.IdSpmpob ?? DBNull.Value;
- command.Parameters.Add("@IDPRSN", SqlDbType.Int).Value = (object)template.IdPrsn ?? DBNull.Value;
- command.Parameters.Add("@IDSPKMMK", SqlDbType.Int).Value = (object)template.IdSpkmmk ?? DBNull.Value;
- command.Parameters.Add("@IDSPVDKL", SqlDbType.Int).Value = (object)template.IdSpvdkl ?? DBNull.Value;
- command.Parameters.Add("@IDPRSNVD", SqlDbType.Int).Value = (object)template.IdPrsnvd ?? DBNull.Value;
- command.Parameters.Add("@NNZVPV", SqlDbType.NVarChar, 60).Value = normalizedNumber;
- command.Parameters.Add("@PRMK", SqlDbType.Int).Value = template.Prmk;
- command.Parameters.Add("@DTPRM", SqlDbType.DateTime).Value = document.AcceptedOn;
- command.Parameters.Add("@DTVDM", SqlDbType.DateTime).Value = (object)document.IssuedOn ?? DBNull.Value;
- command.Parameters.Add("@STMK", SqlDbType.Money).Value = (object)template.Stmk ?? DBNull.Value;
- command.Parameters.Add("@STMKDP", SqlDbType.Money).Value = (object)template.Stmkdp ?? DBNull.Value;
- command.Parameters.Add("@NCSRMK", SqlDbType.Money).Value = (object)template.NcSrmk ?? DBNull.Value;
- command.Parameters.Add("@idprsnsd", SqlDbType.Int).Value = (object)template.IdPrsnsd ?? DBNull.Value;
- command.Parameters.Add("@idprsnpr", SqlDbType.Int).Value = (object)template.IdPrsnpr ?? DBNull.Value;
- command.Parameters.Add("@idprsnvy", SqlDbType.Int).Value = (object)template.IdPrsnvy ?? DBNull.Value;
- command.Parameters.Add("@idsptsmp", SqlDbType.Int).Value = (object)template.IdSptsmp ?? DBNull.Value;
- command.Parameters.Add("@idspssmp", SqlDbType.Int).Value = (object)template.IdSpssmp ?? DBNull.Value;
- command.Parameters.Add("@GUIDEKZMK", SqlDbType.UniqueIdentifier).Value = Guid.NewGuid();
- command.Parameters.Add("@NRVRMNDmp", SqlDbType.Decimal).Value = (object)template.Nrvrmndmp ?? DBNull.Value;
- command.Parameters["@NRVRMNDmp"].Precision = 10;
- command.Parameters["@NRVRMNDmp"].Scale = 2;
- command.Parameters.Add("@NRVRMmp", SqlDbType.Decimal).Value = (object)template.Nrvrmmp ?? DBNull.Value;
- command.Parameters["@NRVRMmp"].Precision = 10;
- command.Parameters["@NRVRMmp"].Scale = 2;
- command.Parameters.Add("@VRMKFK", SqlDbType.Decimal).Value = (object)template.Vrmkfk ?? DBNull.Value;
- command.Parameters["@VRMKFK"].Precision = 10;
- command.Parameters["@VRMKFK"].Scale = 2;
- command.Parameters.Add("@IDKSP", SqlDbType.Int).Value = (object)template.IdKsp ?? DBNull.Value;
- command.Parameters.Add("@DPZNmp", SqlDbType.NVarChar, 100).Value = (object)template.Dpznmp ?? DBNull.Value;
- command.Parameters.Add("@HRTCmp", SqlDbType.NVarChar, 80).Value = (object)template.Hrtcmp ?? DBNull.Value;
- command.Parameters.Add("@IDSPVDSBMK", SqlDbType.Int).Value = (object)template.IdSpvdsbmk ?? DBNull.Value;
- command.Parameters.Add("@IDEKZETL", SqlDbType.Int).Value = (object)template.IdEkzetl ?? DBNull.Value;
-
- command.ExecuteNonQuery();
+ command.Parameters.Add("@NewDocumentNumber", SqlDbType.NVarChar, 60).Value = document.DocumentNumber;
+ command.Parameters.Add("@AcceptedOn", SqlDbType.DateTime).Value = document.AcceptedOn;
+ command.Parameters.Add("@IssuedOn", SqlDbType.DateTime).Value = (object)document.IssuedOn ?? DBNull.Value;
+ command.Parameters.Add("@CurrentDocumentNumber", SqlDbType.NVarChar, 60).Value = currentDocumentNumber;
+ return Convert.ToInt32(command.ExecuteScalar());
}
}
private sealed class DeleteBlockerInfo
{
- public string TableName { get; set; }
-
public int RowCount { get; set; }
+
+ public string TableName { get; set; }
}
- private static int GetInt32(IDataRecord record, string columnName)
+ private sealed class InstrumentIdentityInfo
{
- return Convert.ToInt32(record[columnName]);
- }
-
- private static int? GetNullableInt32(IDataRecord record, string columnName)
- {
- return record[columnName] == DBNull.Value ? (int?)null : Convert.ToInt32(record[columnName]);
- }
-
- private static DateTime? GetNullableDateTime(IDataRecord record, string columnName)
- {
- return record[columnName] == DBNull.Value ? (DateTime?)null : Convert.ToDateTime(record[columnName]);
- }
-
- private static bool? GetNullableBoolean(IDataRecord record, string columnName)
- {
- return record[columnName] == DBNull.Value ? (bool?)null : Convert.ToBoolean(record[columnName]);
- }
-
- private static decimal? GetNullableDecimal(IDataRecord record, string columnName)
- {
- return record[columnName] == DBNull.Value ? (decimal?)null : Convert.ToDecimal(record[columnName]);
- }
-
- private static string GetString(IDataRecord record, string columnName)
- {
- return record[columnName] == DBNull.Value ? string.Empty : Convert.ToString(record[columnName]);
+ public string DuplicateKey { get; set; }
}
}
}
diff --git a/XLAB/PsvModels.cs b/XLAB/PsvModels.cs
index 37e3689..db52a42 100644
--- a/XLAB/PsvModels.cs
+++ b/XLAB/PsvModels.cs
@@ -14,32 +14,115 @@ namespace XLAB
}
}
- public sealed class PsvDocumentSummary
+ public sealed class CustomerReference
{
- public string DocumentNumber { get; set; }
-
- public DateTime? AcceptedOn { get; set; }
-
- public DateTime? IssuedOn { get; set; }
-
- public string DepartmentName { get; set; }
+ public int CustomerId { get; set; }
public string CustomerName { get; set; }
- public int ItemCount { get; set; }
+ public override string ToString()
+ {
+ return CustomerName ?? string.Empty;
+ }
+ }
- public int IssuedCount { get; set; }
+ public sealed class PsvDocumentSummary : ObservableObject
+ {
+ private DateTime? _acceptedOn;
+ private string _customerName;
+ private int? _customerId;
+ private string _departmentName;
+ private string _documentKey;
+ private string _documentNumber;
+ private int _failedCount;
+ private bool _isDraft;
+ private int _issuedCount;
+ private DateTime? _issuedOn;
+ private int _itemCount;
+ private int _passedCount;
- public int PassedCount { get; set; }
-
- public int FailedCount { get; set; }
-
- public bool IsDraft { get; set; }
+ public DateTime? AcceptedOn
+ {
+ get { return _acceptedOn; }
+ set
+ {
+ if (SetProperty(ref _acceptedOn, value))
+ {
+ OnPropertyChanged("AcceptedMonthGroup");
+ }
+ }
+ }
public string AcceptedMonthGroup
{
get { return AcceptedOn.HasValue ? AcceptedOn.Value.ToString("yyyy-MM") : "Без даты"; }
}
+
+ public string CustomerName
+ {
+ get { return _customerName; }
+ set { SetProperty(ref _customerName, value); }
+ }
+
+ public int? CustomerId
+ {
+ get { return _customerId; }
+ set { SetProperty(ref _customerId, value); }
+ }
+
+ public string DepartmentName
+ {
+ get { return _departmentName; }
+ set { SetProperty(ref _departmentName, value); }
+ }
+
+ public string DocumentKey
+ {
+ get { return _documentKey; }
+ set { SetProperty(ref _documentKey, value); }
+ }
+
+ public string DocumentNumber
+ {
+ get { return _documentNumber; }
+ set { SetProperty(ref _documentNumber, value); }
+ }
+
+ public int FailedCount
+ {
+ get { return _failedCount; }
+ set { SetProperty(ref _failedCount, value); }
+ }
+
+ public bool IsDraft
+ {
+ get { return _isDraft; }
+ set { SetProperty(ref _isDraft, value); }
+ }
+
+ public int IssuedCount
+ {
+ get { return _issuedCount; }
+ set { SetProperty(ref _issuedCount, value); }
+ }
+
+ public DateTime? IssuedOn
+ {
+ get { return _issuedOn; }
+ set { SetProperty(ref _issuedOn, value); }
+ }
+
+ public int ItemCount
+ {
+ get { return _itemCount; }
+ set { SetProperty(ref _itemCount, value); }
+ }
+
+ public int PassedCount
+ {
+ get { return _passedCount; }
+ set { SetProperty(ref _passedCount, value); }
+ }
}
public sealed class PsvDocumentLine
@@ -76,16 +159,36 @@ namespace XLAB
public bool? IsPassed { get; set; }
+ public DateTime? VerificationPerformedOn { get; set; }
+
+ public int? VerifierId { get; set; }
+
public string VerifierName { get; set; }
public string StickerNumber { get; set; }
+ public int? VerificationDocumentFormId { get; set; }
+
+ public int? VerificationDocumentLinkTypeId { get; set; }
+
public string VerificationDocumentNumber { get; set; }
public DateTime? VerificationDocumentDate { get; set; }
+ public string RejectionReason { get; set; }
+
public string Notes { get; set; }
+ public bool IsPendingInsert { get; set; }
+
+ public string DuplicateKey
+ {
+ get
+ {
+ return BuildDuplicateKey(InstrumentType, RangeText, RegistryNumber, SerialNumber);
+ }
+ }
+
public string ResultText
{
get
@@ -116,6 +219,20 @@ namespace XLAB
return string.Format("{0} от {1:d}", VerificationDocumentNumber, VerificationDocumentDate.Value);
}
}
+
+ public static string BuildDuplicateKey(string instrumentType, string rangeText, string registryNumber, string serialNumber)
+ {
+ return string.Join("|",
+ NormalizeKeyPart(instrumentType),
+ NormalizeKeyPart(rangeText),
+ NormalizeKeyPart(registryNumber),
+ NormalizeKeyPart(serialNumber));
+ }
+
+ private static string NormalizeKeyPart(string value)
+ {
+ return string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim().ToUpperInvariant();
+ }
}
public sealed class PsvDocumentGroupSummary
@@ -147,37 +264,69 @@ namespace XLAB
{
private bool _isSelected;
+ public string AccuracyText { get; set; }
+
+ public string CustomerName { get; set; }
+
+ public bool HasTemplate { get; set; }
+
+ public int InstrumentId { get; set; }
+
+ public string InstrumentName { get; set; }
+
+ public string InstrumentType { get; set; }
+
+ public string InventoryNumber { get; set; }
+
public bool IsSelected
{
get { return _isSelected; }
set { SetProperty(ref _isSelected, value); }
}
- public int InstrumentId { get; set; }
+ public DateTime? LastAcceptedOn { get; set; }
- public int TypeSizeId { get; set; }
-
- public string SerialNumber { get; set; }
-
- public string InventoryNumber { get; set; }
-
- public string CustomerName { get; set; }
-
- public string InstrumentType { get; set; }
-
- public string InstrumentName { get; set; }
+ public string LastDocumentNumber { get; set; }
public string MeasurementArea { get; set; }
public string RangeText { get; set; }
- public string AccuracyText { get; set; }
+ public string RegistryNumber { get; set; }
- public string LastDocumentNumber { get; set; }
-
- public DateTime? LastAcceptedOn { get; set; }
+ public string SerialNumber { get; set; }
public string TemplateSource { get; set; }
+
+ public int TypeSizeId { get; set; }
+ }
+
+ public sealed class PersonReference
+ {
+ public int PersonId { get; set; }
+
+ public string FullName { get; set; }
+
+ public override string ToString()
+ {
+ return FullName ?? string.Empty;
+ }
+ }
+
+ public sealed class DocumentFormReference
+ {
+ public int DocumentFormId { get; set; }
+
+ public int LinkTypeId { get; set; }
+
+ public string DocumentKindName { get; set; }
+
+ public string DocumentFormName { get; set; }
+
+ public override string ToString()
+ {
+ return DocumentFormName ?? string.Empty;
+ }
}
public sealed class DocumentEditorResult
@@ -189,6 +338,44 @@ namespace XLAB
public DateTime? IssuedOn { get; set; }
}
+ public sealed class VerificationEditSeed
+ {
+ public DocumentFormReference DocumentForm { get; set; }
+
+ public bool IsPassed { get; set; }
+
+ public string RejectionReason { get; set; }
+
+ public string StickerNumber { get; set; }
+
+ public DateTime? VerificationDate { get; set; }
+
+ public string VerificationDocumentNumber { get; set; }
+
+ public int? VerifierId { get; set; }
+ }
+
+ public sealed class VerificationEditResult
+ {
+ public int DocumentFormId { get; set; }
+
+ public int DocumentLinkTypeId { get; set; }
+
+ public bool IsPassed { get; set; }
+
+ public string RejectionReason { get; set; }
+
+ public string StickerNumber { get; set; }
+
+ public DateTime VerificationDate { get; set; }
+
+ public string VerificationDocumentNumber { get; set; }
+
+ public int VerifierId { get; set; }
+
+ public string VerifierName { get; set; }
+ }
+
internal sealed class DocumentDeleteResult
{
public int DeletedEkzMkFctvlCount { get; set; }
@@ -198,62 +385,75 @@ namespace XLAB
public int DeletedDmsCount { get; set; }
}
+ internal sealed class DocumentSaveResult
+ {
+ public string DocumentNumber { get; set; }
+
+ public int InsertedEkzMkCount { get; set; }
+
+ public int SkippedDuplicateCount { get; set; }
+
+ public int SkippedWithoutTemplateCount { get; set; }
+
+ public int UpdatedEkzMkCount { get; set; }
+ }
+
internal sealed class EkzMkTemplate
{
- public int? IdSpmu { get; set; }
+ public string Dpznmp { get; set; }
- public int? IdGrsi { get; set; }
+ public string Hrtcmp { get; set; }
- public int? IdKsprl { get; set; }
-
- public int? IdSpvdmc { get; set; }
+ public int? IdEkzetl { get; set; }
public int IdFrpd { get; set; }
- public int? IdSpmpob { get; set; }
+ public int? IdGrsi { get; set; }
+
+ public int? IdKsp { get; set; }
+
+ public int? IdKsprl { get; set; }
public int? IdPrsn { get; set; }
- public int? IdSpkmmk { get; set; }
+ public int? IdPrsnpr { get; set; }
- public int? IdSpvdkl { get; set; }
+ public int? IdPrsnsd { get; set; }
public int? IdPrsnvd { get; set; }
+ public int? IdPrsnvy { get; set; }
+
+ public int? IdSpkmmk { get; set; }
+
+ public int? IdSpmpob { get; set; }
+
+ public int? IdSpmu { get; set; }
+
+ public int? IdSpssmp { get; set; }
+
+ public int? IdSptsmp { get; set; }
+
+ public int? IdSpvdkl { get; set; }
+
+ public int? IdSpvdsbmk { get; set; }
+
+ public int? IdSpvdmc { get; set; }
+
+ public decimal? NcSrmk { get; set; }
+
+ public decimal? Nrvrmmp { get; set; }
+
+ public decimal? Nrvrmndmp { get; set; }
+
public int Prmk { get; set; }
+ public string SourceDescription { get; set; }
+
public decimal? Stmk { get; set; }
public decimal? Stmkdp { get; set; }
- public decimal? NcSrmk { get; set; }
-
- public int? IdPrsnsd { get; set; }
-
- public int? IdPrsnpr { get; set; }
-
- public int? IdPrsnvy { get; set; }
-
- public int? IdSptsmp { get; set; }
-
- public int? IdSpssmp { get; set; }
-
- public decimal? Nrvrmndmp { get; set; }
-
- public decimal? Nrvrmmp { get; set; }
-
public decimal? Vrmkfk { get; set; }
-
- public int? IdKsp { get; set; }
-
- public string Dpznmp { get; set; }
-
- public string Hrtcmp { get; set; }
-
- public int? IdSpvdsbmk { get; set; }
-
- public int? IdEkzetl { get; set; }
-
- public string SourceDescription { get; set; }
}
}
diff --git a/XLAB/SelectInstrumentsWindow.xaml b/XLAB/SelectInstrumentsWindow.xaml
new file mode 100644
index 0000000..d40ad25
--- /dev/null
+++ b/XLAB/SelectInstrumentsWindow.xaml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/XLAB/SelectInstrumentsWindow.xaml.cs b/XLAB/SelectInstrumentsWindow.xaml.cs
new file mode 100644
index 0000000..a8ad827
--- /dev/null
+++ b/XLAB/SelectInstrumentsWindow.xaml.cs
@@ -0,0 +1,20 @@
+using System.Windows;
+
+namespace XLAB
+{
+ public partial class SelectInstrumentsWindow : Window
+ {
+ internal SelectInstrumentsWindow(SelectInstrumentsWindowViewModel viewModel)
+ {
+ InitializeComponent();
+ DataContext = viewModel;
+ viewModel.CloseRequested += ViewModelOnCloseRequested;
+ }
+
+ private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
+ {
+ DialogResult = dialogResult;
+ Close();
+ }
+ }
+}
diff --git a/XLAB/SelectInstrumentsWindowViewModel.cs b/XLAB/SelectInstrumentsWindowViewModel.cs
new file mode 100644
index 0000000..7993d31
--- /dev/null
+++ b/XLAB/SelectInstrumentsWindowViewModel.cs
@@ -0,0 +1,129 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.ComponentModel;
+using System.Linq;
+using System.Windows.Input;
+
+namespace XLAB
+{
+ internal sealed class SelectInstrumentsWindowViewModel : ObservableObject
+ {
+ private string _searchText;
+ private string _statusText;
+
+ public SelectInstrumentsWindowViewModel(string customerName, IReadOnlyList instruments)
+ {
+ CustomerName = customerName ?? string.Empty;
+ Instruments = new ObservableCollection(instruments ?? new List());
+ InstrumentsView = System.Windows.Data.CollectionViewSource.GetDefaultView(Instruments);
+ InstrumentsView.Filter = FilterInstruments;
+
+ foreach (var instrument in Instruments)
+ {
+ instrument.PropertyChanged += InstrumentOnPropertyChanged;
+ }
+
+ ConfirmCommand = new RelayCommand(Confirm);
+ CancelCommand = new RelayCommand(Cancel);
+ UpdateStatus();
+ }
+
+ public event EventHandler CloseRequested;
+
+ public ICommand CancelCommand { get; private set; }
+
+ public ICommand ConfirmCommand { get; private set; }
+
+ public string CustomerName { get; private set; }
+
+ public ObservableCollection Instruments { get; private set; }
+
+ public ICollectionView InstrumentsView { get; private set; }
+
+ public string SearchText
+ {
+ get { return _searchText; }
+ set
+ {
+ if (SetProperty(ref _searchText, value))
+ {
+ InstrumentsView.Refresh();
+ UpdateStatus();
+ }
+ }
+ }
+
+ public string StatusText
+ {
+ get { return _statusText; }
+ private set { SetProperty(ref _statusText, value); }
+ }
+
+ public IReadOnlyList GetSelectedItems()
+ {
+ return Instruments.Where(delegate(AvailableInstrumentItem item) { return item.IsSelected; }).ToList();
+ }
+
+ private void Cancel(object parameter)
+ {
+ RaiseCloseRequested(false);
+ }
+
+ private void Confirm(object parameter)
+ {
+ RaiseCloseRequested(true);
+ }
+
+ private bool FilterInstruments(object item)
+ {
+ var instrument = item as AvailableInstrumentItem;
+ if (instrument == null)
+ {
+ return false;
+ }
+
+ if (string.IsNullOrWhiteSpace(SearchText))
+ {
+ return true;
+ }
+
+ return Contains(instrument.RegistryNumber, SearchText)
+ || Contains(instrument.InstrumentName, SearchText)
+ || Contains(instrument.InstrumentType, SearchText)
+ || Contains(instrument.RangeText, SearchText)
+ || Contains(instrument.AccuracyText, SearchText)
+ || Contains(instrument.SerialNumber, SearchText);
+ }
+
+ private void InstrumentOnPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == "IsSelected")
+ {
+ UpdateStatus();
+ }
+ }
+
+ private static bool Contains(string source, string searchText)
+ {
+ return !string.IsNullOrWhiteSpace(source)
+ && source.IndexOf(searchText, StringComparison.OrdinalIgnoreCase) >= 0;
+ }
+
+ private void RaiseCloseRequested(bool? dialogResult)
+ {
+ var handler = CloseRequested;
+ if (handler != null)
+ {
+ handler(this, dialogResult);
+ }
+ }
+
+ private void UpdateStatus()
+ {
+ var visibleCount = InstrumentsView.Cast