This commit is contained in:
Курнат Андрей
2026-03-23 21:24:09 +03:00
parent bf9f54f91c
commit 74d793948e
471 changed files with 6560 additions and 22 deletions

View File

@@ -29,6 +29,8 @@ namespace XLAB2
public string InventoryNumber { get; set; }
public string StickerNumbers { get; set; }
public string Notes { get; set; }
}
@@ -48,6 +50,10 @@ namespace XLAB2
public DateTime? VerificationDocumentDate { get; set; }
public string StickerNumber { get; set; }
public string VerifierName { get; set; }
public int PeriodMonths { get; set; }
public DateTime? AcceptedOn { get; set; }

View File

@@ -166,6 +166,7 @@ SELECT
ownerOrg.NMFRPD AS OwnerOrganizationName,
z.NNZV AS SerialNumber,
z.NNIN AS InventoryNumber,
stickers.StickerNumbers AS StickerNumbers,
CAST(z.DSEKZ AS nvarchar(max)) AS Notes
FROM dbo.EKZ z
JOIN dbo.TPRZ tprz ON tprz.IDTPRZ = z.IDTPRZ
@@ -173,6 +174,25 @@ JOIN dbo.TIPS tips ON tips.IDTIPS = tprz.IDTIPS
JOIN dbo.SPNMTP names ON names.IDSPNMTP = tips.IDSPNMTP
JOIN dbo.SPOI areas ON areas.IDSPOI = tips.IDSPOI
JOIN dbo.FRPD ownerOrg ON ownerOrg.IDFRPD = z.IDFRPDV
OUTER APPLY
(
SELECT STUFF(
(
SELECT N' ' + sticker.StickerNumber
FROM
(
SELECT DISTINCT LTRIM(RTRIM(m.NNNKL)) AS StickerNumber
FROM dbo.EKZMK m
WHERE m.IDEKZ = z.IDEKZ
AND NULLIF(LTRIM(RTRIM(m.NNNKL)), N'') IS NOT NULL
) sticker
ORDER BY sticker.StickerNumber
FOR XML PATH(''), TYPE
).value('.', 'nvarchar(max)'),
1,
1,
N'') AS StickerNumbers
) stickers
WHERE ISNULL(z.IsDeleted, 0) = 0
ORDER BY ownerOrg.NMFRPD, areas.NMOI, names.NMTP, tips.TP, tprz.DPZN, z.NNZV, z.IDEKZ;";
@@ -202,6 +222,7 @@ ORDER BY ownerOrg.NMFRPD, areas.NMOI, names.NMTP, tips.TP, tprz.DPZN, z.NNZV, z.
OwnerOrganizationName = ReferenceDirectorySqlHelpers.GetString(reader, "OwnerOrganizationName"),
SerialNumber = ReferenceDirectorySqlHelpers.GetString(reader, "SerialNumber"),
InventoryNumber = ReferenceDirectorySqlHelpers.GetString(reader, "InventoryNumber"),
StickerNumbers = ReferenceDirectorySqlHelpers.GetString(reader, "StickerNumbers"),
Notes = ReferenceDirectorySqlHelpers.GetString(reader, "Notes")
});
}
@@ -222,6 +243,8 @@ SELECT
m.NNZVPV AS DocumentNumber,
verificationDocument.NNDMS AS VerificationDocumentNumber,
verificationDocument.DTDMS AS VerificationDocumentDate,
m.NNNKL AS StickerNumber,
verifier.PRFIO AS VerifierName,
m.PRMK AS PeriodMonths,
m.DTPRM AS AcceptedOn,
m.DTMKPL AS PlannedOn,
@@ -232,6 +255,7 @@ SELECT
FROM dbo.EKZMK m
LEFT JOIN dbo.SPVDMK verificationType ON verificationType.IDSPVDMK = m.IDSPVDMK
LEFT JOIN dbo.FRPD organization ON organization.IDFRPD = m.IDFRPD
LEFT JOIN dbo.PRSN verifier ON verifier.IDPRSN = m.IDPRSN
OUTER APPLY
(
SELECT TOP (1)
@@ -271,6 +295,8 @@ ORDER BY ISNULL(m.DTPRM, CONVERT(datetime, '19000101', 112)) DESC, m.IDEKZMK DES
DocumentNumber = ReferenceDirectorySqlHelpers.GetString(reader, "DocumentNumber"),
VerificationDocumentNumber = ReferenceDirectorySqlHelpers.GetString(reader, "VerificationDocumentNumber"),
VerificationDocumentDate = ReferenceDirectorySqlHelpers.GetNullableDateTime(reader, "VerificationDocumentDate"),
StickerNumber = ReferenceDirectorySqlHelpers.GetString(reader, "StickerNumber"),
VerifierName = ReferenceDirectorySqlHelpers.GetString(reader, "VerifierName"),
PeriodMonths = ReferenceDirectorySqlHelpers.GetInt32(reader, "PeriodMonths"),
AcceptedOn = ReferenceDirectorySqlHelpers.GetNullableDateTime(reader, "AcceptedOn"),
PlannedOn = ReferenceDirectorySqlHelpers.GetNullableDateTime(reader, "PlannedOn"),

View File

@@ -119,28 +119,25 @@
IsReadOnly="True"
HeadersVisibility="Column">
<DataGrid.Columns>
<DataGridTextColumn Header="Документ"
<DataGridTextColumn Header="ПСВ/Акт-справка"
Width="220"
Binding="{Binding DocumentNumber}" />
<DataGridTextColumn Header="Документ по поверке"
Width="180"
Binding="{Binding VerificationDocumentDisplay}" />
<DataGridTextColumn Header="Вид МК"
Width="120"
Binding="{Binding VerificationTypeName}" />
<DataGridTextColumn Header="Организация"
Width="220"
Binding="{Binding VerificationOrganizationName}" />
<DataGridTextColumn Header="Номер наклейки"
Width="140"
Binding="{Binding StickerNumber}" />
<DataGridTextColumn Header="Поверитель"
Width="180"
Binding="{Binding VerifierName}" />
<DataGridTextColumn Header="Период, мес."
Width="95"
Binding="{Binding PeriodMonths}" />
<DataGridTextColumn Header="Принят"
Width="95"
Binding="{Binding AcceptedOn, StringFormat=d}" />
<DataGridTextColumn Header="План"
Width="95"
Binding="{Binding PlannedOn, StringFormat=d}" />
<DataGridTextColumn Header="Выполнен"
<DataGridTextColumn Header="Поверен"
Width="95"
Binding="{Binding PerformedOn, StringFormat=d}" />
<DataGridTextColumn Header="Выдан"

View File

@@ -183,6 +183,7 @@ namespace XLAB2
OwnerOrganizationName = source.OwnerOrganizationName,
SerialNumber = source.SerialNumber,
InventoryNumber = source.InventoryNumber,
StickerNumbers = source.StickerNumbers,
Notes = source.Notes
};
}
@@ -422,6 +423,7 @@ namespace XLAB2
item == null ? null : item.RegistryNumber,
item == null ? null : item.SerialNumber,
item == null ? null : item.InventoryNumber,
item == null ? null : item.StickerNumbers,
item == null ? null : item.Notes
}.Where(delegate(string value) { return !string.IsNullOrWhiteSpace(value); }))
.ToUpperInvariant();

