Compare commits

...

2 Commits

Author SHA1 Message Date
Курнат Андрей
ff133e0215 edit 2026-03-18 20:45:53 +03:00
Курнат Андрей
dedd1c5c25 edit 2026-03-17 23:53:30 +03:00
8 changed files with 628 additions and 106 deletions

View File

@@ -1,9 +1,148 @@
<Application x:Class="XLAB.App" <Application x:Class="XLAB.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:XLAB" xmlns:local="clr-namespace:XLAB"
StartupUri="MainWindow.xaml"> StartupUri="MainWindow.xaml">
<Application.Resources> <Application.Resources>
<LinearGradientBrush x:Key="AppWindowBackgroundBrush" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#FFF8FAFD" Offset="0" />
<GradientStop Color="#FFF2F6FB" Offset="1" />
</LinearGradientBrush>
<SolidColorBrush x:Key="AppSurfaceBrush" Color="#FFFFFFFF" />
<SolidColorBrush x:Key="AppAccentBrush" Color="#FF5C7FA8" />
<SolidColorBrush x:Key="AppAccentSoftBrush" Color="#FFDDE8F3" />
<SolidColorBrush x:Key="AppBorderBrush" Color="#FFC9D6E2" />
<SolidColorBrush x:Key="AppTextBrush" Color="#FF263645" />
<SolidColorBrush x:Key="AppMutedTextBrush" Color="#FF6B7B88" />
<SolidColorBrush x:Key="AppButtonBrush" Color="#FFF5F8FC" />
<SolidColorBrush x:Key="AppButtonHoverBrush" Color="#FFEAF2FA" />
<SolidColorBrush x:Key="AppSelectionBrush" Color="#FFDDEAF7" />
<SolidColorBrush x:Key="AppSelectionTextBrush" Color="#FF17324A" />
<SolidColorBrush x:Key="OpenDocumentTenDaysBrush" Color="#FFF2F8EA" />
<SolidColorBrush x:Key="OpenDocumentTwentyDaysBrush" Color="#FFFCF4E3" />
<SolidColorBrush x:Key="OpenDocumentOverdueBrush" Color="#FFFBE7E7" />
<SolidColorBrush x:Key="OpenDocumentTenDaysIndicatorBrush" Color="#FFB7D79F" />
<SolidColorBrush x:Key="OpenDocumentTwentyDaysIndicatorBrush" Color="#FFF0C87A" />
<SolidColorBrush x:Key="OpenDocumentOverdueIndicatorBrush" Color="#FFE2A0A0" />
<Style TargetType="{x:Type Window}">
<Setter Property="Background" Value="{StaticResource AppWindowBackgroundBrush}" />
<Setter Property="Foreground" Value="{StaticResource AppTextBrush}" />
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="{StaticResource AppTextBrush}" />
</Style>
<Style TargetType="{x:Type GroupBox}">
<Setter Property="Background" Value="{StaticResource AppSurfaceBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource AppBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource AppAccentBrush}" />
</Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="{StaticResource AppButtonBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource AppBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource AppTextBrush}" />
<Setter Property="Padding" Value="10,4" />
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{StaticResource AppSurfaceBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource AppBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource AppTextBrush}" />
<Setter Property="Padding" Value="6,3" />
</Style>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="Background" Value="{StaticResource AppSurfaceBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource AppBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource AppTextBrush}" />
</Style>
<Style TargetType="{x:Type DatePicker}">
<Setter Property="Background" Value="{StaticResource AppSurfaceBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource AppBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource AppTextBrush}" />
</Style>
<Style TargetType="{x:Type CheckBox}">
<Setter Property="Foreground" Value="{StaticResource AppTextBrush}" />
</Style>
<Style TargetType="{x:Type RadioButton}">
<Setter Property="Foreground" Value="{StaticResource AppTextBrush}" />
</Style>
<Style TargetType="{x:Type Menu}">
<Setter Property="Background" Value="{StaticResource AppSurfaceBrush}" />
<Setter Property="Foreground" Value="{StaticResource AppTextBrush}" />
</Style>
<Style TargetType="{x:Type ContextMenu}">
<Setter Property="Background" Value="{StaticResource AppSurfaceBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource AppBorderBrush}" />
<Setter Property="Foreground" Value="{StaticResource AppTextBrush}" />
</Style>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Foreground" Value="{StaticResource AppTextBrush}" />
<Setter Property="Background" Value="Transparent" />
</Style>
<Style TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="{StaticResource AppSurfaceBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource AppBorderBrush}" />
</Style>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Padding" Value="0" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="{StaticResource AppBorderBrush}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource AppSelectionBrush}" />
<Setter Property="Foreground" Value="{StaticResource AppSelectionTextBrush}" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type DataGrid}">
<Setter Property="Background" Value="{StaticResource AppSurfaceBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource AppBorderBrush}" />
<Setter Property="RowBackground" Value="#FFFFFFFF" />
<Setter Property="AlternatingRowBackground" Value="#FFF7FAFD" />
<Setter Property="ColumnHeaderStyle">
<Setter.Value>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="Background" Value="#FFEAF2FA" />
<Setter Property="Foreground" Value="{StaticResource AppAccentBrush}" />
<Setter Property="BorderBrush" Value="{StaticResource AppBorderBrush}" />
<Setter Property="FontWeight" Value="SemiBold" />
</Style>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="{StaticResource AppTextBrush}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource AppSelectionBrush}" />
<Setter Property="Foreground" Value="{StaticResource AppSelectionTextBrush}" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="BorderBrush" Value="#FFDCE5EE" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{StaticResource AppSelectionBrush}" />
<Setter Property="Foreground" Value="{StaticResource AppSelectionTextBrush}" />
</Trigger>
</Style.Triggers>
</Style>
</Application.Resources> </Application.Resources>
</Application> </Application>

View File

@@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Новый ПСВ" Title="Новый ПСВ"
Height="220" Height="240"
Width="430" Width="430"
ResizeMode="NoResize" ResizeMode="NoResize"
WindowStartupLocation="CenterOwner"> WindowStartupLocation="CenterOwner">

View File

