770 lines
30 KiB
C#
770 lines
30 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Globalization;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Reflection;
|
||
using System.Runtime.InteropServices;
|
||
|
||
namespace XLAB2
|
||
{
|
||
internal sealed class PsvPrintService
|
||
{
|
||
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)
|
||
{
|
||
if (document == null)
|
||
{
|
||
throw new ArgumentNullException("document");
|
||
}
|
||
|
||
if (lines == null)
|
||
{
|
||
throw new ArgumentNullException("lines");
|
||
}
|
||
|
||
if (lines.Count == 0)
|
||
{
|
||
throw new InvalidOperationException("В выбранном ПСВ нет строк для печати.");
|
||
}
|
||
|
||
var templateFileName = document.IssuedOn.HasValue ? "ClosePsv.docx" : "OpenPsv.docx";
|
||
PrintWordTemplate(
|
||
templateFileName,
|
||
document.DocumentNumber,
|
||
delegate(object wordDocument)
|
||
{
|
||
PopulatePsvTemplate((dynamic)wordDocument, document, lines);
|
||
});
|
||
}
|
||
|
||
public void PrintVerificationDocument(PsvDocumentLine line)
|
||
{
|
||
if (line == null)
|
||
{
|
||
throw new ArgumentNullException("line");
|
||
}
|
||
|
||
if (!line.IsPassed.HasValue)
|
||
{
|
||
throw new InvalidOperationException("Для печати документа о поверке не указан результат поверки.");
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(line.VerificationDocumentNumber))
|
||
{
|
||
throw new InvalidOperationException("Для печати документа о поверке не указан номер документа.");
|
||
}
|
||
|
||
if (!line.VerificationPerformedOn.HasValue && !line.VerificationDocumentDate.HasValue)
|
||
{
|
||
throw new InvalidOperationException("Для печати документа о поверке не указана дата поверки.");
|
||
}
|
||
|
||
if (!line.IsPassed.Value && string.IsNullOrWhiteSpace(line.RejectionReason))
|
||
{
|
||
throw new InvalidOperationException("Для печати извещения о непригодности не указана причина непригодности.");
|
||
}
|
||
|
||
var templateFileName = line.IsPassed.Value ? "Svid.docx" : "Izv.docx";
|
||
PrintWordTemplate(
|
||
templateFileName,
|
||
line.VerificationDocumentNumber,
|
||
delegate(object wordDocument)
|
||
{
|
||
PopulateVerificationTemplate((dynamic)wordDocument, line);
|
||
});
|
||
}
|
||
|
||
private static void PrintWordTemplate(string templateFileName, string printNumber, Action<object> populateDocument)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(templateFileName))
|
||
{
|
||
throw new ArgumentException("Не указано имя шаблона печати.", "templateFileName");
|
||
}
|
||
|
||
if (populateDocument == null)
|
||
{
|
||
throw new ArgumentNullException("populateDocument");
|
||
}
|
||
|
||
var templatePath = ResolveTemplatePath(templateFileName);
|
||
var workingCopyPath = CreateWorkingCopy(templatePath, printNumber);
|
||
object wordApplication = null;
|
||
object wordDocument = null;
|
||
object dialogs = null;
|
||
object printDialog = null;
|
||
|
||
try
|
||
{
|
||
var wordType = Type.GetTypeFromProgID("Word.Application");
|
||
if (wordType == null)
|
||
{
|
||
throw new InvalidOperationException("Microsoft Word не найден. Печать ПСВ по шаблону DOCX недоступна.");
|
||
}
|
||
|
||
wordApplication = Activator.CreateInstance(wordType);
|
||
dynamic word = wordApplication;
|
||
word.Visible = true;
|
||
word.DisplayAlerts = WordAlertsNone;
|
||
|
||
wordDocument = word.Documents.Open(
|
||
FileName: workingCopyPath,
|
||
ConfirmConversions: false,
|
||
ReadOnly: false,
|
||
AddToRecentFiles: false,
|
||
Visible: true);
|
||
|
||
populateDocument(wordDocument);
|
||
((dynamic)wordDocument).Save();
|
||
word.Activate();
|
||
((dynamic)wordDocument).Activate();
|
||
|
||
dialogs = word.Dialogs;
|
||
printDialog = ((dynamic)dialogs).Item(PrintDialogId);
|
||
((dynamic)printDialog).Show();
|
||
|
||
((dynamic)wordDocument).Close(WordCloseDoNotSaveChanges);
|
||
wordDocument = null;
|
||
|
||
word.Quit();
|
||
wordApplication = null;
|
||
}
|
||
finally
|
||
{
|
||
ReleaseComObject(printDialog);
|
||
ReleaseComObject(dialogs);
|
||
ReleaseComObject(wordDocument);
|
||
ReleaseComObject(wordApplication);
|
||
TryDeleteFile(workingCopyPath);
|
||
}
|
||
}
|
||
|
||
private static void PopulatePsvTemplate(dynamic document, PsvDocumentSummary summary, IReadOnlyList<PsvDocumentLine> lines)
|
||
{
|
||
var groupedLines = BuildPrintedGroups(lines, summary.IssuedOn.HasValue);
|
||
|
||
ReplacePlaceholder(document, "number", NormalizeText(summary.DocumentNumber));
|
||
ReplacePlaceholder(document, "div", NormalizeText(summary.CustomerName));
|
||
ReplacePlaceholder(document, "date", FormatDate(summary.AcceptedOn));
|
||
ReplacePlaceholder(document, "count", lines.Count.ToString(CultureInfo.InvariantCulture));
|
||
ReplacePlaceholder(document, "person", string.Empty);
|
||
|
||
if (summary.IssuedOn.HasValue)
|
||
{
|
||
ReplacePlaceholder(document, "today", FormatDate(summary.IssuedOn));
|
||
ReplacePlaceholder(document, "good", lines.Count(delegate(PsvDocumentLine line) { return line.IsPassed == true; }).ToString(CultureInfo.InvariantCulture));
|
||
ReplacePlaceholder(document, "bad", lines.Count(delegate(PsvDocumentLine line) { return line.IsPassed == false; }).ToString(CultureInfo.InvariantCulture));
|
||
}
|
||
else
|
||
{
|
||
var dueDate = summary.AcceptedOn.HasValue
|
||
? summary.AcceptedOn.Value.AddDays(30)
|
||
: (DateTime?)null;
|
||
ReplacePlaceholder(document, "next", FormatDate(dueDate));
|
||
}
|
||
|
||
FillTable(document, groupedLines, summary.IssuedOn.HasValue);
|
||
}
|
||
|
||
private static void PopulateVerificationTemplate(dynamic document, PsvDocumentLine line)
|
||
{
|
||
var verificationDate = ResolveVerificationDate(line);
|
||
|
||
ReplacePlaceholder(document, "number", NormalizeText(line.VerificationDocumentNumber));
|
||
ReplacePlaceholder(document, "nextpovdate", FormatDate(ResolveNextVerificationDate(line, verificationDate)));
|
||
ReplacePlaceholder(document, "name", NormalizeText(line.InstrumentName));
|
||
ReplacePlaceholder(document, "type (рег. № gr)", BuildVerificationTypeText(line));
|
||
ReplacePlaceholder(document, "serial", NormalizeText(line.SerialNumber));
|
||
ReplacePlaceholder(document, "erial", NormalizeText(line.SerialNumber));
|
||
ReplacePlaceholder(document, "method", string.Empty);
|
||
ReplacePlaceholder(document, "temp", string.Empty);
|
||
ReplacePlaceholder(document, "hum", string.Empty);
|
||
ReplacePlaceholder(document, "press", string.Empty);
|
||
ReplacePlaceholder(document, "person", NormalizeText(line.VerifierName));
|
||
ReplacePlaceholder(document, "reason", NormalizeText(line.RejectionReason));
|
||
ReplacePlaceholder(document, "date", FormatDate(verificationDate));
|
||
}
|
||
|
||
private static void FillTable(dynamic document, IReadOnlyList<PrintedGroupRow> rowsToPrint, bool isClosedDocument)
|
||
{
|
||
dynamic table = null;
|
||
|
||
try
|
||
{
|
||
table = document.Tables.Item(1);
|
||
EnsurePsvTableLayout(table, isClosedDocument ? ClosePsvTableColumnCount : OpenPsvTableColumnCount);
|
||
|
||
for (var index = 0; index < rowsToPrint.Count; index++)
|
||
{
|
||
var rowData = rowsToPrint[index];
|
||
dynamic row = null;
|
||
|
||
try
|
||
{
|
||
row = table.Rows.Add();
|
||
SetCellText(row, 1, (index + 1).ToString(CultureInfo.InvariantCulture), true);
|
||
SetCellText(row, 2, rowData.InstrumentName, false);
|
||
SetCellText(row, 3, rowData.InstrumentType, false);
|
||
SetCellText(row, 4, rowData.RangeText, false);
|
||
SetCellText(row, 5, rowData.SerialNumberText, false);
|
||
SetCellText(row, 6, rowData.GroupCount.ToString(CultureInfo.InvariantCulture), true);
|
||
|
||
if (isClosedDocument)
|
||
{
|
||
SetCellText(row, 7, rowData.PassedCount > 0 ? rowData.PassedCount.ToString(CultureInfo.InvariantCulture) : string.Empty, true);
|
||
SetCellText(row, 8, rowData.FailedCount > 0 ? rowData.FailedCount.ToString(CultureInfo.InvariantCulture) : string.Empty, true);
|
||
SetCellText(row, 9, rowData.VerificationDocumentText, false);
|
||
SetCellText(row, 10, rowData.StickerNumberText, false);
|
||
SetCellText(row, 11, rowData.VerifierNameText, false);
|
||
SetCellText(row, 12, rowData.Notes, false);
|
||
}
|
||
else
|
||
{
|
||
SetCellText(row, 7, rowData.Notes, false);
|
||
}
|
||
}
|
||
finally
|
||
{
|
||
ReleaseComObject(row);
|
||
}
|
||
}
|
||
|
||
// If trailing document text spills onto a new page, move the last table row with it.
|
||
EnsureTableSpillsToNextPage(document, table);
|
||
}
|
||
finally
|
||
{
|
||
ReleaseComObject(table);
|
||
}
|
||
}
|
||
|
||
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)
|
||
{
|
||
throw new InvalidOperationException("В шаблоне ПСВ не найдена таблица для печати.");
|
||
}
|
||
|
||
var actualColumnCount = 0;
|
||
|
||
try
|
||
{
|
||
actualColumnCount = Convert.ToInt32(table.Columns.Count, CultureInfo.InvariantCulture);
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
throw new InvalidOperationException("Не удалось определить структуру таблицы шаблона ПСВ.", ex);
|
||
}
|
||
|
||
if (actualColumnCount != expectedColumnCount)
|
||
{
|
||
throw new InvalidOperationException(
|
||
string.Format(
|
||
CultureInfo.InvariantCulture,
|
||
"Шаблон ПСВ имеет неверную структуру таблицы: ожидается {0} колонок, найдено {1}.",
|
||
expectedColumnCount,
|
||
actualColumnCount));
|
||
}
|
||
}
|
||
|
||
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;
|
||
|
||
try
|
||
{
|
||
cell = row.Cells.Item(columnIndex);
|
||
cell.Range.Text = NormalizeText(value);
|
||
cell.Range.Bold = 0;
|
||
cell.Range.Font.Underline = 0;
|
||
cell.Range.ParagraphFormat.Alignment = centerAlign ? 1 : 0;
|
||
}
|
||
finally
|
||
{
|
||
ReleaseComObject(cell);
|
||
}
|
||
}
|
||
|
||
private static void ReplacePlaceholder(dynamic document, string placeholder, string replacement)
|
||
{
|
||
dynamic range = null;
|
||
dynamic find = null;
|
||
|
||
try
|
||
{
|
||
range = document.Content;
|
||
find = range.Find;
|
||
find.ClearFormatting();
|
||
find.Replacement.ClearFormatting();
|
||
find.Execute(
|
||
FindText: placeholder,
|
||
MatchCase: false,
|
||
MatchWholeWord: false,
|
||
MatchWildcards: false,
|
||
MatchSoundsLike: false,
|
||
MatchAllWordForms: false,
|
||
Forward: true,
|
||
Wrap: 1,
|
||
Format: false,
|
||
ReplaceWith: NormalizeText(replacement),
|
||
Replace: 2);
|
||
}
|
||
finally
|
||
{
|
||
ReleaseComObject(find);
|
||
ReleaseComObject(range);
|
||
}
|
||
}
|
||
|
||
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>())
|
||
.GroupBy(delegate(PsvDocumentLine line)
|
||
{
|
||
return new PrintGroupKey
|
||
{
|
||
InstrumentType = NormalizeText(line == null ? null : line.InstrumentType),
|
||
RangeText = NormalizeText(line == null ? null : line.RangeText),
|
||
RegistryNumber = NormalizeText(line == null ? null : line.RegistryNumber)
|
||
};
|
||
})
|
||
.OrderBy(delegate(IGrouping<PrintGroupKey, PsvDocumentLine> group) { return group.Key.InstrumentType; }, StringComparer.OrdinalIgnoreCase)
|
||
.ThenBy(delegate(IGrouping<PrintGroupKey, PsvDocumentLine> group) { return group.Key.RegistryNumber; }, StringComparer.OrdinalIgnoreCase)
|
||
.ThenBy(delegate(IGrouping<PrintGroupKey, PsvDocumentLine> group) { return group.Key.RangeText; }, StringComparer.OrdinalIgnoreCase)
|
||
.Select(delegate(IGrouping<PrintGroupKey, PsvDocumentLine> group)
|
||
{
|
||
var materializedLines = group.Where(delegate(PsvDocumentLine line) { return line != null; }).ToList();
|
||
|
||
return new PrintedGroupRow
|
||
{
|
||
InstrumentName = BuildInstrumentNameText(materializedLines),
|
||
InstrumentType = group.Key.InstrumentType,
|
||
RangeText = group.Key.RangeText,
|
||
SerialNumberText = BuildSerialNumberText(materializedLines),
|
||
GroupCount = materializedLines.Count,
|
||
PassedCount = materializedLines.Count(delegate(PsvDocumentLine line) { return line.IsPassed == true; }),
|
||
FailedCount = materializedLines.Count(delegate(PsvDocumentLine line) { return line.IsPassed == false; }),
|
||
VerificationDocumentText = includeClosedDetails ? BuildVerificationDocumentText(materializedLines) : string.Empty,
|
||
StickerNumberText = includeClosedDetails ? BuildStickerNumberText(materializedLines) : string.Empty,
|
||
VerifierNameText = includeClosedDetails ? BuildVerifierNameText(materializedLines) : string.Empty,
|
||
Notes = BuildNotesText(materializedLines)
|
||
};
|
||
})
|
||
.ToList();
|
||
}
|
||
|
||
private static string BuildInstrumentNameText(IReadOnlyList<PsvDocumentLine> lines)
|
||
{
|
||
return string.Join("; ", lines
|
||
.Select(delegate(PsvDocumentLine line) { return NormalizeText(line.InstrumentName); })
|
||
.Where(delegate(string value) { return !string.IsNullOrWhiteSpace(value); })
|
||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||
.OrderBy(delegate(string value) { return value; }, StringComparer.OrdinalIgnoreCase)
|
||
.ToArray());
|
||
}
|
||
|
||
private static string BuildSerialNumberText(IReadOnlyList<PsvDocumentLine> lines)
|
||
{
|
||
var serialNumbers = lines
|
||
.Select(delegate(PsvDocumentLine line) { return NormalizeText(line.SerialNumber); })
|
||
.Where(delegate(string value) { return !string.IsNullOrWhiteSpace(value); })
|
||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||
.OrderBy(delegate(string value) { return value; }, StringComparer.OrdinalIgnoreCase)
|
||
.ToList();
|
||
|
||
if (serialNumbers.Count == 0)
|
||
{
|
||
return string.Empty;
|
||
}
|
||
|
||
if (serialNumbers.Count > 10)
|
||
{
|
||
return string.Format(CultureInfo.InvariantCulture, "{0} зав. номеров", serialNumbers.Count);
|
||
}
|
||
|
||
return string.Join(", ", serialNumbers.ToArray());
|
||
}
|
||
|
||
private static string BuildNotesText(IReadOnlyList<PsvDocumentLine> lines)
|
||
{
|
||
return string.Join("; ", lines
|
||
.Select(delegate(PsvDocumentLine line) { return NormalizeText(line == null ? null : line.Notes); })
|
||
.Where(delegate(string value) { return !string.IsNullOrWhiteSpace(value); })
|
||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||
.OrderBy(delegate(string value) { return value; }, StringComparer.OrdinalIgnoreCase)
|
||
.ToArray());
|
||
}
|
||
|
||
private static string BuildVerificationDocumentText(IReadOnlyList<PsvDocumentLine> lines)
|
||
{
|
||
return string.Join("; ", lines
|
||
.Select(FormatVerificationDocument)
|
||
.Where(delegate(string value) { return !string.IsNullOrWhiteSpace(value); })
|
||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||
.OrderBy(delegate(string value) { return value; }, StringComparer.OrdinalIgnoreCase)
|
||
.ToArray());
|
||
}
|
||
|
||
private static string BuildStickerNumberText(IReadOnlyList<PsvDocumentLine> lines)
|
||
{
|
||
return string.Join(", ", lines
|
||
.Select(delegate(PsvDocumentLine line) { return NormalizeText(line == null ? null : line.StickerNumber); })
|
||
.Where(delegate(string value) { return !string.IsNullOrWhiteSpace(value); })
|
||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||
.OrderBy(delegate(string value) { return value; }, StringComparer.OrdinalIgnoreCase)
|
||
.ToArray());
|
||
}
|
||
|
||
private static string BuildVerifierNameText(IReadOnlyList<PsvDocumentLine> lines)
|
||
{
|
||
return string.Join("; ", lines
|
||
.Select(delegate(PsvDocumentLine line) { return NormalizeText(line == null ? null : line.VerifierName); })
|
||
.Where(delegate(string value) { return !string.IsNullOrWhiteSpace(value); })
|
||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||
.OrderBy(delegate(string value) { return value; }, StringComparer.OrdinalIgnoreCase)
|
||
.ToArray());
|
||
}
|
||
|
||
private static string FormatVerificationDocument(PsvDocumentLine line)
|
||
{
|
||
if (line == null)
|
||
{
|
||
return string.Empty;
|
||
}
|
||
|
||
var number = NormalizeText(line.VerificationDocumentNumber);
|
||
var date = FormatDate(line.VerificationDocumentDate);
|
||
|
||
if (string.IsNullOrWhiteSpace(number))
|
||
{
|
||
return date;
|
||
}
|
||
|
||
if (string.IsNullOrWhiteSpace(date))
|
||
{
|
||
return number;
|
||
}
|
||
|
||
return string.Format(CultureInfo.InvariantCulture, "{0} от {1}", number, date);
|
||
}
|
||
|
||
private static string BuildVerificationTypeText(PsvDocumentLine line)
|
||
{
|
||
if (line == null)
|
||
{
|
||
return string.Empty;
|
||
}
|
||
|
||
var type = NormalizeText(line.InstrumentType);
|
||
var registryNumber = NormalizeText(line.RegistryNumber);
|
||
|
||
if (string.IsNullOrWhiteSpace(type))
|
||
{
|
||
return string.Empty;
|
||
}
|
||
|
||
return string.IsNullOrWhiteSpace(registryNumber)
|
||
? type
|
||
: string.Format(CultureInfo.InvariantCulture, "{0} (рег. № {1})", type, registryNumber);
|
||
}
|
||
|
||
private static DateTime? ResolveVerificationDate(PsvDocumentLine line)
|
||
{
|
||
if (line == null)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
return line.VerificationPerformedOn ?? line.VerificationDocumentDate;
|
||
}
|
||
|
||
private static DateTime? ResolveNextVerificationDate(PsvDocumentLine line, DateTime? verificationDate)
|
||
{
|
||
if (line == null || !line.IsPassed.HasValue || !line.IsPassed.Value)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
if (!verificationDate.HasValue || line.PeriodMonths <= 0)
|
||
{
|
||
return null;
|
||
}
|
||
|
||
return verificationDate.Value.AddMonths(line.PeriodMonths);
|
||
}
|
||
|
||
private static string ResolveTemplatePath(string fileName)
|
||
{
|
||
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
||
var candidates = new[]
|
||
{
|
||
Path.Combine(baseDirectory, fileName),
|
||
Path.GetFullPath(Path.Combine(baseDirectory, "..", fileName)),
|
||
Path.GetFullPath(Path.Combine(baseDirectory, "..", "..", fileName)),
|
||
Path.GetFullPath(Path.Combine(baseDirectory, "..", "..", "..", fileName))
|
||
};
|
||
|
||
var templatePath = candidates.FirstOrDefault(File.Exists);
|
||
if (templatePath == null)
|
||
{
|
||
throw new FileNotFoundException(string.Format("Не найден шаблон печати ПСВ: {0}.", fileName), fileName);
|
||
}
|
||
|
||
return templatePath;
|
||
}
|
||
|
||
private static string CreateWorkingCopy(string templatePath, string documentNumber)
|
||
{
|
||
var tempDirectory = Path.Combine(Path.GetTempPath(), "XLAB", "Print");
|
||
Directory.CreateDirectory(tempDirectory);
|
||
|
||
var safeDocumentNumber = string.IsNullOrWhiteSpace(documentNumber)
|
||
? "PSV"
|
||
: string.Concat(documentNumber.Where(delegate(char ch)
|
||
{
|
||
return !Path.GetInvalidFileNameChars().Contains(ch);
|
||
}));
|
||
|
||
if (string.IsNullOrWhiteSpace(safeDocumentNumber))
|
||
{
|
||
safeDocumentNumber = "PSV";
|
||
}
|
||
|
||
var tempFileName = string.Format(
|
||
CultureInfo.InvariantCulture,
|
||
"{0}_{1:yyyyMMdd_HHmmss_fff}_{2}",
|
||
safeDocumentNumber,
|
||
DateTime.Now,
|
||
Path.GetFileName(templatePath));
|
||
|
||
var workingCopyPath = Path.Combine(tempDirectory, tempFileName);
|
||
File.Copy(templatePath, workingCopyPath, true);
|
||
return workingCopyPath;
|
||
}
|
||
|
||
private static string FormatDate(DateTime? value)
|
||
{
|
||
return value.HasValue
|
||
? value.Value.ToString("dd.MM.yyyy", CultureInfo.InvariantCulture)
|
||
: string.Empty;
|
||
}
|
||
|
||
private static string NormalizeText(string value)
|
||
{
|
||
return string.IsNullOrWhiteSpace(value) ? string.Empty : value.Trim();
|
||
}
|
||
|
||
private static void TryDeleteFile(string path)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
|
||
{
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
File.Delete(path);
|
||
}
|
||
catch (IOException)
|
||
{
|
||
}
|
||
catch (UnauthorizedAccessException)
|
||
{
|
||
}
|
||
}
|
||
|
||
private static void ReleaseComObject(object value)
|
||
{
|
||
if (value == null || !Marshal.IsComObject(value))
|
||
{
|
||
return;
|
||
}
|
||
|
||
try
|
||
{
|
||
Marshal.FinalReleaseComObject(value);
|
||
}
|
||
catch (ArgumentException)
|
||
{
|
||
}
|
||
}
|
||
|
||
private sealed class PrintedGroupRow
|
||
{
|
||
public int FailedCount { get; set; }
|
||
|
||
public int GroupCount { get; set; }
|
||
|
||
public string InstrumentName { get; set; }
|
||
|
||
public string InstrumentType { get; set; }
|
||
|
||
public string Notes { get; set; }
|
||
|
||
public int PassedCount { get; set; }
|
||
|
||
public string RangeText { get; set; }
|
||
|
||
public string SerialNumberText { get; set; }
|
||
|
||
public string StickerNumberText { get; set; }
|
||
|
||
public string VerificationDocumentText { get; set; }
|
||
|
||
public string VerifierNameText { get; set; }
|
||
}
|
||
|
||
private sealed class PrintGroupKey : IEquatable<PrintGroupKey>
|
||
{
|
||
public string InstrumentType { get; set; }
|
||
|
||
public string RangeText { get; set; }
|
||
|
||
public string RegistryNumber { get; set; }
|
||
|
||
public bool Equals(PrintGroupKey other)
|
||
{
|
||
return other != null
|
||
&& string.Equals(InstrumentType ?? string.Empty, other.InstrumentType ?? string.Empty, StringComparison.OrdinalIgnoreCase)
|
||
&& string.Equals(RangeText ?? string.Empty, other.RangeText ?? string.Empty, StringComparison.OrdinalIgnoreCase)
|
||
&& string.Equals(RegistryNumber ?? string.Empty, other.RegistryNumber ?? string.Empty, StringComparison.OrdinalIgnoreCase);
|
||
}
|
||
|
||
public override bool Equals(object obj)
|
||
{
|
||
return Equals(obj as PrintGroupKey);
|
||
}
|
||
|
||
public override int GetHashCode()
|
||
{
|
||
return string.Concat(
|
||
(InstrumentType ?? string.Empty).ToUpperInvariant(), "|",
|
||
(RangeText ?? string.Empty).ToUpperInvariant(), "|",
|
||
(RegistryNumber ?? string.Empty).ToUpperInvariant())
|
||
.GetHashCode();
|
||
}
|
||
}
|
||
}
|
||
}
|