View File

@@ -434,7 +434,7 @@
SelectedItem="{Binding SelectedDocumentLine, Mode=TwoWay}"
AutoGenerateColumns="False"
CanUserAddRows="False"
IsReadOnly="True"
IsReadOnly="{Binding IsDocumentLinesReadOnly}"
HeadersVisibility="Column">
<DataGrid.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
@@ -475,21 +475,30 @@
</DataGridTemplateColumn>
<DataGridTextColumn Header="Зав. №"
Width="120"
IsReadOnly="True"
Binding="{Binding SerialNumber}" />
<DataGridTextColumn Header="Комплектность"
Width="240"
Binding="{Binding Completeness, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<DataGridTextColumn Header="Дата поверки"
Width="110"
IsReadOnly="True"
Binding="{Binding VerificationDateDisplay}" />
<DataGridTextColumn Header="Поверитель"
Width="180"
IsReadOnly="True"
Binding="{Binding VerifierName}" />
<DataGridTextColumn Header="Номер наклейки"
Width="150"
IsReadOnly="True"
Binding="{Binding StickerNumber}" />
<DataGridTextColumn Header="Результат поверки"
Width="140"
IsReadOnly="True"
Binding="{Binding ResultText}" />
<DataGridTextColumn Header="Номер документа по поверке"
Width="240"
IsReadOnly="True"
Binding="{Binding VerificationDocumentDisplay}" />
</DataGrid.Columns>
</DataGrid>

View File