@@ -22,11 +22,11 @@
<MenuItem Header="Наименования типов СИ" <MenuItem Header="Наименования типов СИ"
Click="SpnmtpDirectoryMenuItem_Click" /> Click="SpnmtpDirectoryMenuItem_Click" />
</MenuItem> </MenuItem>
<MenuItem Header="Организации и подразделения" <MenuItem Header="Подразделения"
Click="FrpdDirectoryMenuItem_Click" /> Click="FrpdDirectoryMenuItem_Click" />
<MenuItem Header="Персоны" <MenuItem Header="Персонал"
Click="PrsnDirectoryMenuItem_Click" /> Click="PrsnDirectoryMenuItem_Click" />
<MenuItem Header="Типоразмеры СИ" <MenuItem Header="Типоразмеры"
Click="TypeSizeDirectoryMenuItem_Click" /> Click="TypeSizeDirectoryMenuItem_Click" />
</Menu> </Menu>
@@ -40,22 +40,35 @@
<GroupBox Grid.Column="0" Header="Документы"> <GroupBox Grid.Column="0" Header="Документы">
<Grid Margin="8"> <Grid Margin="8">
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<TextBlock Grid.Row="0" <WrapPanel Grid.Row="0"
Margin="0,0,0,8"
VerticalAlignment="Center">
<RadioButton Margin="0,0,16,0"
GroupName="DocumentModeGroup"
Content="Открытые ПСВ"
IsChecked="{Binding ShowOpenDocuments, Mode=TwoWay}" />
<RadioButton GroupName="DocumentModeGroup"
Content="Закрытые ПСВ (текущий год)"
IsChecked="{Binding ShowClosedDocuments, Mode=TwoWay}" />
</WrapPanel>
<TextBlock Grid.Row="1"
Margin="0,0,0,4" Margin="0,0,0,4"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="Поиск по номеру ПСВ или заказчику" /> Text="Поиск по номеру ПСВ или подразделению" />
<TextBox Grid.Row="1" <TextBox Grid.Row="2"
Margin="0,0,0,8" Margin="0,0,0,8"
Text="{Binding DocumentFilterText, UpdateSourceTrigger=PropertyChanged}" /> Text="{Binding DocumentFilterText, UpdateSourceTrigger=PropertyChanged}" />
<ListBox Grid.Row="2" <ListBox Grid.Row="3"
ItemsSource="{Binding DocumentsView}" ItemsSource="{Binding DocumentsView}"
SelectedItem="{Binding SelectedDocument, Mode=TwoWay}" SelectedItem="{Binding SelectedDocument, Mode=TwoWay}"
BorderThickness="1" BorderThickness="1"
@@ -67,6 +80,7 @@
Command="{Binding AddDocumentCommand}" /> Command="{Binding AddDocumentCommand}" />
<MenuItem Header="Распечатать" <MenuItem Header="Распечатать"
Command="{Binding PrintDocumentCommand}" /> Command="{Binding PrintDocumentCommand}" />
<Separator/>
<MenuItem Header="Удалить" <MenuItem Header="Удалить"
Command="{Binding DeleteDocumentCommand}" /> Command="{Binding DeleteDocumentCommand}" />
</ContextMenu> </ContextMenu>
@@ -85,7 +99,47 @@
<Border Padding="8" <Border Padding="8"
BorderBrush="#DDD" BorderBrush="#DDD"
BorderThickness="0,0,0,1"> BorderThickness="0,0,0,1">
<StackPanel> <Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="18" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Ellipse Grid.Column="0"
Width="10"
Height="10"
Margin="0,4,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Top"
Stroke="#8093A4B5"
StrokeThickness="1">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Visibility" Value="Collapsed" />
<Setter Property="Fill" Value="Transparent" />
<Setter Property="ToolTip" Value="{x:Null}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsOpenDocumentAtTenDays}" Value="True">
<Setter Property="Visibility" Value="Visible" />
<Setter Property="Fill" Value="{StaticResource OpenDocumentTenDaysIndicatorBrush}" />
<Setter Property="ToolTip" Value="С даты приемки прошло 10 дней." />
</DataTrigger>
<DataTrigger Binding="{Binding IsOpenDocumentAtTwentyDays}" Value="True">
<Setter Property="Visibility" Value="Visible" />
<Setter Property="Fill" Value="{StaticResource OpenDocumentTwentyDaysIndicatorBrush}" />
<Setter Property="ToolTip" Value="С даты приемки прошло 20 дней." />
</DataTrigger>
<DataTrigger Binding="{Binding IsOpenDocumentOverdue}" Value="True">
<Setter Property="Visibility" Value="Visible" />
<Setter Property="Fill" Value="{StaticResource OpenDocumentOverdueIndicatorBrush}" />
<Setter Property="ToolTip" Value="Срок ПСВ истек: дата приемки + 30 дней." />
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<StackPanel Grid.Column="1">
<DockPanel LastChildFill="False"> <DockPanel LastChildFill="False">
<TextBlock DockPanel.Dock="Left" <TextBlock DockPanel.Dock="Left"
FontWeight="SemiBold" FontWeight="SemiBold"
@@ -98,12 +152,13 @@
Foreground="DimGray" Foreground="DimGray"
Text="{Binding CustomerName}" /> Text="{Binding CustomerName}" />
</StackPanel> </StackPanel>
</Grid>
</Border> </Border>
</DataTemplate> </DataTemplate>
</ListBox.ItemTemplate> </ListBox.ItemTemplate>
</ListBox> </ListBox>
<TextBlock Grid.Row="3" <TextBlock Grid.Row="4"
Margin="0,8,0,0" Margin="0,8,0,0"
Foreground="DimGray" Foreground="DimGray"
Text="{Binding DocumentStatusText}" /> Text="{Binding DocumentStatusText}" />
@@ -142,6 +197,7 @@
<TextBox Grid.Row="0" <TextBox Grid.Row="0"
Grid.Column="1" Grid.Column="1"
Margin="0,0,12,8" Margin="0,0,12,8"
IsEnabled="{Binding IsDocumentHeaderEditable}"
Text="{Binding DocumentNumberEditor, UpdateSourceTrigger=PropertyChanged}" /> Text="{Binding DocumentNumberEditor, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Grid.Row="0" <TextBlock Grid.Row="0"
@@ -152,6 +208,7 @@
<DatePicker Grid.Row="0" <DatePicker Grid.Row="0"
Grid.Column="3" Grid.Column="3"
Margin="0,0,12,8" Margin="0,0,12,8"
IsEnabled="{Binding IsDocumentHeaderEditable}"
SelectedDate="{Binding HeaderReceivedOn, Mode=TwoWay}" SelectedDate="{Binding HeaderReceivedOn, Mode=TwoWay}"
SelectedDateFormat="Short" /> SelectedDateFormat="Short" />
@@ -163,6 +220,7 @@
<DatePicker Grid.Row="0" <DatePicker Grid.Row="0"
Grid.Column="5" Grid.Column="5"
Margin="0,0,12,8" Margin="0,0,12,8"
IsEnabled="{Binding IsDocumentHeaderEditable}"
SelectedDate="{Binding HeaderIssuedOn, Mode=TwoWay}" SelectedDate="{Binding HeaderIssuedOn, Mode=TwoWay}"
SelectedDateFormat="Short" /> SelectedDateFormat="Short" />
@@ -172,6 +230,7 @@
HorizontalAlignment="Right"> HorizontalAlignment="Right">
<Button Width="120" <Button Width="120"
Margin="0,0,0,8" Margin="0,0,0,8"
IsEnabled="{Binding IsDocumentHeaderEditable}"
Command="{Binding SaveDocumentHeaderCommand}" Command="{Binding SaveDocumentHeaderCommand}"
Content="Сохранить" /> Content="Сохранить" />
</StackPanel> </StackPanel>
@@ -180,7 +239,7 @@
Grid.Column="0" Grid.Column="0"
Margin="0,0,8,6" Margin="0,0,8,6"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="Заказчик" /> Text="Подразделение" />
<ComboBox Grid.Row="1" <ComboBox Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
@@ -191,18 +250,6 @@
SelectedValue="{Binding SelectedCustomerId, Mode=TwoWay}" SelectedValue="{Binding SelectedCustomerId, Mode=TwoWay}"
IsEnabled="{Binding IsCustomerEditable}" /> IsEnabled="{Binding IsCustomerEditable}" />
<TextBlock Grid.Row="1"
Grid.Column="4"
Margin="0,0,8,6"
VerticalAlignment="Center"
Text="Подразделение" />
<TextBox Grid.Row="1"
Grid.Column="5"
Grid.ColumnSpan="2"
Margin="0,0,0,6"
IsReadOnly="True"
Text="{Binding HeaderDepartmentName, Mode=OneWay}" />
<TextBlock Grid.Row="2" <TextBlock Grid.Row="2"
Grid.ColumnSpan="7" Grid.ColumnSpan="7"
Foreground="DimGray" Foreground="DimGray"
@@ -224,6 +271,7 @@
Command="{Binding OpenInstrumentPickerCommand}" /> Command="{Binding OpenInstrumentPickerCommand}" />
<MenuItem Header="Добавить по типу" <MenuItem Header="Добавить по типу"
Command="{Binding OpenInstrumentTypePickerCommand}" /> Command="{Binding OpenInstrumentTypePickerCommand}" />
<Separator/>
<MenuItem Header="Удалить" <MenuItem Header="Удалить"
Command="{Binding DeleteSelectedGroupsCommand}" /> Command="{Binding DeleteSelectedGroupsCommand}" />
</ContextMenu> </ContextMenu>
@@ -263,7 +311,7 @@
<DataGridTextColumn Header="Годных" <DataGridTextColumn Header="Годных"
Width="90" Width="90"
Binding="{Binding GoodCount}" /> Binding="{Binding GoodCount}" />
<DataGridTextColumn Header="Забраковано" <DataGridTextColumn Header="Забракованых"
Width="105" Width="105"
Binding="{Binding RejectedCount}" /> Binding="{Binding RejectedCount}" />
</DataGrid.Columns> </DataGrid.Columns>
@@ -296,7 +344,7 @@
HeadersVisibility="Column"> HeadersVisibility="Column">
<DataGrid.ContextMenu> <DataGrid.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"> <ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Клонировать поверку по зав. №..." <MenuItem Header="Клонировать поверку в выбранные строки"
Command="{Binding CloneLineVerificationCommand}" /> Command="{Binding CloneLineVerificationCommand}" />
<MenuItem Header="Распечатать документ о поверке" <MenuItem Header="Распечатать документ о поверке"
Command="{Binding PrintVerificationDocumentCommand}" /> Command="{Binding PrintVerificationDocumentCommand}" />
@@ -308,10 +356,14 @@
<Separator/> <Separator/>
<MenuItem Header="Отменить проверку" <MenuItem Header="Отменить проверку"
Command="{Binding ResetLineVerificationCommand}" /> Command="{Binding ResetLineVerificationCommand}" />
<MenuItem Header="Удалить"
Command="{Binding DeleteSelectedLinesCommand}" />
</ContextMenu> </ContextMenu>
</DataGrid.ContextMenu> </DataGrid.ContextMenu>
<DataGrid.RowStyle> <DataGrid.RowStyle>
<Style TargetType="DataGridRow"> <Style TargetType="DataGridRow">
<EventSetter Event="MouseDoubleClick"
Handler="DocumentLineRow_MouseDoubleClick" />
<EventSetter Event="PreviewMouseRightButtonDown" <EventSetter Event="PreviewMouseRightButtonDown"
Handler="DocumentLineRow_PreviewMouseRightButtonDown" /> Handler="DocumentLineRow_PreviewMouseRightButtonDown" />
</Style> </Style>
@@ -330,6 +382,9 @@
<DataGridTextColumn Header="Зав. №" <DataGridTextColumn Header="Зав. №"
Width="120" Width="120"
Binding="{Binding SerialNumber}" /> Binding="{Binding SerialNumber}" />
<DataGridTextColumn Header="Дата поверки"
Width="110"
Binding="{Binding VerificationDateDisplay}" />
<DataGridTextColumn Header="Поверитель" <DataGridTextColumn Header="Поверитель"
Width="180" Width="180"
Binding="{Binding VerifierName}" /> Binding="{Binding VerifierName}" />

