TBF : Output.DB.ProductionMonitoring --> Output.DB.ProductionTracing.

This commit is contained in:
Milan Hanajik
2018-08-28 10:12:39 +02:00
parent fa818c5cf8
commit 6aee0a71ed
11 changed files with 60 additions and 60 deletions
@@ -0,0 +1,48 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
namespace TBF.BenchControl.Output.DB.ProductionTracing
{
public enum CodeType
{
UniqueNr,
FlowtubeNr, /// Prvé 3 znaky sa zhodujú s poslednými 3 znakmi názvu
FlowtubeNrLU, /// Začiatok kódu sa zhoduje s názvom
BatchNr,
BatchNrContainingPartName,
DateMMYY,
QualityCheck,
}
public enum CodeForm
{
Barcode,
QRCode,
Keyboard,
OkNok,
}
public enum CodeLocation
{
OnPart,
OnPallet,
}
public enum LifetimeManagement
{
None,
OneYear,
Count,
}
public enum ReleaseStatus
{
In_preparation,
Released,
ReleasedActive,
Deactivated,
Count,
}
}
@@ -0,0 +1,26 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System.Collections.Generic;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Output.DB.ProductionTracing
{
public class Factory : IComponentFactory
{
public string ClassName { get { return this.GetType().Namespace.Substring(17); } }
public void ResetStaticProperties() { Tracing.ResetStaticProperties(); }
public IComponent DummyComponent() { return new Tracing(); }
public IComponent GetComponent(IComponentCfg cfg, IList<IComponent> components) { return new Tracing(cfg); }
public IComponentCfg DefaultConfig() { return new TracingCfg(this.GetType().Namespace.Substring(24), this); }
public IComponentCfg CmpntCfgFromCmpntEntity(Config.Entities.Component component)
{
return ComponentCfgBase.CreateFromDbEntity(TracingCfg.Serializer, component, this);
}
}
}
@@ -0,0 +1,246 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using log4net;
using NHibernate;
using Config.Entities;
using TracingDB.Entities;
namespace TBF.BenchControl.Output.DB.ProductionTracing
{
public enum Retv
{
OK,
Error,
}
public class Tracing : ComponentBase, IOperation, GenericDevices.IResultsWriter, Generic.IDevice
{
private static readonly ILog log = LogManager.GetLogger(typeof(Tracing));
public override string ToString() { return string.Format("Monitoring({0})", Cfg.ToString(1)); }
public const string WorkstepName = "Test_bench";
TracingCfg monitoringCfg;
string workplace { get { return monitoringCfg.Workplace; } }
enum CurrentOp
{
None,
SaveMonitoringRecords,
}
CurrentOp currentOp;
bool opCompleted;
bool anyError;
/// <summary>
/// Results to print
/// </summary>
Results.Entities.Batch batch;
ISessionFactory sessionFactory; /// Factory to create database sessions initialized in the constructor
IList<Process> processes;
Dictionary<int, Process> processDictionary;
Dictionary<int, IList<Workstep>> workstepsDictionary;
public Tracing() {}
public Tracing(Generic.IComponentCfg cfg)
: base(cfg)
{
monitoringCfg = cfg as TracingCfg;
currentOp = CurrentOp.None;
log.Debug(this.ToString());
}
public void Initialize()
{
if (monitoringCfg.DebugLevel == DebugMode.Simulate) return;
///
/// Session factory is used to create database sessions
///
sessionFactory = FluentNHibernate.Cfg.Fluently
.Configure()
.Database(FluentNHibernate.Cfg.Db.MySQLConfiguration.Standard.ConnectionString(monitoringCfg.ConnStr))
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<TracingDB.Entities.Process>())
.ExposeConfiguration(TracingDB.DB.BuildSchema)
.BuildSessionFactory();
///
/// Read processes and worksteps from the database (this verifies DB connection as well)
///
log.WarnFormat("Reading processes/worksteps from production monitoring DB started");
ReadProcessesFromDB(sessionFactory.OpenSession());
log.WarnFormat("Reading processes/worksteps from production monitoring DB completed");
}
public void RunDeviceBefore() { }
public void RunDeviceAfter() {}
public void StopDevice() {}
public void StopDevice2() {}
/// <summary>
/// Writes the test cycle results into a file, Events: Event.ResultsWritten
/// </summary>
/// <param name="procedure">Procedure to print the results of</param>
/// <param name="unsortedResults">Results to write into the file</param>
/// <returns>Reference to the operation</returns>
public IOperation WriteResultsOp(Results.Entities.Batch batch)
{
if (currentOp != CurrentOp.None)
throw new Exception("Sequence error");
else
currentOp = CurrentOp.SaveMonitoringRecords;
this.batch = batch;
return this;
}
/// <summary>Start this operation</summary>
public void Start()
{
opCompleted = false;
anyError = false;
}
/// <summary>Run this operation</summary>
/// <returns>Event.ResultsWritten or Event.Error</returns>
public Event Run()
{
if (monitoringCfg.DebugLevel == DebugMode.Simulate || batch.WaterMeters.Count == 0)
{
opCompleted = true;
return Event.ResultsWritten;
}
if (currentOp == CurrentOp.SaveMonitoringRecords)
{
if (!opCompleted)
{
ITransaction transaction = null;
try
{
ISession session = sessionFactory.OpenSession();
transaction = session.BeginTransaction();
int wrCount = WriteResultsToDatabase(session, batch);
transaction.Commit();
session.Flush();
opCompleted = true;
log.ErrorFormat("Batch {0}: {1} of {2} watermeters written to production monitoring DB",
batch.BatchNr, wrCount, batch.WaterMeters.Count);
}
catch (Exception exc)
{
if (transaction != null && !transaction.WasCommitted) transaction.Rollback();
anyError = true;
log.WarnFormat("Failed to write batch {0} results to production monitoring DB: {1}",
batch.BatchNr, exc.Message);
}
}
if (anyError)
return Event.ResultsNotWritten;
else
return Event.ResultsWritten;
}
else
{
return Event.None;
}
}
/// <summary>Stop this operation</summary>
public void Stop()
{
currentOp = CurrentOp.None;
}
/// <summary>
/// Write results of a batch of water meters to the DB
/// </summary>
/// <param name="session">DB session</param>
/// <param name="batch">Batch entity</param>
int WriteResultsToDatabase(ISession session, Results.Entities.Batch batch)
{
int wrCount = 0;
foreach (var wMtr in batch.WaterMeters)
{
wrCount += SaveSingleWM2DB(session, wMtr);
}
return wrCount;
}
/// <summary>
/// Write one meter results to the DB
/// </summary>
/// <param name="session">DB session</param>
/// <param name="wm">Watermeter entity</param>
/// <returns>Number of written reference record</returns>
int SaveSingleWM2DB(ISession session, Results.Entities.WaterMeter wm)
{
if (string.IsNullOrEmpty(wm.SerialNr)) return 0; /// Without PCB number there is no DB activity
///
/// Get all already existing reference records with Code == wm.SerialNr, refRecords[0] will be the most recent one
///
IList<ReferenceRecord> refRecords;
int trialsCount = 0;
do
{
if (trialsCount > 0) ReadProcessesFromDB(session);
refRecords = session.QueryOver<ReferenceRecord>()
.Where(rr => (rr.Code == wm.SerialNr))
.OrderBy(rr => rr.TimeStamp).Desc
.List();
trialsCount++;
}
while (refRecords.Count == 0 && trialsCount <= 2);
///
/// Save a new reference record from this test bench if workstep "Test_bench" is defined in the obtained WM process
///
IList<Workstep> worksteps;
if ((refRecords.Count > 0) && workstepsDictionary.TryGetValue(refRecords[0].Process.Id, out worksteps) && (worksteps.Count == 1))
{
session.SaveOrUpdate(new ReferenceRecord(refRecords[0].Process, worksteps[0], wm.SerialNr, Users.GlobalData.CurrentUser.UserName, workplace, wm.Passed ? 0 : 1));
return 1;
}
return 0;
}
/// <summary>
/// Updates processes, processDictionary and workstepsDictionary
/// </summary>
/// <param name="session">DB session</param>
void ReadProcessesFromDB(ISession session)
{
processes = session.QueryOver<Process>().List();
processDictionary = new Dictionary<int, Process>();
workstepsDictionary = new Dictionary<int, IList<Workstep>>();
foreach (var pr in processes)
{
IList<Workstep> worksteps = session.QueryOver<Workstep>().Where(ws => ((ws.Process == pr) && (ws.Name == WorkstepName))).List();
processDictionary.Add(pr.Id, pr);
workstepsDictionary.Add(pr.Id, worksteps);
}
}
}
}
@@ -0,0 +1,41 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System.Xml.Serialization;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Output.DB.ProductionTracing
{
public class TracingCfg : ComponentCfgBase, Generic.IComponentCfg
{
public static XmlSerializer Serializer = XmlSerializer.FromTypes(new[] { typeof(TracingCfg) })[0];
public override XmlSerializer GetSerializer() { return Serializer; }
public IComponentCfgCtrl GetControl() { return new TracingCfgCtrl(); }
public string Workplace;
public string ConnStr;
/// Private parameterless constructor invoked by all other (public) constructors
TracingCfg()
{
ParentName = string.Empty;
Workplace = "WR10";
ConnStr = "SERVER=10.42.128.16; DATABASE=st_wr_shared_config; UID=u9305784; PASSWORD=p89344390; CHARSET=utf8;";
}
public TracingCfg(string name, IComponentFactory factory)
: this()
{
this.Name = name;
this.Factory = factory;
}
public string ToString(int i)
{
return string.Format("Name={0}, Workplace={1}", Name, Workplace);
}
}
}
@@ -0,0 +1,80 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
using System.Windows.Forms;
using Config.Entities;
using TBF.BenchControl.Generic;
namespace TBF.BenchControl.Output.DB.ProductionTracing
{
public partial class TracingCfgCtrl : Configs.ConfigCtrlUtils, IComponentCfgCtrl
{
public bool ShowMore { get { return false; } }
TracingCfg config;
public IComponentCfg Config
{
get { return config as IComponentCfg; }
set
{
config = value as TracingCfg;
Redraw();
}
}
public TracingCfgCtrl()
{
InitializeComponent();
}
private void WriterCfgCtrl_Load(object sender, EventArgs e)
{
Redraw();
}
public void Closing()
{
}
void Redraw()
{
if (config == null) return; /// Control was not loaded, settings were not changed
classNameLabel.Text = config.Factory.ClassName;
nameTextBox.Text = config.Name;
workplaceTextBox.Text = config.Workplace;
connStrTextBox.Text = config.ConnStr;
}
public void Unlock()
{
nameTextBox.Enabled = true;
workplaceTextBox.Enabled = true;
connStrTextBox.Enabled = true;
}
public CfgUpdateFlags VerifyCfg(ref string message)
{
return CfgUpdateFlags.None;
}
public CfgUpdateFlags UpdateCfg()
{
CfgUpdateFlags flags = CfgUpdateFlags.None;
if (config == null) return CfgUpdateFlags.Error; /// Control was not loaded, settings were not changed
if (config.Name != nameTextBox.Text)
{
config.Name = nameTextBox.Text;
flags |= CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd;
}
flags |= UpdateDifferent(ref config.Workplace, workplaceTextBox.Text, CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
flags |= UpdateDifferent(ref config.ConnStr, connStrTextBox.Text, CfgUpdateFlags.AnyChange | CfgUpdateFlags.RestartRqrd);
return flags;
}
}
}
@@ -0,0 +1,132 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
namespace TBF.BenchControl.Output.DB.ProductionTracing
{
partial class TracingCfgCtrl
{
/// <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 Component 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.nameTextBox = new System.Windows.Forms.TextBox();
this.nameLabel = new System.Windows.Forms.Label();
this.classNameLabel = new System.Windows.Forms.Label();
this.workplaceTextBox = new System.Windows.Forms.TextBox();
this.workplaceLabel = new System.Windows.Forms.Label();
this.connStrTextBox = new System.Windows.Forms.TextBox();
this.connStrLabel = new System.Windows.Forms.Label();
this.SuspendLayout();
//
// nameTextBox
//
this.nameTextBox.Enabled = false;
this.nameTextBox.Location = new System.Drawing.Point(110, 41);
this.nameTextBox.Name = "nameTextBox";
this.nameTextBox.Size = new System.Drawing.Size(146, 20);
this.nameTextBox.TabIndex = 2;
//
// nameLabel
//
this.nameLabel.AutoSize = true;
this.nameLabel.Location = new System.Drawing.Point(15, 44);
this.nameLabel.Name = "nameLabel";
this.nameLabel.Size = new System.Drawing.Size(35, 13);
this.nameLabel.TabIndex = 1;
this.nameLabel.Text = "Name";
//
// classNameLabel
//
this.classNameLabel.AutoSize = true;
this.classNameLabel.Location = new System.Drawing.Point(107, 19);
this.classNameLabel.Name = "classNameLabel";
this.classNameLabel.Size = new System.Drawing.Size(83, 13);
this.classNameLabel.TabIndex = 0;
this.classNameLabel.Text = "ComonentName";
//
// workplaceTextBox
//
this.workplaceTextBox.Enabled = false;
this.workplaceTextBox.Location = new System.Drawing.Point(110, 67);
this.workplaceTextBox.Name = "workplaceTextBox";
this.workplaceTextBox.Size = new System.Drawing.Size(146, 20);
this.workplaceTextBox.TabIndex = 4;
//
// workplaceLabel
//
this.workplaceLabel.AutoSize = true;
this.workplaceLabel.Location = new System.Drawing.Point(15, 70);
this.workplaceLabel.Name = "workplaceLabel";
this.workplaceLabel.Size = new System.Drawing.Size(59, 13);
this.workplaceLabel.TabIndex = 3;
this.workplaceLabel.Text = "Workplace";
//
// connStrTextBox
//
this.connStrTextBox.Enabled = false;
this.connStrTextBox.Location = new System.Drawing.Point(110, 93);
this.connStrTextBox.Name = "connStrTextBox";
this.connStrTextBox.Size = new System.Drawing.Size(327, 20);
this.connStrTextBox.TabIndex = 22;
//
// connStrLabel
//
this.connStrLabel.AutoSize = true;
this.connStrLabel.Location = new System.Drawing.Point(15, 96);
this.connStrLabel.Name = "connStrLabel";
this.connStrLabel.Size = new System.Drawing.Size(89, 13);
this.connStrLabel.TabIndex = 21;
this.connStrLabel.Text = "Connection string";
//
// MonitoringCfgCtrl
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.connStrTextBox);
this.Controls.Add(this.connStrLabel);
this.Controls.Add(this.workplaceTextBox);
this.Controls.Add(this.workplaceLabel);
this.Controls.Add(this.nameTextBox);
this.Controls.Add(this.nameLabel);
this.Controls.Add(this.classNameLabel);
this.Name = "MonitoringCfgCtrl";
this.Size = new System.Drawing.Size(450, 230);
this.Load += new System.EventHandler(this.WriterCfgCtrl_Load);
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.TextBox nameTextBox;
private System.Windows.Forms.Label nameLabel;
private System.Windows.Forms.Label classNameLabel;
private System.Windows.Forms.TextBox workplaceTextBox;
private System.Windows.Forms.Label workplaceLabel;
private System.Windows.Forms.TextBox connStrTextBox;
private System.Windows.Forms.Label connStrLabel;
}
}
@@ -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>
@@ -0,0 +1,61 @@
///
/// Copyright (c) 2018 Sensus Slovensko a.s.
///
using System;
using System.Collections.Generic;
using MySql.Data.MySqlClient;
namespace TBF.BenchControl.Output.DB.ProductionTracing
{
public class WMPart
{
public string Name;
public int ProcessId;
public string OraDBType;
public string Description;
public string Code;
public DateTime TimeStamp;
public CodeType CodeType;
public CodeForm CodeForm;
public CodeLocation CodeLocation;
public string UserName;
public string Workplace;
public WMPart() {}
public static IList<WMPart> FindWMParts(MySqlConnection dbConn, string pcbNumber)
{
IList<WMPart> foundParts = new List<WMPart>(); /// initially empty
if (string.IsNullOrEmpty(pcbNumber)) return foundParts; /// return an empty list
try
{
dbConn.Open();
//IList<Entities.ReferenceRecord> referenceRecords = session
// .QueryOver<Entities.ReferenceRecord>()
// .Where(x => (x.Code == pcbNumber))
// .OrderBy(x => x.TimeStamp).Desc
// .List<Entities.ReferenceRecord>();
MySqlCommand cmd = dbConn.CreateCommand();
cmd.CommandText = string.Format("SELECT Id, TimeStamp, UserName, Workplace, Result, Process_id, Workstep_id FROM ReferenceRecord WHERE Code = {0}", pcbNumber);
cmd.ExecuteNonQuery();
MySqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
foundParts.Add( new WMPart() { Code = pcbNumber, ProcessId = dr.GetInt32(5), /* etc */ } );
}
dr.Close();
cmd.Dispose();
}
catch
{
}
return foundParts;
}
}
}