@@ -206,6 +206,11 @@ namespace XLAB2
}
}
public bool IsDocumentLinesReadOnly
{
get { return !CanModifySelectedDocument(); }
}
public DateTime? HeaderIssuedOn
{
get { return _headerIssuedOn; }
@@ -228,6 +233,7 @@ namespace XLAB2
RaiseCommandStates();
OnPropertyChanged("IsCustomerEditable");
OnPropertyChanged("IsDocumentHeaderEditable");
OnPropertyChanged("IsDocumentLinesReadOnly");
}
}
}
@@ -293,6 +299,7 @@ namespace XLAB2
RaiseCommandStates();
OnPropertyChanged("IsCustomerEditable");
OnPropertyChanged("IsDocumentHeaderEditable");
OnPropertyChanged("IsDocumentLinesReadOnly");
LoadSelectedDocumentAsync();
}
}
@@ -2537,7 +2544,8 @@ namespace XLAB2
var wasDraft = selectedDocument.IsDraft;
var closingNow = !selectedDocument.IssuedOn.HasValue && request.IssuedOn.HasValue;
var printDocument = closingNow ? CreateSavedDocumentSummaryForPrint(selectedDocument, request) : null;
var result = await Task.Run(delegate { return _service.SaveDocument(currentDocumentNumber, request, pendingLines); });
var documentLinesSnapshot = DocumentLines.ToList();
var result = await Task.Run(delegate { return _service.SaveDocument(currentDocumentNumber, request, documentLinesSnapshot); });
_pendingLinesByDocumentKey.Remove(documentKey);
if (wasDraft)

View File

