edit
This commit is contained in:
@@ -9,6 +9,8 @@ namespace XLAB
|
||||
|
||||
IReadOnlyList<AvailableInstrumentItem> ShowInstrumentPickerDialog(string customerName, IReadOnlyList<AvailableInstrumentItem> instruments);
|
||||
|
||||
InstrumentTypeSelectionResult ShowInstrumentTypeDialog(string customerName, IReadOnlyList<AvailableInstrumentItem> instrumentTypes);
|
||||
|
||||
VerificationEditResult ShowVerificationDialog(
|
||||
VerificationEditSeed seed,
|
||||
IReadOnlyList<PersonReference> verifiers,
|
||||
@@ -52,6 +54,16 @@ namespace XLAB
|
||||
return result.HasValue && result.Value ? viewModel.GetSelectedItems() : null;
|
||||
}
|
||||
|
||||
public InstrumentTypeSelectionResult ShowInstrumentTypeDialog(string customerName, IReadOnlyList<AvailableInstrumentItem> instrumentTypes)
|
||||
{
|
||||
var viewModel = new SelectInstrumentTypeWindowViewModel(customerName, instrumentTypes);
|
||||
var window = new SelectInstrumentTypeWindow(viewModel);
|
||||
window.Owner = _owner;
|
||||
|
||||
var result = window.ShowDialog();
|
||||
return result.HasValue && result.Value ? viewModel.GetResult() : null;
|
||||
}
|
||||
|
||||
public VerificationEditResult ShowVerificationDialog(
|
||||
VerificationEditSeed seed,
|
||||
IReadOnlyList<PersonReference> verifiers,
|
||||
|
||||
@@ -198,6 +198,8 @@
|
||||
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
|
||||
<MenuItem Header="Добавить по заводским номерам"
|
||||
Command="{Binding OpenInstrumentPickerCommand}" />
|
||||
<MenuItem Header="Добавить по типу"
|
||||
Command="{Binding OpenInstrumentTypePickerCommand}" />
|
||||
<MenuItem Header="Удалить"
|
||||
Command="{Binding DeleteSelectedGroupsCommand}" />
|
||||
</ContextMenu>
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace XLAB
|
||||
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; });
|
||||
OpenInstrumentTypePickerCommand = new RelayCommand(delegate { OpenInstrumentTypePickerAsync(); }, 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(); });
|
||||
@@ -169,6 +170,8 @@ namespace XLAB
|
||||
|
||||
public ICommand OpenInstrumentPickerCommand { get; private set; }
|
||||
|
||||
public ICommand OpenInstrumentTypePickerCommand { get; private set; }
|
||||
|
||||
public ICommand RefreshDocumentsCommand { get; private set; }
|
||||
|
||||
public ICommand ResetLineVerificationCommand { get; private set; }
|
||||
@@ -513,12 +516,141 @@ namespace XLAB
|
||||
&& source.IndexOf(filter, StringComparison.OrdinalIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
private string BuildOpenDocumentConflictMessage(IEnumerable<OpenDocumentConflictInfo> conflicts)
|
||||
{
|
||||
var materializedConflicts = NormalizeOpenDocumentConflicts(conflicts);
|
||||
if (materializedConflicts.Count == 0)
|
||||
{
|
||||
return "Прибор уже находится в другой открытой ПСВ этого заказчика.";
|
||||
}
|
||||
|
||||
var preview = materializedConflicts
|
||||
.Take(5)
|
||||
.Select(delegate(OpenDocumentConflictInfo conflict)
|
||||
{
|
||||
return string.Format("зав. № {0} -> {1}", conflict.SerialNumber, conflict.DocumentNumber);
|
||||
})
|
||||
.ToList();
|
||||
|
||||
var suffix = materializedConflicts.Count > preview.Count
|
||||
? string.Format(" Еще конфликтов: {0}.", materializedConflicts.Count - preview.Count)
|
||||
: string.Empty;
|
||||
|
||||
return string.Format(
|
||||
"Приборы уже находятся в других открытых ПСВ этого заказчика: {0}.{1}",
|
||||
string.Join("; ", preview.ToArray()),
|
||||
suffix);
|
||||
}
|
||||
|
||||
private List<OpenDocumentConflictInfo> FindOpenDocumentConflicts(IEnumerable<PsvDocumentLine> candidateLines)
|
||||
{
|
||||
if (SelectedDocument == null || !SelectedDocument.CustomerId.HasValue || candidateLines == null)
|
||||
{
|
||||
return new List<OpenDocumentConflictInfo>();
|
||||
}
|
||||
|
||||
var conflicts = FindPendingOpenDocumentConflicts(SelectedDocument, candidateLines);
|
||||
conflicts.AddRange(_service.FindOpenDocumentConflicts(
|
||||
SelectedDocument.CustomerId.Value,
|
||||
SelectedDocument.IsDraft ? null : SelectedDocument.DocumentNumber,
|
||||
candidateLines));
|
||||
|
||||
return NormalizeOpenDocumentConflicts(conflicts);
|
||||
}
|
||||
|
||||
private List<OpenDocumentConflictInfo> FindPendingOpenDocumentConflicts(PsvDocumentSummary currentDocument, IEnumerable<PsvDocumentLine> candidateLines)
|
||||
{
|
||||
if (currentDocument == null || !currentDocument.CustomerId.HasValue || candidateLines == null)
|
||||
{
|
||||
return new List<OpenDocumentConflictInfo>();
|
||||
}
|
||||
|
||||
var candidateKeys = new HashSet<string>(
|
||||
candidateLines
|
||||
.Where(delegate(PsvDocumentLine line)
|
||||
{
|
||||
return line != null
|
||||
&& line.TypeSizeId > 0
|
||||
&& !string.IsNullOrWhiteSpace(line.SerialNumber);
|
||||
})
|
||||
.Select(delegate(PsvDocumentLine line) { return line.OpenDocumentConflictKey; }),
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
if (candidateKeys.Count == 0)
|
||||
{
|
||||
return new List<OpenDocumentConflictInfo>();
|
||||
}
|
||||
|
||||
var conflicts = new List<OpenDocumentConflictInfo>();
|
||||
|
||||
foreach (var pendingLinesByDocument in _pendingLinesByDocumentKey)
|
||||
{
|
||||
if (string.Equals(pendingLinesByDocument.Key, currentDocument.DocumentKey, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var otherDocument = Documents.FirstOrDefault(delegate(PsvDocumentSummary document)
|
||||
{
|
||||
return string.Equals(document.DocumentKey, pendingLinesByDocument.Key, StringComparison.OrdinalIgnoreCase);
|
||||
});
|
||||
|
||||
if (otherDocument == null
|
||||
|| !otherDocument.CustomerId.HasValue
|
||||
|| otherDocument.CustomerId.Value != currentDocument.CustomerId.Value)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var otherLine in pendingLinesByDocument.Value.Where(delegate(PsvDocumentLine line)
|
||||
{
|
||||
return line != null
|
||||
&& line.TypeSizeId > 0
|
||||
&& !string.IsNullOrWhiteSpace(line.SerialNumber);
|
||||
}))
|
||||
{
|
||||
if (!candidateKeys.Contains(otherLine.OpenDocumentConflictKey))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
conflicts.Add(new OpenDocumentConflictInfo
|
||||
{
|
||||
DocumentNumber = otherDocument.DocumentNumber,
|
||||
TypeSizeId = otherLine.TypeSizeId,
|
||||
SerialNumber = otherLine.SerialNumber
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return NormalizeOpenDocumentConflicts(conflicts);
|
||||
}
|
||||
|
||||
private static List<OpenDocumentConflictInfo> NormalizeOpenDocumentConflicts(IEnumerable<OpenDocumentConflictInfo> conflicts)
|
||||
{
|
||||
return (conflicts ?? Enumerable.Empty<OpenDocumentConflictInfo>())
|
||||
.Where(delegate(OpenDocumentConflictInfo conflict) { return conflict != null; })
|
||||
.GroupBy(delegate(OpenDocumentConflictInfo conflict)
|
||||
{
|
||||
return string.Format(
|
||||
"{0}|{1}|{2}",
|
||||
conflict.DocumentNumber ?? string.Empty,
|
||||
conflict.TypeSizeId,
|
||||
conflict.SerialNumber ?? string.Empty);
|
||||
}, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(delegate(IGrouping<string, OpenDocumentConflictInfo> group) { return group.First(); })
|
||||
.OrderBy(delegate(OpenDocumentConflictInfo conflict) { return conflict.SerialNumber ?? string.Empty; })
|
||||
.ThenBy(delegate(OpenDocumentConflictInfo conflict) { return conflict.DocumentNumber ?? string.Empty; })
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private PsvDocumentLine CreatePendingLine(AvailableInstrumentItem item)
|
||||
{
|
||||
return new PsvDocumentLine
|
||||
{
|
||||
CardId = 0,
|
||||
InstrumentId = item.InstrumentId,
|
||||
TypeSizeId = item.TypeSizeId,
|
||||
SerialNumber = item.SerialNumber,
|
||||
InventoryNumber = item.InventoryNumber,
|
||||
CustomerName = item.CustomerName,
|
||||
@@ -547,6 +679,41 @@ namespace XLAB
|
||||
};
|
||||
}
|
||||
|
||||
private PsvDocumentLine CreatePendingTypeLine(AvailableInstrumentItem item, string serialNumber)
|
||||
{
|
||||
return new PsvDocumentLine
|
||||
{
|
||||
CardId = 0,
|
||||
InstrumentId = 0,
|
||||
TypeSizeId = item.TypeSizeId,
|
||||
SerialNumber = string.IsNullOrWhiteSpace(serialNumber) ? string.Empty : serialNumber.Trim(),
|
||||
InventoryNumber = string.Empty,
|
||||
CustomerName = SelectedDocument == null ? string.Empty : SelectedDocument.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 static void ApplyVerificationResultCore(PsvDocumentLine line, VerificationEditResult result)
|
||||
{
|
||||
if (line == null || result == null)
|
||||
@@ -1146,6 +1313,50 @@ namespace XLAB
|
||||
AddSelectedInstruments(selectedItems);
|
||||
}
|
||||
|
||||
private void OpenInstrumentTypePickerAsync()
|
||||
{
|
||||
if (SelectedDocument == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!SelectedDocument.CustomerId.HasValue)
|
||||
{
|
||||
_dialogService.ShowWarning("Сначала выберите заказчика в ПСВ.");
|
||||
return;
|
||||
}
|
||||
|
||||
OpenInstrumentTypePickerCoreAsync(SelectedDocument.CustomerName);
|
||||
}
|
||||
|
||||
private async void OpenInstrumentTypePickerCoreAsync(string customerName)
|
||||
{
|
||||
IReadOnlyList<AvailableInstrumentItem> instrumentTypes;
|
||||
|
||||
try
|
||||
{
|
||||
IsBusy = true;
|
||||
instrumentTypes = await Task.Run(delegate { return _service.LoadInstrumentTypes(); });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_dialogService.ShowError(ex.Message);
|
||||
return;
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsBusy = false;
|
||||
}
|
||||
|
||||
var result = _dialogService.ShowInstrumentTypeDialog(customerName, instrumentTypes);
|
||||
if (result == null || result.TypeItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
AddSelectedTypeInstrument(result);
|
||||
}
|
||||
|
||||
private void AddSelectedInstruments(IReadOnlyList<AvailableInstrumentItem> selectedItems)
|
||||
{
|
||||
if (SelectedDocument == null)
|
||||
@@ -1160,13 +1371,45 @@ namespace XLAB
|
||||
_pendingLinesByDocumentKey[SelectedDocument.DocumentKey] = pendingLines;
|
||||
}
|
||||
|
||||
var candidateLines = selectedItems
|
||||
.Where(delegate(AvailableInstrumentItem item) { return item != null; })
|
||||
.Select(CreatePendingLine)
|
||||
.ToList();
|
||||
|
||||
List<OpenDocumentConflictInfo> openDocumentConflicts;
|
||||
try
|
||||
{
|
||||
openDocumentConflicts = FindOpenDocumentConflicts(candidateLines);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_dialogService.ShowError(ex.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
var openConflictKeys = new HashSet<string>(
|
||||
openDocumentConflicts.Select(delegate(OpenDocumentConflictInfo conflict) { return conflict.OpenDocumentConflictKey; }),
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var duplicateKeys = new HashSet<string>(DocumentLines.Select(delegate(PsvDocumentLine line) { return line.DuplicateKey; }), StringComparer.OrdinalIgnoreCase);
|
||||
var addedCount = 0;
|
||||
var skippedDuplicateCount = 0;
|
||||
var skippedOpenDocumentCount = 0;
|
||||
var skippedWithoutTemplateCount = 0;
|
||||
|
||||
foreach (var item in selectedItems)
|
||||
{
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (openConflictKeys.Contains(PsvDocumentLine.BuildOpenDocumentConflictKey(item.TypeSizeId, item.SerialNumber)))
|
||||
{
|
||||
skippedOpenDocumentCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!item.HasTemplate)
|
||||
{
|
||||
skippedWithoutTemplateCount++;
|
||||
@@ -1208,11 +1451,98 @@ namespace XLAB
|
||||
messages.Add(string.Format("Пропущено без шаблона EKZMK: {0}.", skippedWithoutTemplateCount));
|
||||
}
|
||||
|
||||
if (messages.Count > 0)
|
||||
if (skippedOpenDocumentCount > 0)
|
||||
{
|
||||
_dialogService.ShowInfo(string.Join(" ", messages.ToArray()));
|
||||
messages.Add(string.Format("Пропущено из-за других открытых ПСВ: {0}.", skippedOpenDocumentCount));
|
||||
messages.Add(BuildOpenDocumentConflictMessage(openDocumentConflicts));
|
||||
}
|
||||
|
||||
if (messages.Count > 0)
|
||||
{
|
||||
var message = string.Join(" ", messages.ToArray());
|
||||
if (addedCount == 0 && skippedOpenDocumentCount > 0)
|
||||
{
|
||||
_dialogService.ShowWarning(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
_dialogService.ShowInfo(message);
|
||||
}
|
||||
}
|
||||
|
||||
RaiseCommandStates();
|
||||
OnPropertyChanged("IsCustomerEditable");
|
||||
}
|
||||
|
||||
private void AddSelectedTypeInstrument(InstrumentTypeSelectionResult result)
|
||||
{
|
||||
if (SelectedDocument == null || result == null || result.TypeItem == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<PsvDocumentLine> pendingLines;
|
||||
if (!_pendingLinesByDocumentKey.TryGetValue(SelectedDocument.DocumentKey, out pendingLines))
|
||||
{
|
||||
pendingLines = new List<PsvDocumentLine>();
|
||||
_pendingLinesByDocumentKey[SelectedDocument.DocumentKey] = pendingLines;
|
||||
}
|
||||
|
||||
var serialNumber = string.IsNullOrWhiteSpace(result.SerialNumber) ? string.Empty : result.SerialNumber.Trim();
|
||||
if (string.IsNullOrWhiteSpace(serialNumber))
|
||||
{
|
||||
_dialogService.ShowWarning("Введите заводской номер.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!result.TypeItem.HasTemplate)
|
||||
{
|
||||
_dialogService.ShowWarning("Выбранный тип нельзя добавить: для него не найден шаблон EKZMK или период МК.");
|
||||
return;
|
||||
}
|
||||
|
||||
var candidateLine = CreatePendingTypeLine(result.TypeItem, serialNumber);
|
||||
List<OpenDocumentConflictInfo> openDocumentConflicts;
|
||||
try
|
||||
{
|
||||
openDocumentConflicts = FindOpenDocumentConflicts(new[] { candidateLine });
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_dialogService.ShowError(ex.Message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (openDocumentConflicts.Count > 0)
|
||||
{
|
||||
_dialogService.ShowWarning(BuildOpenDocumentConflictMessage(openDocumentConflicts));
|
||||
return;
|
||||
}
|
||||
|
||||
var duplicateKey = PsvDocumentLine.BuildDuplicateKey(
|
||||
result.TypeItem.InstrumentType,
|
||||
result.TypeItem.RangeText,
|
||||
result.TypeItem.RegistryNumber,
|
||||
serialNumber);
|
||||
|
||||
if (DocumentLines.Any(delegate(PsvDocumentLine line)
|
||||
{
|
||||
return string.Equals(line.DuplicateKey, duplicateKey, StringComparison.OrdinalIgnoreCase);
|
||||
}))
|
||||
{
|
||||
_dialogService.ShowWarning("Такой прибор уже есть в ПСВ.");
|
||||
return;
|
||||
}
|
||||
|
||||
pendingLines.Add(candidateLine);
|
||||
|
||||
if (SelectedDocument.IsDraft)
|
||||
{
|
||||
SelectedDocument.ItemCount = pendingLines.Count;
|
||||
}
|
||||
|
||||
LoadSelectedDocumentAsync();
|
||||
_dialogService.ShowInfo("Прибор по типу добавлен в ПСВ.");
|
||||
RaiseCommandStates();
|
||||
OnPropertyChanged("IsCustomerEditable");
|
||||
}
|
||||
@@ -1254,6 +1584,7 @@ namespace XLAB
|
||||
((RelayCommand)MarkLinePassedCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)MarkLineRejectedCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)OpenInstrumentPickerCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)OpenInstrumentTypePickerCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)RefreshDocumentsCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)ResetLineVerificationCommand).RaiseCanExecuteChanged();
|
||||
((RelayCommand)SaveDocumentHeaderCommand).RaiseCanExecuteChanged();
|
||||
@@ -1398,7 +1729,12 @@ namespace XLAB
|
||||
}
|
||||
|
||||
var pendingLines = GetPendingLines(SelectedDocument)
|
||||
.Where(delegate(PsvDocumentLine line) { return line.InstrumentId > 0; })
|
||||
.Where(delegate(PsvDocumentLine line)
|
||||
{
|
||||
return line != null
|
||||
&& (line.InstrumentId > 0
|
||||
|| (line.TypeSizeId > 0 && !string.IsNullOrWhiteSpace(line.SerialNumber)));
|
||||
})
|
||||
.ToList();
|
||||
if (SelectedDocument.IsDraft && pendingLines.Count == 0)
|
||||
{
|
||||
@@ -1406,11 +1742,19 @@ namespace XLAB
|
||||
return;
|
||||
}
|
||||
|
||||
var openDocumentConflicts = FindPendingOpenDocumentConflicts(SelectedDocument, pendingLines);
|
||||
if (openDocumentConflicts.Count > 0)
|
||||
{
|
||||
_dialogService.ShowWarning(BuildOpenDocumentConflictMessage(openDocumentConflicts));
|
||||
return;
|
||||
}
|
||||
|
||||
var request = new DocumentEditorResult
|
||||
{
|
||||
DocumentNumber = DocumentNumberEditor.Trim(),
|
||||
AcceptedOn = HeaderReceivedOn.Value,
|
||||
IssuedOn = HeaderIssuedOn
|
||||
IssuedOn = HeaderIssuedOn,
|
||||
CustomerId = SelectedDocument.CustomerId ?? SelectedCustomerId
|
||||
};
|
||||
|
||||
var currentDocumentNumber = SelectedDocument.IsDraft ? null : SelectedDocument.DocumentNumber;
|
||||
|
||||
@@ -210,6 +210,7 @@ ORDER BY MAX(m.DTPRM) DESC, m.NNZVPV DESC;";
|
||||
SELECT
|
||||
m.IDEKZMK AS CardId,
|
||||
z.IDEKZ AS InstrumentId,
|
||||
z.IDTPRZ AS TypeSizeId,
|
||||
z.NNZV AS SerialNumber,
|
||||
z.NNIN AS InventoryNumber,
|
||||
ownerOrg.NMFRPD AS CustomerName,
|
||||
@@ -279,6 +280,7 @@ ORDER BY areas.NMOI, names.NMTP, tips.TP, z.NNZV;";
|
||||
{
|
||||
CardId = GetInt32(reader, "CardId"),
|
||||
InstrumentId = GetInt32(reader, "InstrumentId"),
|
||||
TypeSizeId = GetInt32(reader, "TypeSizeId"),
|
||||
SerialNumber = GetString(reader, "SerialNumber"),
|
||||
InventoryNumber = GetString(reader, "InventoryNumber"),
|
||||
CustomerName = GetString(reader, "CustomerName"),
|
||||
@@ -425,6 +427,109 @@ ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, z.NNZV;";
|
||||
return instruments;
|
||||
}
|
||||
|
||||
public IReadOnlyList<AvailableInstrumentItem> LoadInstrumentTypes()
|
||||
{
|
||||
const string sql = @"
|
||||
SELECT
|
||||
0 AS InstrumentId,
|
||||
sizeInfo.IDTPRZ AS TypeSizeId,
|
||||
CAST(N'' AS nvarchar(30)) AS SerialNumber,
|
||||
CAST(N'' AS nvarchar(30)) AS InventoryNumber,
|
||||
CAST(N'' AS nvarchar(255)) 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 typeTemplate.LastDocumentNumber IS NOT NULL
|
||||
OR periodByType.PRMK IS NOT NULL
|
||||
THEN CAST(1 AS bit)
|
||||
ELSE CAST(0 AS bit)
|
||||
END AS HasTemplate,
|
||||
typeTemplate.LastDocumentNumber AS LastDocumentNumber,
|
||||
typeTemplate.LastAcceptedOn AS LastAcceptedOn,
|
||||
CASE
|
||||
WHEN typeTemplate.LastDocumentNumber IS NOT NULL THEN N'Шаблон по типоразмеру'
|
||||
WHEN periodByType.PRMK IS NOT NULL THEN N'Период из TPRMCP'
|
||||
ELSE N''
|
||||
END AS TemplateSource
|
||||
FROM dbo.TPRZ sizeInfo
|
||||
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
|
||||
JOIN dbo.EKZ instrumentOfSameType ON instrumentOfSameType.IDEKZ = history.IDEKZ
|
||||
WHERE instrumentOfSameType.IDTPRZ = sizeInfo.IDTPRZ
|
||||
ORDER BY ISNULL(history.DTPRM, CONVERT(datetime, '19000101', 112)) DESC, history.IDEKZMK DESC
|
||||
) typeTemplate
|
||||
OUTER APPLY
|
||||
(
|
||||
SELECT TOP (1)
|
||||
t.PRMK
|
||||
FROM dbo.TPRMCP t
|
||||
WHERE t.IDTPRZ = sizeInfo.IDTPRZ
|
||||
ORDER BY t.IDTPRMCP DESC
|
||||
) periodByType
|
||||
ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, sizeInfo.NNGSRS;";
|
||||
|
||||
var instrumentTypes = new List<AvailableInstrumentItem>();
|
||||
|
||||
using (var connection = CreateConnection())
|
||||
using (var command = new SqlCommand(sql, connection))
|
||||
{
|
||||
connection.Open();
|
||||
command.CommandTimeout = 60;
|
||||
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
instrumentTypes.Add(new AvailableInstrumentItem
|
||||
{
|
||||
InstrumentId = GetInt32(reader, "InstrumentId"),
|
||||
TypeSizeId = GetInt32(reader, "TypeSizeId"),
|
||||
SerialNumber = GetString(reader, "SerialNumber"),
|
||||
InventoryNumber = GetString(reader, "InventoryNumber"),
|
||||
CustomerName = GetString(reader, "CustomerName"),
|
||||
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")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return instrumentTypes;
|
||||
}
|
||||
|
||||
public IReadOnlyList<OpenDocumentConflictInfo> FindOpenDocumentConflicts(int customerId, string currentDocumentNumber, IEnumerable<PsvDocumentLine> candidateLines)
|
||||
{
|
||||
if (customerId <= 0 || candidateLines == null)
|
||||
{
|
||||
return new List<OpenDocumentConflictInfo>();
|
||||
}
|
||||
|
||||
using (var connection = CreateConnection())
|
||||
{
|
||||
connection.Open();
|
||||
return LoadOpenDocumentConflicts(connection, null, customerId, currentDocumentNumber, candidateLines);
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetLineVerification(int cardId)
|
||||
{
|
||||
if (cardId <= 0)
|
||||
@@ -576,9 +681,9 @@ ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, z.NNZV;";
|
||||
var distinctPendingLines = pendingLines == null
|
||||
? new List<PsvDocumentLine>()
|
||||
: pendingLines
|
||||
.Where(delegate(PsvDocumentLine line) { return line != null && line.InstrumentId > 0; })
|
||||
.GroupBy(delegate(PsvDocumentLine line) { return line.InstrumentId; })
|
||||
.Select(delegate(IGrouping<int, PsvDocumentLine> group) { return group.First(); })
|
||||
.Where(IsPendingLineReadyForSave)
|
||||
.GroupBy(GetPendingLineSaveKey, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(delegate(IGrouping<string, PsvDocumentLine> group) { return group.First(); })
|
||||
.ToList();
|
||||
|
||||
using (var connection = CreateConnection())
|
||||
@@ -592,6 +697,20 @@ ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, z.NNZV;";
|
||||
throw new InvalidOperationException(string.Format("ПСВ с номером \"{0}\" уже существует.", normalizedNumber));
|
||||
}
|
||||
|
||||
if (document.CustomerId.HasValue)
|
||||
{
|
||||
var openDocumentConflicts = LoadOpenDocumentConflicts(
|
||||
connection,
|
||||
transaction,
|
||||
document.CustomerId.Value,
|
||||
currentDocumentNumber,
|
||||
distinctPendingLines);
|
||||
if (openDocumentConflicts.Count > 0)
|
||||
{
|
||||
throw new InvalidOperationException(BuildOpenDocumentConflictMessage(openDocumentConflicts));
|
||||
}
|
||||
}
|
||||
|
||||
var updatedEkzMkCount = 0;
|
||||
if (!string.IsNullOrWhiteSpace(currentDocumentNumber))
|
||||
{
|
||||
@@ -611,9 +730,18 @@ ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, z.NNZV;";
|
||||
|
||||
foreach (var pendingLine in distinctPendingLines)
|
||||
{
|
||||
var duplicateKey = pendingLine.DuplicateKey;
|
||||
if (string.IsNullOrWhiteSpace(duplicateKey))
|
||||
{
|
||||
throw new InvalidOperationException("Не удалось определить ключ дубликата для строки ПСВ.");
|
||||
}
|
||||
|
||||
var instrumentId = pendingLine.InstrumentId;
|
||||
var instrumentIdentity = LoadInstrumentIdentity(connection, transaction, instrumentId);
|
||||
if (instrumentIdentity == null)
|
||||
var instrumentIdentity = new InstrumentIdentityInfo
|
||||
{
|
||||
DuplicateKey = duplicateKey
|
||||
};
|
||||
if (string.IsNullOrWhiteSpace(duplicateKey))
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("Прибор IDEKZ={0} не найден.", instrumentId));
|
||||
}
|
||||
@@ -624,6 +752,7 @@ ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, z.NNZV;";
|
||||
continue;
|
||||
}
|
||||
|
||||
instrumentId = ResolveInstrumentIdForPendingLine(connection, transaction, document, pendingLine);
|
||||
var template = LoadTemplate(connection, transaction, instrumentId);
|
||||
if (template == null)
|
||||
{
|
||||
@@ -786,6 +915,62 @@ ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, z.NNZV;";
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetPendingLineSaveKey(PsvDocumentLine line)
|
||||
{
|
||||
if (line == null)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
return line.InstrumentId > 0
|
||||
? string.Format("ID:{0}", line.InstrumentId)
|
||||
: string.Format("NEW:{0}", line.DuplicateKey ?? string.Empty);
|
||||
}
|
||||
|
||||
private static bool IsPendingLineReadyForSave(PsvDocumentLine line)
|
||||
{
|
||||
return line != null
|
||||
&& (line.InstrumentId > 0
|
||||
|| (line.TypeSizeId > 0 && !string.IsNullOrWhiteSpace(line.SerialNumber)));
|
||||
}
|
||||
|
||||
private static int ResolveInstrumentIdForPendingLine(SqlConnection connection, SqlTransaction transaction, DocumentEditorResult document, PsvDocumentLine pendingLine)
|
||||
{
|
||||
if (pendingLine == null)
|
||||
{
|
||||
throw new InvalidOperationException("Строка ПСВ для сохранения не задана.");
|
||||
}
|
||||
|
||||
if (pendingLine.InstrumentId > 0)
|
||||
{
|
||||
return pendingLine.InstrumentId;
|
||||
}
|
||||
|
||||
if (pendingLine.TypeSizeId <= 0)
|
||||
{
|
||||
throw new InvalidOperationException("Для новой строки ПСВ не указан типоразмер прибора.");
|
||||
}
|
||||
|
||||
var serialNumber = string.IsNullOrWhiteSpace(pendingLine.SerialNumber) ? null : pendingLine.SerialNumber.Trim();
|
||||
if (serialNumber == null)
|
||||
{
|
||||
throw new InvalidOperationException("Для новой строки ПСВ не указан заводской номер.");
|
||||
}
|
||||
|
||||
if (!document.CustomerId.HasValue)
|
||||
{
|
||||
throw new InvalidOperationException("Для добавления прибора по типу должен быть выбран заказчик ПСВ.");
|
||||
}
|
||||
|
||||
var existingInstrumentId = FindExistingInstrumentId(connection, transaction, pendingLine.TypeSizeId, document.CustomerId.Value, serialNumber);
|
||||
if (existingInstrumentId.HasValue)
|
||||
{
|
||||
return existingInstrumentId.Value;
|
||||
}
|
||||
|
||||
return InsertInstrument(connection, transaction, pendingLine.TypeSizeId, document.CustomerId.Value, serialNumber);
|
||||
}
|
||||
|
||||
private static List<int> NormalizeCardIds(IEnumerable<int> cardIds, string invalidCardMessage, string emptyListMessage)
|
||||
{
|
||||
if (cardIds == null)
|
||||
@@ -807,6 +992,196 @@ ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, z.NNZV;";
|
||||
return normalizedCardIds;
|
||||
}
|
||||
|
||||
private static int? FindExistingInstrumentId(SqlConnection connection, SqlTransaction transaction, int typeSizeId, int customerId, string serialNumber)
|
||||
{
|
||||
const string sql = @"
|
||||
SELECT TOP (1) z.IDEKZ
|
||||
FROM dbo.EKZ z
|
||||
WHERE z.IDTPRZ = @TypeSizeId
|
||||
AND z.IDFRPDV = @CustomerId
|
||||
AND z.NNZV = @SerialNumber
|
||||
AND ISNULL(z.IsDeleted, 0) = 0
|
||||
ORDER BY z.IDEKZ DESC;";
|
||||
|
||||
using (var command = new SqlCommand(sql, connection, transaction))
|
||||
{
|
||||
command.CommandTimeout = 60;
|
||||
command.Parameters.Add("@TypeSizeId", SqlDbType.Int).Value = typeSizeId;
|
||||
command.Parameters.Add("@CustomerId", SqlDbType.Int).Value = customerId;
|
||||
command.Parameters.Add("@SerialNumber", SqlDbType.VarChar, 30).Value = serialNumber;
|
||||
|
||||
var result = command.ExecuteScalar();
|
||||
return result == null || result == DBNull.Value ? (int?)null : Convert.ToInt32(result);
|
||||
}
|
||||
}
|
||||
|
||||
private static int InsertInstrument(SqlConnection connection, SqlTransaction transaction, int typeSizeId, int customerId, string serialNumber)
|
||||
{
|
||||
const string sql = @"
|
||||
INSERT INTO dbo.EKZ
|
||||
(
|
||||
IDTPRZ,
|
||||
IDFRPDV,
|
||||
KLSIPR,
|
||||
NNZV,
|
||||
GUIDEKZ,
|
||||
IsDeleted
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
@TypeSizeId,
|
||||
@CustomerId,
|
||||
@Klsipr,
|
||||
@SerialNumber,
|
||||
@GuidEkz,
|
||||
0
|
||||
);
|
||||
|
||||
SELECT CAST(SCOPE_IDENTITY() AS int);";
|
||||
|
||||
using (var command = new SqlCommand(sql, connection, transaction))
|
||||
{
|
||||
command.CommandTimeout = 60;
|
||||
command.Parameters.Add("@TypeSizeId", SqlDbType.Int).Value = typeSizeId;
|
||||
command.Parameters.Add("@CustomerId", SqlDbType.Int).Value = customerId;
|
||||
command.Parameters.Add("@Klsipr", SqlDbType.Int).Value = 1;
|
||||
command.Parameters.Add("@SerialNumber", SqlDbType.VarChar, 30).Value = serialNumber;
|
||||
command.Parameters.Add("@GuidEkz", SqlDbType.UniqueIdentifier).Value = Guid.NewGuid();
|
||||
return Convert.ToInt32(command.ExecuteScalar());
|
||||
}
|
||||
}
|
||||
|
||||
private static string BuildOpenDocumentConflictMessage(IEnumerable<OpenDocumentConflictInfo> conflicts)
|
||||
{
|
||||
var materializedConflicts = conflicts == null
|
||||
? new List<OpenDocumentConflictInfo>()
|
||||
: conflicts
|
||||
.Where(delegate(OpenDocumentConflictInfo conflict) { return conflict != null; })
|
||||
.GroupBy(delegate(OpenDocumentConflictInfo conflict)
|
||||
{
|
||||
return string.Format(
|
||||
"{0}|{1}|{2}",
|
||||
conflict.DocumentNumber ?? string.Empty,
|
||||
conflict.TypeSizeId,
|
||||
conflict.SerialNumber ?? string.Empty);
|
||||
}, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(delegate(IGrouping<string, OpenDocumentConflictInfo> group) { return group.First(); })
|
||||
.OrderBy(delegate(OpenDocumentConflictInfo conflict) { return conflict.SerialNumber ?? string.Empty; })
|
||||
.ThenBy(delegate(OpenDocumentConflictInfo conflict) { return conflict.DocumentNumber ?? string.Empty; })
|
||||
.ToList();
|
||||
|
||||
if (materializedConflicts.Count == 0)
|
||||
{
|
||||
return "Прибор уже находится в другой открытой ПСВ этого заказчика.";
|
||||
}
|
||||
|
||||
var preview = materializedConflicts
|
||||
.Take(5)
|
||||
.Select(delegate(OpenDocumentConflictInfo conflict)
|
||||
{
|
||||
return string.Format("зав. № {0} -> {1}", conflict.SerialNumber, conflict.DocumentNumber);
|
||||
})
|
||||
.ToList();
|
||||
|
||||
var suffix = materializedConflicts.Count > preview.Count
|
||||
? string.Format(" Еще конфликтов: {0}.", materializedConflicts.Count - preview.Count)
|
||||
: string.Empty;
|
||||
|
||||
return string.Format(
|
||||
"Приборы уже находятся в других открытых ПСВ этого заказчика: {0}.{1}",
|
||||
string.Join("; ", preview.ToArray()),
|
||||
suffix);
|
||||
}
|
||||
|
||||
private static List<OpenDocumentConflictInfo> LoadOpenDocumentConflicts(
|
||||
SqlConnection connection,
|
||||
SqlTransaction transaction,
|
||||
int customerId,
|
||||
string currentDocumentNumber,
|
||||
IEnumerable<PsvDocumentLine> candidateLines)
|
||||
{
|
||||
var normalizedCandidates = candidateLines == null
|
||||
? new List<PsvDocumentLine>()
|
||||
: candidateLines
|
||||
.Where(delegate(PsvDocumentLine line)
|
||||
{
|
||||
return line != null
|
||||
&& line.TypeSizeId > 0
|
||||
&& !string.IsNullOrWhiteSpace(line.SerialNumber);
|
||||
})
|
||||
.GroupBy(delegate(PsvDocumentLine line) { return line.OpenDocumentConflictKey; }, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(delegate(IGrouping<string, PsvDocumentLine> group) { return group.First(); })
|
||||
.ToList();
|
||||
|
||||
if (customerId <= 0 || normalizedCandidates.Count == 0)
|
||||
{
|
||||
return new List<OpenDocumentConflictInfo>();
|
||||
}
|
||||
|
||||
const string sql = @"
|
||||
WITH ActiveDocuments AS
|
||||
(
|
||||
SELECT m.NNZVPV
|
||||
FROM dbo.EKZMK m
|
||||
WHERE NULLIF(LTRIM(RTRIM(m.NNZVPV)), N'') IS NOT NULL
|
||||
GROUP BY m.NNZVPV
|
||||
HAVING MAX(m.DTVDM) IS NULL
|
||||
)
|
||||
SELECT DISTINCT
|
||||
m.NNZVPV AS DocumentNumber,
|
||||
z.IDTPRZ AS TypeSizeId,
|
||||
LTRIM(RTRIM(z.NNZV)) AS SerialNumber
|
||||
FROM ActiveDocuments activeDocuments
|
||||
JOIN dbo.EKZMK m ON m.NNZVPV = activeDocuments.NNZVPV
|
||||
JOIN dbo.EKZ z ON z.IDEKZ = m.IDEKZ
|
||||
WHERE z.IDFRPDV = @CustomerId
|
||||
AND z.IDTPRZ = @TypeSizeId
|
||||
AND LTRIM(RTRIM(z.NNZV)) = @SerialNumber
|
||||
AND (@CurrentDocumentNumber = N'' OR m.NNZVPV <> @CurrentDocumentNumber)
|
||||
ORDER BY m.NNZVPV;";
|
||||
|
||||
var conflicts = new List<OpenDocumentConflictInfo>();
|
||||
|
||||
foreach (var candidateLine in normalizedCandidates)
|
||||
{
|
||||
using (var command = new SqlCommand(sql, connection, transaction))
|
||||
{
|
||||
command.CommandTimeout = 60;
|
||||
command.Parameters.Add("@CustomerId", SqlDbType.Int).Value = customerId;
|
||||
command.Parameters.Add("@TypeSizeId", SqlDbType.Int).Value = candidateLine.TypeSizeId;
|
||||
command.Parameters.Add("@SerialNumber", SqlDbType.VarChar, 30).Value = candidateLine.SerialNumber.Trim();
|
||||
command.Parameters.Add("@CurrentDocumentNumber", SqlDbType.NVarChar, 60).Value = currentDocumentNumber ?? string.Empty;
|
||||
|
||||
using (var reader = command.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
conflicts.Add(new OpenDocumentConflictInfo
|
||||
{
|
||||
DocumentNumber = GetString(reader, "DocumentNumber"),
|
||||
TypeSizeId = GetInt32(reader, "TypeSizeId"),
|
||||
SerialNumber = GetString(reader, "SerialNumber")
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return conflicts
|
||||
.GroupBy(delegate(OpenDocumentConflictInfo conflict)
|
||||
{
|
||||
return string.Format(
|
||||
"{0}|{1}|{2}",
|
||||
conflict.DocumentNumber ?? string.Empty,
|
||||
conflict.TypeSizeId,
|
||||
conflict.SerialNumber ?? string.Empty);
|
||||
}, StringComparer.OrdinalIgnoreCase)
|
||||
.Select(delegate(IGrouping<string, OpenDocumentConflictInfo> group) { return group.First(); })
|
||||
.OrderBy(delegate(OpenDocumentConflictInfo conflict) { return conflict.SerialNumber ?? string.Empty; })
|
||||
.ThenBy(delegate(OpenDocumentConflictInfo conflict) { return conflict.DocumentNumber ?? string.Empty; })
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static SqlConnection CreateConnection()
|
||||
{
|
||||
var connectionString = ConfigurationManager.ConnectionStrings["AsumsSql"];
|
||||
@@ -1179,6 +1554,7 @@ VALUES
|
||||
NULL,
|
||||
NULL,
|
||||
@NNZVPV,
|
||||
NULL,
|
||||
@NNNKL,
|
||||
@PRMK,
|
||||
@DTMKFK,
|
||||
|
||||
@@ -133,6 +133,8 @@ namespace XLAB
|
||||
|
||||
public int InstrumentId { get; set; }
|
||||
|
||||
public int TypeSizeId { get; set; }
|
||||
|
||||
public string SerialNumber { get; set; }
|
||||
|
||||
public string InventoryNumber { get; set; }
|
||||
@@ -197,6 +199,14 @@ namespace XLAB
|
||||
}
|
||||
}
|
||||
|
||||
public string OpenDocumentConflictKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return BuildOpenDocumentConflictKey(TypeSizeId, SerialNumber);
|
||||
}
|
||||
}
|
||||
|
||||
public string ResultText
|
||||
{
|
||||
get
|
||||
@@ -237,6 +247,11 @@ namespace XLAB
|
||||
NormalizeKeyPart(serialNumber));
|
||||
}
|
||||
|
||||
public static string BuildOpenDocumentConflictKey(int typeSizeId, string serialNumber)
|
||||
{
|
||||
return string.Format("{0}|{1}", typeSizeId, NormalizeKeyPart(serialNumber));
|
||||
}
|
||||
|
||||
private static string NormalizeKeyPart(string value)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim().ToUpperInvariant();
|
||||
@@ -352,6 +367,15 @@ namespace XLAB
|
||||
public DateTime AcceptedOn { get; set; }
|
||||
|
||||
public DateTime? IssuedOn { get; set; }
|
||||
|
||||
public int? CustomerId { get; set; }
|
||||
}
|
||||
|
||||
public sealed class InstrumentTypeSelectionResult
|
||||
{
|
||||
public AvailableInstrumentItem TypeItem { get; set; }
|
||||
|
||||
public string SerialNumber { get; set; }
|
||||
}
|
||||
|
||||
public sealed class VerificationEditSeed
|
||||
@@ -392,6 +416,23 @@ namespace XLAB
|
||||
public string VerifierName { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class OpenDocumentConflictInfo
|
||||
{
|
||||
public string DocumentNumber { get; set; }
|
||||
|
||||
public int TypeSizeId { get; set; }
|
||||
|
||||
public string SerialNumber { get; set; }
|
||||
|
||||
public string OpenDocumentConflictKey
|
||||
{
|
||||
get
|
||||
{
|
||||
return PsvDocumentLine.BuildOpenDocumentConflictKey(TypeSizeId, SerialNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DocumentDeleteResult
|
||||
{
|
||||
public int DeletedEkzMkFctvlCount { get; set; }
|
||||
|
||||
93
XLAB/SelectInstrumentTypeWindow.xaml
Normal file
93
XLAB/SelectInstrumentTypeWindow.xaml
Normal file
@@ -0,0 +1,93 @@
|
||||
<Window x:Class="XLAB.SelectInstrumentTypeWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Добавить по типу"
|
||||
Height="720"
|
||||
Width="1120"
|
||||
MinHeight="520"
|
||||
MinWidth="900"
|
||||
WindowStartupLocation="CenterOwner">
|
||||
<Grid Margin="12">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock FontWeight="SemiBold"
|
||||
Text="{Binding CustomerName, StringFormat=Заказчик: {0}}" />
|
||||
|
||||
<StackPanel Grid.Row="1"
|
||||
Margin="0,8,0,8"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock Width="150"
|
||||
Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Поиск" />
|
||||
<TextBox Width="320"
|
||||
Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</StackPanel>
|
||||
|
||||
<DataGrid Grid.Row="2"
|
||||
ItemsSource="{Binding InstrumentTypesView}"
|
||||
SelectedItem="{Binding SelectedType, Mode=TwoWay}"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserAddRows="False"
|
||||
IsReadOnly="True"
|
||||
HeadersVisibility="Column">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Header="Номер госреестра"
|
||||
Width="120"
|
||||
Binding="{Binding RegistryNumber}" />
|
||||
<DataGridTextColumn Header="Наименование"
|
||||
Width="240"
|
||||
Binding="{Binding InstrumentName}" />
|
||||
<DataGridTextColumn Header="Тип"
|
||||
Width="150"
|
||||
Binding="{Binding InstrumentType}" />
|
||||
<DataGridTextColumn Header="Диапазон"
|
||||
Width="180"
|
||||
Binding="{Binding RangeText}" />
|
||||
<DataGridTextColumn Header="Характеристики"
|
||||
Width="160"
|
||||
Binding="{Binding AccuracyText}" />
|
||||
<DataGridTextColumn Header="Область"
|
||||
Width="*"
|
||||
Binding="{Binding MeasurementArea}" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
|
||||
<StackPanel Grid.Row="3"
|
||||
Margin="0,10,0,0"
|
||||
Orientation="Horizontal">
|
||||
<TextBlock Width="150"
|
||||
Margin="0,0,8,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Заводской номер" />
|
||||
<TextBox Width="320"
|
||||
Text="{Binding SerialNumber, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="4"
|
||||
Margin="0,8,0,0"
|
||||
Foreground="DimGray"
|
||||
Text="{Binding StatusText}" />
|
||||
|
||||
<StackPanel Grid.Row="5"
|
||||
Margin="0,12,0,0"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
<Button Width="90"
|
||||
Margin="0,0,8,0"
|
||||
IsDefault="True"
|
||||
Command="{Binding ConfirmCommand}"
|
||||
Content="Сохранить" />
|
||||
<Button Width="90"
|
||||
Command="{Binding CancelCommand}"
|
||||
Content="Отмена" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
20
XLAB/SelectInstrumentTypeWindow.xaml.cs
Normal file
20
XLAB/SelectInstrumentTypeWindow.xaml.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
public partial class SelectInstrumentTypeWindow : Window
|
||||
{
|
||||
internal SelectInstrumentTypeWindow(SelectInstrumentTypeWindowViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
DataContext = viewModel;
|
||||
viewModel.CloseRequested += ViewModelOnCloseRequested;
|
||||
}
|
||||
|
||||
private void ViewModelOnCloseRequested(object sender, bool? dialogResult)
|
||||
{
|
||||
DialogResult = dialogResult;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
161
XLAB/SelectInstrumentTypeWindowViewModel.cs
Normal file
161
XLAB/SelectInstrumentTypeWindowViewModel.cs
Normal file
@@ -0,0 +1,161 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace XLAB
|
||||
{
|
||||
internal sealed class SelectInstrumentTypeWindowViewModel : ObservableObject
|
||||
{
|
||||
private string _searchText;
|
||||
private AvailableInstrumentItem _selectedType;
|
||||
private string _serialNumber;
|
||||
private string _statusText;
|
||||
|
||||
public SelectInstrumentTypeWindowViewModel(string customerName, IReadOnlyList<AvailableInstrumentItem> instrumentTypes)
|
||||
{
|
||||
CustomerName = customerName ?? string.Empty;
|
||||
InstrumentTypes = new ObservableCollection<AvailableInstrumentItem>(instrumentTypes ?? new List<AvailableInstrumentItem>());
|
||||
InstrumentTypesView = CollectionViewSource.GetDefaultView(InstrumentTypes);
|
||||
InstrumentTypesView.Filter = FilterTypes;
|
||||
|
||||
ConfirmCommand = new RelayCommand(Confirm, CanConfirm);
|
||||
CancelCommand = new RelayCommand(Cancel);
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
public event EventHandler<bool?> CloseRequested;
|
||||
|
||||
public ICommand CancelCommand { get; private set; }
|
||||
|
||||
public ICommand ConfirmCommand { get; private set; }
|
||||
|
||||
public string CustomerName { get; private set; }
|
||||
|
||||
public ObservableCollection<AvailableInstrumentItem> InstrumentTypes { get; private set; }
|
||||
|
||||
public ICollectionView InstrumentTypesView { get; private set; }
|
||||
|
||||
public string SearchText
|
||||
{
|
||||
get { return _searchText; }
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _searchText, value))
|
||||
{
|
||||
InstrumentTypesView.Refresh();
|
||||
UpdateStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AvailableInstrumentItem SelectedType
|
||||
{
|
||||
get { return _selectedType; }
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _selectedType, value))
|
||||
{
|
||||
((RelayCommand)ConfirmCommand).RaiseCanExecuteChanged();
|
||||
UpdateStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string SerialNumber
|
||||
{
|
||||
get { return _serialNumber; }
|
||||
set
|
||||
{
|
||||
if (SetProperty(ref _serialNumber, value))
|
||||
{
|
||||
((RelayCommand)ConfirmCommand).RaiseCanExecuteChanged();
|
||||
UpdateStatus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public string StatusText
|
||||
{
|
||||
get { return _statusText; }
|
||||
private set { SetProperty(ref _statusText, value); }
|
||||
}
|
||||
|
||||
public InstrumentTypeSelectionResult GetResult()
|
||||
{
|
||||
return SelectedType == null
|
||||
? null
|
||||
: new InstrumentTypeSelectionResult
|
||||
{
|
||||
TypeItem = SelectedType,
|
||||
SerialNumber = string.IsNullOrWhiteSpace(SerialNumber) ? string.Empty : SerialNumber.Trim()
|
||||
};
|
||||
}
|
||||
|
||||
private void Cancel(object parameter)
|
||||
{
|
||||
RaiseCloseRequested(false);
|
||||
}
|
||||
|
||||
private bool CanConfirm(object parameter)
|
||||
{
|
||||
return SelectedType != null
|
||||
&& !string.IsNullOrWhiteSpace(SerialNumber);
|
||||
}
|
||||
|
||||
private void Confirm(object parameter)
|
||||
{
|
||||
RaiseCloseRequested(true);
|
||||
}
|
||||
|
||||
private bool FilterTypes(object item)
|
||||
{
|
||||
var instrumentType = item as AvailableInstrumentItem;
|
||||
if (instrumentType == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(SearchText))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Contains(instrumentType.RegistryNumber, SearchText)
|
||||
|| Contains(instrumentType.InstrumentName, SearchText)
|
||||
|| Contains(instrumentType.InstrumentType, SearchText)
|
||||
|| Contains(instrumentType.RangeText, SearchText)
|
||||
|| Contains(instrumentType.AccuracyText, SearchText)
|
||||
|| Contains(instrumentType.MeasurementArea, SearchText);
|
||||
}
|
||||
|
||||
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 = InstrumentTypesView.Cast<object>().Count();
|
||||
StatusText = string.Format(
|
||||
"Всего типов: {0}. По фильтру: {1}. Выбран тип: {2}. Заводской номер: {3}.",
|
||||
InstrumentTypes.Count,
|
||||
visibleCount,
|
||||
SelectedType == null ? "нет" : "да",
|
||||
string.IsNullOrWhiteSpace(SerialNumber) ? "не указан" : "указан");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,6 +90,15 @@
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SelectInstrumentsWindowViewModel.cs" />
|
||||
<Page Include="SelectInstrumentTypeWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="SelectInstrumentTypeWindow.xaml.cs">
|
||||
<DependentUpon>SelectInstrumentTypeWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="SelectInstrumentTypeWindowViewModel.cs" />
|
||||
<Page Include="VerificationEditWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
||||
Reference in New Issue
Block a user