#region Namespace using System; using System.Diagnostics; using System.Reflection; using System.ServiceModel; using com.itac.mes.proxy; using www.siplace.com.OIB._2008._05.SetupCenter.Contracts.Data; using www.siplace.com.OIB._2008._05.SetupCenter.Contracts.Service; using OibClient = Asm.As.Oib.Client; using com.itac.mes.imsapi.domain.container; using System.Collections.Generic; using com.itac.mes.imsapi; using KeyValue = com.itac.mes.imsapi.domain.container.KeyValue; using com.itac.mes.imsapi.data; using System.Configuration; using com.itac.mes.simm; using com.itac.mes.tools; using com.itac.mes.imsapi.client.dotnet; #endregion namespace Itac.Oib.Simm { [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] public class SetupCenterExternalControlReceiver : ISiplaceSetupCenterExternalControl, IDisposable, IReceiver { #region Fields private readonly OibClient.OibSetupCenterExternalControlEvents _oibSetupCenterExternalControlEvents; private IIMSApiDotNet imsapi; private IMSApiSessionContextStruct sessionContext; private ItacXmlSerializer serializer; private long firstASMTime = new DateTime(1900, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; private long msdOpenTime = DateTime.MinValue.Ticks; private long lastItacTimeTicks = new DateTime(3000, 12, 31, 23, 59, 59, DateTimeKind.Utc).Ticks; private long firstItacTimeTicks = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks; /// /// the station Number is configured, must not be empty and MUST exist and valid!!! /// if the stationNumber is not valid (licensed etc) all requests are rejected!! /// private string stationNumber; private int transactionCode; // some optional values, default false private bool mslLevelCheck; private ConfigCode expirationMaster; private ConfigCode mslMaster; private ConfigCode quantityMaster; #endregion #region Constructor public SetupCenterExternalControlReceiver(OibClient.OibSetupCenterExternalControlEvents oibSetupCenterExternalControlEvents, IIMSApiDotNet imsapi, IMSApiSessionContextStruct newSessionContext, String stationNumber, int transactionCode, ConfigCode quantityMaster, ConfigCode mslMaster, ConfigCode expirationMaster) { _oibSetupCenterExternalControlEvents = oibSetupCenterExternalControlEvents; if (oibSetupCenterExternalControlEvents != null) { oibSetupCenterExternalControlEvents.Ping = Ping; oibSetupCenterExternalControlEvents.GetNewPackagingUnitData = GetNewPackagingUnitData; oibSetupCenterExternalControlEvents.GetPackagingUnitControlStatus = GetPackagingUnitControlStatus; } this.imsapi = imsapi; this.sessionContext = newSessionContext; this.stationNumber = stationNumber; this.transactionCode = transactionCode; this.quantityMaster = quantityMaster; this.mslMaster = mslMaster; this.expirationMaster = expirationMaster; serializer = new ItacXmlSerializer(); // evaluate some optional parameters from appConfig file if (!String.IsNullOrEmpty(System.Configuration.ConfigurationManager.AppSettings["mslLevelCheck"])) { mslLevelCheck = bool.Parse(ConfigurationManager.AppSettings["mslLevelCheck"].ToString()); LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, "optional parameter 'mslLevelCheck' set '" + mslLevelCheck.ToString() + "'"); } } public void Dispose() { if (_oibSetupCenterExternalControlEvents != null) _oibSetupCenterExternalControlEvents.Dispose(); } #endregion #region Start/Stop public void StartReceiver() { _oibSetupCenterExternalControlEvents.Start(); } public void StopReceiver() { _oibSetupCenterExternalControlEvents.Stop(); } #endregion #region toolFunctions // muss noch weiter getestet werden... public void DeepCopy(object sourceObject, object destObject) { Type sourceType = sourceObject.GetType(); Type destType = destObject.GetType(); MemberInfo[] sourceMbrInfoArray = sourceType.GetMembers(); MemberInfo[] destMbrInfoArray = destType.GetMembers(); foreach (MemberInfo sourceMbrInfo in sourceMbrInfoArray) { if (sourceMbrInfo.MemberType == MemberTypes.Property) { LogHandler.log(Constants.LOGGER, TraceEventType.Error, "" + sourceMbrInfo + " is a " + sourceMbrInfo.MemberType); // alle einfachen TypeNameConverter direkt prüfen (int, String, bool) // komplexe Typen ??? PropertyInfo sourcePropInfo = sourceType.GetProperty(sourceMbrInfo.Name); // gibt es das Property auch im Zielobjekt foreach (MemberInfo destMbrInfo in destMbrInfoArray) { // identischer Name, identischerr Typ if (destMbrInfo.MemberType == sourceMbrInfo.MemberType && destMbrInfo.Name == sourceMbrInfo.Name) { PropertyInfo destPropInfo = destType.GetProperty(destMbrInfo.Name); object sourceValue = sourcePropInfo.GetValue(sourceObject, null); object destValue = destPropInfo.GetValue(destObject, null); if (sourcePropInfo.PropertyType == typeof(String) || sourcePropInfo.PropertyType == typeof(int) || sourcePropInfo.PropertyType == typeof(Int32) || sourcePropInfo.PropertyType == typeof(Int64) || sourcePropInfo.PropertyType == typeof(long) || sourcePropInfo.PropertyType == typeof(bool) || sourcePropInfo.PropertyType == typeof(Boolean)) { if (sourceValue != destValue) { LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, "primitive type copy value"); destPropInfo.SetValue(destObject, sourceValue, null); } } else if (!sourceType.IsArray) { // komplexer Typ, kein Array LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, sourceMbrInfo.Name + " is complex type "); if (sourceValue != null) { DeepCopy(sourceValue, destValue); } else { LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, sourceMbrInfo.Name + " is complex type, sourceValue is null"); } } } } } } } public void applyToPackagingUnit(SmtContainer container, ref PackagingUnit p) { p.BatchId = container.supplierChargeNumber; // p.BatchPackagingUnit= p.BrightnessClass = container.classification; ; // p.Comment=""; p.ComponentBarcode = ""; p.ComponentName = container.materialBinPartNumber; // p.ConsumptionDate = getDateValue(resultValues[indexMap[""]]); // special case: itac 31.12.3000 is unexpired, in ASM 31.12.9999 if (container.expirationDate >= new DateTime(2037, 12, 31)) { p.ExpiryDate = DateTime.MaxValue.ToUniversalTime(); } else { p.ExpiryDate = container.expirationDate; // getDateValue(resultValues[indexMap["EXPIRATION_DATE"]]); } // p.Extra1=""; // p.Extra2=""; // p.Extra3=""; // p.GreyZone= if (p.LastProductionDate <= new DateTime(1901, 01, 01, 00, 00, 00, DateTimeKind.Utc)) { p.LastProductionDate = DateTime.MinValue.ToUniversalTime(); } // p.ManufactureLocation // p.ManufacturePartNumber p.Manufacturer = container.supplierName; p.ManufacturerDate = container.dateCreated; p.MsdLevel = MslLevel.toCode(container.mslLevel); string mslState = container.mslState; if ("C".Equals(mslState)) { p.MsdOpenDate = DateTime.MinValue.ToUniversalTime(); } else { // take open date from MES p.MsdOpenDate = container.mslOpenDate; // correction of MSD open Date when unopened if (p.MsdOpenDate <= new DateTime(1901, 01, 01, 00, 00, 00, DateTimeKind.Utc)) { p.MsdOpenDate = DateTime.MinValue.ToUniversalTime(); } } // p.OrderingCode = ; p.OriginalQuantity = container.quantity;// Convert.ToInt32(double.Parse(resultValues[indexMap["MATERIAL_BIN_QTY_TOTAL"]])); p.PurchaseOrderNumber = container.huNumber; p.Quantity = container.materialBinQuantityActual; // Convert.ToInt32(Double.Parse(resultValues[indexMap["MATERIAL_BIN_QTY_ACTUAL"]])); // p.RevisionLevel; // p.RoHS // p.Serial // p.ShippingNoteNumber // p.SplicedPackagingUnit p.Supplier = container.supplierName; // p.SupplierData // p.UID; } public void mapValues(PackagingUnit pu, string[] materialBinUploadKeys, ref string[] result, int index) { foreach (string s in materialBinUploadKeys) { switch (s) { case "ERROR_CODE": result[index++] = "0"; break; case "MATERIAL_BIN_NUMBER": result[index++] = pu.UID; break; default: result[index++] = "0"; break; } } } public void deepAddUnit(PackagingUnit packUnit, ref Dictionary packagingUnitMap) { packagingUnitMap.Add(packUnit.UID, packUnit); if (packUnit.SplicedPackagingUnit != null) { deepAddUnit(packUnit.SplicedPackagingUnit, ref packagingUnitMap); } } #endregion toolFunctions #region ISiplaceSetupCenterExternalControl Members /// /// Check for the client if this service is available. /// /// public bool Ping() { LogHandler.log(Constants.LOGGER, TraceEventType.Information, "SetupCenterExternalControl.Ping"); return true; } /// /// Gets the packaging unit control status. /// /// The packaging unit locations. /// List of ExternalControlResults for reading the data /// ResultState UNKNOWN=0;OK = 1;NOT_OK=2; public ExternalControlResult[] GetNewPackagingUnitData(PackagingUnitLocation[] packagingUnitLocations) { LogHandler.log(Constants.LOGGER, TraceEventType.Information, "SetupCenterExternalControl.GetNewPackagingUnit()\n" + serializer.serialize(packagingUnitLocations).ToString()); KeyValue[] matBinfilters = new KeyValue[] { new KeyValue("MATERIAL_BIN_NUMBER", "") }; AttributeInfo[] attributes = new AttributeInfo[0]; string[] resultValues; try { ExternalControlResult[] result = new ExternalControlResult[packagingUnitLocations.Length]; for (int i = 0; i < packagingUnitLocations.Length; i++) { result[i] = new ExternalControlResult(); result[i].PackagingUnit = packagingUnitLocations[i].PackagingUnit; matBinfilters[0].value = packagingUnitLocations[i].PackagingUnit.UID; int imsapiResult = imsapi.mlGetMaterialBinData(sessionContext, stationNumber, matBinfilters, attributes, SmtContainer.MAXIMAL_INFORMATION, out resultValues); // return all relevant PackagingUnit infos known in iTAC.MES.Suite if (imsapiResult < 0 || imsapiResult == 1) // 1 = no data found { result[i].ResultState = 2; result[i].Messages = new ExternalControlResultMessage[] { new ExternalControlResultMessage() }; result[i].Messages[0].Message = "UID " + packagingUnitLocations[i].PackagingUnit.UID + " unknown in iTAC.MES.Suite"; } else { // OK, Info gathered result[i].ResultState = 1; result[i].Messages = new ExternalControlResultMessage[] { }; PackagingUnit p = result[i].PackagingUnit; try { SmtContainer knownContainer = new ImsApiMapTool().getStruct(typeof(SmtContainer), SmtContainer.MAXIMAL_INFORMATION, resultValues); applyToPackagingUnit(knownContainer, ref p); } catch (Exception e) { result[i].ResultState = 2; result[i].Messages = new ExternalControlResultMessage[] { new ExternalControlResultMessage() }; result[i].Messages[0].Message = e.Message.ToString(); } } } LogHandler.log(Constants.LOGGER, TraceEventType.Information, serializer.serialize(result).ToString()); return result; } catch (Exception) { // Fehler, keine weitere info vorhanden, da die Applikation nicht läuft return new ExternalControlResult[0]; } } /// /// Gets the packaging unit control status. /// /// The packaging unit locations. /// List of ExternalControlResults for reading the data public ExternalControlResult[] GetPackagingUnitControlStatus(PackagingUnitLocation[] packagingUnitLocations) { LogHandler.log(Constants.LOGGER, TraceEventType.Information, "SetupCenterExternalControl.GetPackagingUnitControlStatus:\n" + serializer.serialize(packagingUnitLocations).ToString()); if (!mslLevelCheck) { LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, "mslLevel check switched off by confguration"); } KeyValue[] matBinfilters = new KeyValue[] { new KeyValue("MATERIAL_BIN_NUMBER", "") }; AttributeInfo[] attributes = new AttributeInfo[0]; // flag wether to update any qty or not. LinkedList updateQtyList = new LinkedList(); try { ExternalControlResult[] result = new ExternalControlResult[packagingUnitLocations.Length]; for (int resultIndex = 0; resultIndex < packagingUnitLocations.Length; resultIndex++) { result[resultIndex] = new ExternalControlResult(); result[resultIndex].PackagingUnit = packagingUnitLocations[resultIndex].PackagingUnit; PackagingUnit packagingUnit = packagingUnitLocations[resultIndex].PackagingUnit; // ResultState UNKNOWN = 0; OK = 1; NOT_OK = 2; result[resultIndex].ResultState = 1; result[resultIndex].Messages = new ExternalControlResultMessage[] { }; string[] resultValues; matBinfilters[0].value = packagingUnitLocations[resultIndex].PackagingUnit.UID; int imsapiResult = imsapi.mlGetMaterialBinData(sessionContext, stationNumber, matBinfilters, attributes, SmtContainer.MINIMAL_INFORMATION, out resultValues); if (imsapiResult < 0 || imsapiResult == 1) // 1 = no data found { // Packaging Units unknown in MES.Suite must be rejected // Error, Packaging Unit not found in mes.suite result[resultIndex].ResultState = 2; ExternalControlResultMessage message = new ExternalControlResultMessage(); message.Message = "PackagingUnit '" + packagingUnitLocations[resultIndex].PackagingUnit.UID + "' unknown in iTAC.MES.Suite"; result[resultIndex].Messages = new ExternalControlResultMessage[] { message }; } else { // find any differences in quantities and update the values in MES.Suite SmtContainer knownContainer = new ImsApiMapTool().getStruct(typeof(SmtContainer), SmtContainer.MINIMAL_INFORMATION, resultValues); LogHandler.log(Constants.LOGGER, TraceEventType.Information, serializer.serialize(knownContainer).ToString()); LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, "quantityMaster=" + quantityMaster); adjustQuantity(quantityMaster, ref knownContainer, ref packagingUnit, ref updateQtyList); // any differences in mslLevel? if (mslLevelCheck) { LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, "mslLevelCheck=true"); LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, String.Format("UID: {0} MsdLevel(ASM): {1}, MslLevel(iTAC): {2}", packagingUnit.UID, packagingUnit.MsdLevel, knownContainer.mslLevel)); if (!knownContainer.mslLevel.ToLower().Equals(MslLevel.toString(packagingUnit.MsdLevel))) { // failure, wrong MslLevel result[resultIndex].ResultState = 2; ExternalControlResultMessage message = new ExternalControlResultMessage(); message.Message = String.Format("PackagingUnit {0} has MsdLevel {1} in SetupCenter, but Level {2} in iTAC.MES.Suite", packagingUnit.UID, MslLevel.toString(packagingUnit.MsdLevel), knownContainer.mslLevel); result[resultIndex].Messages = new ExternalControlResultMessage[] { message }; } // continue with next container continue; } // any differences in msl state? if (mslMaster == ConfigCode.SIMM) { LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, "mslMaster=" + mslMaster.ToString()); LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, String.Format("UID: {0} MsdOpen(ASM): {1}, MslState(iTAC): {2}", packagingUnit.UID, isMsdOpen(packagingUnit.MsdOpenDate), knownContainer.mslState)); // iTAC states : C = geschützt / verschweißt(Closed) O = ungeschützt / offen(Open) B = in der Rücktrocknung (Baking) // ASM closed: MsdOpenDate = 2.1.1900 KeyValue[] mslEventParams = new KeyValue[] { new KeyValue("BOOK_DATE", getImsApiDateString(packagingUnit.MsdOpenDate)) }; KeyValue[] mslStopEventParams = new KeyValue[] { new KeyValue("BOOK_DATE", "-1") }; string[] mslObjectKeys = new String[] { "ERROR_CODE", "MATERIAL_BIN_NUMBER" }; string[] mslObjectValues = new String[] { "0", packagingUnit.UID }; string[] mslResultValues = new String[] { }; if (knownContainer.mslState.Equals("C") && isMsdOpen(packagingUnit.MsdOpenDate)) { // closed in iTAC, open in ASM--> required to open in iTAC!!! int mslStartExpirationCode = imsapi.mslStartObjectExpiration(sessionContext, stationNumber, mslEventParams, mslObjectKeys, mslObjectValues, out mslResultValues); if (mslStartExpirationCode < 0) { result[resultIndex].ResultState = 2; ExternalControlResultMessage message = new ExternalControlResultMessage(); message.Message = String.Format("PackagingUnit {0} not opened in iTAC.MES.Suite", packagingUnit.UID); result[resultIndex].Messages = new ExternalControlResultMessage[] { message }; continue; } } else if (knownContainer.mslState.Equals("O") && !isMsdOpen(packagingUnit.MsdOpenDate) && packagingUnit.MsdOpenDate.Ticks > DateTime.MinValue.Ticks) { // open in iTAC, closed in ASM--> required to close in iTAC!!! int mslStopExpirationCode = imsapi.mslStopObjectExpiration(sessionContext, stationNumber, mslStopEventParams, mslObjectKeys, mslObjectValues, out mslResultValues); if (mslStopExpirationCode < 0) { result[resultIndex].ResultState = 2; ExternalControlResultMessage message = new ExternalControlResultMessage(); message.Message = String.Format("PackagingUnit {0} not closed in iTAC.MES.Suite", packagingUnit.UID); result[resultIndex].Messages = new ExternalControlResultMessage[] { message }; continue; } } } else if (mslMaster == ConfigCode.MES) { LogHandler.log(Constants.LOGGER, TraceEventType.Warning, "this mode is currently not supported!"); } LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, "expirationMaster=" + expirationMaster.ToString()); if (!adjustExpiration(expirationMaster, ref knownContainer, ref packagingUnit, ref imsapi, ref result[resultIndex])) { continue; } // SiMM-Corrections if (packagingUnit.MsdOpenDate <= new DateTime(1900, 01, 01)) { packagingUnit.MsdOpenDate = DateTime.MinValue.ToUniversalTime(); } if (packagingUnit.ConsumptionDate <= new DateTime(1900, 01, 01)) { packagingUnit.ConsumptionDate = DateTime.MinValue.ToUniversalTime(); } if (packagingUnit.ExpiryDate <= new DateTime(1900, 01, 01)) { packagingUnit.ExpiryDate = DateTime.MinValue.ToUniversalTime(); } if (packagingUnit.LastProductionDate <= new DateTime(1900, 01, 01)) { packagingUnit.LastProductionDate = DateTime.MinValue.ToUniversalTime(); } if (packagingUnit.ManufacturerDate <= new DateTime(1900, 01, 01)) { packagingUnit.ManufacturerDate = DateTime.MinValue.ToUniversalTime(); } } } if (quantityMaster == ConfigCode.SIMM && updateQtyList.Count > 0) { MaterialBinBooking[] matBinBookingArray = new MaterialBinBooking[updateQtyList.Count]; updateQtyList.CopyTo(matBinBookingArray, 0); string[] materialBinBookingUploadValues = new ImsApiMapTool().getValueArray(matBinBookingArray, MaterialBinBooking.MAXIMAL_INFORMATION); ; string[] materialBinBookingsResultValues = null; int retUpdateQty = imsapi.mlUploadMaterialBinBooking(sessionContext, stationNumber, MaterialBinBooking.MAXIMAL_INFORMATION, materialBinBookingUploadValues, out materialBinBookingsResultValues); } LogHandler.log(Constants.LOGGER, TraceEventType.Information, serializer.serialize(result).ToString()); return result; } catch (Exception) { // Fehler, keine weitere info vorhanden, da die Applikation nicht läuft return new ExternalControlResult[0]; } } public void adjustQuantity(ConfigCode quantityMaster, ref SmtContainer knownContainer, ref PackagingUnit packagingUnit, ref LinkedList updateQtyList) { if (quantityMaster == ConfigCode.SIMM) { LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, String.Format("UID: {0} Qty(ASM): {1}, Qty(iTAC): {2}", packagingUnit.UID, packagingUnit.Quantity, knownContainer.materialBinQuantityActual)); if (packagingUnit.Quantity != knownContainer.materialBinQuantityActual) { // udpate the MES with the quantity from ASM MaterialBinBooking matBinBooking = new MaterialBinBooking(); matBinBooking.materialBinNumber = packagingUnit.UID; matBinBooking.transactionCode = transactionCode.ToString(); matBinBooking.materialBinQuantityActual = packagingUnit.Quantity; updateQtyList.AddLast(matBinBooking); } } else if (quantityMaster == ConfigCode.MES) { LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, String.Format("UID: {0} Qty(ASM): {1}, Qty(iTAC): {2}", packagingUnit.UID, packagingUnit.Quantity, knownContainer.materialBinQuantityActual)); if (packagingUnit.Quantity != knownContainer.materialBinQuantityActual) { packagingUnit.Quantity = knownContainer.materialBinQuantityActual; } } } public bool adjustExpiration(ConfigCode expirationMaster, ref SmtContainer knownContainer, ref PackagingUnit packagingUnit, ref IIMSApiDotNet imsapi, ref ExternalControlResult result) { if (expirationMaster == ConfigCode.SIMM) { if (packagingUnit.ExpiryDate == DateTime.MinValue) { LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, String.Format("UID: {0} no expiration set", packagingUnit.UID)); return true; } LogHandler.log(Constants.LOGGER, TraceEventType.Verbose, String.Format("UID: {0} expiryDate(ASM): {1}, expirationDate(iTAC): {2}", packagingUnit.UID, packagingUnit.ExpiryDate, knownContainer.expirationDate)); if (expirationDateDifferent(packagingUnit.ExpiryDate, knownContainer.expirationDate)) { // update expirationDate in iTAC KeyValue[] keyValueArray = new KeyValue[1]; keyValueArray[0] = new KeyValue("EXPIRATION_DATE_FINAL", getImsApiDateString(packagingUnit.ExpiryDate)); int changeBinResult = imsapi.mlChangeMaterialBinData(sessionContext, stationNumber, packagingUnit.UID, keyValueArray); if (changeBinResult < 0) { // reject container result.ResultState = 2; ExternalControlResultMessage message = new ExternalControlResultMessage(); message.Message = String.Format("PackagingUnit {0} expiration date final not updated in iTAC.MES.Suite", packagingUnit.UID); result.Messages = new ExternalControlResultMessage[] { message }; return false; } } } else if (expirationMaster == ConfigCode.MES) { LogHandler.log(Constants.LOGGER, TraceEventType.Warning, "this mode is currently not supported!"); return true; } return true; } public string getImsApiDateString(DateTime expiryDate) { if (expiryDate.Ticks >= lastItacTimeTicks) { return "32535212399000"; } if (expiryDate.Ticks <= firstItacTimeTicks) { return "0"; } return expiryDate.ToUniversalTime().Subtract( new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc) ).TotalMilliseconds.ToString(); } public bool expirationDateDifferent(DateTime expiryDate, DateTime expirationDate) { // both values after 30.12.3000 00:00:00 --> same... if (expiryDate.Day >= 30 && expiryDate.Month >= 12 && expiryDate.Year >= 3000 && expirationDate.Day >= 30 && expirationDate.Month >= 12 && expirationDate.Year >= 3000) { return false; } return expiryDate.Ticks != expirationDate.Ticks; } public bool isMsdOpen(DateTime msdOpenDate) { return (msdOpenDate.Ticks > msdOpenTime); } #endregion } }