@@ -11,6 +11,8 @@ namespace XLAB2
{
internal sealed class PsvDataService
{
private const int EkzMkCompletenessMaxLength = 600;
public bool DocumentNumberExists(string documentNumber, string excludeDocumentNumber)
{
var normalizedNumber = NormalizeDocumentNumber(documentNumber);
@@ -1816,7 +1818,7 @@ ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, sizeInfo.NNGSRS;";
}
}
public DocumentSaveResult SaveDocument(string currentDocumentNumber, DocumentEditorResult document, IEnumerable<PsvDocumentLine> pendingLines)
public DocumentSaveResult SaveDocument(string currentDocumentNumber, DocumentEditorResult document, IEnumerable<PsvDocumentLine> documentLines)
{
if (document == null)
{
@@ -1831,13 +1833,22 @@ ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, sizeInfo.NNGSRS;";
document.DocumentNumber = normalizedNumber;
var distinctPendingLines = pendingLines == null
var materializedDocumentLines = documentLines == null
? new List<PsvDocumentLine>()
: pendingLines
: documentLines
.Where(delegate(PsvDocumentLine line) { return line != null; })
.ToList();
var distinctPendingLines = materializedDocumentLines
.Where(IsPendingLineReadyForSave)
.GroupBy(GetPendingLineSaveKey, StringComparer.OrdinalIgnoreCase)
.Select(delegate(IGrouping<string, PsvDocumentLine> group) { return group.First(); })
.ToList();
var persistedLines = materializedDocumentLines
.Where(delegate(PsvDocumentLine line) { return !line.IsPendingInsert && line.CardId > 0; })
.GroupBy(delegate(PsvDocumentLine line) { return line.CardId; })
.Select(delegate(IGrouping<int, PsvDocumentLine> group) { return group.First(); })
.ToList();
using (var connection = CreateConnection())
{
@@ -1872,6 +1883,12 @@ ORDER BY names.NMTP, tips.TP, sizeInfo.DPZN, sizeInfo.NNGSRS;";
{
throw new InvalidOperationException("Строки EKZMK для выбранного ПСВ не найдены.");
}
var updatedCompletenessCount = UpdateDocumentLineCompleteness(connection, transaction, normalizedNumber, persistedLines);
if (updatedCompletenessCount > updatedEkzMkCount)
{
updatedEkzMkCount = updatedCompletenessCount;
}
}
var insertedEkzMkCount = 0;
@@ -3203,7 +3220,7 @@ VALUES
@idsptsmp,
@idspssmp,
@GUIDEKZMK,
NULL,
@DSEKZMK,
NULL,
NULL,
NULL,
@@ -3257,6 +3274,9 @@ SELECT CAST(SCOPE_IDENTITY() AS int);";
command.Parameters.Add("@idsptsmp", SqlDbType.Int).Value = (object)template.IdSptsmp ?? DBNull.Value;
command.Parameters.Add("@idspssmp", SqlDbType.Int).Value = (object)template.IdSpssmp ?? DBNull.Value;
command.Parameters.Add("@GUIDEKZMK", SqlDbType.UniqueIdentifier).Value = Guid.NewGuid();
command.Parameters.Add("@DSEKZMK", SqlDbType.NVarChar, EkzMkCompletenessMaxLength).Value = pendingLine == null
? DBNull.Value
: (object)NormalizeOptionalCompleteness(pendingLine.Notes) ?? DBNull.Value;
command.Parameters.Add("@NRVRMNDmp", SqlDbType.Decimal).Value = (object)template.Nrvrmndmp ?? DBNull.Value;
command.Parameters["@NRVRMNDmp"].Precision = 10;
command.Parameters["@NRVRMNDmp"].Scale = 2;
@@ -4297,6 +4317,75 @@ ORDER BY blocker.TableName;";
return normalizedValue;
}
private static int UpdateDocumentLineCompleteness(
SqlConnection connection,
SqlTransaction transaction,
string documentNumber,
IEnumerable<PsvDocumentLine> persistedLines)
{
var materializedLines = persistedLines == null
? new List<PsvDocumentLine>()
: persistedLines
.Where(delegate(PsvDocumentLine line) { return line != null && line.CardId > 0; })
.GroupBy(delegate(PsvDocumentLine line) { return line.CardId; })
.Select(delegate(IGrouping<int, PsvDocumentLine> group) { return group.First(); })
.ToList();
var updatedCount = 0;
foreach (var line in materializedLines)
{
updatedCount += UpdateDocumentLineCompletenessCore(
connection,
transaction,
documentNumber,
line.CardId,
NormalizeOptionalCompleteness(line.Notes));
}
return updatedCount;
}
private static int UpdateDocumentLineCompletenessCore(
SqlConnection connection,
SqlTransaction transaction,
string documentNumber,
int cardId,
string completeness)
{
const string sql = @"
UPDATE dbo.EKZMK
SET DSEKZMK = @Completeness
WHERE NNZVPV = @DocumentNumber
AND IDEKZMK = @CardId;
SELECT @@ROWCOUNT;";
using (var command = new SqlCommand(sql, connection, transaction))
{
command.CommandTimeout = SqlServerConnectionFactory.Current.Options.CommandTimeoutSeconds;
command.Parameters.Add("@DocumentNumber", SqlDbType.NVarChar, 60).Value = documentNumber;
command.Parameters.Add("@CardId", SqlDbType.Int).Value = cardId;
command.Parameters.Add("@Completeness", SqlDbType.NVarChar, EkzMkCompletenessMaxLength).Value = (object)completeness ?? DBNull.Value;
return Convert.ToInt32(command.ExecuteScalar());
}
}
private static string NormalizeOptionalCompleteness(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
return null;
}
var normalizedValue = value.Trim();
if (normalizedValue.Length > EkzMkCompletenessMaxLength)
{
throw new InvalidOperationException(string.Format("Комплектность не должна превышать {0} символов.", EkzMkCompletenessMaxLength));
}
return normalizedValue;
}
private static int UpdateDocumentHeader(SqlConnection connection, SqlTransaction transaction, string currentDocumentNumber, DocumentEditorResult document)
{
const string sql = @"

View File

@@ -204,6 +204,7 @@ namespace XLAB2
public sealed class PsvDocumentLine : ObservableObject
{
private bool _isBatchSelected;
private string _notes;
public int CardId { get; set; }
@@ -257,7 +258,23 @@ namespace XLAB2
public string RejectionReason { get; set; }
public string Notes { get; set; }
public string Notes
{
get { return _notes; }
set
{
if (SetProperty(ref _notes, value))
{
OnPropertyChanged("Completeness");
}
}
}
public string Completeness
{
get { return Notes; }
set { Notes = value; }
}
public bool IsPendingInsert { get; set; }

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.InteropServices;
namespace XLAB2
@@ -12,8 +13,11 @@ namespace XLAB2
private const int OpenPsvTableColumnCount = 7;
private const int ClosePsvTableColumnCount = 12;
private const int PrintDialogId = 88;
private const int WordActiveEndAdjustedPageNumber = 1;
private const int WordAlertsNone = 0;
private const int WordParagraphTrue = -1;
private const int WordCloseDoNotSaveChanges = 0;
private const int WordStatisticPages = 2;
public void PrintDocument(PsvDocumentSummary document, IReadOnlyList<PsvDocumentLine> lines)
{
@@ -232,6 +236,9 @@ namespace XLAB2
ReleaseComObject(row);
}
}
// If trailing document text spills onto a new page, move the last table row with it.
EnsureTableSpillsToNextPage(document, table);
}
finally
{
@@ -239,6 +246,60 @@ namespace XLAB2
}
}
private static void EnsureTableSpillsToNextPage(dynamic document, dynamic table)
{
if (document == null || table == null)
{
return;
}
var rowCount = Convert.ToInt32(table.Rows.Count, CultureInfo.InvariantCulture);
if (rowCount <= 1)
{
return;
}
RepaginateDocument(document);
var totalPages = InvokeComIntMethod(document, "ComputeStatistics", WordStatisticPages);
if (totalPages <= 1)
{
return;
}
dynamic lastRow = null;
dynamic firstCell = null;
dynamic lastRowRange = null;
dynamic firstCellRange = null;
dynamic paragraphFormat = null;
try
{
lastRow = table.Rows.Item(rowCount);
lastRowRange = lastRow.Range;
var lastRowPage = GetRangePageNumber(lastRowRange);
if (lastRowPage >= totalPages)
{
return;
}
firstCell = lastRow.Cells.Item(1);
firstCellRange = firstCell.Range;
paragraphFormat = firstCellRange.ParagraphFormat;
paragraphFormat.PageBreakBefore = WordParagraphTrue;
RepaginateDocument(document);
}
finally
{
ReleaseComObject(paragraphFormat);
ReleaseComObject(firstCellRange);
ReleaseComObject(lastRowRange);
ReleaseComObject(firstCell);
ReleaseComObject(lastRow);
}
}
private static void EnsurePsvTableLayout(dynamic table, int expectedColumnCount)
{
if (table == null)
@@ -268,6 +329,16 @@ namespace XLAB2
}
}
private static int GetRangePageNumber(object range)
{
return InvokeComIndexedIntProperty(range, "Information", WordActiveEndAdjustedPageNumber);
}
private static void RepaginateDocument(object document)
{
InvokeComMethod(document, "Repaginate");
}
private static void SetCellText(dynamic row, int columnIndex, string value, bool centerAlign)
{
dynamic cell = null;
@@ -317,6 +388,55 @@ namespace XLAB2
}
}
private static int InvokeComIndexedIntProperty(object target, string propertyName, object argument)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
return Convert.ToInt32(
target.GetType().InvokeMember(
propertyName,
BindingFlags.GetProperty,
null,
target,
new[] { argument }),
CultureInfo.InvariantCulture);
}
private static int InvokeComIntMethod(object target, string methodName, object argument)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
return Convert.ToInt32(
target.GetType().InvokeMember(
methodName,
BindingFlags.InvokeMethod,
null,
target,
new[] { argument }),
CultureInfo.InvariantCulture);
}
private static void InvokeComMethod(object target, string methodName)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
target.GetType().InvokeMember(
methodName,
BindingFlags.InvokeMethod,
null,
target,
Array.Empty<object>());
}
private static IReadOnlyList<PrintedGroupRow> BuildPrintedGroups(IEnumerable<PsvDocumentLine> lines, bool includeClosedDetails)
{
return (lines ?? Enumerable.Empty<PsvDocumentLine>())
@@ -378,7 +498,7 @@ namespace XLAB2
return string.Empty;
}
if (serialNumbers.Count > 3)
if (serialNumbers.Count > 10)
{
return string.Format(CultureInfo.InvariantCulture, "{0} зав. номеров", serialNumbers.Count);
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,19 @@
{
"runtimeOptions": {
"tfm": "net10.0",
"frameworks": [
{
"name": "Microsoft.NETCore.App",
"version": "10.0.0"
},
{
"name": "Microsoft.WindowsDesktop.App",
"version": "10.0.0"
}
],
"configProperties": {
"System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false,
"CSWINRT_USE_WINDOWS_UI_XAML_PROJECTIONS": false
}
}
}

View File

@@ -0,0 +1,18 @@
{
"Database": {
"ApplicationName": "XLAB2",
"CommandTimeoutSeconds": 60,
"ConnectRetryCount": 3,
"ConnectRetryIntervalSeconds": 10,
"ConnectTimeoutSeconds": 15,
"Database": "ASUMS",
"Encrypt": false,
"IntegratedSecurity": true,
"MultipleActiveResultSets": true,
"Pooling": true,
"MaxPoolSize": 100,
"MinPoolSize": 0,
"Server": "SEVENHILL\\SQLEXPRESS",
"TrustServerCertificate": true
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More