View File

@@ -35,6 +35,19 @@ namespace XLAB
} }
} }
private void DocumentLineRow_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var row = sender as DataGridRow;
if (row == null)
{
return;
}
row.IsSelected = true;
row.Focus();
_viewModel.TryEditVerificationFromDoubleClick(row.Item as PsvDocumentLine);
}
private void DocumentGroupRow_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) private void DocumentGroupRow_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{ {
var row = sender as DataGridRow; var row = sender as DataGridRow;

View File

@@ -25,10 +25,12 @@ namespace XLAB
private DateTime? _headerReceivedOn; private DateTime? _headerReceivedOn;
private bool _isBusy; private bool _isBusy;
private string _lineStatusText; private string _lineStatusText;
private PsvDocumentLine _lastCloneSourceLine;
private int? _selectedCustomerId; private int? _selectedCustomerId;
private PsvDocumentSummary _selectedDocument; private PsvDocumentSummary _selectedDocument;
private PsvDocumentGroupSummary _selectedDocumentGroup; private PsvDocumentGroupSummary _selectedDocumentGroup;
private PsvDocumentLine _selectedDocumentLine; private PsvDocumentLine _selectedDocumentLine;
private bool _showClosedDocuments;
public MainWindowViewModel(PsvDataService service, IDialogService dialogService) public MainWindowViewModel(PsvDataService service, IDialogService dialogService)
{ {
@@ -49,14 +51,15 @@ namespace XLAB
DocumentLinesView = CollectionViewSource.GetDefaultView(DocumentLines); DocumentLinesView = CollectionViewSource.GetDefaultView(DocumentLines);
DocumentLinesView.Filter = FilterDocumentLines; DocumentLinesView.Filter = FilterDocumentLines;
AddDocumentCommand = new RelayCommand(delegate { AddDocument(); }, delegate { return !IsBusy; }); AddDocumentCommand = new RelayCommand(delegate { AddDocument(); }, delegate { return !IsBusy && !ShowClosedDocuments; });
CloneLineVerificationCommand = new RelayCommand(delegate { CloneSelectedLineVerificationAsync(); }, delegate { return CanCloneSelectedLineVerification(); }); CloneLineVerificationCommand = new RelayCommand(delegate { CloneSelectedLineVerificationAsync(); }, delegate { return CanCloneSelectedLineVerification(); });
DeleteDocumentCommand = new RelayCommand(delegate { DeleteDocumentAsync(); }, delegate { return !IsBusy && SelectedDocument != null; }); DeleteDocumentCommand = new RelayCommand(delegate { DeleteDocumentAsync(); }, delegate { return !IsBusy && SelectedDocument != null; });
DeleteSelectedLinesCommand = new RelayCommand(delegate { DeleteSelectedLinesAsync(); }, delegate { return CanDeleteSelectedLines(); });
DeleteSelectedGroupsCommand = new RelayCommand(delegate { DeleteSelectedGroupsAsync(); }, delegate { return CanDeleteSelectedGroups(); }); DeleteSelectedGroupsCommand = new RelayCommand(delegate { DeleteSelectedGroupsAsync(); }, delegate { return CanDeleteSelectedGroups(); });
MarkLinePassedCommand = new RelayCommand(delegate { EditLineVerificationAsync(true); }, delegate { return CanEditSelectedLineVerification(); }); MarkLinePassedCommand = new RelayCommand(delegate { EditLineVerificationAsync(true); }, delegate { return CanEditSelectedLineVerification(); });
MarkLineRejectedCommand = new RelayCommand(delegate { EditLineVerificationAsync(false); }, 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; }); OpenInstrumentPickerCommand = new RelayCommand(delegate { OpenInstrumentPickerAsync(); }, delegate { return CanAddInstrumentsToSelectedDocument(); });
OpenInstrumentTypePickerCommand = new RelayCommand(delegate { OpenInstrumentTypePickerAsync(); }, delegate { return !IsBusy && SelectedDocument != null && SelectedDocument.CustomerId.HasValue; }); OpenInstrumentTypePickerCommand = new RelayCommand(delegate { OpenInstrumentTypePickerAsync(); }, delegate { return CanAddInstrumentsToSelectedDocument(); });
PrintDocumentCommand = new RelayCommand(delegate { PrintSelectedDocumentAsync(); }, delegate { return CanPrintSelectedDocument(); }); PrintDocumentCommand = new RelayCommand(delegate { PrintSelectedDocumentAsync(); }, delegate { return CanPrintSelectedDocument(); });
PrintVerificationDocumentCommand = new RelayCommand(delegate { PrintSelectedVerificationDocumentAsync(); }, delegate { return CanPrintSelectedVerificationDocument(); }); PrintVerificationDocumentCommand = new RelayCommand(delegate { PrintSelectedVerificationDocumentAsync(); }, delegate { return CanPrintSelectedVerificationDocument(); });
RefreshDocumentsCommand = new RelayCommand(delegate { RefreshDocumentsAsync(null, null); }, delegate { return !IsBusy; }); RefreshDocumentsCommand = new RelayCommand(delegate { RefreshDocumentsAsync(null, null); }, delegate { return !IsBusy; });
@@ -85,6 +88,35 @@ namespace XLAB
} }
} }
public bool ShowClosedDocuments
{
get { return _showClosedDocuments; }
set
{
if (!SetProperty(ref _showClosedDocuments, value))
{
return;
}
OnPropertyChanged("ShowOpenDocuments");
OnPropertyChanged("IsDocumentHeaderEditable");
RaiseCommandStates();
RefreshDocumentsAsync(null, null);
}
}
public bool ShowOpenDocuments
{
get { return !ShowClosedDocuments; }
set
{
if (value)
{
ShowClosedDocuments = false;
}
}
}
public ObservableCollection<PsvDocumentLine> DocumentLines { get; private set; } public ObservableCollection<PsvDocumentLine> DocumentLines { get; private set; }
public ICollectionView DocumentLinesView { get; private set; } public ICollectionView DocumentLinesView { get; private set; }
@@ -109,6 +141,8 @@ namespace XLAB
public ICommand DeleteDocumentCommand { get; private set; } public ICommand DeleteDocumentCommand { get; private set; }
public ICommand DeleteSelectedLinesCommand { get; private set; }
public ICommand DeleteSelectedGroupsCommand { get; private set; } public ICommand DeleteSelectedGroupsCommand { get; private set; }
public string GroupDetailFilterText public string GroupDetailFilterText
@@ -129,6 +163,16 @@ namespace XLAB
private set { SetProperty(ref _headerDepartmentName, value); } private set { SetProperty(ref _headerDepartmentName, value); }
} }
public bool IsDocumentHeaderEditable
{
get
{
return !IsBusy
&& SelectedDocument != null
&& !IsDocumentClosed(SelectedDocument);
}
}
public DateTime? HeaderIssuedOn public DateTime? HeaderIssuedOn
{ {
get { return _headerIssuedOn; } get { return _headerIssuedOn; }
@@ -150,6 +194,7 @@ namespace XLAB
{ {
RaiseCommandStates(); RaiseCommandStates();
OnPropertyChanged("IsCustomerEditable"); OnPropertyChanged("IsCustomerEditable");
OnPropertyChanged("IsDocumentHeaderEditable");
} }
} }
} }
@@ -210,9 +255,11 @@ namespace XLAB
{ {
if (SetProperty(ref _selectedDocument, value)) if (SetProperty(ref _selectedDocument, value))
{ {
_lastCloneSourceLine = null;
FillHeaderFromSelection(); FillHeaderFromSelection();
RaiseCommandStates(); RaiseCommandStates();
OnPropertyChanged("IsCustomerEditable"); OnPropertyChanged("IsCustomerEditable");
OnPropertyChanged("IsDocumentHeaderEditable");
LoadSelectedDocumentAsync(); LoadSelectedDocumentAsync();
} }
} }
@@ -237,6 +284,11 @@ namespace XLAB
{ {
if (SetProperty(ref _selectedDocumentLine, value)) if (SetProperty(ref _selectedDocumentLine, value))
{ {
if (CanUseLineAsCloneSource(value))
{
_lastCloneSourceLine = value;
}
RaiseCommandStates(); RaiseCommandStates();
} }
} }
@@ -297,7 +349,7 @@ namespace XLAB
InsertDraftIntoCollection(draft); InsertDraftIntoCollection(draft);
DocumentsView.Refresh(); DocumentsView.Refresh();
SelectedDocument = draft; SelectedDocument = draft;
DocumentStatusText = string.Format("Документов: {0}.", Documents.Count); DocumentStatusText = BuildDocumentStatusText(Documents.Count);
} }
private void ApplySelectedCustomer() private void ApplySelectedCustomer()
@@ -321,6 +373,11 @@ namespace XLAB
return false; return false;
} }
if (IsDocumentClosed(SelectedDocument))
{
return false;
}
if (!SelectedDocument.IsDraft) if (!SelectedDocument.IsDraft)
{ {
return true; return true;
@@ -331,11 +388,16 @@ namespace XLAB
private bool CanDeleteSelectedGroups() private bool CanDeleteSelectedGroups()
{ {
return !IsBusy return CanModifySelectedDocument()
&& SelectedDocument != null
&& GetDeleteTargetGroups().Count > 0; && GetDeleteTargetGroups().Count > 0;
} }
private bool CanDeleteSelectedLines()
{
return CanModifySelectedDocument()
&& GetDeleteTargetLines().Count > 0;
}
private bool CanPrintSelectedDocument() private bool CanPrintSelectedDocument()
{ {
return !IsBusy return !IsBusy
@@ -346,14 +408,17 @@ namespace XLAB
private bool CanEditSelectedLineVerification() private bool CanEditSelectedLineVerification()
{ {
var targetLines = GetVerificationTargetLines(); var targetLines = GetVerificationTargetLines();
return !IsBusy return CanModifySelectedDocument()
&& targetLines.Count > 0 && targetLines.Count > 0
&& targetLines.All(delegate(PsvDocumentLine line) { return !HasVerificationData(line); }); && targetLines.All(delegate(PsvDocumentLine line) { return !HasVerificationData(line); });
} }
private bool CanCloneSelectedLineVerification() private bool CanCloneSelectedLineVerification()
{ {
return !IsBusy && CanUseLineAsCloneSource(SelectedDocumentLine); var sourceLine = ResolveCloneSourceLine();
return CanModifySelectedDocument()
&& CanUseLineAsCloneSource(sourceLine)
&& GetCheckedCloneTargetLines(sourceLine).Count > 0;
} }
private bool CanPrintSelectedVerificationDocument() private bool CanPrintSelectedVerificationDocument()
@@ -364,11 +429,28 @@ namespace XLAB
private bool CanResetSelectedLineVerification() private bool CanResetSelectedLineVerification()
{ {
var targetLines = GetVerificationTargetLines(); var targetLines = GetVerificationTargetLines();
return !IsBusy return CanModifySelectedDocument()
&& targetLines.Count > 0 && targetLines.Count > 0
&& targetLines.All(HasVerificationData); && targetLines.All(HasVerificationData);
} }
private bool CanModifySelectedDocument()
{
return !IsBusy
&& SelectedDocument != null
&& !IsDocumentClosed(SelectedDocument);
}
private bool CanAddInstrumentsToSelectedDocument()
{
return CanModifySelectedDocument() && SelectedDocument.CustomerId.HasValue;
}
private static bool IsDocumentClosed(PsvDocumentSummary document)
{
return document != null && document.IssuedOn.HasValue;
}
private static bool HasVerificationData(PsvDocumentLine line) private static bool HasVerificationData(PsvDocumentLine line)
{ {
return line != null return line != null
@@ -436,6 +518,14 @@ namespace XLAB
return true; return true;
} }
private bool CanEditVerificationFromDoubleClick(PsvDocumentLine line)
{
return CanModifySelectedDocument()
&& line != null
&& line.IsPassed.HasValue
&& HasVerificationData(line);
}
private List<PsvDocumentLine> GetCheckedDocumentLines() private List<PsvDocumentLine> GetCheckedDocumentLines()
{ {
return DocumentLinesView.Cast<object>() return DocumentLinesView.Cast<object>()
@@ -477,6 +567,57 @@ namespace XLAB
: new List<PsvDocumentLine> { SelectedDocumentLine }; : new List<PsvDocumentLine> { SelectedDocumentLine };
} }
private List<PsvDocumentLine> GetDeleteTargetLines()
{
var checkedLines = GetCheckedDocumentLines();
if (checkedLines.Count > 0)
{
return checkedLines;
}
return SelectedDocumentLine == null
? new List<PsvDocumentLine>()
: new List<PsvDocumentLine> { SelectedDocumentLine };
}
private List<PsvDocumentLine> GetCheckedCloneTargetLines(PsvDocumentLine sourceLine)
{
if (sourceLine == null)
{
return new List<PsvDocumentLine>();
}
return GetCheckedDocumentLines()
.Where(delegate(PsvDocumentLine line)
{
return line != null
&& !ReferenceEquals(line, sourceLine)
&& BelongsToSameGroup(line, sourceLine);
})
.ToList();
}
private PsvDocumentLine ResolveCloneSourceLine()
{
if (CanUseLineAsCloneSource(SelectedDocumentLine))
{
return SelectedDocumentLine;
}
if (_lastCloneSourceLine != null
&& DocumentLines.Contains(_lastCloneSourceLine)
&& CanUseLineAsCloneSource(_lastCloneSourceLine))
{
return _lastCloneSourceLine;
}
var checkedSourceLines = GetCheckedDocumentLines()
.Where(CanUseLineAsCloneSource)
.ToList();
return checkedSourceLines.Count == 1 ? checkedSourceLines[0] : null;
}
private void ClearCollections<T>(ObservableCollection<T> collection) private void ClearCollections<T>(ObservableCollection<T> collection)
{ {
collection.Clear(); collection.Clear();
@@ -925,54 +1066,27 @@ namespace XLAB
private void CloneSelectedLineVerificationAsync() private void CloneSelectedLineVerificationAsync()
{ {
var sourceLine = SelectedDocumentLine; var sourceLine = ResolveCloneSourceLine();
if (!CanUseLineAsCloneSource(sourceLine)) if (!CanUseLineAsCloneSource(sourceLine))
{ {
_dialogService.ShowWarning("В выбранной строке нет полной поверки, пригодной для клонирования."); _dialogService.ShowWarning("Выберите строку-источник с заполненной поверкой. Источник можно выделить строкой или отметить единственную подходящую строку чекбоксом.");
return; return;
} }
var serialNumbers = _dialogService.ShowCloneVerificationDialog(CreateCloneVerificationSeed(sourceLine)); var checkedLines = GetCheckedDocumentLines();
if (serialNumbers == null || serialNumbers.Count == 0) if (checkedLines.Count == 0)
{ {
_dialogService.ShowWarning("Отметьте чекбоксами строки, в которые нужно склонировать поверочные данные.");
return; return;
} }
var sourceSerialNumber = NormalizeSerialNumber(sourceLine.SerialNumber); var includedSourceSerialNumber = checkedLines.Any(delegate(PsvDocumentLine line) { return ReferenceEquals(line, sourceLine); });
var requestedSerialNumbers = new HashSet<string>(serialNumbers, StringComparer.OrdinalIgnoreCase); var matchedLines = GetCheckedCloneTargetLines(sourceLine);
var includedSourceSerialNumber = !string.IsNullOrWhiteSpace(sourceSerialNumber)
&& requestedSerialNumbers.Remove(sourceSerialNumber);
var matchedLines = DocumentLines
.Where(delegate(PsvDocumentLine line)
{
return line != null
&& !ReferenceEquals(line, sourceLine)
&& BelongsToSameGroup(line, sourceLine)
&& requestedSerialNumbers.Contains(NormalizeSerialNumber(line.SerialNumber));
})
.ToList();
var matchedSerialNumbers = new HashSet<string>(
matchedLines
.Select(delegate(PsvDocumentLine line) { return NormalizeSerialNumber(line.SerialNumber); })
.Where(delegate(string serialNumber) { return !string.IsNullOrWhiteSpace(serialNumber); }),
StringComparer.OrdinalIgnoreCase);
var missingSerialNumbers = serialNumbers
.Where(delegate(string serialNumber)
{
var normalized = NormalizeSerialNumber(serialNumber);
return !string.IsNullOrWhiteSpace(normalized)
&& !string.Equals(normalized, sourceSerialNumber, StringComparison.OrdinalIgnoreCase)
&& !matchedSerialNumbers.Contains(normalized);
})
.ToList();
var targetLines = matchedLines.Where(delegate(PsvDocumentLine line) { return !HasVerificationData(line); }).ToList(); var targetLines = matchedLines.Where(delegate(PsvDocumentLine line) { return !HasVerificationData(line); }).ToList();
var skippedWithExistingVerificationCount = matchedLines.Count - targetLines.Count; var skippedWithExistingVerificationCount = matchedLines.Count - targetLines.Count;
if (targetLines.Count == 0) if (targetLines.Count == 0)
{ {
ShowCloneVerificationResult(0, skippedWithExistingVerificationCount, missingSerialNumbers, includedSourceSerialNumber, true); ShowCloneVerificationResult(0, skippedWithExistingVerificationCount, includedSourceSerialNumber, true);
return; return;
} }
@@ -992,7 +1106,7 @@ namespace XLAB
} }
RefreshAfterLineVerificationChanged(sourceLine); RefreshAfterLineVerificationChanged(sourceLine);
ShowCloneVerificationResult(targetLines.Count, skippedWithExistingVerificationCount, missingSerialNumbers, includedSourceSerialNumber, false); ShowCloneVerificationResult(targetLines.Count, skippedWithExistingVerificationCount, includedSourceSerialNumber, false);
return; return;
} }
@@ -1006,14 +1120,13 @@ namespace XLAB
} }
await ReloadSelectedDocumentLinesAsync(); await ReloadSelectedDocumentLinesAsync();
ShowCloneVerificationResult(targetLines.Count, skippedWithExistingVerificationCount, missingSerialNumbers, includedSourceSerialNumber, false); ShowCloneVerificationResult(targetLines.Count, skippedWithExistingVerificationCount, includedSourceSerialNumber, false);
}); });
} }
private void ShowCloneVerificationResult( private void ShowCloneVerificationResult(
int clonedCount, int clonedCount,
int skippedWithExistingVerificationCount, int skippedWithExistingVerificationCount,
IReadOnlyList<string> missingSerialNumbers,
bool includedSourceSerialNumber, bool includedSourceSerialNumber,
bool showWarning) bool showWarning)
{ {
@@ -1033,14 +1146,9 @@ namespace XLAB
messages.Add("Номер строки-источника пропущен."); messages.Add("Номер строки-источника пропущен.");
} }
if (missingSerialNumbers != null && missingSerialNumbers.Count > 0)
{
messages.Add(string.Format("Не найдены заводские номера: {0}.", BuildSerialNumberPreview(missingSerialNumbers)));
}
if (messages.Count == 0) if (messages.Count == 0)
{ {
messages.Add("Подходящих строк для клонирования не найдено."); messages.Add("Подходящих отмеченных строк для клонирования не найдено.");
} }
var message = string.Join(" ", messages.ToArray()); var message = string.Join(" ", messages.ToArray());
@@ -1064,6 +1172,22 @@ namespace XLAB
EditLineVerificationCoreAsync(targetLines, isPassed); EditLineVerificationCoreAsync(targetLines, isPassed);
} }
public void TryEditVerificationFromDoubleClick(PsvDocumentLine line)
{
if (line == null)
{
return;
}
SelectedDocumentLine = line;
if (!CanEditVerificationFromDoubleClick(line))
{
return;
}
EditLineVerificationCoreAsync(new[] { line }, line.IsPassed.Value);
}
private async void EditLineVerificationCoreAsync(IReadOnlyList<PsvDocumentLine> targetLines, bool isPassed) private async void EditLineVerificationCoreAsync(IReadOnlyList<PsvDocumentLine> targetLines, bool isPassed)
{ {
IReadOnlyList<DocumentFormReference> documentForms; IReadOnlyList<DocumentFormReference> documentForms;
@@ -1214,7 +1338,7 @@ namespace XLAB
Documents.Remove(draft); Documents.Remove(draft);
DocumentsView.Refresh(); DocumentsView.Refresh();
SelectedDocument = Documents.Count > 0 ? Documents[0] : null; SelectedDocument = Documents.Count > 0 ? Documents[0] : null;
DocumentStatusText = string.Format("Документов: {0}.", Documents.Count); DocumentStatusText = BuildDocumentStatusText(Documents.Count);
} }
private void PrintSelectedDocumentAsync() private void PrintSelectedDocumentAsync()
@@ -1331,7 +1455,115 @@ namespace XLAB
UpdateDocumentSummaryFromLines(selectedDocument, pendingLines); UpdateDocumentSummaryFromLines(selectedDocument, pendingLines);
ApplyDocumentLines(pendingLines, SelectedDocumentGroup); ApplyDocumentLines(pendingLines, SelectedDocumentGroup);
DocumentsView.Refresh(); DocumentsView.Refresh();
DocumentStatusText = string.Format("Документов: {0}.", Documents.Count); DocumentStatusText = BuildDocumentStatusText(Documents.Count);
}
else if (remainingPersistedCount == 0 && remainingPendingCount > 0)
{
if (!_draftDocuments.Any(delegate(PsvDocumentSummary draft) { return draft.DocumentKey == selectedDocumentKey; }))
{
_draftDocuments.Add(selectedDocument);
}
selectedDocument.IsDraft = true;
UpdateDocumentSummaryFromLines(selectedDocument, pendingLines);
await RefreshDocumentsCoreAsync(selectedDocumentKey, selectedDocumentNumber);
}
else
{
await RefreshDocumentsCoreAsync(selectedDocumentKey, selectedDocumentNumber);
}
var messages = new List<string>();
if (deletedPendingCount > 0)
{
messages.Add(string.Format("Удалено черновых строк: {0}.", deletedPendingCount));
}
if (deletedResult.DeletedEkzMkFctvlCount > 0)
{
messages.Add(string.Format("Удалено строк EKZMKFCTVL: {0}.", deletedResult.DeletedEkzMkFctvlCount));
}
if (deletedResult.DeletedEkzMkCount > 0)
{
messages.Add(string.Format("Удалено строк EKZMK: {0}.", deletedResult.DeletedEkzMkCount));
}
if (deletedResult.DeletedDmsCount > 0)
{
messages.Add(string.Format("Удалено связанных DMS: {0}.", deletedResult.DeletedDmsCount));
}
if (messages.Count > 0)
{
_dialogService.ShowInfo(string.Join(" ", messages.ToArray()));
}
});
}
private void DeleteSelectedLinesAsync()
{
if (SelectedDocument == null)
{
return;
}
var targetLines = GetDeleteTargetLines();
if (targetLines.Count == 0)
{
return;
}
if (!_dialogService.Confirm(string.Format(
"Удалить из ПСВ \"{0}\" строк приборов: {1}?",
SelectedDocument.DocumentNumber,
targetLines.Count)))
{
return;
}
var selectedDocument = SelectedDocument;
var selectedDocumentKey = selectedDocument.DocumentKey;
var selectedDocumentNumber = selectedDocument.DocumentNumber;
RunBusyOperation(async delegate
{
var pendingLines = GetPendingLines(selectedDocument);
var pendingLinesToRemove = pendingLines
.Where(delegate(PsvDocumentLine line) { return targetLines.Any(delegate(PsvDocumentLine targetLine) { return ReferenceEquals(line, targetLine); }); })
.ToList();
var persistedCardIds = targetLines
.Where(delegate(PsvDocumentLine line) { return !line.IsPendingInsert; })
.Select(delegate(PsvDocumentLine line) { return line.CardId; })
.Distinct()
.ToList();
foreach (var pendingLine in pendingLinesToRemove)
{
pendingLines.Remove(pendingLine);
}
var deletedPendingCount = pendingLinesToRemove.Count;
var deletedResult = new DocumentGroupDeleteResult();
if (persistedCardIds.Count > 0)
{
deletedResult = await Task.Run(delegate
{
return _service.DeleteDocumentGroups(selectedDocumentNumber, persistedCardIds);
});
}
var remainingPendingCount = pendingLines.Count;
var remainingPersistedCount = DocumentLines.Count(delegate(PsvDocumentLine line) { return !line.IsPendingInsert; }) - persistedCardIds.Count;
if (selectedDocument.IsDraft)
{
UpdateDocumentSummaryFromLines(selectedDocument, pendingLines);
ApplyDocumentLines(pendingLines, SelectedDocumentGroup);
DocumentsView.Refresh();
DocumentStatusText = BuildDocumentStatusText(Documents.Count);
} }
else if (remainingPersistedCount == 0 && remainingPendingCount > 0) else if (remainingPersistedCount == 0 && remainingPendingCount > 0)
{ {
@@ -1457,11 +1689,6 @@ namespace XLAB
return false; return false;
} }
if (document.IssuedOn.HasValue)
{
return false;
}
if (!string.IsNullOrWhiteSpace(DocumentFilterText) if (!string.IsNullOrWhiteSpace(DocumentFilterText)
&& !Contains(document.DocumentNumber, DocumentFilterText) && !Contains(document.DocumentNumber, DocumentFilterText)
&& !Contains(document.CustomerName, DocumentFilterText)) && !Contains(document.CustomerName, DocumentFilterText))
@@ -1472,6 +1699,16 @@ namespace XLAB
return true; return true;
} }
private string BuildDocumentStatusText(int count)
{
if (ShowClosedDocuments)
{
return string.Format("Закрытых ПСВ за {0:yyyy}: {1}.", DateTime.Today, count);
}
return string.Format("Открытых ПСВ: {0}.", count);
}
private bool FilterDocumentLines(object item) private bool FilterDocumentLines(object item)
{ {
var line = item as PsvDocumentLine; var line = item as PsvDocumentLine;
@@ -1972,6 +2209,7 @@ namespace XLAB
((RelayCommand)AddDocumentCommand).RaiseCanExecuteChanged(); ((RelayCommand)AddDocumentCommand).RaiseCanExecuteChanged();
((RelayCommand)CloneLineVerificationCommand).RaiseCanExecuteChanged(); ((RelayCommand)CloneLineVerificationCommand).RaiseCanExecuteChanged();
((RelayCommand)DeleteDocumentCommand).RaiseCanExecuteChanged(); ((RelayCommand)DeleteDocumentCommand).RaiseCanExecuteChanged();
((RelayCommand)DeleteSelectedLinesCommand).RaiseCanExecuteChanged();
((RelayCommand)DeleteSelectedGroupsCommand).RaiseCanExecuteChanged(); ((RelayCommand)DeleteSelectedGroupsCommand).RaiseCanExecuteChanged();
((RelayCommand)MarkLinePassedCommand).RaiseCanExecuteChanged(); ((RelayCommand)MarkLinePassedCommand).RaiseCanExecuteChanged();
((RelayCommand)MarkLineRejectedCommand).RaiseCanExecuteChanged(); ((RelayCommand)MarkLineRejectedCommand).RaiseCanExecuteChanged();
@@ -2041,13 +2279,15 @@ namespace XLAB
{ {
DocumentStatusText = "Загрузка списка ПСВ..."; DocumentStatusText = "Загрузка списка ПСВ...";
var databaseDocuments = await Task.Run(delegate { return _service.LoadDocuments(); }); var databaseDocuments = await Task.Run(delegate { return _service.LoadDocuments(ShowClosedDocuments); });
var currentDocumentKey = documentKeyToSelect ?? (SelectedDocument != null ? SelectedDocument.DocumentKey : null); var currentDocumentKey = documentKeyToSelect ?? (SelectedDocument != null ? SelectedDocument.DocumentKey : null);
var currentDocumentNumber = documentNumberToSelect ?? (SelectedDocument != null ? SelectedDocument.DocumentNumber : null); var currentDocumentNumber = documentNumberToSelect ?? (SelectedDocument != null ? SelectedDocument.DocumentNumber : null);
ClearCollections(Documents); ClearCollections(Documents);
foreach (var draft in _draftDocuments.OrderByDescending(delegate(PsvDocumentSummary item) { return item.AcceptedOn ?? DateTime.MinValue; })) foreach (var draft in _draftDocuments
.Where(delegate(PsvDocumentSummary item) { return !ShowClosedDocuments; })
.OrderByDescending(delegate(PsvDocumentSummary item) { return item.AcceptedOn ?? DateTime.MinValue; }))
{ {
Documents.Add(draft); Documents.Add(draft);
} }
@@ -2084,7 +2324,7 @@ namespace XLAB
SelectedDocument = Documents[0]; SelectedDocument = Documents[0];
} }
DocumentStatusText = string.Format("Документов: {0}.", Documents.Count); DocumentStatusText = BuildDocumentStatusText(Documents.Count);
} }
private void SaveDocumentAsync() private void SaveDocumentAsync()

