Mike Phares 3c30da0bb1 Removed Infineon.Mesa.gpcl6 and added Includes
Bug in yml
dotnet tool
PackageReference arrangement
RDS Blank
Change int dotnet test
nuget ^
[spcepiworld].[dbo].[evnt_inf]
Assembly Version
WS Result bug fix and Nuget bump, PSN, Reactor and Extra RDS rule
OpenInsightApi and testRunTitle
editorconfig bugs
Fix Type
serializerValue
RDS oversight
PropertyNameCaseInsensitive
SP1 was different
Save check for file already present
NoWaitDirectory
MoveArchive allow empty directory and continueOnError for clean files
CreatePointerFile and more on NoWaitDirectory
2023-03-20 14:35:35 -07:00

486 lines
20 KiB
C#

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace Adaptation.FileHandlers.TIBCO.Transport;
public class Job
{
#nullable restore
public string AutomationMode { get; }
public string BasicType { get; }
public string CreationUser { get; }
public string Equipment { get; }
public string JobName { get; }
public string LastUpdateUser { get; }
public string LotName { get; }
public string LotState { get; }
public string PackageName { get; }
public string ProcessSpecName { get; }
public string ProcessType { get; }
public string ProductName { get; }
public string Qty { get; }
public string Qty2 { get; }
public string RecipeName { get; }
public string SpecName { get; }
public string StateModel { get; }
public string Status { get; }
//
public bool IsAreaSi { get; }
public DateTime DateTime { get; }
public List<Item> Items { get; }
public Job(string lsl2SQLConnectionString, string metrologyFileShare, string mid)
{
const int zero = 0;
Items = new List<Item>();
if (string.IsNullOrEmpty(mid) || mid[zero] != '{' || mid[mid.Length - 1] != '}' || !mid.Contains("\"Si\""))
IsAreaSi = false;
else
{
string psn;
string zone;
string layer;
int? rdsNumber;
string comment;
const string hyphen = "-";
Input input = JsonSerializer.Deserialize<Input>(mid);
if (!long.TryParse(input.Sequence, out long sequence))
DateTime = DateTime.Now;
else
DateTime = new DateTime(sequence);
int? reactorNumber = GetReactorNumber(input);
(int? workOrderNumber, int? _, int? workOrderCassette, int? slotNumber, bool isWorkOrder) = GetWorkOrder(input);
if (isWorkOrder || reactorNumber.HasValue)
(layer, psn, rdsNumber, zone) = (string.Empty, string.Empty, null, string.Empty);
else if (!string.IsNullOrEmpty(input.MID) && input.MID.Length is not 2 and not 3)
(layer, psn, rdsNumber, reactorNumber, zone) = Get(input);
else
(layer, psn, rdsNumber, reactorNumber, zone) = Get(metrologyFileShare, input);
if (IsValid(rdsNumber))
(comment, layer, rdsNumber, psn, reactorNumber, zone) = GetWithValidRDS(lsl2SQLConnectionString, layer, psn, rdsNumber, reactorNumber, zone);
else if (isWorkOrder || reactorNumber.HasValue)
(comment, layer, rdsNumber, psn, reactorNumber, zone) = Get(lsl2SQLConnectionString, layer, psn, reactorNumber, slotNumber, workOrderNumber, workOrderCassette, zone);
else
(comment, layer, zone) = (hyphen, hyphen, hyphen);
Qty = "1";
Status = hyphen; // INFO
CreationUser = hyphen; // ?
LotState = hyphen; // LAYER2
LastUpdateUser = hyphen; // ?
Equipment = input.MesEntity; // ?
PackageName = hyphen; // WAFER_ID
Qty2 = input.Sequence; // SEQUENCE
RecipeName = input.Recipe; // PPID
IsAreaSi = input.Area == "Si"; // N/A
StateModel = input.EquipmentType; // ?
JobName = DateTime.Ticks.ToString(); // ?
SpecName = !string.IsNullOrEmpty(layer) ? layer : hyphen; // LAYER
ProductName = !string.IsNullOrEmpty(psn) ? psn : hyphen; // PRODUCT
AutomationMode = string.Concat(DateTime.Ticks, ".", input.MesEntity); // ?
ProcessSpecName = !string.IsNullOrEmpty(zone) ? zone : hyphen; // WAFER_POS
BasicType = !string.IsNullOrEmpty(comment) ? comment : hyphen; // BASIC_TYPE
LotName = rdsNumber is not null ? rdsNumber.Value.ToString() : hyphen; // MID
ProcessType = reactorNumber is not null ? reactorNumber.Value.ToString() : hyphen; // PROCESS_JOBID
Items.Add(new Item { Name = "0", Type = "NA", Number = (0 + 1).ToString(), Qty = "1", CarrierName = hyphen });
}
}
private static int? GetReactorNumber(Input input)
{
int? result;
bool isReactor = !string.IsNullOrEmpty(input.MID) && input.MID.Length == 2 && Regex.IsMatch(input.MID, "^[0-9]{2}$");
if (!isReactor)
result = null;
else if (!int.TryParse(input.MID, out int reactor))
result = null;
else
result = reactor;
return result;
}
private static (int?, int?, int?, int?, bool) GetWorkOrder(Input input)
{
int? slotNumber;
int? workOrderStep = null;
int? workOrderNumber = null;
MatchCollection[] collection;
int? workOrderCassette = null;
if (string.IsNullOrEmpty(input.MID))
collection = Array.Empty<MatchCollection>();
else
{
string pattern = @"^([oiOI])?([0-9]{6,7})\.([0-5]{1})\.([0-9]{1,2})$"; // o171308.1.51
collection = (from l in input.MID.Split('-') select Regex.Matches(l, pattern)).ToArray();
}
foreach (MatchCollection matchCollection in collection)
{
if (matchCollection.Count == 0)
continue;
if (!matchCollection[0].Success || matchCollection[0].Groups.Count != 5)
continue;
if (!int.TryParse(matchCollection[0].Groups[3].Value, out int workOrderStepValue))
continue;
if (!int.TryParse(matchCollection[0].Groups[2].Value, out int workOrderNumberValue))
continue;
if (!int.TryParse(matchCollection[0].Groups[4].Value, out int workOrderCassetteValue))
continue;
workOrderStep = workOrderStepValue;
workOrderNumber = workOrderNumberValue;
workOrderCassette = workOrderCassetteValue;
break;
}
if (string.IsNullOrEmpty(input.Slot) || !int.TryParse(input.Slot, out int slot))
slotNumber = null;
else
slotNumber = slot;
return new(workOrderNumber, workOrderStep, workOrderCassette, slotNumber, workOrderStep is not null || workOrderNumber is not null || workOrderCassette is not null);
}
private static bool IsValid(int? rdsNumber) => !IsInvalid(rdsNumber);
private static bool IsInvalid(int? rdsNumber) => rdsNumber is null or < 100000 or > 100000000;
private static (string, string) GetReactorAndRDS(string defaultReactor, string defaultRDS, string text, string formattedText, string[] segments, bool hasRDS)
{
string rds;
string reactor;
if (string.IsNullOrEmpty(text) || segments.Length == 0 || string.IsNullOrEmpty(formattedText) || (segments.Length > 1 && !hasRDS))
reactor = defaultReactor;
else
reactor = segments[0];
if (segments.Length <= 1 || !int.TryParse(segments[1], out int rdsValue) || rdsValue < 99)
rds = defaultRDS;
else
rds = segments[1];
if (reactor.Length > 3)
{
rds = reactor;
reactor = defaultReactor;
}
return new(reactor, rds);
}
private static (string, string) GetLayerAndPSN(string defaultLayer, string defaultPSN, string[] segments, bool hasRDS)
{
string psn;
string layer;
if (segments.Length <= 2 || (segments.Length > 1 && !hasRDS))
{
psn = defaultPSN;
layer = defaultLayer;
}
else
{
string[] segmentsB = segments[2].Split('.');
psn = segmentsB[0];
if (segmentsB.Length <= 1)
layer = defaultLayer;
else
{
layer = segmentsB[1];
if (layer.Length > 1 && layer[0] == '0')
layer = layer.Substring(1);
}
}
return (layer, psn);
}
private static string GetZone(string[] segments)
{
string result;
if (segments.Length <= 3)
result = string.Empty;
else
{
result = segments[3];
if (result.Length > 1 && result[0] == '0')
result = result.Substring(1);
}
return result;
}
private static (string, string, int, int?, string) Get(Input input)
{
string psn;
string rds;
string zone;
string layer;
int rdsNumber;
string reactor;
int? reactorNumber;
string defaultPSN = string.Empty;
string defaultRDS = string.Empty;
string defaultLayer = string.Empty;
string defaultReactor = string.Empty;
string[] segments = input.MID.Split(new char[] { '-' });
bool hasRDS = Regex.IsMatch(input.MID, "[-]?[0-9]{5,}[-]?");
string formattedText = Regex.Replace(input.MID, @"[\\,\/,\:,\*,\?,\"",\<,\>,\|]", "_").Split('\r')[0].Split('\n')[0];
(reactor, rds) = GetReactorAndRDS(defaultReactor, defaultRDS, input.MID, formattedText, segments, hasRDS);
if (string.IsNullOrEmpty(rds))
rdsNumber = 0;
else
_ = int.TryParse(segments[1], out rdsNumber);
if (IsInvalid(rdsNumber) || !int.TryParse(reactor, out int reactorCheck))
{
psn = string.Empty;
zone = string.Empty;
layer = string.Empty;
reactorNumber = null;
}
else
{
reactorNumber = reactorCheck;
(layer, psn) = GetLayerAndPSN(defaultLayer, defaultPSN, segments, hasRDS);
zone = GetZone(segments);
}
return new(layer, psn, rdsNumber, reactorNumber, zone);
}
private static (string, string, int?, int?, string) Get(string metrologyFileShare, Input input)
{
string[] files;
string[] lines;
string moveFile;
int? reactor = null;
int? rdsNumber = null;
string psn = string.Empty;
string zone = string.Empty;
string layer = string.Empty;
string usedDirectory = Path.Combine(metrologyFileShare, "Used");
if (!Directory.Exists(metrologyFileShare))
throw new Exception($"Unable to access file-share <{metrologyFileShare}>");
if (!Directory.Exists(usedDirectory))
_ = Directory.CreateDirectory(usedDirectory);
if (string.IsNullOrEmpty(input.MID))
files = Array.Empty<string>();
else
files = Directory.GetFiles(metrologyFileShare, $"*-{input.MID}.rsv", SearchOption.TopDirectoryOnly);
foreach (string file in files.OrderByDescending(l => new FileInfo(l).LastWriteTime))
{
lines = File.ReadAllLines(file);
foreach (string line in lines)
{
if (string.IsNullOrEmpty(line))
continue;
if (!int.TryParse(line, out int rds) || IsInvalid(rds))
continue;
rdsNumber = rds;
break;
}
if (rdsNumber is not null)
{
moveFile = Path.Combine(usedDirectory, Path.GetFileName(file));
if (File.Exists(moveFile))
File.Delete(file);
else
File.Move(file, moveFile);
break;
}
}
return new(layer, psn, rdsNumber, reactor, zone);
}
private static string GetRunJson(string lsl2SQLConnectionString, int? rds, int? workOrderNumber, int? workOrderCassette, int? slot, int? reactor)
{
StringBuilder result = new();
string commandText = GetCommandText(rds, workOrderNumber, workOrderCassette, slot, reactor);
try
{
using SqlConnection sqlConnection = new(lsl2SQLConnectionString);
sqlConnection.Open();
using SqlCommand sqlCommand = new(commandText, sqlConnection);
SqlDataReader sqlDataReader = sqlCommand.ExecuteReader(CommandBehavior.SequentialAccess);
while (sqlDataReader.Read())
_ = result.Append(sqlDataReader.GetString(0));
}
catch (Exception)
{
_ = result.Clear();
}
return result.ToString();
}
private static string GetCommandText(int? rds, int? workOrderNumber, int? workOrderCassette, int? slot, int? reactor)
{
StringBuilder result = new();
_ = result.Append(" select ").
Append(" rr.rds_no ").
Append(" , rr.reactor ").
Append(" , rr.ps_no ").
Append(" , rr.load_lock_side ").
Append(" , rr.reactor_type ").
Append(" , rr.recipe_name ").
Append(" , rr.recipe_no ").
Append(" , rr.spec_type ").
Append(" , ( ").
Append(" select max(wm.zone) ").
Append(" from lsl2sql.dbo.wm_in_slot_no wm ").
Append(" where wm.wo_no = rr.wo_no ").
Append(" and wm.rds_no = rr.rds_no ").
Append(" and wm.in_cass_no = ").Append(workOrderCassette is null ? -1 : workOrderCassette.Value).Append(' ').
Append(" and wm.slot_no = ").Append(slot is null ? -1 : slot.Value).Append(' ').
Append(" ) zone ").
Append(" from lsl2sql.dbo.react_run rr ").
Append(" where rr.rds_no = ").Append(rds is null ? -1 : rds.Value).Append(' ').
Append(" union all ").
Append(" select ").
Append(" rr.rds_no ").
Append(" , rr.reactor ").
Append(" , rr.ps_no ").
Append(" , rr.load_lock_side ").
Append(" , rr.reactor_type ").
Append(" , rr.recipe_name ").
Append(" , rr.recipe_no ").
Append(" , rr.spec_type ").
Append(" , ( ").
Append(" select max(wm.zone) ").
Append(" from lsl2sql.dbo.wm_in_slot_no wm ").
Append(" where wm.wo_no = rr.wo_no ").
Append(" and wm.rds_no = rr.rds_no ").
Append(" and wm.in_cass_no = ").Append(workOrderCassette is null ? -1 : workOrderCassette.Value).Append(' ').
Append(" and wm.slot_no = ").Append(slot is null ? -1 : slot.Value).Append(' ').
Append(" ) zone ").
Append(" from lsl2sql.dbo.react_run rr ").
Append(" where rr.rds_no = ( ").
Append(" select max(wm.rds_no) ").
Append(" from lsl2sql.dbo.wm_in_slot_no wm ").
Append(" where wm.wo_no = ").Append(workOrderNumber is null ? -1 : workOrderNumber.Value).Append(' ').
Append(" and wm.in_cass_no = ").Append(workOrderCassette is null ? -1 : workOrderCassette.Value).Append(' ').
Append(" and wm.slot_no = ").Append(slot is null ? -1 : slot.Value).Append(' ').
Append(" ) ").
Append(" union all ").
Append(" select ").
Append(" rr.rds_no ").
Append(" , rr.reactor ").
Append(" , rr.ps_no ").
Append(" , rr.load_lock_side ").
Append(" , rr.reactor_type ").
Append(" , rr.recipe_name ").
Append(" , rr.recipe_no ").
Append(" , rr.spec_type ").
Append(" , ( ").
Append(" select max(wm.zone) ").
Append(" from lsl2sql.dbo.wm_in_slot_no wm ").
Append(" where wm.wo_no = rr.wo_no ").
Append(" and wm.rds_no = rr.rds_no ").
Append(" and wm.in_cass_no = ").Append(workOrderCassette is null ? -1 : workOrderCassette.Value).Append(' ').
Append(" and wm.slot_no = ").Append(slot is null ? -1 : slot.Value).Append(' ').
Append(" ) zone ").
Append(" from lsl2sql.dbo.react_run rr ").
Append(" where rr.rds_no = ( ").
Append(" select max(qa.rds_no) ").
Append(" from lsl2sql.dbo.react_run qa ").
Append(" where qa.load_sig != '' ").
Append(" and qa.load_sig_dtm > '2022-07-01 00:00:00.000' ").
Append(" and qa.reactor = ").Append(reactor is null ? -1 : reactor.Value).Append(' ').
Append(" ) ").
Append(" for json path ");
return result.ToString();
}
private static (string, string, int?, string, int?, string) Get(string lsl2SQLConnectionString, string layer, string psn, int? reactorNumber, int? slotNumber, int? workOrderNumber, int? workOrderCassette, string zone)
{
int? rdsNumber;
string comment;
const int zero = 0;
const string hyphen = "-";
string json = GetRunJson(lsl2SQLConnectionString, rds: null, workOrderNumber, workOrderCassette, slotNumber, reactorNumber);
if (string.IsNullOrEmpty(json))
{
rdsNumber = null;
comment = hyphen;
psn = string.Empty;
zone = string.Empty;
}
else
{
Run[] runs;
try
{ runs = JsonSerializer.Deserialize<Run[]>(json); }
catch (Exception)
{ runs = Array.Empty<Run>(); }
if (!runs.Any())
{
rdsNumber = null;
comment = hyphen;
psn = string.Empty;
zone = string.Empty;
}
else
{
rdsNumber = runs[zero].RdsNo;
if (string.IsNullOrEmpty(psn))
psn = runs[zero].PSN;
if (string.IsNullOrEmpty(zone))
zone = runs[zero].Zone;
if (string.IsNullOrEmpty(layer))
layer = runs[zero].EpiLayer;
reactorNumber = runs[zero].Reactor;
string loadLockSide = runs[zero].LoadLockSide;
string loadLockSideFull = loadLockSide switch
{
"L" => "Left",
"R" => "Right",
_ => loadLockSide,
};
comment = $"{loadLockSideFull} - {runs[zero].ReactorType}";
}
}
return new(comment, layer, rdsNumber, psn, reactorNumber, zone);
}
private static (string, string, int?, string, int?, string) GetWithValidRDS(string lsl2SQLConnectionString, string layer, string psn, int? rdsNumber, int? reactorNumber, string zone)
{
string comment;
const int zero = 0;
const string hyphen = "-";
string json = GetRunJson(lsl2SQLConnectionString, rdsNumber, workOrderNumber: null, workOrderCassette: null, slot: null, reactor: null);
if (string.IsNullOrEmpty(json))
{
comment = hyphen;
zone = string.Empty;
}
else
{
Run[] runs;
try
{ runs = JsonSerializer.Deserialize<Run[]>(json); }
catch (Exception)
{ runs = Array.Empty<Run>(); }
if (!runs.Any())
{
comment = hyphen;
zone = string.Empty;
}
else
{
if (string.IsNullOrEmpty(psn))
psn = runs[zero].PSN;
if (string.IsNullOrEmpty(zone))
zone = runs[zero].Zone;
if (string.IsNullOrEmpty(layer))
layer = runs[zero].EpiLayer;
reactorNumber = runs[zero].Reactor;
string loadLockSide = runs[zero].LoadLockSide;
string loadLockSideFull = loadLockSide switch
{
"L" => "Left",
"R" => "Right",
_ => loadLockSide,
};
comment = $"{loadLockSideFull} - {runs[zero].ReactorType}";
}
}
return new(comment, layer, rdsNumber, psn, reactorNumber, zone);
}
}