<Feat>: Add customer XML structure mapping support in ResultsWriter, increase revision to 3.9.3145.102

Cause:

- The customer XML format requires batch, DUT, group and test-level metadata.
- ResultsWriter did not provide variables for test position, repetition index, batch duration, DUT test duration or aggregated test statuses.
- Missing WaterMeterData could cause a NullReferenceException while evaluating WM Type.

Solution:

1. Added XML mapping variables
   - Added TestPositionInBatch and TestRepetitionNr.
   - Added BatchTime and TestsTotalTime.
   - Added PassedFromAllTests and PassedFromRepeatedTests.

2. Added hierarchical result evaluation
   - Evaluates the overall PANEL/DUT status from all tests.
   - Evaluates GROUP status from repeated instances of the selected test.

3. Improved meter data handling
   - Made WM Type evaluation null-safe when WaterMeterData is unavailable.

4. Increased revision
   - Updated revision to 3.9.3145.102.
This commit is contained in:
2026-09-04 08:20:50 +02:00
parent d3c8813012
commit 136be96e1b
46 changed files with 1754 additions and 288 deletions
+2 -2
View File
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("3.9.3145.101")]
[assembly: AssemblyFileVersion("3.9.3145.101")]
[assembly: AssemblyVersion("3.9.3145.102")]
[assembly: AssemblyFileVersion("3.9.3145.102")]
+54 -27
View File
@@ -2841,6 +2841,15 @@ namespace TBF.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Loading.
/// </summary>
internal static string Loading {
get {
return ResourceManager.GetString("Loading", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Loading the procedure.
/// </summary>
@@ -3579,6 +3588,15 @@ namespace TBF.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Not loaded.
/// </summary>
internal static string Not_loaded {
get {
return ResourceManager.GetString("Not_loaded", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Notes.
/// </summary>
@@ -5640,6 +5658,15 @@ namespace TBF.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Simulated.
/// </summary>
internal static string Simulated {
get {
return ResourceManager.GetString("Simulated", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Simultaneous with next step.
/// </summary>
@@ -7137,6 +7164,24 @@ namespace TBF.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Writer.
/// </summary>
internal static string Writer {
get {
return ResourceManager.GetString("Writer", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Writer selection.
/// </summary>
internal static string Writer_selection {
get {
return ResourceManager.GetString("Writer_selection", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Writing to the production tracing DB failed.
/// </summary>
@@ -7146,6 +7191,15 @@ namespace TBF.Resources {
}
}
/// <summary>
/// Looks up a localized string similar to Writted.
/// </summary>
internal static string Writted {
get {
return ResourceManager.GetString("Writted", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Wrong iPerl counting direction.
/// </summary>
@@ -7190,32 +7244,5 @@ namespace TBF.Resources {
return ResourceManager.GetString("Zeroing_chdr", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Loading.
/// </summary>
internal static string Loading {
get {
return ResourceManager.GetString("Loading", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Simulated.
/// </summary>
internal static string Simulated {
get {
return ResourceManager.GetString("Simulated", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Not loaded.
/// </summary>
internal static string Not_loaded {
get {
return ResourceManager.GetString("Not_loaded", resourceCulture);
}
}
}
}
+14 -4
View File
@@ -636,6 +636,10 @@
<data name="Printer" xml:space="preserve">
<value>Tiskárna</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Writer" type="System.Resources.ResXNullRef, System.Windows.Forms">
<value />
</data>
<data name="Version" xml:space="preserve">
<value>Verze</value>
</data>
@@ -1746,6 +1750,15 @@
<data name="Test_in_calculation" xml:space="preserve">
<value>Probíhá výpočet</value>
</data>
<data name="Loading" xml:space="preserve">
<value>Načítání</value>
</data>
<data name="Simulated" xml:space="preserve">
<value>Simulace</value>
</data>
<data name="Not_loaded" xml:space="preserve">
<value>Nenačteno</value>
</data>
<data name="Arrangement_of_test" xml:space="preserve">
<value>Uspořádání testu</value>
</data>
@@ -1767,7 +1780,4 @@
<data name="Reload" xml:space="preserve">
<value>Znovu otevřít</value>
</data>
<data name="Loading" xml:space="preserve"><value>Načítání</value></data>
<data name="Simulated" xml:space="preserve"><value>Simulace</value></data>
<data name="Not_loaded" xml:space="preserve"><value>Nenačteno</value></data>
</root>
</root>
+14 -4
View File
@@ -639,6 +639,10 @@
<data name="Printer" xml:space="preserve">
<value>Drucker</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Writer" type="System.Resources.ResXNullRef, System.Windows.Forms">
<value />
</data>
<data name="Version" xml:space="preserve">
<value>Version</value>
</data>
@@ -2196,6 +2200,15 @@
<data name="Units" xml:space="preserve">
<value />
</data>
<data name="Loading" xml:space="preserve">
<value>Laden</value>
</data>
<data name="Simulated" xml:space="preserve">
<value>Simuliert</value>
</data>
<data name="Not_loaded" xml:space="preserve">
<value>Nicht geladen</value>
</data>
<data name="Meter_types_tested" xml:space="preserve">
<value>Wasserzähler geprüft</value>
</data>
@@ -2229,7 +2242,4 @@
<data name="Opto_head_was_disabled_by_the_user" xml:space="preserve">
<value>Abtastkopf wurde deaktiviert vom Benutzer!</value>
</data>
<data name="Loading" xml:space="preserve"><value>Laden</value></data>
<data name="Simulated" xml:space="preserve"><value>Simuliert</value></data>
<data name="Not_loaded" xml:space="preserve"><value>Nicht geladen</value></data>
</root>
</root>
+10 -4
View File
@@ -138,7 +138,13 @@
<data name="Units" xml:space="preserve">
<value />
</data>
<data name="Loading" xml:space="preserve"><value>Cargando</value></data>
<data name="Simulated" xml:space="preserve"><value>Simulado</value></data>
<data name="Not_loaded" xml:space="preserve"><value>No cargado</value></data>
</root>
<data name="Loading" xml:space="preserve">
<value>Cargando</value>
</data>
<data name="Simulated" xml:space="preserve">
<value>Simulado</value>
</data>
<data name="Not_loaded" xml:space="preserve">
<value>No cargado</value>
</data>
</root>
+14 -4
View File
@@ -636,6 +636,10 @@
<data name="Printer" xml:space="preserve">
<value>Imprimante</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Writer" type="System.Resources.ResXNullRef, System.Windows.Forms">
<value />
</data>
<data name="Version" xml:space="preserve">
<value>Version</value>
</data>
@@ -2013,6 +2017,15 @@
<data name="Units" xml:space="preserve">
<value />
</data>
<data name="Loading" xml:space="preserve">
<value>Chargement</value>
</data>
<data name="Simulated" xml:space="preserve">
<value>Simulé</value>
</data>
<data name="Not_loaded" xml:space="preserve">
<value>Non chargé</value>
</data>
<data name="Meter_types_tested" xml:space="preserve">
<value>Types compteurs testés</value>
</data>
@@ -2028,7 +2041,4 @@
<data name="Test_time_s_chdr" xml:space="preserve">
<value>Temps test [s]</value>
</data>
<data name="Loading" xml:space="preserve"><value>Chargement</value></data>
<data name="Simulated" xml:space="preserve"><value>Simulé</value></data>
<data name="Not_loaded" xml:space="preserve"><value>Non chargé</value></data>
</root>
</root>
+17 -4
View File
@@ -636,6 +636,10 @@
<data name="Printer" xml:space="preserve">
<value>stampa</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Writer" type="System.Resources.ResXNullRef, System.Windows.Forms">
<value />
</data>
<data name="Version" xml:space="preserve">
<value>versione</value>
</data>
@@ -1314,6 +1318,9 @@
<data name="Printed" xml:space="preserve">
<value>stampare</value>
</data>
<data name="Writted" type="System.Resources.ResXNullRef, System.Windows.Forms">
<value />
</data>
<data name="Do_you_want_to_delete_the_procedure" xml:space="preserve">
<value>vuoi cancellare la procedura?</value>
</data>
@@ -1770,6 +1777,15 @@
<data name="Units" xml:space="preserve">
<value />
</data>
<data name="Loading" xml:space="preserve">
<value>Caricamento</value>
</data>
<data name="Simulated" xml:space="preserve">
<value>Simulato</value>
</data>
<data name="Not_loaded" xml:space="preserve">
<value>Non caricato</value>
</data>
<data name="Meter_types_tested" xml:space="preserve">
<value>tipi di contatori testati</value>
</data>
@@ -1800,7 +1816,4 @@
<data name="Drain" xml:space="preserve">
<value>Drenare</value>
</data>
<data name="Loading" xml:space="preserve"><value>Caricamento</value></data>
<data name="Simulated" xml:space="preserve"><value>Simulato</value></data>
<data name="Not_loaded" xml:space="preserve"><value>Non caricato</value></data>
</root>
</root>
+14 -4
View File
@@ -627,6 +627,10 @@
<data name="Printer" xml:space="preserve">
<value>Drukarka</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Writer" type="System.Resources.ResXNullRef, System.Windows.Forms">
<value />
</data>
<data name="Version" xml:space="preserve">
<value>Wersja</value>
</data>
@@ -1653,6 +1657,15 @@
<data name="Units" xml:space="preserve">
<value />
</data>
<data name="Loading" xml:space="preserve">
<value>Ładowanie</value>
</data>
<data name="Simulated" xml:space="preserve">
<value>Symulacja</value>
</data>
<data name="Not_loaded" xml:space="preserve">
<value>Nie wczytano</value>
</data>
<data name="Arrangement_of_test" xml:space="preserve">
<value>Układ testu</value>
</data>
@@ -1704,7 +1717,4 @@
<data name="Again" xml:space="preserve">
<value>Jeszcze raz</value>
</data>
<data name="Loading" xml:space="preserve"><value>Ładowanie</value></data>
<data name="Simulated" xml:space="preserve"><value>Symulacja</value></data>
<data name="Not_loaded" xml:space="preserve"><value>Nie wczytano</value></data>
</root>
</root>
+10 -1
View File
@@ -664,6 +664,9 @@
<data name="Printer" xml:space="preserve">
<value>Printer</value>
</data>
<data name="Writer" xml:space="preserve">
<value>Writer</value>
</data>
<data name="Version" xml:space="preserve">
<value>Version</value>
</data>
@@ -1348,6 +1351,9 @@
<data name="Printed" xml:space="preserve">
<value>Printed</value>
</data>
<data name="Writted" xml:space="preserve">
<value>Writted</value>
</data>
<data name="Do_you_want_to_delete_the_procedure" xml:space="preserve">
<value>Do you want to delete the procedure?</value>
</data>
@@ -2422,6 +2428,9 @@
<data name="Printer_selection" xml:space="preserve">
<value>Printer selection</value>
</data>
<data name="Writer_selection" xml:space="preserve">
<value>Writer selection</value>
</data>
<data name="Show_cycle_beginning_form" xml:space="preserve">
<value>Show cycle beginning form</value>
</data>
@@ -2503,4 +2512,4 @@
<data name="Not_loaded" xml:space="preserve">
<value>Not loaded</value>
</data>
</root>
</root>
+14 -4
View File
@@ -519,6 +519,10 @@
<data name="Printer" xml:space="preserve">
<value>Imprimanta</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Writer" type="System.Resources.ResXNullRef, System.Windows.Forms">
<value />
</data>
<data name="Version" xml:space="preserve">
<value>Versiunea</value>
</data>
@@ -828,6 +832,15 @@
<data name="Units" xml:space="preserve">
<value />
</data>
<data name="Loading" xml:space="preserve">
<value>Se încarcă</value>
</data>
<data name="Simulated" xml:space="preserve">
<value>Simulat</value>
</data>
<data name="Not_loaded" xml:space="preserve">
<value>Neîncărcat</value>
</data>
<data name="cold" xml:space="preserve">
<value>rece</value>
</data>
@@ -852,7 +865,4 @@
<data name="WMSN" xml:space="preserve">
<value>seria</value>
</data>
<data name="Loading" xml:space="preserve"><value>Se încarcă</value></data>
<data name="Simulated" xml:space="preserve"><value>Simulat</value></data>
<data name="Not_loaded" xml:space="preserve"><value>Neîncărcat</value></data>
</root>
</root>
+14 -4
View File
@@ -627,6 +627,10 @@
<data name="Printer" xml:space="preserve">
<value>Принтер</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Writer" type="System.Resources.ResXNullRef, System.Windows.Forms">
<value />
</data>
<data name="Version" xml:space="preserve">
<value>Версия</value>
</data>
@@ -1563,6 +1567,15 @@
<data name="Units" xml:space="preserve">
<value />
</data>
<data name="Loading" xml:space="preserve">
<value>Загрузка</value>
</data>
<data name="Simulated" xml:space="preserve">
<value>Симуляция</value>
</data>
<data name="Not_loaded" xml:space="preserve">
<value>Не загружено</value>
</data>
<data name="cold" xml:space="preserve">
<value>холодный</value>
</data>
@@ -1617,7 +1630,4 @@
<data name="Again" xml:space="preserve">
<value>Снова</value>
</data>
<data name="Loading" xml:space="preserve"><value>Загрузка</value></data>
<data name="Simulated" xml:space="preserve"><value>Симуляция</value></data>
<data name="Not_loaded" xml:space="preserve"><value>Не загружено</value></data>
</root>
</root>
+10 -4
View File
@@ -265,7 +265,13 @@
<data name="Test_in_calculation" xml:space="preserve">
<value>Prebieha výpočet</value>
</data>
<data name="Loading" xml:space="preserve"><value>Načítavanie</value></data>
<data name="Simulated" xml:space="preserve"><value>Simulácia</value></data>
<data name="Not_loaded" xml:space="preserve"><value>Nenačítané</value></data>
</root>
<data name="Loading" xml:space="preserve">
<value>Načítavanie</value>
</data>
<data name="Simulated" xml:space="preserve">
<value>Simulácia</value>
</data>
<data name="Not_loaded" xml:space="preserve">
<value>Nenačítané</value>
</data>
</root>
+23 -13
View File
@@ -627,6 +627,10 @@
<data name="Printer" xml:space="preserve">
<value>打印机</value>
</data>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="Writer" type="System.Resources.ResXNullRef, System.Windows.Forms">
<value />
</data>
<data name="Version" xml:space="preserve">
<value>版本</value>
</data>
@@ -1155,6 +1159,24 @@
<data name="Voltage" xml:space="preserve">
<value>Voltage</value>
</data>
<data name="PulsesPerUnit" xml:space="preserve">
<value />
</data>
<data name="PulsesPerKilogram" xml:space="preserve">
<value />
</data>
<data name="Units" xml:space="preserve">
<value />
</data>
<data name="Loading" xml:space="preserve">
<value>正在加载</value>
</data>
<data name="Simulated" xml:space="preserve">
<value>模拟</value>
</data>
<data name="Not_loaded" xml:space="preserve">
<value>未加载</value>
</data>
<data name="cold" xml:space="preserve">
<value>冷</value>
</data>
@@ -1197,16 +1219,4 @@
<data name="Lats_changed_by" xml:space="preserve">
<value>最后修改者</value>
</data>
<data name="PulsesPerUnit" xml:space="preserve">
<value />
</data>
<data name="PulsesPerKilogram" xml:space="preserve">
<value />
</data>
<data name="Units" xml:space="preserve">
<value />
</data>
<data name="Loading" xml:space="preserve"><value>正在加载</value></data>
<data name="Simulated" xml:space="preserve"><value>模拟</value></data>
<data name="Not_loaded" xml:space="preserve"><value>未加载</value></data>
</root>
</root>
@@ -92,7 +92,7 @@ namespace TBF.Rig.DataEntry.HeatMeters12
ShuffleTextBoxes(TBF.Data.WMsCount, TBF.Data.LineSize);
foreach (var wm in waterMeters) if (wm != null) wm.Passed = wm.PassedFromTests();
foreach (var wm in waterMeters) if (wm != null) wm.Passed = wm.PassedFromAllTests();
Height = 147 + WaterMetersCount * 45; /// Adjust the window size
@@ -85,7 +85,7 @@ namespace TBF.Rig.DataEntry.HeatMeters6
ShuffleTextBoxes(TBF.Data.WMsCount, TBF.Data.LineSize);
foreach (var wm in waterMeters) if (wm != null) wm.Passed = wm.PassedFromTests();
foreach (var wm in waterMeters) if (wm != null) wm.Passed = wm.PassedFromAllTests();
Height = 147 + WaterMetersCount * 45; /// Adjust the window size
@@ -253,7 +253,7 @@ namespace TBF.Rig.DataEntry.S620
checkBoxes[i].Enabled = true; /// Allow 'disabled' check box change
/// Highlight failed water meters
if (!waterMeters[i].PassedFromTests())
if (!waterMeters[i].PassedFromAllTests())
{
bodyNrBoxes[i].BackColor = System.Drawing.Color.Pink;
serialNrBoxes[i].BackColor = System.Drawing.Color.Pink;
@@ -312,7 +312,7 @@ namespace TBF.Rig.DataEntry.S620
assignedSNs.Clear();
for (int i = 0; i < textBoxesCount; i++)
{
if (waterMeters[i].PassedFromTests() && !string.IsNullOrEmpty(bodyNrBoxes[i].Text) && checkBoxes[i].Checked)
if (waterMeters[i].PassedFromAllTests() && !string.IsNullOrEmpty(bodyNrBoxes[i].Text) && checkBoxes[i].Checked)
{
int nextSN = GetNextSerialNr();
serialNrBoxes[i].Text = (nextSN > 0) ? nextSN.ToString() : string.Empty;
@@ -345,7 +345,7 @@ namespace TBF.Rig.DataEntry.S620
checkBoxes[i].Enabled = true; /// Allow 'disabled' check box change
/// Highlight failed water meters
if (!waterMeters[i].PassedFromTests())
if (!waterMeters[i].PassedFromAllTests())
{
bodyNrBoxes[i].BackColor = System.Drawing.Color.Pink;
serialNrBoxes[i].BackColor = System.Drawing.Color.Pink;
@@ -439,7 +439,7 @@ namespace TBF.Rig.DataEntry.S620
for (int i = 0; i < textBoxesCount; i++)
{
bool passed = waterMeters[i].PassedFromTests();
bool passed = waterMeters[i].PassedFromAllTests();
if (passed && !string.IsNullOrEmpty(bodyNrBoxes[i].Text) && checkBoxes[i].Checked && lastProducedPcsCount < order.PiecesCount)
{
int currentSerialNr = (lastAssignedSN < order.SNFirst)
@@ -94,7 +94,7 @@ namespace TBF.Rig.DataEntry.Standard12
ShuffleTextBoxes(TBF.Data.WMsCount, TBF.Data.LineSize);
foreach (var wm in waterMeters) if (wm != null) wm.Passed = wm.PassedFromTests();
foreach (var wm in waterMeters) if (wm != null) wm.Passed = wm.PassedFromAllTests();
Height = 147 + WaterMetersCount * 45; /// Adjust the window size
@@ -559,7 +559,7 @@ namespace TBF.Rig.Output.DB.DatabaseWriter
wflowSummary.WorkstepName,
workplace,
Common.CurrentUser.UserName(),
wm.PassedFromTests() ? 0 : 1);
wm.PassedFromAllTests() ? 0 : 1);
if (refRecord.StepRecords == null)
{
refRecord.StepRecords = new List<StepRecord> { stepRecord };
@@ -558,7 +558,7 @@ namespace TBF.Rig.Output.DB.ProductionTracing
wflowSummary.WorkstepName,
workplace,
Common.CurrentUser.UserName(),
wm.PassedFromTests() ? 0 : 1);
wm.PassedFromAllTests() ? 0 : 1);
if (refRecord.StepRecords == null)
{
refRecord.StepRecords = new List<StepRecord> { stepRecord };
+406 -93
View File
@@ -243,8 +243,9 @@ namespace TBF.Rig.Output.DB.ResultsWriter
/// Writes all enabled water meters in a batch.
/// </summary>
/// <remarks>
/// XML payload targets are generated once per batch. Every enabled water
/// meter contributes one logical repeat record to the same XML document.
/// XML payload targets are generated once per enabled water meter. Every
/// published test of that meter contributes one logical repeat record to
/// the meter-specific XML document.
///
/// Legacy Insert output keeps its existing behavior: every published
/// regular meter test is written with its concrete test ID context.
@@ -305,7 +306,7 @@ namespace TBF.Rig.Output.DB.ResultsWriter
}
/// <summary>
/// Generates and writes one XML payload for the complete batch.
/// Generates and writes one XML payload for every enabled water meter.
/// </summary>
private void WriteXmlBatchResults(
Batch batch,
@@ -326,29 +327,109 @@ namespace TBF.Rig.Output.DB.ResultsWriter
new XmlPayloadRequestBuilder(
storageCfg);
PayloadGenerationRequest generationRequest =
BuildBatchPayloadGenerationRequest(
enabledMeters);
List<string> errors =
new List<string>();
string payloadIdentifier =
BuildBatchPayloadIdentifier(
enabledMeters);
foreach (WaterMeter wm
in enabledMeters)
{
try
{
WriteXmlMeterResults(
wm,
storageCfg,
payloadBuilder);
}
catch (Exception exc)
{
string serialNumber =
GetMeterSerialNumber(
wm);
errors.Add(
string.Format(
CultureInfo.InvariantCulture,
"Meter '{0}': {1}",
serialNumber,
exc.Message));
log.ErrorFormat(
"Failed to write XML payload for meter '{0}': {1}",
serialNumber,
exc);
}
}
if (errors.Count > 0)
{
throw new InvalidOperationException(
string.Format(
CultureInfo.InvariantCulture,
"Failed to write {0} of {1} meter XML payload(s): {2}",
errors.Count,
enabledMeters.Count,
string.Join(" | ", errors)));
}
log.WarnFormat(
"ResultsWriter wrote {0} meter-specific XML payload(s). Target={1}, Technology={2}, Mode={3}.",
enabledMeters.Count,
storageCfg.DataStorageType,
storageCfg.TechnologyType,
storageCfg.WriteMode);
}
/// <summary>
/// Generates, archives when configured, and writes one meter-specific XML payload.
/// </summary>
private void WriteXmlMeterResults(
WaterMeter wm,
WriterCfg storageCfg,
XmlPayloadRequestBuilder payloadBuilder)
{
if (wm == null)
{
throw new ArgumentNullException(
nameof(wm));
}
PayloadGenerationRequest generationRequest =
BuildMeterPayloadGenerationRequest(
wm);
PayloadFileNameContext fileNameContext =
new PayloadFileNameContext
{
SerialNumber =
GetMeterSerialNumber(
wm),
Timestamp =
DateTime.Now,
Result =
storageCfg.IsXmlFileTarget() ||
storageCfg.ArchivePayload
? ResolveMeterResultCode(
wm)
: "U"
};
XmlPayloadBuildResult buildResult;
if (storageCfg.IsStoredProcedurePayloadTarget())
{
buildResult =
payloadBuilder.Build(
payloadBuilder.BuildWithFileNameContext(
generationRequest,
payloadIdentifier);
fileNameContext);
}
else if (storageCfg.IsXmlFileTarget())
{
buildResult =
payloadBuilder.BuildFile(
payloadBuilder.BuildFileWithFileNameContext(
generationRequest,
payloadIdentifier);
fileNameContext);
}
else
{
@@ -372,7 +453,7 @@ namespace TBF.Rig.Output.DB.ResultsWriter
buildResult.OutputFileName))
{
log.InfoFormat(
"XML batch payload generated: {0}",
"XML meter payload generated: {0}",
buildResult.OutputFileName);
}
@@ -387,36 +468,8 @@ namespace TBF.Rig.Output.DB.ResultsWriter
}
log.WarnFormat(
"ResultsWriter wrote one XML payload for {0} enabled water meter(s). Target={1}, Technology={2}, Mode={3}.",
enabledMeters.Count,
storageCfg.DataStorageType,
storageCfg.TechnologyType,
storageCfg.WriteMode);
}
/// <summary>
/// Creates a stable identifier used by the XML request builder for one batch.
/// </summary>
private string BuildBatchPayloadIdentifier(
IList<WaterMeter> enabledMeters)
{
if (enabledMeters == null ||
enabledMeters.Count == 0)
{
return "BATCH";
}
string firstSerial =
Convert.ToString(
enabledMeters[0].SerialNr);
if (string.IsNullOrWhiteSpace(
firstSerial))
{
return "BATCH";
}
return firstSerial;
"ResultsWriter wrote XML payload for meter '{0}'.",
fileNameContext.SerialNumber);
}
/// <summary>
@@ -478,10 +531,21 @@ namespace TBF.Rig.Output.DB.ResultsWriter
request.RepeatPrototypePath =
builder.GetDefaultRepeatPrototypePath();
return builder.BuildPreview(
return builder.BuildPreviewWithFileNameContext(
request,
Convert.ToString(
wm.SerialNr));
new PayloadFileNameContext
{
SerialNumber =
GetMeterSerialNumber(
wm),
Result =
ResolveMeterResultCode(
wm),
Timestamp =
DateTime.Now
});
}
/// <summary>
@@ -624,34 +688,32 @@ namespace TBF.Rig.Output.DB.ResultsWriter
}
/// <summary>
/// Creates one runtime XML mapping request for the complete batch.
/// Creates one runtime XML mapping request for one water meter.
/// </summary>
/// <param name="enabledMeters">
/// Enabled water meters that must be represented in the generated payload.
/// <param name="wm">
/// Water meter represented by the generated payload.
/// </param>
/// <remarks>
/// <para>
/// Every enabled water meter creates one logical repeat record. All
/// destinations located inside the repeating XML prototype are populated
/// into that same record.
/// Single destinations are evaluated once for the current meter. Every
/// published regular test creates one logical repeat record inside the
/// same meter-specific document.
/// </para>
///
/// <para>
/// Result evaluation first uses the meter-level context. If that does not
/// produce a value, the same result item is evaluated against the actual
/// published measurement-test IDs in procedure order. This preserves
/// meter-level values while also allowing test-result variables to be
/// populated in the XML record.
/// Repeat destinations are evaluated with the concrete test ID. A
/// meter-level fallback is used only when the test-specific evaluation is
/// empty, allowing shared meter data to be repeated when explicitly
/// mapped inside the prototype.
/// </para>
/// </remarks>
private PayloadGenerationRequest BuildBatchPayloadGenerationRequest(
IList<WaterMeter> enabledMeters)
private PayloadGenerationRequest BuildMeterPayloadGenerationRequest(
WaterMeter wm)
{
PayloadGenerationRequest request =
new PayloadGenerationRequest();
if (enabledMeters == null ||
enabledMeters.Count == 0 ||
if (wm == null ||
resultsWriterCfg.SelectedItems == null)
{
return request;
@@ -680,14 +742,6 @@ namespace TBF.Rig.Output.DB.ResultsWriter
.ToList();
//
// One-time XML destinations exist only once in the document.
// Evaluate them from the first enabled water meter. This preserves
// the existing one-time mapping model while repeat destinations are
// created once for every enabled water meter.
//
WaterMeter firstMeter =
enabledMeters[0];
for (int singleIndex = 0;
singleIndex < singleItems.Count;
singleIndex++)
@@ -699,7 +753,7 @@ namespace TBF.Rig.Output.DB.ResultsWriter
string sourceKey =
string.Format(
CultureInfo.InvariantCulture,
"Batch.Single.{0}",
"Meter.Single.{0}",
singleIndex);
request.SingleMappings.Add(
@@ -715,46 +769,63 @@ namespace TBF.Rig.Output.DB.ResultsWriter
request.SingleValues.SetValue(
sourceKey,
EvaluateXmlMappedValue(
firstMeter,
wm,
item));
}
//
// Every enabled water meter becomes one logical repeat record.
// Every published test of this meter becomes one logical repeat
// record. This matches /BATCH/PANEL/DUT/GROUP/TEST references.
//
for (int meterIndex = 0;
meterIndex < enabledMeters.Count;
meterIndex++)
IList<MeterTestRslt> publishedTests =
GetPublishedTests(
wm);
for (int testIndex = 0;
testIndex < publishedTests.Count;
testIndex++)
{
WaterMeter wm =
enabledMeters[
meterIndex];
MeterTestRslt mtr =
publishedTests[
testIndex];
string testId =
mtr.Name() ??
string.Empty;
PayloadRepeatRecord record =
new PayloadRepeatRecord();
for (int repeatIndex = 0;
repeatIndex < repeatItems.Count;
repeatIndex++)
{
Results.WMeterRsltItemSpec item =
repeatItems[
repeatIndex];
IEnumerable<IGrouping<string, Results.WMeterRsltItemSpec>>
destinationGroups =
repeatItems.GroupBy(
item =>
item.Caption,
StringComparer.Ordinal);
int destinationIndex =
0;
foreach (IGrouping<string, Results.WMeterRsltItemSpec> destinationGroup
in destinationGroups)
{
string sourceKey =
string.Format(
CultureInfo.InvariantCulture,
"Batch.Repeat.{0}.{1}",
meterIndex,
repeatIndex);
"Meter.Test.{0}.{1}",
testIndex,
destinationIndex);
AddRecordMapping(
record,
sourceKey,
item.Caption,
EvaluateXmlMappedValue(
destinationGroup.Key,
ResolveRepeatDestinationValue(
wm,
item));
testId,
destinationGroup));
destinationIndex++;
}
if (record.Mappings.Count > 0)
@@ -767,6 +838,248 @@ namespace TBF.Rig.Output.DB.ResultsWriter
return request;
}
/// <summary>
/// Resolves one repeating destination for one concrete meter test.
/// </summary>
/// <remarks>
/// Multiple configured TBF results may intentionally share one repeat
/// destination. Test-specific values are preferred. A meter-level value
/// is used only when none of the candidates resolves in the current test
/// context.
/// </remarks>
private string ResolveRepeatDestinationValue(
WaterMeter wm,
string testId,
IEnumerable<Results.WMeterRsltItemSpec> candidates)
{
if (wm == null)
{
return string.Empty;
}
IList<Results.WMeterRsltItemSpec> items =
(candidates ??
Enumerable.Empty<Results.WMeterRsltItemSpec>())
.Where(
item =>
item != null)
.ToList();
string value =
ResolveFirstRepeatValue(
wm,
testId,
items,
true);
if (!string.IsNullOrWhiteSpace(value))
{
return value;
}
return ResolveFirstRepeatValue(
wm,
testId,
items,
false);
}
/// <summary>
/// Resolves the first unambiguous repeat value from one evaluation scope.
/// </summary>
private string ResolveFirstRepeatValue(
WaterMeter wm,
string testId,
IEnumerable<Results.WMeterRsltItemSpec> candidates,
bool useTestContext)
{
string selectedValue =
string.Empty;
string selectedSource =
string.Empty;
foreach (Results.WMeterRsltItemSpec item
in candidates)
{
string candidateValue =
useTestContext
? item.Print(
wm,
testId ??
string.Empty)
: item.Print(
wm);
if (string.IsNullOrWhiteSpace(
candidateValue))
{
continue;
}
if (string.IsNullOrWhiteSpace(
selectedValue))
{
selectedValue =
candidateValue;
selectedSource =
item.Name ??
string.Empty;
continue;
}
if (!string.Equals(
selectedValue,
candidateValue,
StringComparison.Ordinal))
{
log.WarnFormat(
"Repeat destination has multiple values for WM position {0}, TestID='{1}'. Using source '{2}'.",
wm.WMPosition,
testId,
selectedSource);
break;
}
}
return selectedValue;
}
/// <summary>
/// Returns published regular tests in measurement-procedure order.
/// </summary>
private IList<MeterTestRslt> GetPublishedTests(
WaterMeter wm)
{
if (wm == null)
{
return new List<MeterTestRslt>();
}
return wm.RegularMeterTestRslts()
.Where(
mtr =>
mtr != null &&
mtr.Publish() ==
Publish.Always)
.ToList();
}
/// <summary>
/// Returns a stable meter identifier for diagnostics and file naming.
/// </summary>
private string GetMeterSerialNumber(
WaterMeter wm)
{
if (wm == null)
return "UNKNOWN";
string serialNumber =
Convert.ToString(
wm.SerialNr,
CultureInfo.InvariantCulture);
if (!string.IsNullOrWhiteSpace(
serialNumber))
{
return serialNumber.Trim();
}
return string.Format(
CultureInfo.InvariantCulture,
"WM_POSITION_{0}",
wm.WMPosition);
}
/// <summary>
/// Resolves the P/F file-name token from the standard TBF meter result.
/// </summary>
/// <remarks>
/// The file name is metadata and is not derived by parsing a
/// customer-specific XML path. Existing configurations normally expose
/// the standard result as "Test passed()". Unknown or unavailable values
/// are represented by U so that the payload is never mislabeled as a
/// pass or failure.
/// </remarks>
private string ResolveMeterResultCode(
WaterMeter wm)
{
if (wm == null ||
resultsWriterCfg.SelectedItems == null)
{
return "U";
}
Results.WMeterRsltItemSpec resultItem =
resultsWriterCfg.SelectedItems
.FirstOrDefault(
item =>
item != null &&
string.Equals(
item.Name,
"Test passed()",
StringComparison.OrdinalIgnoreCase));
if (resultItem == null)
{
resultItem =
resultsWriterCfg.SelectedItems
.FirstOrDefault(
item =>
item != null &&
!IsRepeatDestination(
item.Caption) &&
!string.IsNullOrWhiteSpace(
item.Caption) &&
item.Caption.EndsWith(
"/@STATUS",
StringComparison.OrdinalIgnoreCase));
}
if (resultItem == null)
return "U";
string resultValue =
resultItem.Print(
wm);
string normalized =
(resultValue ??
string.Empty)
.Trim()
.ToUpperInvariant();
switch (normalized)
{
case "1":
case "TRUE":
case "YES":
case "PASS":
case "PASSED":
case "P":
return "P";
case "0":
case "FALSE":
case "NO":
case "FAIL":
case "FAILED":
case "F":
return "F";
default:
log.WarnFormat(
"Meter result could not be converted to P/F for WM position {0}. Value='{1}'. Using U.",
wm.WMPosition,
resultValue);
return "U";
}
}
/// <summary>
/// Evaluates one configured result item for XML output.
/// </summary>
@@ -1275,4 +1588,4 @@ namespace TBF.Rig.Output.DB.ResultsWriter
}
}
}
}
}
@@ -3,8 +3,10 @@
///
using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using TBF.Rig.Output.DataStorage.UniDataStorageWriter.Interfaces;
namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.Formatters
@@ -60,11 +62,27 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.Formatters
/// Generates a production payload and creates a stored-procedure request.
/// </summary>
/// <remarks>
/// This method preserves the original stored-procedure behavior.
/// Compatibility overload for callers that supplied the previous file prefix.
/// </remarks>
public XmlPayloadBuildResult Build(
PayloadGenerationRequest generationRequest,
string archiveFilePrefix = null)
{
return BuildWithFileNameContext(
generationRequest,
CreateLegacyFileNameContext(
archiveFilePrefix));
}
/// <summary>
/// Generates a production payload and creates a stored-procedure request.
/// </summary>
/// <remarks>
/// This method preserves the original stored-procedure behavior.
/// </remarks>
public XmlPayloadBuildResult BuildWithFileNameContext(
PayloadGenerationRequest generationRequest,
PayloadFileNameContext fileNameContext)
{
if (generationRequest == null)
throw new ArgumentNullException(
@@ -81,7 +99,7 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.Formatters
string outputFileName =
CreatePayloadFileName(
archiveFilePrefix,
fileNameContext,
false);
if (cfg.ArchivePayload)
@@ -133,13 +151,29 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.Formatters
/// Generates a production payload and creates an XML-file request.
/// </summary>
/// <remarks>
/// The physical file is not written here. The returned request is sent
/// through UniDataStorageWriter and is handled by
/// <see cref="TBF.Rig.Output.DataStorage.UniDataStorageWriter.Writers.XmlFileWriter"/>.
/// Compatibility overload for callers that supplied the previous file prefix.
/// </remarks>
public XmlPayloadBuildResult BuildFile(
PayloadGenerationRequest generationRequest,
string filePrefix = null)
{
return BuildFileWithFileNameContext(
generationRequest,
CreateLegacyFileNameContext(
filePrefix));
}
/// <summary>
/// Generates a production payload and creates an XML-file request.
/// </summary>
/// <remarks>
/// The physical file is not written here. The returned request is sent
/// through UniDataStorageWriter and is handled by
/// <see cref="TBF.Rig.Output.DataStorage.UniDataStorageWriter.Writers.XmlFileWriter"/>.
/// </remarks>
public XmlPayloadBuildResult BuildFileWithFileNameContext(
PayloadGenerationRequest generationRequest,
PayloadFileNameContext fileNameContext)
{
if (generationRequest == null)
throw new ArgumentNullException(
@@ -153,7 +187,7 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.Formatters
string outputFileName =
CreatePayloadFileName(
filePrefix,
fileNameContext,
false);
DataWriteRequest request =
@@ -192,6 +226,20 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.Formatters
public XmlPayloadBuildResult BuildPreview(
PayloadGenerationRequest generationRequest,
string archiveFilePrefix = null)
{
return BuildPreviewWithFileNameContext(
generationRequest,
CreateLegacyFileNameContext(
archiveFilePrefix));
}
/// <summary>
/// Generates and saves a preview payload without executing a database
/// operation or a production XML-file write request.
/// </summary>
public XmlPayloadBuildResult BuildPreviewWithFileNameContext(
PayloadGenerationRequest generationRequest,
PayloadFileNameContext fileNameContext)
{
if (generationRequest == null)
throw new ArgumentNullException(
@@ -208,7 +256,7 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.Formatters
string outputFileName =
CreatePayloadFileName(
archiveFilePrefix,
fileNameContext,
true);
string archiveFilePath =
@@ -249,6 +297,26 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.Formatters
.Payload;
}
/// <summary>
/// Converts the previous generic prefix argument to the new naming context.
/// </summary>
private PayloadFileNameContext CreateLegacyFileNameContext(
string identifier)
{
return new PayloadFileNameContext
{
SerialNumber =
identifier ??
string.Empty,
Result =
"U",
Timestamp =
DateTime.Now
};
}
/// <summary>
/// Validates the common XML reference configuration.
/// </summary>
@@ -384,48 +452,159 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.Formatters
}
/// <summary>
/// Creates the standard generated payload file name.
/// Creates a generated payload file name from the configured convention.
/// </summary>
private string CreatePayloadFileName(
string payloadIdentifier,
PayloadFileNameContext context,
bool preview)
{
string payloadName =
GetPayloadBaseName();
context =
context ??
new PayloadFileNameContext();
string safeIdentifier =
CreateSafeFileNamePart(
payloadIdentifier);
string template =
string.IsNullOrWhiteSpace(
cfg.PayloadFileNameTemplate)
? WriterCfg.DefaultPayloadFileNameTemplate
: cfg.PayloadFileNameTemplate.Trim();
string timestamp =
DateTime.Now.ToString(
"yyyyMMdd_HHmmss_fff");
DateTime timestamp =
context.Timestamp ==
default(DateTime)
? DateTime.Now
: context.Timestamp;
string fileName =
payloadName;
ReplaceTimestampToken(
template,
timestamp);
fileName =
ReplaceToken(
fileName,
"SerialNumber",
context.SerialNumber);
fileName =
ReplaceToken(
fileName,
"Identifier",
context.SerialNumber);
fileName =
ReplaceToken(
fileName,
"Result",
context.Result);
fileName =
ReplaceToken(
fileName,
"PayloadName",
GetPayloadBaseName());
if (fileName.IndexOf('{') >= 0 ||
fileName.IndexOf('}') >= 0)
{
throw new InvalidOperationException(
"Payload file name template contains an unsupported or incomplete token: " +
template);
}
fileName =
Path.GetFileName(
fileName);
fileName =
CreateSafeFileNamePart(
fileName);
if (string.IsNullOrWhiteSpace(
fileName))
{
throw new InvalidOperationException(
"Payload file name template produced an empty file name.");
}
if (!fileName.EndsWith(
".xml",
StringComparison.OrdinalIgnoreCase))
{
fileName +=
".xml";
}
if (preview)
{
fileName +=
"_PREVIEW";
fileName =
Path.GetFileNameWithoutExtension(
fileName) +
"_PREVIEW.xml";
}
if (!string.IsNullOrWhiteSpace(
safeIdentifier))
{
fileName +=
"_" +
safeIdentifier;
}
fileName +=
"_" +
timestamp +
".xml";
return fileName;
}
/// <summary>
/// Replaces the timestamp token and supports an optional .NET format string.
/// </summary>
private string ReplaceTimestampToken(
string template,
DateTime timestamp)
{
const string pattern =
@"\{Timestamp(?::([^{}]+))?\}";
try
{
return Regex.Replace(
template,
pattern,
match =>
{
string format =
match.Groups[1].Success
? match.Groups[1].Value
: "yyyyMMdd_HHmmss_fff";
return timestamp.ToString(
format,
CultureInfo.InvariantCulture);
},
RegexOptions.IgnoreCase);
}
catch (FormatException exc)
{
throw new InvalidOperationException(
"Payload file name template contains an invalid Timestamp format: " +
template,
exc);
}
}
/// <summary>
/// Replaces one case-insensitive file-name token with a safe value.
/// </summary>
private string ReplaceToken(
string template,
string tokenName,
string value)
{
string pattern =
"\\{" +
Regex.Escape(
tokenName) +
"\\}";
return Regex.Replace(
template,
pattern,
match =>
CreateSafeFileNamePart(
value),
RegexOptions.IgnoreCase);
}
/// <summary>
/// Derives a generic payload name from the customer reference file.
/// </summary>
@@ -562,6 +741,46 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.Formatters
}
}
/// <summary>
/// Supplies generic metadata used by the configured payload file-name template.
/// </summary>
public class PayloadFileNameContext
{
public PayloadFileNameContext()
{
SerialNumber = string.Empty;
Result = "U";
Timestamp = DateTime.Now;
}
/// <summary>
/// Gets or sets the tested device serial number.
/// </summary>
public string SerialNumber
{
get;
set;
}
/// <summary>
/// Gets or sets the short result code, normally P, F or U.
/// </summary>
public string Result
{
get;
set;
}
/// <summary>
/// Gets or sets the timestamp associated with this payload.
/// </summary>
public DateTime Timestamp
{
get;
set;
}
}
/// <summary>
/// Contains generated XML and the optional physical write request.
/// </summary>
@@ -167,6 +167,11 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
payloadParameterNameTextBox.Text = config.PayloadParameterName ?? string.Empty;
archivePayloadCheckBox.Checked = config.ArchivePayload;
payloadArchivePathTextBox.Text = config.PayloadArchivePath ?? string.Empty;
payloadFileNameTemplateTextBox.Text =
string.IsNullOrWhiteSpace(
config.PayloadFileNameTemplate)
? WriterCfg.DefaultPayloadFileNameTemplate
: config.PayloadFileNameTemplate;
dataStorageTypeComboBox.Items.Clear();
@@ -469,6 +474,26 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
payloadArchivePathTextBox.Text,
CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
string payloadFileNameTemplate =
(payloadFileNameTemplateTextBox.Text ??
string.Empty)
.Trim();
if (string.IsNullOrWhiteSpace(
payloadFileNameTemplate))
{
payloadFileNameTemplate =
WriterCfg.DefaultPayloadFileNameTemplate;
payloadFileNameTemplateTextBox.Text =
payloadFileNameTemplate;
}
flags |= UpdateDifferent(
ref config.PayloadFileNameTemplate,
payloadFileNameTemplate,
CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
return flags;
}
@@ -490,6 +515,17 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
tmpCfg.PayloadParameterName = (payloadParameterNameTextBox.Text ?? string.Empty).Trim();
tmpCfg.ArchivePayload = archivePayloadCheckBox.Checked;
tmpCfg.PayloadArchivePath = (payloadArchivePathTextBox.Text ?? string.Empty).Trim();
tmpCfg.PayloadFileNameTemplate =
(payloadFileNameTemplateTextBox.Text ??
string.Empty)
.Trim();
if (string.IsNullOrWhiteSpace(
tmpCfg.PayloadFileNameTemplate))
{
tmpCfg.PayloadFileNameTemplate =
WriterCfg.DefaultPayloadFileNameTemplate;
}
tmpCfg.WriteTemplates = writeTemplatesListBox.Items
.Cast<string>()
@@ -1443,6 +1479,7 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
sb.AppendLine("Archive payload: " + cfg.ArchivePayload);
if (cfg.ArchivePayload)
sb.AppendLine("Payload archive path: " + Safe(cfg.PayloadArchivePath));
sb.AppendLine("Payload file name: " + Safe(cfg.PayloadFileNameTemplate));
sb.AppendLine();
return sb.ToString();
@@ -1745,6 +1782,14 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
browsePayloadArchiveButton.Visible =
!xmlFilePayload;
payloadFileNameTemplateLabel.Visible =
storedProcedurePayload ||
xmlFilePayload;
payloadFileNameTemplateTextBox.Visible =
storedProcedurePayload ||
xmlFilePayload;
payloadParameterNameTextBox.Enabled =
isUnlocked &&
storedProcedurePayload;
@@ -1763,6 +1808,12 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
browsePayloadArchiveButton.Enabled =
archivePathEnabled;
payloadFileNameTemplateTextBox.Enabled =
isUnlocked &&
(xmlFilePayload ||
(storedProcedurePayload &&
archivePayloadCheckBox.Checked));
}
/// <summary>
@@ -1894,4 +1945,4 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
hint ?? string.Empty);
}
}
}
}
@@ -82,6 +82,8 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
this.browsePayloadTemplateButton = new System.Windows.Forms.Button();
this.payloadTemplatePathTextBox = new System.Windows.Forms.TextBox();
this.payloadTemplatePathLabel = new System.Windows.Forms.Label();
this.payloadFileNameTemplateTextBox = new System.Windows.Forms.TextBox();
this.payloadFileNameTemplateLabel = new System.Windows.Forms.Label();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.groupBox3.SuspendLayout();
@@ -139,9 +141,9 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
this.groupBox1.Controls.Add(this.info2Button);
this.groupBox1.Controls.Add(this.sourceTestResultTextBox);
this.groupBox1.Controls.Add(this.connectToDataSourceButton);
this.groupBox1.Location = new System.Drawing.Point(8, 394);
this.groupBox1.Location = new System.Drawing.Point(8, 422);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(473, 325);
this.groupBox1.Size = new System.Drawing.Size(473, 297);
this.groupBox1.TabIndex = 15;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "Data storage source testing";
@@ -162,7 +164,7 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
this.sourceTestResultTextBox.Multiline = true;
this.sourceTestResultTextBox.Name = "sourceTestResultTextBox";
this.sourceTestResultTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.sourceTestResultTextBox.Size = new System.Drawing.Size(437, 267);
this.sourceTestResultTextBox.Size = new System.Drawing.Size(437, 239);
this.sourceTestResultTextBox.TabIndex = 15;
//
// connectToDataSourceButton
@@ -179,9 +181,9 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
this.groupBox2.Controls.Add(this.info4Button);
this.groupBox2.Controls.Add(this.writeTestResultTextBox);
this.groupBox2.Controls.Add(this.writeDataByParamAndTemplateButton);
this.groupBox2.Location = new System.Drawing.Point(487, 394);
this.groupBox2.Location = new System.Drawing.Point(487, 422);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(463, 325);
this.groupBox2.Size = new System.Drawing.Size(463, 297);
this.groupBox2.TabIndex = 16;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Complete write testing";
@@ -202,7 +204,7 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
this.writeTestResultTextBox.Multiline = true;
this.writeTestResultTextBox.Name = "writeTestResultTextBox";
this.writeTestResultTextBox.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this.writeTestResultTextBox.Size = new System.Drawing.Size(446, 266);
this.writeTestResultTextBox.Size = new System.Drawing.Size(446, 238);
this.writeTestResultTextBox.TabIndex = 18;
//
// writeDataByParamAndTemplateButton
@@ -224,9 +226,9 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
this.groupBox3.Controls.Add(this.listBoxWriteParams);
this.groupBox3.Controls.Add(this.writeParamValueTextBox);
this.groupBox3.Controls.Add(this.info5Button);
this.groupBox3.Location = new System.Drawing.Point(956, 394);
this.groupBox3.Location = new System.Drawing.Point(956, 422);
this.groupBox3.Name = "groupBox3";
this.groupBox3.Size = new System.Drawing.Size(316, 325);
this.groupBox3.Size = new System.Drawing.Size(316, 297);
this.groupBox3.TabIndex = 17;
this.groupBox3.TabStop = false;
this.groupBox3.Text = "Component interface testing";
@@ -281,7 +283,7 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
this.listBoxWriteParams.FormattingEnabled = true;
this.listBoxWriteParams.Location = new System.Drawing.Point(9, 188);
this.listBoxWriteParams.Name = "listBoxWriteParams";
this.listBoxWriteParams.Size = new System.Drawing.Size(297, 121);
this.listBoxWriteParams.Size = new System.Drawing.Size(297, 95);
this.listBoxWriteParams.TabIndex = 22;
//
// writeParamValueTextBox
@@ -484,6 +486,8 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
//
// groupBox6
//
this.groupBox6.Controls.Add(this.payloadFileNameTemplateTextBox);
this.groupBox6.Controls.Add(this.payloadFileNameTemplateLabel);
this.groupBox6.Controls.Add(this.browsePayloadArchiveButton);
this.groupBox6.Controls.Add(this.payloadArchivePathTextBox);
this.groupBox6.Controls.Add(this.payloadArchivePathLabel);
@@ -495,7 +499,7 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
this.groupBox6.Controls.Add(this.payloadTemplatePathLabel);
this.groupBox6.Location = new System.Drawing.Point(8, 258);
this.groupBox6.Name = "groupBox6";
this.groupBox6.Size = new System.Drawing.Size(1264, 130);
this.groupBox6.Size = new System.Drawing.Size(1264, 158);
this.groupBox6.TabIndex = 26;
this.groupBox6.TabStop = false;
this.groupBox6.Text = "Payload template setting";
@@ -582,6 +586,24 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
this.payloadTemplatePathLabel.TabIndex = 0;
this.payloadTemplatePathLabel.Text = "Payload template:";
//
// payloadFileNameTemplateTextBox
//
this.payloadFileNameTemplateTextBox.Enabled = false;
this.payloadFileNameTemplateTextBox.Location = new System.Drawing.Point(120, 116);
this.payloadFileNameTemplateTextBox.Name = "payloadFileNameTemplateTextBox";
this.payloadFileNameTemplateTextBox.Size = new System.Drawing.Size(1000, 20);
this.payloadFileNameTemplateTextBox.TabIndex = 10;
this.payloadFileNameTemplateTextBox.Text = "{SerialNumber}_{Timestamp:yyyyMMdd_HHmmss}_{Result}.xml";
//
// payloadFileNameTemplateLabel
//
this.payloadFileNameTemplateLabel.AutoSize = true;
this.payloadFileNameTemplateLabel.Location = new System.Drawing.Point(9, 119);
this.payloadFileNameTemplateLabel.Name = "payloadFileNameTemplateLabel";
this.payloadFileNameTemplateLabel.Size = new System.Drawing.Size(96, 13);
this.payloadFileNameTemplateLabel.TabIndex = 9;
this.payloadFileNameTemplateLabel.Text = "Payload file name:";
//
// WriterCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -674,5 +696,7 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter.UI
private System.Windows.Forms.Label payloadArchivePathLabel;
private System.Windows.Forms.TextBox payloadArchivePathTextBox;
private System.Windows.Forms.Button browsePayloadArchiveButton;
private System.Windows.Forms.Label payloadFileNameTemplateLabel;
private System.Windows.Forms.TextBox payloadFileNameTemplateTextBox;
}
}
}
@@ -32,6 +32,9 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter
/// </remarks>
public class WriterCfg : ComponentCfgBase, Generic.IComponentCfg, IParamsProvider
{
public const string DefaultPayloadFileNameTemplate =
"{SerialNumber}_{Timestamp:yyyyMMdd_HHmmss}_{Result}.xml";
/// <summary>
/// Serializer used by the TBF configuration framework.
/// </summary>
@@ -120,6 +123,15 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter
/// </summary>
public string PayloadArchivePath;
/// <summary>
/// User-configurable file-name template used for XML output and archived payloads.
/// </summary>
/// <remarks>
/// Supported tokens are {SerialNumber}, {Timestamp[:format]}, {Result}
/// and {PayloadName}.
/// </remarks>
public string PayloadFileNameTemplate;
/// <summary>
/// Initializes a new configuration instance with safe defaults.
/// </summary>
@@ -167,6 +179,7 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter
PayloadParameterName = string.Empty;
ArchivePayload = false;
PayloadArchivePath = string.Empty;
PayloadFileNameTemplate = DefaultPayloadFileNameTemplate;
}
private readonly string[] paramNames =
@@ -181,6 +194,7 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter
"Payload parameter name", // 7
"Archive payload", // 8
"Payload archive path", // 9
"Payload file name", // 10
};
/// <summary>
@@ -303,6 +317,12 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter
case 9:
return PayloadArchivePath ?? string.Empty;
case 10:
return string.IsNullOrWhiteSpace(
PayloadFileNameTemplate)
? DefaultPayloadFileNameTemplate
: PayloadFileNameTemplate;
default:
return string.Format(
"Name={0}, DataStorageType={1}, TechnologyType={2}, WriteMode={3}",
@@ -385,6 +405,10 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter
PayloadArchivePath = strValue;
return CfgUpdateFlags.RestartRqrd;
case 10:
PayloadFileNameTemplate = strValue;
return CfgUpdateFlags.RestartRqrd;
default:
return CfgUpdateFlags.None;
}
@@ -508,6 +532,18 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter
return true;
case 10:
if (UsesXmlPayload() &&
string.IsNullOrWhiteSpace(strValue))
{
message =
"Payload file name template must not be empty for XML payload output.";
return false;
}
return true;
default:
message = "Invalid parameter index.";
return false;
@@ -582,6 +618,11 @@ namespace TBF.Rig.Output.DataStorage.UniDataStorageWriter
target.PayloadParameterName = PayloadParameterName;
target.ArchivePayload = ArchivePayload;
target.PayloadArchivePath = PayloadArchivePath;
target.PayloadFileNameTemplate =
string.IsNullOrWhiteSpace(
PayloadFileNameTemplate)
? DefaultPayloadFileNameTemplate
: PayloadFileNameTemplate;
}
/// <summary>
+2 -2
View File
@@ -52,7 +52,7 @@ namespace TBF.Rig.Output.Printers
public static void GetStatus(string printerName)
{
/// Perform the search for printers and return the listing as a collection
/// Perform the search for writers and return the listing as a collection
var mgmtSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_Printer");
var mgmtCollection = mgmtSearcher.Get();
@@ -99,7 +99,7 @@ namespace TBF.Rig.Output.Printers
return true;
}
/// Perform the search for printers and return the listing as a collection
/// Perform the search for writers and return the listing as a collection
var mgmtSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_Printer");
var mgmtCollection = mgmtSearcher.Get();
+1 -1
View File
@@ -1485,7 +1485,7 @@ namespace TBF.Rig.Sequences
else
{
/// Determine whether the watermeter passed all required tests
wm.Passed = wm.PassedFromTests();
wm.Passed = wm.PassedFromAllTests();
}
}
@@ -1022,7 +1022,7 @@ namespace TBF.Rig.TestMethods.S640Communication
Results.Entities.WaterMeter wm = ProcessData.BatchRslts.Batch.WaterMeters[i];
if (optoHeads[i] != null && optoHeads[i].PcbNumber != 0 && wm != null && !wm.Disabled)
{
if (!wm.PassedFromTests())
if (!wm.PassedFromAllTests())
{
/// Red background
eRegisterNumbers[i].BackColor = Color.Pink;
@@ -1101,7 +1101,7 @@ namespace TBF.Rig.TestMethods.S640Communication
{
if (optoHeads[i] != null && optoHeads[i].PcbNumber != 0 &&
waterMeters[i] != null && !waterMeters[i].Disabled &&
(activity == S640Activity.Start || waterMeters[i].PassedFromTests()))
(activity == S640Activity.Start || waterMeters[i].PassedFromAllTests()))
{
count++;
@@ -1137,7 +1137,7 @@ namespace TBF.Rig.TestMethods.S640Communication
optoHeads[i].PcbNumber != 0 &&
ProcessData.BatchRslts.Batch.WaterMeters[i] != null &&
!ProcessData.BatchRslts.Batch.WaterMeters[i].Disabled &&
(activity == S640Activity.Start || ProcessData.BatchRslts.Batch.WaterMeters[i].PassedFromTests()))
(activity == S640Activity.Start || ProcessData.BatchRslts.Batch.WaterMeters[i].PassedFromAllTests()))
{
Results.Entities.WaterMeter wm = ProcessData.BatchRslts.Batch.WaterMeters[i];
@@ -2180,7 +2180,7 @@ namespace TBF.Rig.TestMethods.iPerlCommunication
if ((q2CorrType == Q2CorrType.ConditionalUpdate ||
q2CorrType == Q2CorrType.ConditionalUpdateRL ||
q2CorrType == Q2CorrType.ConditionalUpdateLR) && wm.PassedFromTests())
q2CorrType == Q2CorrType.ConditionalUpdateLR) && wm.PassedFromAllTests())
{
resultStr = string.Format("No Q2 correction update");
rfidDataLogger.InfoFormat("{0}({1}): No Q2 correction update", ihead.Name, ihead.SerialNr);
@@ -2046,7 +2046,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
if ((q2CorrType == Q2CorrType.ConditionalUpdate ||
q2CorrType == Q2CorrType.ConditionalUpdateRL ||
q2CorrType == Q2CorrType.ConditionalUpdateLR) && wm.PassedFromTests())
q2CorrType == Q2CorrType.ConditionalUpdateLR) && wm.PassedFromAllTests())
{
resultStr = string.Format("No Q2 correction update");
rfidDataLogger.InfoFormat("{0}({1}): No Q2 correction update", ihead.Name, ihead.SerialNr);
@@ -2046,7 +2046,7 @@ namespace TBF.Rig.Uni.SharedDialogs.SmartMetersCommunication.implementations
if ((q2CorrType == Q2CorrType.ConditionalUpdate ||
q2CorrType == Q2CorrType.ConditionalUpdateRL ||
q2CorrType == Q2CorrType.ConditionalUpdateLR) && wm.PassedFromTests())
q2CorrType == Q2CorrType.ConditionalUpdateLR) && wm.PassedFromAllTests())
{
resultStr = string.Format("No Q2 correction update");
rfidDataLogger.InfoFormat("{0}({1}): No Q2 correction update", ihead.Name, ihead.SerialNr);
+9
View File
@@ -3305,6 +3305,12 @@
<Compile Include="UI\ResultsMI\PreviousResultsDlg.designer.cs">
<DependentUpon>PreviousResultsDlg.cs</DependentUpon>
</Compile>
<Compile Include="UI\ResultsMI\WriteResultsSelectionDlg.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="UI\ResultsMI\WriteResultsSelectionDlg.Designer.cs">
<DependentUpon>WriteResultsSelectionDlg.cs</DependentUpon>
</Compile>
<Compile Include="UI\ResultsMI\PrintResultsSelectionDlg.cs">
<SubType>Form</SubType>
</Compile>
@@ -4345,6 +4351,9 @@
<EmbeddedResource Include="UI\ResultsMI\PreviousResultsDlg.resx">
<DependentUpon>PreviousResultsDlg.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="UI\ResultsMI\WriteResultsSelectionDlg.resx">
<DependentUpon>WriteResultsSelectionDlg.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="UI\ResultsMI\PrintResultsSelectionDlg.resx">
<DependentUpon>PrintResultsSelectionDlg.cs</DependentUpon>
</EmbeddedResource>
+18 -6
View File
@@ -39,13 +39,14 @@
this.batchNrLabel = new System.Windows.Forms.Label();
this.showButton = new System.Windows.Forms.Button();
this.swVerLabel = new System.Windows.Forms.Label();
this.writeButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// sendReloadButton
//
this.sendReloadButton.Location = new System.Drawing.Point(832, 2);
this.sendReloadButton.Location = new System.Drawing.Point(893, 2);
this.sendReloadButton.Name = "sendReloadButton";
this.sendReloadButton.Size = new System.Drawing.Size(104, 23);
this.sendReloadButton.Size = new System.Drawing.Size(64, 23);
this.sendReloadButton.TabIndex = 15;
this.sendReloadButton.Text = "Again";
this.sendReloadButton.UseVisualStyleBackColor = true;
@@ -127,7 +128,7 @@
//
// showButton
//
this.showButton.Location = new System.Drawing.Point(939, 2);
this.showButton.Location = new System.Drawing.Point(963, 2);
this.showButton.Name = "showButton";
this.showButton.Size = new System.Drawing.Size(104, 23);
this.showButton.TabIndex = 17;
@@ -144,10 +145,21 @@
this.swVerLabel.TabIndex = 18;
this.swVerLabel.Text = "SW Ver.";
//
// writeButton
//
this.writeButton.Location = new System.Drawing.Point(822, 2);
this.writeButton.Name = "writeButton";
this.writeButton.Size = new System.Drawing.Size(65, 23);
this.writeButton.TabIndex = 19;
this.writeButton.Text = "Again";
this.writeButton.UseVisualStyleBackColor = true;
this.writeButton.Click += new System.EventHandler(this.writeButton_Click);
//
// PreviousResultCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.writeButton);
this.Controls.Add(this.swVerLabel);
this.Controls.Add(this.showButton);
this.Controls.Add(this.batchNrLabel);
@@ -160,7 +172,7 @@
this.Controls.Add(this.endTimeLabel);
this.Controls.Add(this.startTimeLabel);
this.Name = "PreviousResultCtrl";
this.Size = new System.Drawing.Size(1048, 26);
this.Size = new System.Drawing.Size(1070, 26);
this.ResumeLayout(false);
this.PerformLayout();
@@ -179,6 +191,6 @@
private System.Windows.Forms.Label batchNrLabel;
private System.Windows.Forms.Button showButton;
private System.Windows.Forms.Label swVerLabel;
}
private System.Windows.Forms.Button writeButton;
}
}
+7 -1
View File
@@ -91,6 +91,7 @@ namespace TBF.UI.ResultsMI
/// 'Show' button
showButton.Text = Strings.Show;
writeButton.Text = "Write";
}
public void UpdateSentState(bool sent)
@@ -141,5 +142,10 @@ namespace TBF.UI.ResultsMI
}
#endif
}
}
private void writeButton_Click(object sender, EventArgs e)
{
parent.OnWrite(this, new PreviousResultIdEventArgs(BatchNr, SerialNrs));
}
}
}
+36 -33
View File
@@ -1,33 +1,33 @@
namespace TBF.UI.ResultsMI
{
partial class PreviousResultsDlg
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
partial class PreviousResultsDlg
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.closeButton = new System.Windows.Forms.Button();
this.previousButton = new System.Windows.Forms.Button();
@@ -160,6 +160,7 @@
//
// reloadButton
//
this.reloadButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.reloadButton.Location = new System.Drawing.Point(1009, 23);
this.reloadButton.Name = "reloadButton";
this.reloadButton.Size = new System.Drawing.Size(37, 23);
@@ -170,6 +171,8 @@
//
// procedureTextBox
//
this.procedureTextBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.procedureTextBox.Location = new System.Drawing.Point(472, 25);
this.procedureTextBox.Name = "procedureTextBox";
this.procedureTextBox.Size = new System.Drawing.Size(523, 20);
@@ -243,10 +246,10 @@
this.CancelButton = this.closeButton;
this.ClientSize = new System.Drawing.Size(1194, 892);
this.Controls.Add(this.vertSplitContainer);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable;
this.MaximizeBox = true;
this.Name = "PreviousResultsDlg";
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;
this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Show;
this.Text = "Previous results";
this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.PreviousResultsDlg_FormClosing);
this.Load += new System.EventHandler(this.PreviousResultsDlg_Load);
@@ -262,12 +265,12 @@
this.filterGroupBox.PerformLayout();
this.ResumeLayout(false);
}
}
#endregion
#endregion
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.Button closeButton;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.Button closeButton;
private System.Windows.Forms.Button previousButton;
private System.Windows.Forms.Button nextButton;
private System.Windows.Forms.SplitContainer vertSplitContainer;
@@ -282,5 +285,5 @@
private System.Windows.Forms.Button reloadButton;
private System.Windows.Forms.Label snLabel;
private System.Windows.Forms.TextBox snTextBox;
}
}
}
+61 -1
View File
@@ -59,7 +59,13 @@ namespace TBF.UI.ResultsMI
else DoPrint(sndr, args);
};
SendAgainHandler += delegate(object sndr, PreviousResultIdEventArgs args)
WriteHandler += delegate (object sndr, PreviousResultIdEventArgs args)
{
if (InvokeRequired) { Invoke(new EventHandler<PreviousResultIdEventArgs>(DoWrite), sndr, args); }
else DoWrite(sndr, args);
};
SendAgainHandler += delegate(object sndr, PreviousResultIdEventArgs args)
{
if (InvokeRequired) { Invoke(new EventHandler<PreviousResultIdEventArgs>(DoSendAgain), sndr, args); }
else DoSendAgain(sndr, args);
@@ -274,6 +280,60 @@ namespace TBF.UI.ResultsMI
}
}
public event EventHandler<PreviousResultIdEventArgs> WriteHandler;
/// <summary>
/// Called from PreviousResultCtrl when 'Print' button pressed.
/// </summary>
public void OnWrite(object sender, PreviousResultIdEventArgs data) //...MF
{
if (PrintHandler == null)
return;
try
{
WriteHandler(sender, data);
}
catch (Exception e)
{
// Log to file / internal logger
log.Error("WriteHandler(...) failed", e);
// Show message box to user
MessageBox.Show(
"Writing failed.\n\n" +
"Error: " + e.Message +
"\n\nCheck write settings or try again.",
"Writing error",
MessageBoxButtons.OK,
MessageBoxIcon.Error
);
}
}
public void DoWrite(object sender, PreviousResultIdEventArgs data)
{
foreach (var b in batches)
{
if (b.BatchNr == data.BatchNr)
{
IList<IResultsWriter> writers = new List<IResultsWriter>();
foreach (var c in TBF.Rig.StateMachine.Components)
{
if (c is IResultsWriter) writers.Add(c as IResultsWriter);
}
var dlg = new WriteResultsSelectionDlg(writers, b);
if (dlg.ShowDialog() != DialogResult.OK) return;
TBF.Rig.IOperation writeResultsOp = dlg.SelectedWriter.ProcessResultsOp(b);
writeResultsOp.Start();
TBF.Rig.Event e;
do { e = writeResultsOp.Run(); }
while (e != TBF.Rig.Event.ResultsWritten && e != TBF.Rig.Event.ErrorProcessingResults);
writeResultsOp.Stop();
}
}
}
public event EventHandler<PreviousResultIdEventArgs> SendAgainHandler;
+2 -2
View File
@@ -35,11 +35,11 @@
this.editPrinterButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// printersComboBox
// writersComboBox
//
this.printersComboBox.FormattingEnabled = true;
this.printersComboBox.Location = new System.Drawing.Point(121, 27);
this.printersComboBox.Name = "printersComboBox";
this.printersComboBox.Name = "writersComboBox";
this.printersComboBox.Size = new System.Drawing.Size(392, 21);
this.printersComboBox.TabIndex = 0;
//
+114
View File
@@ -0,0 +1,114 @@
namespace TBF.UI.ResultsMI
{
partial class WriteResultsSelectionDlg
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.writersComboBox = new System.Windows.Forms.ComboBox();
this.writerLabel = new System.Windows.Forms.Label();
this.okButton = new System.Windows.Forms.Button();
this.cancelButton = new System.Windows.Forms.Button();
this.editWriterButton = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// writersComboBox
//
this.writersComboBox.FormattingEnabled = true;
this.writersComboBox.Location = new System.Drawing.Point(121, 27);
this.writersComboBox.Name = "writersComboBox";
this.writersComboBox.Size = new System.Drawing.Size(392, 21);
this.writersComboBox.TabIndex = 0;
//
// writerLabel
//
this.writerLabel.AutoSize = true;
this.writerLabel.Location = new System.Drawing.Point(36, 30);
this.writerLabel.Name = "writerLabel";
this.writerLabel.Size = new System.Drawing.Size(35, 13);
this.writerLabel.TabIndex = 1;
this.writerLabel.Text = "Writer";
//
// okButton
//
this.okButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.okButton.Location = new System.Drawing.Point(305, 68);
this.okButton.Name = "okButton";
this.okButton.Size = new System.Drawing.Size(92, 40);
this.okButton.TabIndex = 4;
this.okButton.Text = "OK";
this.okButton.UseVisualStyleBackColor = true;
this.okButton.Click += new System.EventHandler(this.okButton_Click);
//
// cancelButton
//
this.cancelButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.cancelButton.Location = new System.Drawing.Point(421, 68);
this.cancelButton.Name = "cancelButton";
this.cancelButton.Size = new System.Drawing.Size(92, 40);
this.cancelButton.TabIndex = 5;
this.cancelButton.Text = "Cancel";
this.cancelButton.UseVisualStyleBackColor = true;
this.cancelButton.Click += new System.EventHandler(this.cancelButton_Click);
//
// editWriterButton
//
this.editWriterButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
this.editWriterButton.Location = new System.Drawing.Point(121, 68);
this.editWriterButton.Name = "editWriterButton";
this.editWriterButton.Size = new System.Drawing.Size(92, 40);
this.editWriterButton.TabIndex = 6;
this.editWriterButton.Text = "Edit writer";
this.editWriterButton.UseVisualStyleBackColor = true;
this.editWriterButton.Click += new System.EventHandler(this.editPrinterButton_Click);
//
// WriteResultsSelectionDlg
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(546, 127);
this.Controls.Add(this.editWriterButton);
this.Controls.Add(this.cancelButton);
this.Controls.Add(this.okButton);
this.Controls.Add(this.writerLabel);
this.Controls.Add(this.writersComboBox);
this.Name = "WriteResultsSelectionDlg";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Database and water meter selection";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.ComboBox writersComboBox;
private System.Windows.Forms.Label writerLabel;
private System.Windows.Forms.Button okButton;
private System.Windows.Forms.Button cancelButton;
private System.Windows.Forms.Button editWriterButton;
}
}
@@ -0,0 +1,86 @@
///
/// Copyright (c) 2023 Sensus Slovensko a.s.
///
using Common;
using NHibernate;
using Results.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using TBF.Resources;
using TBF.Rig.Generic;
using TBF.Rig.GenericDevices;
using TBF.UI.Bench.Components;
using Config.Entities;
namespace TBF.UI.ResultsMI
{
public partial class WriteResultsSelectionDlg : Form
{
readonly IList<IResultsWriter> writers;
public IResultsWriter SelectedWriter;
public Batch batch;
public WriteResultsSelectionDlg(IList<IResultsWriter> writer, Batch batch)
{
this.writers = writer;
this.batch = batch;
InitializeComponent();
this.Icon = Properties.Resources.TBF_icon;
Localize();
if (writer != null)
foreach (var p in writer)
writersComboBox.Items.Add(p.Name);
}
void Localize()
{
Text = Strings.Writer_selection;
writerLabel.Text = Strings.Writer;
okButton.Text = Strings.OkBtnText;
cancelButton.Text = Strings.CancelBtnText;
}
private void okButton_Click(object sender, EventArgs e)
{
if (writersComboBox.SelectedItem != null)
{
SelectedWriter = writers.FirstOrDefault(x => x.Name == writersComboBox.SelectedItem.ToString());
}
if (SelectedWriter == null)
{
MessageBox.Show("Invalid selection");
return;
}
DialogResult = DialogResult.OK;
Close();
}
private void cancelButton_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
Close();
}
private void editPrinterButton_Click(object sender, EventArgs e)
{
if (writers != null)
foreach (var p in writers)
if (p.Cfg.Name == writersComboBox.Text)
{
ComponentParametersDlg writerCfgForm = new ComponentParametersDlg(this, p.Cfg.Id);
writerCfgForm.ComponentCfgCtrl = p.Cfg.GetControl(null);
writerCfgForm.ComponentCfgCtrl.Config = p.Cfg;
DialogResult dr = writerCfgForm.ShowDialog();
if (dr != DialogResult.OK) return;
}
}
}
}
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>