View File

@@ -492,9 +492,9 @@ SELECT @@ROWCOUNT;";
} }
} }
public IReadOnlyList<PsvDocumentSummary> LoadDocuments() public IReadOnlyList<PsvDocumentSummary> LoadDocuments(bool loadClosedDocumentsForCurrentYear)
{ {
const string sql = @" var sql = @"
SELECT SELECT
m.NNZVPV AS DocumentNumber, m.NNZVPV AS DocumentNumber,
MAX(m.DTPRM) AS AcceptedOn, MAX(m.DTPRM) AS AcceptedOn,
@@ -512,14 +512,27 @@ LEFT JOIN dbo.FRPD dep ON dep.IDFRPD = m.IDFRPD
LEFT JOIN dbo.FRPD ownerOrg ON ownerOrg.IDFRPD = z.IDFRPDV LEFT JOIN dbo.FRPD ownerOrg ON ownerOrg.IDFRPD = z.IDFRPDV
WHERE NULLIF(LTRIM(RTRIM(m.NNZVPV)), N'') IS NOT NULL WHERE NULLIF(LTRIM(RTRIM(m.NNZVPV)), N'') IS NOT NULL
GROUP BY m.NNZVPV GROUP BY m.NNZVPV
HAVING MAX(m.DTVDM) IS NULL HAVING " + (loadClosedDocumentsForCurrentYear
ORDER BY MAX(m.DTPRM) DESC, m.NNZVPV DESC;"; ? "MAX(m.DTVDM) >= @IssuedFrom AND MAX(m.DTVDM) < @IssuedTo"
: "MAX(m.DTVDM) IS NULL") + @"
ORDER BY " + (loadClosedDocumentsForCurrentYear
? "MAX(m.DTVDM) DESC"
: "MAX(m.DTPRM) DESC") + @", m.NNZVPV DESC;";
var documents = new List<PsvDocumentSummary>(); var documents = new List<PsvDocumentSummary>();
var today = DateTime.Today;
var currentYearStart = new DateTime(today.Year, 1, 1);
var nextYearStart = currentYearStart.AddYears(1);
using (var connection = CreateConnection()) using (var connection = CreateConnection())
using (var command = new SqlCommand(sql, connection)) using (var command = new SqlCommand(sql, connection))
{ {
if (loadClosedDocumentsForCurrentYear)
{
command.Parameters.Add("@IssuedFrom", SqlDbType.DateTime).Value = currentYearStart;
command.Parameters.Add("@IssuedTo", SqlDbType.DateTime).Value = nextYearStart;
}
connection.Open(); connection.Open();
command.CommandTimeout = 60; command.CommandTimeout = 60;

View File

@@ -49,6 +49,7 @@ namespace XLAB
if (SetProperty(ref _acceptedOn, value)) if (SetProperty(ref _acceptedOn, value))
{ {
OnPropertyChanged("AcceptedMonthGroup"); OnPropertyChanged("AcceptedMonthGroup");
RaiseOpenDocumentTimelinePropertiesChanged();
} }
} }
} }
@@ -109,7 +110,13 @@ namespace XLAB
public DateTime? IssuedOn public DateTime? IssuedOn
{ {
get { return _issuedOn; } get { return _issuedOn; }
set { SetProperty(ref _issuedOn, value); } set
{
if (SetProperty(ref _issuedOn, value))
{
RaiseOpenDocumentTimelinePropertiesChanged();
}
}
} }
public int ItemCount public int ItemCount
@@ -123,6 +130,52 @@ namespace XLAB
get { return _passedCount; } get { return _passedCount; }
set { SetProperty(ref _passedCount, value); } set { SetProperty(ref _passedCount, value); }
} }
public DateTime? DueOn
{
get { return AcceptedOn.HasValue ? AcceptedOn.Value.Date.AddDays(30) : (DateTime?)null; }
}
public bool IsOpenDocumentOverdue
{
get
{
return !IssuedOn.HasValue
&& DueOn.HasValue
&& DateTime.Today.Date >= DueOn.Value.Date;
}
}
public bool IsOpenDocumentAtTwentyDays
{
get
{
return !IssuedOn.HasValue
&& AcceptedOn.HasValue
&& !IsOpenDocumentOverdue
&& (DateTime.Today.Date - AcceptedOn.Value.Date).TotalDays >= 20;
}
}
public bool IsOpenDocumentAtTenDays
{
get
{
return !IssuedOn.HasValue
&& AcceptedOn.HasValue
&& !IsOpenDocumentOverdue
&& !IsOpenDocumentAtTwentyDays
&& (DateTime.Today.Date - AcceptedOn.Value.Date).TotalDays >= 10;
}
}
private void RaiseOpenDocumentTimelinePropertiesChanged()
{
OnPropertyChanged("DueOn");
OnPropertyChanged("IsOpenDocumentOverdue");
OnPropertyChanged("IsOpenDocumentAtTwentyDays");
OnPropertyChanged("IsOpenDocumentAtTenDays");
}
} }
public sealed class PsvDocumentLine : ObservableObject public sealed class PsvDocumentLine : ObservableObject
@@ -220,6 +273,15 @@ namespace XLAB
} }
} }
public string VerificationDateDisplay
{
get
{
var verificationDate = VerificationPerformedOn ?? VerificationDocumentDate;
return verificationDate.HasValue ? verificationDate.Value.ToString("d") : string.Empty;
}
}
public string VerificationDocumentDisplay public string VerificationDocumentDisplay
{ {
get get

Binary file not shown.