using System; using System.Data; using System.Threading; using System.Threading.Tasks; using DataservCycle; using DataservEngine3; using DataservEngine3.Components.Tags; using DataservEngine3.Components.Communications; using DataservEngine3.DataservData; using DataservPlugin; using System.Linq; using System.Data.SqlClient; using System.Collections.Generic; using System.Windows.Forms; [PluginData(Name = "Carrier-MX-MES", Author = "Tim Dekker / Justin Gamble", Description = "Carrier MX uses Database Stored Procedures for Interaction - See Documentation @ `H:\\Appliance\\Customer\\Carrier\\Carrier Mexico Sanata Catarina\\Dataserv Integration`.")] public class CarrierMxMes : AbstractPlugin { bool _debug = true; private static string _carrierImportTagGroup = "Carrier_MX_MES_Info"; private static string _carrierImportErrorCode = "Error_Code";//0 = no error private static string _carrierImportErrorResponse = "Error_Response";//text private static string _carrierImportLastImportTimeName = "LastImportTime"; private static DateTime _carrierImportLastImportTime = DateTime.MinValue; private short _lastChargingFlag = 0; private bool _hasPromptedMesFlag = false; //TODO: Update with what the given system actually uses, error handle if its a single ref system. private static Dictionary> _carrierImportPartTranslation = new Dictionary> { { "Refrigerant", new Dictionary { {"134", "134"}, {"513", "513"}, {"410", "410"}, {"R-410A", "410"}, {"PS40-10A", "410"}, {"PS40-54A", "454"}, {"PS40-54B", "454"}, //PS40-10A {"454", "454"}, //MX A - may not be correct in production {"9", "410"}, {"8", "454"} } } }; private object _tagUpdateLock = new object(); private static CancellationTokenSource _cancelSource = new CancellationTokenSource(); private static Task _carrierImportImportTask; //Production Mode dictates if it is the "Residential" or "Commercial" version //Residential (SPP & SRT) = 1 - Badge, Cascade, Charging Params, Save //Commercial (LCV) = 2 - Badge, Cascade, Charging Params 1, "Save", Charging Params 2, "Save" //MX A = 3 - MasterKey, Params, "Save" //TODO: Environment Flag private static int _carrierMesProductionMode = 2; private static string _carrierMesAppConfigPath = @"c:\siq\App.Config.XML"; private static int _carrierMesAppChainId = -1; private static string _carrierMesAppLine = ""; private static int _carrierMesAppWorkStationId = -1; private static string _carrierMesConnectionString1 = "database=RLCSC_MES;server=dataservtest.siqinc.com;Application Name=DataServ.Net 3.0;Pwd=Dataserv1;User ID=serviquip"; private static string _carrierMesChainValue = ""; private static string _carrierMesLine = ""; private static string _carrierMesWorkStation = ""; //jrg 2023-10-12 MX A has an additional app.config flag for recipe filtering private static string _carrierMesLimitTypeID = ""; private const string CanRunUnit = "CanRunUnit"; private const string CanOverrideReworkUnit = "CanOverrideReworkUnit"; public override void OnEngineLoaded() { if (_debug) AddLogItem("Carrier-MX-MES - DEBUG - Assemblies Loaded."); InitializeTags(); LoadEnvironmentItems(); } private bool CurrentUserHasPermission( string userName, string permission ) { var user = Context.SecurityManager.GetUser(userName); var result = user != null && user.ChallengePermissions(permission); //if the user failed to challenge, let them know if (!result) { AddLogItem($"User {userName} did not have permissions to {permission}."); AddNotificationPrompt($"El usuario actual no tenía permisos para {permission}"); } return result; } public override bool OnScanItemsValidated( DataservEngine3.ScanItemCollection scanItems ) { LoadEnvironmentItems(); Context.DataservTaglist.Tag("TAGGROUP::DATASERVTAGS::TAG::CurrentCycleType").Value = scanItems["CYCLE"].Value; _hasPromptedMesFlag = false; if (_carrierMesProductionMode == 3) { //MX A does not do operator validation. return true; } if (!CurrentUserHasPermission(scanItems["Operator"].Value, CanRunUnit)) return false; //If they turned it to local mode, bypass fillin and do not contact MES if (_carrierMesProductionMode == 0) { scanItems["Model"].Value = scanItems["Serial Number"].Value; AddLogItem($"Model set to {scanItems["Model"].Value} for bypass."); } return true; } public override bool ShouldSkipCircuit( ScanItemCollection scanItems, Circuit circuit ) { AddLogItem($"Is nitrogen active on current recipe: {nitrogenCurrentRecipe}"); if(circuit.Name.StartsWith("Reclaim") || nitrogenCurrentRecipe) return false; //get circuit number var isCircuit2 = circuit.Name.EndsWith("2"); var circuitNumber = isCircuit2 ? "2" : "1"; //jgamble handle bad ref types as skip var recipeFillTypeName = "PresetFillType"; var refTypeSelected = GetRecipeItemValue(circuit.ActiveRecipe, recipeFillTypeName); if (refTypeSelected == "0") { SetError(17, "Refrigerant Type is Not Translated Correctly."); AddNotificationPrompt($"Incorrecta @vcRefType"); return true; } try { var recipeFillQtyName = $"PresetFill{circuitNumber}Quantity"; var refQtySelected = GetRecipeItemValue(circuit.ActiveRecipe, recipeFillQtyName); if (string.IsNullOrEmpty(refQtySelected) || refQtySelected == "0") { return true; } } catch (Exception ex) { SetError(17, "Refrigerant Type is Not Translated Correctly."); AddNotificationPrompt($"Incorrecta @nRefQuanty {circuitNumber} "); return true; } //allow 'local' mode to run un-checked //jrg 2023-10-12 - to make engineers happy for in house run off //we still want quantity parsing to allow skip, but ignore any "previous flag". if (_carrierMesProductionMode == 0) return false; //MX does not do operator valdiation or override if (_carrierMesProductionMode == 3) return false; if (_lastChargingFlag == 1 && !_hasPromptedMesFlag) { AddLogItem($"MES requested a CanCharge Flag of 1, asking for override..."); var mesFlagResult = ShowUserPrompt($"El sistema MES ha marcado este escaneo como que no se puede cargar. ¿Le gustaría reintentar de todos modos?", Prompt.PromptTypes.PasswordYes_No) .GetAwaiter() .GetResult(); var mesOverrideDenied = (DialogResult)mesFlagResult.Answer == DialogResult.No || !CurrentUserHasPermission(mesFlagResult.User.ToString(), CanOverrideReworkUnit); _hasPromptedMesFlag = true; if (mesOverrideDenied) { return true; } } AddLogItem($"Running query for circuit: {circuitNumber}"); //get table and run query var table = Context.DataservTables["ChargerOutput"]; var query = table.Database.QuickQuery($"SELECT COUNT(*) From [Dataserv].[dbo].{table.DatabaseName} WHERE [Serial] = '{scanItems["Serial"].Value}' AND FinalDataCompletionCode_AC1 = 1 AND CircuitNumber = {circuitNumber}"); AddLogItem($"For circuit {circuitNumber}, got back {query.Tables[0].Rows[0][0].ToString()} from the query."); //if zero rows, return false -- do not skip if (query.Tables[0] .Rows[0][0] .ToString() == "0") return false; //if you get to here, there was a previous pass, need to ask for override AddLogItem($"Circuit {circuitNumber} was potentially skipped due to previous charges, asking for override..."); var result = ShowUserPrompt($"Circuito {circuitNumber} se detectó que tenía cargos previos. Haga clic en Sí para continuar cargando, No para omitir.", Prompt.PromptTypes.PasswordYes_No) .GetAwaiter() .GetResult(); //per the above, if the answer is NO, result would be true, meaning we would skip, any other answer would be false (think YES) and we would continue to charge return (DialogResult)result.Answer == DialogResult.No || !CurrentUserHasPermission(result.User.ToString(), CanOverrideReworkUnit); } private void InitializeTags() { var requireSave = false; //check for the base groups and tags to working taglist try { //Groups if (Context.DataservTaglist.TagGroups[_carrierImportTagGroup] == null) { Context.DataservTaglist.TagGroups.Add(new TagGroup(_carrierImportTagGroup, "", 1000, "")); requireSave = true; } //Tags if (Context.DataservTaglist.Tag(_carrierImportTagGroup, _carrierImportErrorCode) == null) { Context.DataservTaglist .TagGroups[_carrierImportTagGroup] .Tags .Add(new Tag(_carrierImportErrorCode, _carrierImportTagGroup, "N/A", Tag.Tag_Type.STR, -1, "")); requireSave = true; } if (Context.DataservTaglist.Tag(_carrierImportTagGroup, _carrierImportErrorResponse) == null) { Context.DataservTaglist .TagGroups[_carrierImportTagGroup] .Tags .Add(new Tag(_carrierImportErrorResponse, _carrierImportTagGroup, "N/A", Tag.Tag_Type.STR, -1, "")); requireSave = true; } if (Context.DataservTaglist.Tag(_carrierImportTagGroup, _carrierImportLastImportTimeName) == null) { Context.DataservTaglist .TagGroups[_carrierImportTagGroup] .Tags .Add(new Tag(_carrierImportLastImportTimeName, _carrierImportTagGroup, "N/A", Tag.Tag_Type.STR, -1, "")); requireSave = true; } //Set all managed tags to 0 initial value foreach (Tag t in Context.DataservTaglist.TagGroups[_carrierImportTagGroup].Tags.Values) { AddLogItem($"Accessing '{t.FullName}' with value '{t.Value}', Attempting to set to '0'"); t.Value = ""; } //we just need this one set to 0 for logic purposes Context.DataservTaglist.Tag(_carrierImportTagGroup, _carrierImportErrorCode) .Value = 0; } catch (Exception ex) { AddLogItem($"Failled to Add Groups and Tags. {ex.Message}"); } } private void LoadEnvironmentItems() { if (Context.DataservEnvironmentItems["CarrierMES_ProductionMode"] != null) { var envProdMode = 0; if (int.TryParse(Context.DataservEnvironmentItems["CarrierMES_ProductionMode"] .Value .ToString() .Trim(), out envProdMode )) { _carrierMesProductionMode = envProdMode; } //update with live changes var envProdModeTag = Context.DataservTaglist.Tag("TAGGROUP::Dataserv Environment Items::TAG::CarrierMES_ProductionMode"); if (envProdModeTag != null && int.TryParse(envProdModeTag.Value.ToString(), out envProdMode)) { _carrierMesProductionMode = envProdMode; } } if (Context.DataservEnvironmentItems["CarrierMES_ConnectionString"] != null) { if (Context.DataservEnvironmentItems["CarrierMES_ConnectionString"] .Value .ToString() .Trim() != string.Empty) { _carrierMesConnectionString1 = Context.DataservEnvironmentItems["CarrierMES_ConnectionString"] .Value .ToString() .Trim(); } //update with live changes var envConStringTag = Context.DataservTaglist.Tag("TAGGROUP::Dataserv Environment Items::TAG::CarrierMES_ConnectionString"); if (envConStringTag != null && envConStringTag.Value.ToString() != string.Empty) { _carrierMesConnectionString1 = envConStringTag.Value.ToString(); } } if (_debug) AddLogItem($"Carrier-MX-MES - Environment Items Loaded: Production Mode: {_carrierMesProductionMode}"); } //Carrier wants us to try to update at scan time as well, if we fail to hit their end point, just use the cache. //cache version should already be loaded because that's what the recipes are now. public override bool OnRecipeRead( ref Recipe recipe, Circuit circuit, ScanItemCollection scanItems, ref string response, ref Request request ) { ClearError(); try { LoadEnvironmentItems(); UpdateAppConfig(); try { //which process are we handling? switch (_carrierMesProductionMode) { case 0: AddLogItem($"Bypassing MES for local"); return true; case 1: ProcessRecipeRead_Res_SPP_SRT(ref recipe, circuit, scanItems, ref response, ref request); break; case 2: ProcessRecipeRead_LCV(ref recipe, circuit, scanItems, ref response, ref request); break; case 3: ProcessRecipeRead_MXA(ref recipe, circuit, scanItems, ref response, ref request); break; default: SetError(10, "Production Mode Set Incorrectly. Check Env."); break; } if (response != string.Empty) { return false; } } catch (Exception ex) { AddLogItem("Carrier-MX-MES - Error Updating On Recipe Read!", ex); return false; } } catch (Exception ex2) { AddLogItem("Carrier-MX-MES - Error Updating On Recipe Read!", ex2); return false; } return true; } public override void OnCircuitComplete( Circuit circuit ) { LoadEnvironmentItems(); var response = ""; if(circuit.Name == "ReclaimCircuit") { //do not submit to MES, this occurs at circuit start return; } //which process are we handling? switch (_carrierMesProductionMode) { case 0: AddLogItem("Bypassing MES for local"); break; case 1: ProcessCircuitComplete_Res_SPP_SRT(circuit, ref response); break; case 2: ProcessCircuitComplete_LCV(circuit, ref response); break; case 3: ProcessCircuitComplete_MXA(circuit, ref response); break; default: SetError(10, "Production Mode Set Incorrectly. Check Env."); break; } AddLogItem($"Carrier-MX-MES - CircuitCompleteResponse : `{response}`"); } private void SetRecipeItem( ref Recipe recipe, string fieldName, object value ) { try { if (recipe.RecipeFields[fieldName] != null) { recipe.RecipeFields[fieldName].Value = value; } //update the recipe table values, these can be retrieved for Dataserv internal use (enables) if (recipe.RecipeTableValues.Keys.Contains(fieldName)) { recipe.RecipeTableValues[fieldName] = value; } else { recipe.RecipeTableValues.Add(fieldName, value); } } catch (Exception ex) { AddLogItem($"Carrier-MX-MES - Error in Recipe Set for '{fieldName}' with '{value.ToString()}'", ex); } } private string GetRecipeItemValue( Recipe recipe, string fieldName ) { if (recipe.RecipeTableValues.Keys.Contains(fieldName)) { return recipe.RecipeTableValues[fieldName] .ToString(); } return string.Empty; } //check if the fluid type is good for this system //if not the calling method needs to report, bad result = 0. private void ValidateFluidType( string unitfluidtype, out decimal resultfluidtype ) { resultfluidtype = 0; try { if (_carrierImportPartTranslation["Refrigerant"] .ContainsKey(unitfluidtype)) { resultfluidtype = Convert.ToDecimal(_carrierImportPartTranslation["Refrigerant"][unitfluidtype]); } } catch (Exception ex) { } } private void SetError( int eCode, string eResponse ) { try { var errorCodeTag = Context.DataservTaglist.Tag(_carrierImportTagGroup, _carrierImportErrorCode); var errorResponseTag = Context.DataservTaglist.Tag(_carrierImportTagGroup, _carrierImportErrorResponse); errorCodeTag.Value = $"{eCode}"; errorResponseTag.Value = eResponse; AddLogItem($"Carrier-MX-MES - SetError: '{eCode.ToString()}' - '{eResponse}'"); } catch (Exception ex) { AddLogItem("Carrier-MX-MES - Error Updating Status!", ex); } } private void ClearError() { try { var errorCodeTag = Context.DataservTaglist.Tag(_carrierImportTagGroup, _carrierImportErrorCode); var errorResponseTag = Context.DataservTaglist.Tag(_carrierImportTagGroup, _carrierImportErrorResponse); errorCodeTag.Value = $"0"; errorResponseTag.Value = ""; } catch (Exception ex) { AddLogItem("Carrier-MX-MES - Error Clearing Status!", ex); } } public bool nitrogenFlagActive = true; public bool nitrogenCurrentRecipe = false; /// /// Where the start cycle comes together for Residential SPP & SRT Chargers. /// * Operator Valid from Scan Item - Operator. /// * Cascade Valid from Scan Item - Scan, CascadeFlag from OperatorValid. /// /// /// /// /// /// /// private void ProcessRecipeRead_Res_SPP_SRT( ref Recipe recipe, Circuit circuit, ScanItemCollection scanItems, ref string response, ref Request request ) { const string recipeFillTypeName = "PresetFillType"; const string spFillTypeParmName = "@vcRefType";//need translate, no examples const string recipeFillQty1Name = "PresetFill1Quantity"; const string spFillQty1ParmName = "@nRef_Weight";//need unit convert kg -> g const string recipeFillQty2Name = "PresetFill2Quantity"; const string spFillQty2ParmName = "@nRef_Weight2";//need unit convert kg -> g const string recipeCircuitTypeName = "CircuitStyle"; const string nitrogenOnlyFlag = "@b40RUFlagUnit"; var hasCharge1 = false; var hasCharge2 = false; nitrogenCurrentRecipe = false; try { var serialScanValue = scanItems["Serial"].Value; var resOperatorValid = ExecuteSP_OperatorValid(scanItems["Operator"].Value); var passOperatorValid = ValidateSqlResult(resOperatorValid); SqlResultIntoRecipe(resOperatorValid, ref recipe); if (passOperatorValid) { //normal charge logic var resMasterKeyValid = ExecuteSP_MasterKey_CascadeWSValid(Convert.ToBoolean(resOperatorValid["@CascadeFlag"].Value), serialScanValue, Convert.ToInt16(resOperatorValid["@iSucc_Code"].Value)); var passMasterKeyValid = ValidateSqlResult(resMasterKeyValid); _lastChargingFlag = Convert.ToInt16(resMasterKeyValid["@ChargingFlag"].Value); SqlResultIntoRecipe(resMasterKeyValid, ref recipe); //special handliong of cascadeWS, we need the vcMaterial but done care about the result flags if(circuit.Name == "ReclaimCircuit") { //we want to submit a failure as soon as possible to MES var message = ""; ProcessCircuitComplete_Res_SPP_SRT(circuit, ref message); //4-20-24 //we still need to set the ref type for the circuit to be valid var resChargingParams = ExecuteSP_Charging_Params(serialScanValue); var passChargingParams = ValidateSqlResult(resChargingParams); var outFluidType = 0M; ValidateFluidType(resChargingParams[spFillTypeParmName] .Value .ToString(), out outFluidType ); if(outFluidType == 0) { response = "Unable to parse fluid type"; return; } SetRecipeItem(ref recipe, recipeFillTypeName, outFluidType); return; } if (passMasterKeyValid) { var resChargingParams = ExecuteSP_Charging_Params(serialScanValue, nitrogenFlagActive); var passChargingParams = ValidateSqlResult(resChargingParams); if (passChargingParams) { if(nitrogenFlagActive){ //nitrogen only early exit check //theres a chance we will need to use a process switch //but if the PLC zeros out the registers this should work according to Amanda bool isNitrogenOnly = resChargingParams[nitrogenOnlyFlag].Value.ToString() == "True"; if(isNitrogenOnly){ nitrogenCurrentRecipe = true; SetRecipeItem(ref recipe, "ENVIRONMENT::EnvReclaimTime", 0F); return; } } //if the above was zero, proceed normally var outFluidType = 0M; ValidateFluidType(resChargingParams[spFillTypeParmName] .Value .ToString(), out outFluidType ); SetRecipeItem(ref recipe, recipeFillTypeName, outFluidType); var outFillQty = 0M; var outFillQty2 = 0M; if (decimal.TryParse(resChargingParams[spFillQty1ParmName] .Value .ToString(), out outFillQty )) { outFillQty *= 1000M; } SetRecipeItem(ref recipe, recipeFillQty1Name, outFillQty); hasCharge1 = outFillQty > 0M; if (decimal.TryParse(resChargingParams[spFillQty2ParmName] .Value .ToString(), out outFillQty2 )) { outFillQty2 *= 1000M;//kg -> grams } SetRecipeItem(ref recipe, recipeFillQty2Name, outFillQty2); hasCharge2 = outFillQty2 > 0M; if (hasCharge1 && hasCharge2) { SetRecipeItem(ref recipe, recipeCircuitTypeName, 3); } else if (hasCharge1 && !hasCharge2) { SetRecipeItem(ref recipe, recipeCircuitTypeName, 1); } else if (!hasCharge1 && hasCharge2) { SetRecipeItem(ref recipe, recipeCircuitTypeName, 2); } } else { response = "Charging Params Invalid"; } } else { response = "MasterKey Invalid"; } } else { response = "Operator Invalid"; } } catch (Exception ex) { response = "Process Failure - SPP/SRT"; SetError(55, response); AddLogItem($"CarrierMX_MES - Error in SPP/SRT Process", ex); } } private void ProcessCircuitComplete_Res_SPP_SRT( Circuit circuit, ref string response ) { try { if (_debug) AddLogItem($"CarrierMX_MES - Starting Circuit Complete Processing SPP/SRT."); var outputMapping = circuit.OutputMappings[0]; var isCurrentUnitPass = false; if (!string.IsNullOrEmpty(outputMapping.DestinationTable.CodeField)) { var completionCodeField = outputMapping.FieldMappings .Cast() .FirstOrDefault(field => field.Destination.Name == outputMapping.DestinationTable.CodeField); isCurrentUnitPass = Context.DataservTaglist .Tag(completionCodeField.Source) .Value .ToString() == "1"; } if(circuit.Name == "ReclaimCircuit") { //reclaim will never 'pass' a unit to MES, always a failure isCurrentUnitPass = false; } //push result to SP var serialScanValue = Context.RegularExpression .Parse($"RUNNINGCYCLE::{circuit.Cycle}::SCANITEM::Serial::SPECIAL::VALUE") .ToString(); var operatorScanValue = Context.RegularExpression .Parse($"RUNNINGCYCLE::{circuit.Cycle}::SCANITEM::Operator::SPECIAL::VALUE") .ToString(); var materialResult = GetRecipeItemValue(circuit.ActiveRecipe, "@vcMaterial"); var resultValue = Convert.ToInt16(isCurrentUnitPass ? GetRecipeItemValue(circuit.ActiveRecipe, "@iSucc_Code") : GetRecipeItemValue(circuit.ActiveRecipe, "@iFailed_Code")); var resSaveResult = ExecuteSP_SaveResults(serialScanValue, resultValue, materialResult, operatorScanValue); var passSaveResults = ValidateSqlResult(resSaveResult); if (!passSaveResults) { AddLogItem($"Unable to save results, returning sql was not valid: {resSaveResult}"); } } catch (Exception ex) { response = "Process Failure - SPP/SRT"; SetError(55, response); AddLogItem($"CarrierMX_MES - Error in SPP/SRT Process", ex); } } /// /// Where the start cycle comes together for LCV. /// * Operator Valid from Scan Item - Operator. /// * Cascade Valid from Scan Item - Scan, CascadeFlag from OperatorValid. /// /// /// /// /// /// /// private void ProcessRecipeRead_LCV( ref Recipe recipe, Circuit circuit, ScanItemCollection scanItems, ref string response, ref Request request ) { if (recipe == null) { AddLogItem($"CarrierMX_MES - Recipe for LCV is Null!"); } var recipeFillTypeName = "PresetFillType"; var spFillTypeParmName = "@vcRefType";//need translate, no examples var recipeFillQty1Name = "PresetFill1Quantity"; var spFillQty1ParmName = "@nRefCharge_KG";//need unit convert kg -> g var recipeFillQty2Name = "PresetFill2Quantity"; var spFillQty2ParmName = "@nRemainRefCharge_KG";//need unit convert kg -> g var recipeCircuitTypeName = "CircuitStyle"; var hasCharge1 = false; var hasCharge2 = false; try { var serialScanValue = scanItems["Serial"].Value; var resOperatorValid = ExecuteSP_OperatorValid(scanItems["Operator"].Value); var passOperatorValid = ValidateSqlResult(resOperatorValid); SqlResultIntoRecipe(resOperatorValid, ref recipe); if (passOperatorValid) { var resMasterKeyValid = ExecuteSP_MasterKey_CascadeWSValid(Convert.ToBoolean(resOperatorValid["@CascadeFlag"].Value), serialScanValue, Convert.ToInt16(resOperatorValid["@iSuccCode"].Value)); var passMasterKeyValid = ValidateSqlResult(resMasterKeyValid); _lastChargingFlag = Convert.ToInt16(resMasterKeyValid["@ChargingFlag"].Value); SqlResultIntoRecipe(resMasterKeyValid, ref recipe); if (passMasterKeyValid) { var resChargingParams = ExecuteSP_LCV_Charging_Params(serialScanValue); var passChargingParams = ValidateSqlResult(resChargingParams); var resChargingParams2 = ExecuteSP_LCV_SecondCharging_Params(serialScanValue); var passChargingParams2 = ValidateSqlResult(resChargingParams2); var outFluidType = 0M; var outFillQty = 0M; var outFillQty2 = 0M; if (passChargingParams) { ValidateFluidType(resChargingParams[spFillTypeParmName] .Value .ToString(), out outFluidType ); SetRecipeItem(ref recipe, recipeFillTypeName, outFluidType); if (decimal.TryParse(resChargingParams[spFillQty1ParmName] .Value .ToString(), out outFillQty )) { outFillQty *= 1000M;//kg -> grams } SetRecipeItem(ref recipe, recipeFillQty1Name, outFillQty); } else { SetRecipeItem(ref recipe, recipeFillTypeName, outFluidType); SetRecipeItem(ref recipe, recipeFillQty1Name, outFillQty); } //It looks like for LCV if their database does not return a charge amount/require second charge, it actually reports as error, we want to just surpress that and continue on if (passChargingParams2) { //only update this from charge 2 if charge 1 wasn't set if (outFluidType == 0M) { ValidateFluidType(resChargingParams2[spFillTypeParmName] .Value .ToString(), out outFluidType ); SetRecipeItem(ref recipe, recipeFillTypeName, outFluidType); } if (decimal.TryParse(resChargingParams2[spFillQty2ParmName] .Value .ToString(), out outFillQty2 )) { outFillQty2 *= 1000M;//kg -> grams } SetRecipeItem(ref recipe, recipeFillQty2Name, outFillQty2); } else { if (outFluidType != 0M) { //clear it so it doesn't show to operator, since this is normal? ClearError(); //first charge was success, we want to preserve the fluid type } else { SetRecipeItem(ref recipe, recipeFillTypeName, outFluidType); } SetRecipeItem(ref recipe, recipeFillQty2Name, outFillQty2); } hasCharge1 = outFillQty > 0M; hasCharge2 = outFillQty2 > 0M; if (hasCharge1 && hasCharge2) { SetRecipeItem(ref recipe, recipeCircuitTypeName, 3); } else if (hasCharge1 && !hasCharge2) { SetRecipeItem(ref recipe, recipeCircuitTypeName, 1); } else if (!hasCharge1 && hasCharge2) { SetRecipeItem(ref recipe, recipeCircuitTypeName, 2); } else { response = "Charging Params Invalid"; } } else { response = "MasterKey Invalid"; } } else { response = "Operator Invalid"; } } catch (Exception ex) { response = "Process Failure - LCV"; SetError(65, response); AddLogItem($"CarrierMX_MES - Error in SPP/SRT Process", ex); } } private void ProcessCircuitComplete_LCV( Circuit circuit, ref string response ) { try { if (_debug) AddLogItem($"CarrierMX_MES - Starting Circuit Complete Processing LCV."); var outputMapping = circuit.OutputMappings[0]; var isCurrentUnitPass = false; if (!string.IsNullOrEmpty(outputMapping.DestinationTable.CodeField)) { var completionCodeField = outputMapping.FieldMappings .Cast() .FirstOrDefault(field => field.Destination.Name == outputMapping.DestinationTable.CodeField); isCurrentUnitPass = Context.DataservTaglist .Tag(completionCodeField.Source) .Value .ToString() == "1"; } //push result to SP var serialScanValue = Context.RegularExpression .Parse($"RUNNINGCYCLE::{circuit.Cycle}::SCANITEM::Serial::SPECIAL::VALUE") .ToString(); var operatorScanValue = Context.RegularExpression .Parse($"RUNNINGCYCLE::{circuit.Cycle}::SCANITEM::Operator::SPECIAL::VALUE") .ToString(); var materialResult = GetRecipeItemValue(circuit.ActiveRecipe, "@vcMaterial"); var resultValue = Convert.ToInt16(isCurrentUnitPass ? GetRecipeItemValue(circuit.ActiveRecipe, "@iSucc_Code") : GetRecipeItemValue(circuit.ActiveRecipe, "@iFailed_Code")); var resSaveResult = ExecuteSP_SaveResults(serialScanValue, resultValue, materialResult, operatorScanValue); var passSaveResults = ValidateSqlResult(resSaveResult); if (!passSaveResults) { AddLogItem($"Unable to save results, returning sql was not valid: {resSaveResult}"); } } catch (Exception ex) { response = "Process Failure - LCV"; SetError(65, response); AddLogItem($"CarrierMX_MES - Error in SPP/SRT Process", ex); } } //====== //MX A process /// /// MX A uses parameters from us, so everything should be direct :crossed_fingers: /// /// /// /// /// /// private void ProcessRecipeRead_MXA( ref Recipe recipe, Circuit circuit, ScanItemCollection scanItems, ref string response, ref Request request ) { const string recipeEvacL = "PresetEvacuationLevel"; const string spEvacL = "@EvacL"; const string recipeEvacT = "PresetEvacuationTime"; const string spEvacT = "@EvacT"; const string recipeVacuumL = "PresetVacuumCheckLevel"; const string spVacuumL = "@VacuumL"; const string recipeVacuumT = "PresetVacuumCheckTime"; const string spVacuumT = "@VacuumT"; //reject just uses regular evac const string recipeRejectEvacL = "PresetRejectEvacuationLevel"; const string spRejectEvacL = "@EvacL"; const string recipeRejectEvacT = "PresetRejectEvacuationTime"; const string spRejectEvacT = "@EvacT"; const string recipeFillTypeName = "PresetFillType"; const string spFillTypeParmName = "@Coolant";//need translate, no examples const string recipeFillQty1Name = "PresetFill1Quantity"; const string spFillQty1ParmName = "@ChargeQty"; const string recipePercent = "PresetFillPercent"; const string spPercent = "@Percent"; var hasCharge1 = false; try { var serialScanValue = scanItems["Serial"].Value; var resMasterKeyValid = ExecuteSP_MXA_ValidateMK_Get(serialScanValue); var passMasterKeyValid = ValidateSqlResult(resMasterKeyValid); SqlResultIntoRecipe(resMasterKeyValid, ref recipe); if (passMasterKeyValid) { var resChargingParams = ExecuteSP_MXA_RecetaMK_Get(serialScanValue); var passChargingParams = ValidateSqlResult(resChargingParams); if (passChargingParams) { var outFluidType = 0M; ValidateFluidType(resChargingParams[spFillTypeParmName] .Value .ToString(), out outFluidType ); SetRecipeItem(ref recipe, recipeFillTypeName, outFluidType); var outFillQty = 0M; if (decimal.TryParse(resChargingParams[spFillQty1ParmName] .Value .ToString(), out outFillQty )) { //MX A stores value in grams, seemingly //outFillQty *= 1000M; } SetRecipeItem(ref recipe, recipeFillQty1Name, outFillQty); //this assumes they're passing us correct values. If it blows up check input/output from SP, probably a null or non-real SetRecipeItem(ref recipe, recipeEvacL, resChargingParams[spEvacL].Value); SetRecipeItem(ref recipe, recipeEvacT, resChargingParams[spEvacT].Value); SetRecipeItem(ref recipe, recipeVacuumL, resChargingParams[spVacuumL].Value); SetRecipeItem(ref recipe, recipeVacuumT, resChargingParams[spVacuumT].Value); SetRecipeItem(ref recipe, recipeRejectEvacL, resChargingParams[spRejectEvacL].Value); SetRecipeItem(ref recipe, recipeRejectEvacT, resChargingParams[spRejectEvacT].Value); //may end up being slightly special? SetRecipeItem(ref recipe, recipePercent, resChargingParams[spPercent].Value); } else { response = "Charging Params Invalid"; } } else { response = "MasterKey Invalid"; } } catch (Exception ex) { response = "Process Failure - MX A"; SetError(55, response); AddLogItem($"CarrierMX_MES - Error in MX A Process", ex); } } private void ProcessCircuitComplete_MXA( Circuit circuit, ref string response ) { try { if (_debug) AddLogItem($"CarrierMX_MES - Starting Circuit Complete Processing MX A."); var outputMapping = circuit.OutputMappings[0]; var isCurrentUnitPass = false; if (!string.IsNullOrEmpty(outputMapping.DestinationTable.CodeField)) { var completionCodeField = outputMapping.FieldMappings .Cast() .FirstOrDefault(field => field.Destination.Name == outputMapping.DestinationTable.CodeField); isCurrentUnitPass = Context.DataservTaglist .Tag(completionCodeField.Source) .Value .ToString() == "1"; } //push result to SP var serialScanValue = Context.RegularExpression .Parse($"RUNNINGCYCLE::{circuit.Cycle}::SCANITEM::Serial::SPECIAL::VALUE") .ToString(); var operatorScanValue = Context.RegularExpression .Parse($"RUNNINGCYCLE::{circuit.Cycle}::SCANITEM::Operator::SPECIAL::VALUE") .ToString(); var materialResult = GetRecipeItemValue(circuit.ActiveRecipe, "@vcMaterial"); var resultValue = Convert.ToInt16(isCurrentUnitPass ? 1 : 0); var resSaveResult = ExecuteSP_MXA_SaveResults(serialScanValue, resultValue); var passSaveResults = ValidateSqlResult(resSaveResult); if (!passSaveResults) { AddLogItem($"Unable to save results, returning sql was not valid: {resSaveResult}"); } } catch (Exception ex) { response = "Process Failure - MX A"; SetError(55, response); AddLogItem($"CarrierMX_MES - Error in MX A Process", ex); } } //END MX A process //====== private SqlParameterCollection ExecuteStoredProcedure( string storedProcedureName, params SqlParameter[] spParams ) { try { //query the database using (var cn = new SqlConnection(_carrierMesConnectionString1)) { AddLogItem($"CarrierMX_MES - Connected"); using (var cmd = new SqlCommand()) { AddLogItem($"CarrierMX_MES - Created Command"); using (var da = new SqlDataAdapter(cmd)) { cmd.Connection = cn; cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = storedProcedureName; cmd.Parameters.AddRange(spParams); cn.Open(); var res = cmd.ExecuteNonQuery(); //res not checked, but possibly needs to be try { if (_debug) AddLogItem($"Carrier-MX-MES - SQL Result '{storedProcedureName}' with Input: '{string.Join(";", spParams.Select(parm => $"{parm.ParameterName} = {parm.Value.ToString()}"))}' - Result '{string.Join(";", (from SqlParameter resparm in cmd.Parameters select resparm).ToArray().Select(parm => $"{parm.ParameterName} = {parm.Value.ToString()}"))}'"); } catch (Exception ex) { //we just want to log each SQL result for trouble shooting. } return cmd.Parameters; } } } } catch (Exception ex) { AddLogItem($"CarrierMX_MES - Issue Executing StoredProcedure", ex); } return null; } private SqlParameterCollection ExecuteSP_OperatorValid( string _operator ) { var isAdmin = Context.SecurityManager.GetUser(_operator) .IsAdmin; //NOTE: this was changed on 9/20/23 to now not use the operator as an argument var parms = new List(); var idChainValue = new SqlParameter("@idChainValue", SqlDbType.SmallInt) {Value = _carrierMesAppChainId}; parms.Add(idChainValue); var vcLine = new SqlParameter("@vcLine", _carrierMesAppLine); parms.Add(vcLine); var vcCredencial = new SqlParameter("@vcCredencial", _operator); parms.Add(vcCredencial); var admUser = new SqlParameter("@SysAdmUser_Flag", isAdmin ? 1 : 0); parms.Add(admUser); var idWorkStation = new SqlParameter("@idWorkStation", SqlDbType.SmallInt) {Value = _carrierMesAppWorkStationId}; parms.Add(idWorkStation); var idApplication = new SqlParameter("@idApplication", SqlDbType.SmallInt) {Value = 0}; parms.Add(idApplication); //outputs var flagSts = new SqlParameter("@FlagSts", SqlDbType.SmallInt); flagSts.Direction = ParameterDirection.Output; parms.Add(flagSts); var errorMessage = new SqlParameter("@ErrorMessage", SqlDbType.VarChar, -1); errorMessage.Direction = ParameterDirection.Output; parms.Add(errorMessage); var cascadeFlag = new SqlParameter("@CascadeFlag", SqlDbType.Bit); cascadeFlag.Direction = ParameterDirection.Output; parms.Add(cascadeFlag); var iSuccCode = new SqlParameter("@iSucc_Code", SqlDbType.SmallInt); iSuccCode.Direction = ParameterDirection.Output; parms.Add(iSuccCode); var iFailedCode = new SqlParameter("@iFailed_Code", SqlDbType.SmallInt); iFailedCode.Direction = ParameterDirection.Output; parms.Add(iFailedCode); var res = ExecuteStoredProcedure("spMES_Params_OperatorValid", parms.ToArray()); return res; } private SqlParameterCollection ExecuteSP_MasterKey_CascadeWSValid( bool bCascadeFlag, string masterKeyScan, short previousSuccessCode ) { var parms = new List(); var idChainValue = new SqlParameter("@idChainValue", SqlDbType.SmallInt) {Value = _carrierMesAppChainId}; parms.Add(idChainValue); var vcLine = new SqlParameter("@vcLine", _carrierMesAppLine); parms.Add(vcLine); var idApplication = new SqlParameter("@idApplication", SqlDbType.SmallInt) {Value = 0}; parms.Add(idApplication); var idWorkStation = new SqlParameter("@idWorkStation", SqlDbType.SmallInt) {Value = _carrierMesAppWorkStationId}; parms.Add(idWorkStation); //these are command specific var cascadeFlag = new SqlParameter("@CascadeFlag", SqlDbType.Bit) {Value = bCascadeFlag}; parms.Add(cascadeFlag); var vcBarcode = new SqlParameter("@vcBarcode", masterKeyScan); parms.Add(vcBarcode); var succCode = new SqlParameter("@SuccCode", masterKeyScan) {Value = previousSuccessCode}; parms.Add(succCode); //outputs var vcMaterial = new SqlParameter("@vcMaterial", SqlDbType.VarChar, 30); vcMaterial.Direction = ParameterDirection.Output; parms.Add(vcMaterial); var flagSts = new SqlParameter("@FlagSts", SqlDbType.SmallInt); flagSts.Direction = ParameterDirection.Output; parms.Add(flagSts); var chargingFlag = new SqlParameter("@ChargingFlag", SqlDbType.SmallInt); chargingFlag.Direction = ParameterDirection.Output; parms.Add(chargingFlag); var errorMessage = new SqlParameter("@ErrorMessage", SqlDbType.VarChar, -1); errorMessage.Direction = ParameterDirection.Output; parms.Add(errorMessage); var res = ExecuteStoredProcedure("spMES_MasterKey_CascadeWSValid", parms.ToArray()); return res; } private SqlParameterCollection ExecuteSP_Charging_Params( string barcode, bool nitrogenFlag = false ) { var parms = new List(); var idChainValue = new SqlParameter("@idChainValue", SqlDbType.SmallInt) {Value = _carrierMesAppChainId}; parms.Add(idChainValue); //these are command specific var vcBarcode = new SqlParameter("@vcBarcode", barcode); parms.Add(vcBarcode); //outputs var flagSts = new SqlParameter("@FlagSts", SqlDbType.SmallInt); flagSts.Direction = ParameterDirection.Output; parms.Add(flagSts); var errorMessage = new SqlParameter("@ErrorMessage", SqlDbType.VarChar, -1); errorMessage.Direction = ParameterDirection.Output; parms.Add(errorMessage); var vcRefType = new SqlParameter("@vcRefType", SqlDbType.VarChar, 30); vcRefType.Direction = ParameterDirection.Output; parms.Add(vcRefType); var nRefWeight = new SqlParameter("@nRef_Weight", SqlDbType.VarChar, 33);//kg nRefWeight.Direction = ParameterDirection.Output; parms.Add(nRefWeight); var nRefWeight2 = new SqlParameter("@nRef_Weight2", SqlDbType.VarChar, 33);//kg nRefWeight2.Direction = ParameterDirection.Output; parms.Add(nRefWeight2); var nRefWeight3 = new SqlParameter("@nRef_Weight3", SqlDbType.VarChar, 33);//kg nRefWeight3.Direction = ParameterDirection.Output; parms.Add(nRefWeight3); if(nitrogenFlag) { var flagUnit = new SqlParameter("@b40RUFlagUnit", SqlDbType.Bit); flagUnit.Direction = ParameterDirection.Output; parms.Add(flagUnit); } var sp_name = nitrogenFlag ? "spMES_Charging_Params_40RU" : "spMES_Charging_Params"; var res = ExecuteStoredProcedure(sp_name, parms.ToArray()); return res; } private SqlParameterCollection ExecuteSP_LCV_Charging_Params( string barcode ) { var parms = new List(); var idChainValue = new SqlParameter("@idChainValue", SqlDbType.SmallInt) {Value = _carrierMesAppChainId}; parms.Add(idChainValue); var vcLine = new SqlParameter("@vcLine", _carrierMesAppLine); parms.Add(vcLine); //these are command specific var vcBarcode = new SqlParameter("@vcBarcode", barcode); parms.Add(vcBarcode); //outputs var flagSts = new SqlParameter("@FlagSts", SqlDbType.SmallInt); flagSts.Direction = ParameterDirection.Output; parms.Add(flagSts); var errorMessage = new SqlParameter("@ErrorMessage", SqlDbType.VarChar, -1); errorMessage.Direction = ParameterDirection.Output; parms.Add(errorMessage); var vcRefType = new SqlParameter("@vcRefType", SqlDbType.VarChar, 30); vcRefType.Direction = ParameterDirection.Output; parms.Add(vcRefType); var nRefChargeKg = new SqlParameter("@nRefCharge_KG", SqlDbType.Decimal);//kg nRefChargeKg.Direction = ParameterDirection.Output; nRefChargeKg.Precision = 9; nRefChargeKg.Scale = 2; parms.Add(nRefChargeKg); var bDoubleSidesUnitFlag = new SqlParameter("@bDoubleSides_UnitFlag", SqlDbType.Bit); bDoubleSidesUnitFlag.Direction = ParameterDirection.Output; parms.Add(bDoubleSidesUnitFlag); var res = ExecuteStoredProcedure("spMES_LCV_Charging_Params", parms.ToArray()); return res; } private SqlParameterCollection ExecuteSP_LCV_SecondCharging_Params( string barcode ) { var parms = new List(); var idChainValue = new SqlParameter("@idChainValue", SqlDbType.SmallInt) {Value = _carrierMesAppChainId}; parms.Add(idChainValue); var vcLine = new SqlParameter("@vcLine", _carrierMesAppLine); parms.Add(vcLine); //these are command specific var vcBarcode = new SqlParameter("@vcBarcode", barcode); parms.Add(vcBarcode); //outputs var flagSts = new SqlParameter("@FlagSts", SqlDbType.SmallInt); flagSts.Direction = ParameterDirection.Output; parms.Add(flagSts); var errorMessage = new SqlParameter("@ErrorMessage", SqlDbType.VarChar, -1); errorMessage.Direction = ParameterDirection.Output; parms.Add(errorMessage); var vcRefType = new SqlParameter("@vcRefType", SqlDbType.VarChar, 30); vcRefType.Direction = ParameterDirection.Output; parms.Add(vcRefType); var nRemainRefChargeKg = new SqlParameter("@nRemainRefCharge_KG", SqlDbType.Decimal);//kg nRemainRefChargeKg.Direction = ParameterDirection.Output; nRemainRefChargeKg.Precision = 9; nRemainRefChargeKg.Scale = 2; parms.Add(nRemainRefChargeKg); var bDoubleSidesUnitFlag = new SqlParameter("@bDoubleSides_UnitFlag", SqlDbType.Bit); bDoubleSidesUnitFlag.Direction = ParameterDirection.Output; parms.Add(bDoubleSidesUnitFlag); var bRemainRefChargeUnit = new SqlParameter("@bRemainRefCharge_Unit", SqlDbType.Bit); bRemainRefChargeUnit.Direction = ParameterDirection.Output; parms.Add(bRemainRefChargeUnit); var res = ExecuteStoredProcedure("spMES_LCV_SecondCharging_Params", parms.ToArray()); return res; } /// /// Send on circuit complete. /// /// Scan /// Value(s) come from spMES_Parms_OperatorValid parameters iSucc_Code & iFailed_Code /// Value comes from the spMES_MasterKey_CascadeWSValid parameter vcMaterial /// /// private SqlParameterCollection ExecuteSP_SaveResults( string barcode, int successFailCode, string material, string operatorNumber ) { var parms = new List(); var idChainValue = new SqlParameter("@idChainValue", SqlDbType.SmallInt) {Value = _carrierMesAppChainId}; parms.Add(idChainValue); var vcLine = new SqlParameter("@vcLine", _carrierMesAppLine); parms.Add(vcLine); var idWorkStation = new SqlParameter("@idWorkStation", SqlDbType.SmallInt) {Value = _carrierMesAppWorkStationId}; parms.Add(idWorkStation); //these are command specific var vcBarcode = new SqlParameter("@vcBarcode", barcode); parms.Add(vcBarcode); var vcMaterial = new SqlParameter("@vcMaterial", material); parms.Add(vcMaterial); var iSuccFailCode = new SqlParameter("@iSuccFail_Code", successFailCode); parms.Add(iSuccFailCode); var vcBcNumOperator = new SqlParameter("@vcBCNum_Operator", operatorNumber); parms.Add(vcBcNumOperator); //outputs var flagSts = new SqlParameter("@FlagSts", SqlDbType.SmallInt); flagSts.Direction = ParameterDirection.Output; parms.Add(flagSts); var errorMessage = new SqlParameter("@ErrorMessage", SqlDbType.VarChar, -1); errorMessage.Direction = ParameterDirection.Output; parms.Add(errorMessage); var res = ExecuteStoredProcedure("spMES_SaveResults", parms.ToArray()); return res; } //======= //MX A Commands private SqlParameterCollection ExecuteSP_MXA_ValidateMK_Get( string masterKeyScan ) { var parms = new List(); var idChainValue = new SqlParameter("@IdChainValue", SqlDbType.VarChar, 50) {Value = _carrierMesAppChainId}; parms.Add(idChainValue); var vcLine = new SqlParameter("@IdLine", SqlDbType.VarChar, 50) {Value = _carrierMesAppLine}; parms.Add(vcLine); var idWorkStation = new SqlParameter("@DeviceID", SqlDbType.VarChar, 50) {Value = _carrierMesAppWorkStationId}; parms.Add(idWorkStation); //these are command specific var vcBarcode = new SqlParameter("@Barcode", SqlDbType.VarChar, 50) {Value = masterKeyScan}; parms.Add(vcBarcode); //outputs var flagSts = new SqlParameter("@FlagSts", SqlDbType.SmallInt); flagSts.Direction = ParameterDirection.Output; parms.Add(flagSts); var errorMessage = new SqlParameter("@ErrorMessage", SqlDbType.VarChar, -1); errorMessage.Direction = ParameterDirection.Output; parms.Add(errorMessage); var res = ExecuteStoredProcedure("spValidateMK_Get", parms.ToArray()); return res; } private SqlParameterCollection ExecuteSP_MXA_RecetaMK_Get( string barcode ) { var parms = new List(); var vcLine = new SqlParameter("@IdLine", SqlDbType.VarChar, 50) {Value = _carrierMesAppLine}; parms.Add(vcLine); var idWorkStation = new SqlParameter("@DeviceID", SqlDbType.VarChar, 50) {Value = _carrierMesAppWorkStationId}; parms.Add(idWorkStation); //these are command specific var vcBarcode = new SqlParameter("@Barcode", SqlDbType.VarChar, 50) {Value = barcode}; parms.Add(vcBarcode); var Limit_Type_ID = new SqlParameter("@Limit_Type_ID", SqlDbType.VarChar, 50) {Value = _carrierMesLimitTypeID}; parms.Add(vcBarcode); //outputs var flagSts = new SqlParameter("@FlagSts", SqlDbType.SmallInt); flagSts.Direction = ParameterDirection.Output; parms.Add(flagSts); var errorMessage = new SqlParameter("@ErrorMessage", SqlDbType.VarChar, -1); errorMessage.Direction = ParameterDirection.Output; parms.Add(errorMessage); var EvacL = new SqlParameter("@EvacL", SqlDbType.Float); EvacL.Direction = ParameterDirection.Output; parms.Add(EvacL); var EvacT = new SqlParameter("@EvacT", SqlDbType.Float); EvacT.Direction = ParameterDirection.Output; parms.Add(EvacT); var VacuumL = new SqlParameter("@VacuumL", SqlDbType.Float); VacuumL.Direction = ParameterDirection.Output; parms.Add(VacuumL); var VacuumT = new SqlParameter("@VacuumT", SqlDbType.Float); VacuumT.Direction = ParameterDirection.Output; parms.Add(VacuumT); var ChargeQty = new SqlParameter("@ChargeQty", SqlDbType.Float); ChargeQty.Direction = ParameterDirection.Output; parms.Add(ChargeQty); var Coolant = new SqlParameter("@Coolant", SqlDbType.Float); Coolant.Direction = ParameterDirection.Output; parms.Add(Coolant); var Percent = new SqlParameter("@Percent", SqlDbType.Float); Percent.Direction = ParameterDirection.Output; parms.Add(Percent); var res = ExecuteStoredProcedure("spMES_Charging_Params", parms.ToArray()); return res; } private SqlParameterCollection ExecuteSP_MXA_SaveResults( string barcode, int successFailCode ) { var parms = new List(); var idChainValue = new SqlParameter("@idChainValue", SqlDbType.VarChar, 100) {Value = _carrierMesAppChainId.ToString()}; parms.Add(idChainValue); var vcLine = new SqlParameter("@IdLine", SqlDbType.VarChar, 100) {Value = _carrierMesAppLine}; parms.Add(vcLine); var idWorkStation = new SqlParameter("@DeviceID", SqlDbType.VarChar, 100) {Value = _carrierMesAppWorkStationId}; parms.Add(idWorkStation); //these are command specific var vcBarcode = new SqlParameter("@Barcode", SqlDbType.VarChar, 100) {Value = barcode}; parms.Add(vcBarcode); var iSuccFailCode = new SqlParameter("@IDFailCode", successFailCode);//0 = failed, 1 = passed, 2 = manual passed (bypass) parms.Add(iSuccFailCode); var Limit_Type_ID = new SqlParameter("@LIMIT_TYPE_ID", SqlDbType.VarChar, 100) {Value = _carrierMesLimitTypeID}; parms.Add(vcBarcode); //outputs var flagSts = new SqlParameter("@FlagSts", SqlDbType.SmallInt); flagSts.Direction = ParameterDirection.Output; parms.Add(flagSts); var errorMessage = new SqlParameter("@ErrorMessage", SqlDbType.VarChar, -1); errorMessage.Direction = ParameterDirection.Output; parms.Add(errorMessage); var res = ExecuteStoredProcedure("spCargadoraResultHeader_SET", parms.ToArray()); return res; } //End MX A Commands //======= private bool ValidateSqlResult( SqlParameterCollection spResult ) { if (spResult.Contains("@FlagSts")) { if (Convert.ToInt16(spResult["@FlagSts"].Value) == 1) { return true; } SetError(51, $"Stored Procedure Failure - {spResult["@ErrorMessage"].Value}"); return false; } SetError(50, "@FlagSts not in Query Result"); return false; } private bool SqlResultIntoRecipe( SqlParameterCollection spResult, ref Recipe recipe ) { try { foreach (SqlParameter param in spResult) { SetRecipeItem(ref recipe, param.ParameterName, param.Value); } } catch (Exception ex) { AddLogItem("Carrier-MX-MES - Error Updating RecipeItem from SqlParameter(s).", ex); return false; } return true; } private void UpdateAppConfig() { try { using (var appXml = new DataSet()) { appXml.ReadXml(_carrierMesAppConfigPath); if (appXml.Tables["AppConfig"] != null) { var appConfig = appXml.Tables["AppConfig"]; if (appConfig.Columns.Contains("IdChainValue") && appConfig.Columns.Contains("vcLine") && appConfig.Columns.Contains("WorkStation_ID")) { if (Convert.IsDBNull(appConfig.Rows[0]["IdChainValue"]) || !int.TryParse(appConfig.Rows[0]["IdChainValue"] .ToString(), out _carrierMesAppChainId )) { SetError(53, $"App.config.xml ChainValue is incorrect."); } if (!Convert.IsDBNull(appConfig.Rows[0]["vcLine"])) { _carrierMesAppLine = appConfig.Rows[0]["vcLine"] .ToString(); } else SetError(53, $"App.config.xml ChainValue is incorrect."); if (Convert.IsDBNull(appConfig.Rows[0]["WorkStation_ID"]) || !int.TryParse(appConfig.Rows[0]["WorkStation_ID"] .ToString(), out _carrierMesAppWorkStationId )) { SetError(53, $"App.config.xml WorkStation_ID is incorrect."); } } //jrg 2023-10-12 - MX A decided on different names... if (appConfig.Columns.Contains("IdLine") && !Convert.IsDBNull(appConfig.Rows[0]["IdLine"])) { _carrierMesAppLine = appConfig.Rows[0]["IdLine"] .ToString(); } //for MX A this may not always be an int? We would need to do the convert @ sp call time if that's the case... if (appConfig.Columns.Contains("DeviceID") && !Convert.IsDBNull(appConfig.Rows[0]["DeviceID"])) { if (!int.TryParse(appConfig.Rows[0]["DeviceID"] .ToString(), out _carrierMesAppWorkStationId )) { SetError(53, $"App.config.xml WorkStation_ID is incorrect."); } } //jrg 2023-10-12 - Added for MX A, will only show up for them if (appConfig.Columns.Contains("Limit_Type_ID") && !Convert.IsDBNull(appConfig.Rows[0]["Limit_Type_ID"])) { _carrierMesLimitTypeID = appConfig.Rows[0]["Limit_Type_ID"] .ToString(); } } } } catch (Exception ex) { SetError(52, $"Exception Parsing App.config"); } if (_debug) AddLogItem($"Carrier-MX-MES - App Config Loaded: ChainID: {_carrierMesAppChainId}; vcLine: {_carrierMesAppLine}; WorkStation_ID: {_carrierMesAppWorkStationId}"); } }