using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using InABox.Core; namespace Comal.Classes { public class ManufacturingPacketArea : IFormula { public Expression> Value => x => x.Height; public Expression>[] Modifiers => new Expression>[] { x => x.Width, x => 0.000001m }; public FormulaOperator Operator => FormulaOperator.Multiply; public FormulaType Type => FormulaType.Virtual; } public class ManufacturingPacketVolume : IFormula { public Expression> Value => x => x.Height; public Expression>[] Modifiers => new Expression>[] { x => x.Width, x => x.Length, x => 0.000000001m }; public FormulaOperator Operator => FormulaOperator.Multiply; public FormulaType Type => FormulaType.Virtual; } public class ManufacturingPacketTime : CoreAggregate { public override Expression> Aggregate => x => x.Time; public override AggregateCalculation Calculation => AggregateCalculation.Sum; public override Dictionary>, Expression>> Links => new Dictionary>, Expression>>() { { ManufacturingPacketStage => ManufacturingPacketStage.Parent.ID, ManufacturingPacket => ManufacturingPacket.ID } }; } public class ManufacturingPacketTimeRemaining : CoreAggregate { public override Expression> Aggregate => x => x.TimeRemaining; public Expression> Link => x => x.Parent.ID; public override AggregateCalculation Calculation => AggregateCalculation.Sum; public override Dictionary>, Expression>> Links => new Dictionary>, Expression>>() { { ManufacturingPacketStage => ManufacturingPacketStage.Parent.ID, ManufacturingPacket => ManufacturingPacket.ID } }; } public class ManufacturingPacketActualTime : CoreAggregate { public override Expression> Aggregate => x => x.WorkDuration; public override AggregateCalculation Calculation => AggregateCalculation.Sum; public override Dictionary>, Expression>> Links => new Dictionary>, Expression>>() { { ManufacturingHistory => ManufacturingHistory.Packet.ID, ManufacturingPacket => ManufacturingPacket.ID } }; } [UserTracking("Manufacturing")] [Caption("Manufacturing")] public class ManufacturingPacket : Entity, IPersistent, IRemotable, IOneToMany, ILicense, IIssues { [TextBoxEditor] [EditorSequence(1)] public string Title { get; set; } [CodeEditor(Visible = Visible.Default, Editable = Editable.Enabled)] [EditorSequence(2)] public string Serial { get; set; } private class SetoutLookup : LookupDefinitionGenerator { public override Filter DefineFilter(ManufacturingPacket[] items) { return new Filter(x => x.JobLink.ID).IsEqualTo(items.First().SetoutLink.JobLink.ID); } public override Columns DefineFilterColumns() => Columns.None().Add(x => x.SetoutLink.JobLink.ID); } [LookupDefinition(typeof(SetoutLookup))] [EditorSequence(3)] [EntityRelationship(DeleteAction.Cascade)] public SetoutLink SetoutLink { get; set; } private class JobITPLookup : LookupDefinitionGenerator { public override Filter DefineFilter(ManufacturingPacket[] items) { if (items.Length == 1) return new Filter(x => x.Job.ID).IsEqualTo(items.First().SetoutLink.JobLink.ID); return LookupFactory.DefineFilter(); } public override Columns DefineFilterColumns() => Columns.None().Add(x => x.SetoutLink.JobLink.ID); } [EditorSequence(4)] [LookupDefinition(typeof(JobITPLookup))] public JobITPLink ITP { get; set; } [TextBoxEditor] [EditorSequence(5)] public string Location { get; set; } // Used to calculate time & materials [EditorSequence(7)] [IntegerEditor] public int Quantity { get; set; } [EditorSequence(8)] [IntegerEditor] // Determines # of barcodes to print public int BarcodeQty { get; set; } [EditorSequence(9)] [TimestampEditor(Editable = Editable.Hidden)] public override DateTime Created { get => base.Created; set => base.Created = value; } [EditorSequence(10)] [DateTimeEditor] public DateTime DueDate { get; set; } [EditorSequence("Design", 101)] [EntityRelationship(DeleteAction.Cascade)] public PDFDocumentLink Drawing { get; set; } // To be overlaid over the PDF document [EditorSequence("Design", 102)] [TextBoxEditor] public string WaterMark { get; set; } [EditorSequence("Design", 103)] public double Height { get; set; } [EditorSequence("Design", 104)] public double Width { get; set; } [EditorSequence("Design", 105)] public double Length { get; set; } [EditorSequence("Manufacturing", 200)] public ManufacturingTemplateLink ManufacturingTemplateLink { get; set; } [EditorSequence("Manufacturing", 201)] [TimestampEditor(Editable = Editable.Disabled)] public DateTime Issued { get; set; } [EditorSequence("Manufacturing", 202)] [LoggableProperty] public bool Priority { get; set; } [EditorSequence("Manufacturing", 203)] [LoggableProperty] public bool Distributed { get; set; } [EditorSequence("Manufacturing", 204)] [TextBoxEditor(Editable = Editable.Disabled)] public string Trolleys { get; set; } [EditorSequence("Manufacturing", 205)] [TimestampEditor(Editable = Editable.Hidden)] public DateTime BarcodePrinted { get; set; } [EditorSequence("Manufacturing", 206)] [DateTimeEditor(Editable = Editable.Disabled)] [SecondaryIndex] public DateTime Completed { get; set; } [SecondaryIndex] [TimestampEditor] [EditorSequence("Manufacturing", 207)] public DateTime Archived { get; set; } = DateTime.MinValue; [CheckBoxEditor] [EditorSequence("Issues", 2)] [LoggableProperty] public bool OnHold { get; set; } [MemoEditor] [EditorSequence("Issues", 1)] [LoggableProperty] public string Issues { get; set; } public override string ToString() { return string.Format("{0} {1}", SetoutLink.Number, Serial); } public static void Progress(IEnumerable packets, ManufacturingPacketStage[] Stages) { //List updates = new List(); foreach (var packet in packets.Where(x => !x.StageLink.Equals(CoreUtils.FullGuid))) { var stages = Stages.Where(x => x.Parent.ID.Equals(packet.ID)); long sequence = 0; var stage = stages.FirstOrDefault(x => x.ID.Equals(packet.StageLink.ID)); if (stage != null) { stage.Completed = DateTime.Now; stage.PercentageComplete = 100.0F; sequence = stage.Sequence; } // Update the pointer to the next stage stage = stages.Where(x => x.Sequence > sequence).FirstOrDefault(); if (stage != null) { stage.QualityStatus = QualityStatus.NotChecked; stage.QualityNotes = ""; stage.Station = 0; stage.Started = DateTime.MinValue; stage.Completed = DateTime.MinValue; stage.PercentageComplete = 0.0F; packet.StageLink.ID = stage.ID; packet.StageLink.Synchronise(stage); } else { packet.StageLink.ID = CoreUtils.FullGuid; } packet.Issued = !packet.StageLink.IsValid() ? DateTime.MinValue : packet.Issued.IsEmpty() ? DateTime.Now : packet.Issued; packet.Completed = packet.StageLink.ID.Equals(CoreUtils.FullGuid) ? packet.Completed.IsEmpty() ? DateTime.Now : packet.Completed : DateTime.MinValue; } } public static void Regress(IEnumerable pkts, ManufacturingPacketStage[] stgs) { foreach(var packet in pkts) { var stages = stgs.Where(x => x.Parent.ID.Equals(packet.ID)); var sequence = long.MaxValue; var stage = stages.FirstOrDefault(x => x.ID.Equals(packet.StageLink.ID)); if (stage != null) { stage.Completed = DateTime.MinValue; stage.PercentageComplete = 0.0F; stage.QualityStatus = QualityStatus.NotChecked; stage.QualityNotes = ""; sequence = stage.Sequence; } // Update the pointer to the previous stage stage = stages.Where(x => x.Sequence < sequence).LastOrDefault(); if (stage != null) { stage.QualityStatus = QualityStatus.NotChecked; stage.QualityNotes = ""; stage.Station = 0; stage.Started = DateTime.MinValue; stage.Completed = DateTime.MinValue; stage.PercentageComplete = 0.0F; } packet.StageLink.ID = stage == null ? Guid.Empty : stage.ID; packet.Issued = !packet.StageLink.IsValid() ? DateTime.MinValue : packet.Issued.IsEmpty() ? DateTime.Now : packet.Issued; packet.DueDate = packet.Issued.IsEmpty() ? DateTime.MinValue : packet.DueDate; packet.Completed = packet.StageLink.ID.Equals(CoreUtils.FullGuid) ? packet.Completed.IsEmpty() ? DateTime.Now : packet.Completed : DateTime.MinValue; } } #region Aggregates [EditorSequence(300)] [DoubleEditor(Editable = Editable.Hidden)] [Formula(typeof(ManufacturingPacketArea))] public double Area { get; set; } [EditorSequence(301)] [DoubleEditor(Editable = Editable.Hidden)] [Formula(typeof(ManufacturingPacketVolume))] public double Volume { get; set; } [EditorSequence(302)] [Aggregate(typeof(ManufacturingPacketTime))] public TimeSpan Time { get; set; } [EditorSequence(303)] [Aggregate(typeof(ManufacturingPacketTimeRemaining))] public TimeSpan TimeRemaining { get; set; } [EditorSequence(304)] [Aggregate(typeof(ManufacturingPacketActualTime))] public TimeSpan ActualTime { get; set; } #endregion #region Internal / NullEditor Properties private class ManufacturingPacketStageLookup : LookupDefinitionGenerator { public override Filter? DefineFilter(ManufacturingPacket[] items) { if (items.Any()) return new Filter(x => x.Parent.ID).IsEqualTo(items.First().ID); return null; } public override Columns DefineFilterColumns() => Columns.None().Add(x => x.ID); } [LookupDefinition(typeof(ManufacturingPacketStageLookup))] [NullEditor] public ManufacturingPacketStageLink StageLink { get; set; } [NullEditor] public QAFormLink QAForm { get; set; } // I think ITPs will end up being linked to a stage, // So this might get obsoleted at some point private class JobStageLookup : LookupDefinitionGenerator { public override Filter DefineFilter(ManufacturingPacket[] items) { if (items.Length == 1) return new Filter(x => x.Job.ID).IsEqualTo(items.First().SetoutLink.JobLink.ID).And(x => x.IsHeader).IsEqualTo(false); return new Filter(x => x.ID).IsEqualTo(Guid.Empty); } public override Columns DefineFilterColumns() => Columns.None().Add(x => x.SetoutLink.JobLink.ID); } [LookupDefinition(typeof(JobStageLookup))] [NullEditor] public JobStageLink JobStage { get; set; } [NullEditor] [EntityRelationship(DeleteAction.SetNull)] public PurchaseOrderItemLink OrderItem { get; set; } [NullEditor] public DateTime EstimatedDate { get; set; } #endregion #region Obsolete Properties // The code of the Linked Manufacturing Template // Suggested - set to obsolete? [NullEditor] [Obsolete("Replaced with ManufacturingTemplateLink.Code", true)] public string Code { get; set; } // The Factory to which this packet template belongs // Suggestion - Set to obsolete? [NullEditor] [Obsolete("Replaced with ManufacturingTemplateLink.FactoryLink.ID")] public string Group { get; set; } [NullEditor] [Obsolete("Replaced with BarcodeQty")] public bool GroupedBarcode { get; set; } private BarcodeType _barcodetype = BarcodeType.Unspecified; [NullEditor] [Obsolete("Replaced with BarcodeQty")] public BarcodeType BarcodeType { get => _barcodetype == BarcodeType.Unspecified ? GroupedBarcode ? BarcodeType.Grouped : BarcodeType.Individual : _barcodetype; set => _barcodetype = value; } // Comes from Setout.Title (Should be Reference) [NullEditor] [Obsolete("Replaced with SetoutLink.Reference")] public string Reference { get; set; } // Comes from Setout.Location [NullEditor] [Obsolete("Replaced with SetoutLink.Description")] public string Description { get; set; } [Obsolete("Replaced With ManufacturingTemplateLink")] [NullEditor] public Guid ManufacturingItemID { get; set; } [NullEditor] [Obsolete("Replaced with ManufacturingPacketLink.Code")] public string Template { get; set; } [Obsolete("Replaced With SetoutLink.JobLink")] [EntityRelationship(DeleteAction.Cascade)] [NullEditor] public JobLink JobLink { get; set; } #endregion #region Functions //public void MovePrevious() //{ // bool bFound = false; // SetoutStage prev = null; // foreach (SetoutStage stage in Stages) // { // if (bFound) // { // stage.Started = DateTime.MinValue; // stage.Completed = DateTime.MinValue; // stage.PercentageComplete = 0.0F; // } // else if (stage.Completed.IsEmpty()) // { // stage.Started = DateTime.MinValue; // stage.Completed = DateTime.MinValue; // stage.PercentageComplete = 0.0F; // bFound = true; // if (prev != null) // prev.Completed = DateTime.MinValue; // } // else // prev = stage; // } // if (prev == null) // Issued = DateTime.MinValue; // Completed = DateTime.MinValue; // Stage = CurrentStage(); //} //public void MoveNext() //{ // bool bFound = false; // bool bComplete = true; // if (Issued.IsEmpty()) // Issued = DateTime.Now; // foreach (SetoutStage stage in Stages) // { // if (bFound) // { // stage.Started = DateTime.MinValue; // stage.Completed = DateTime.MinValue; // stage.PercentageComplete = 0.0F; // bComplete = false; // } // else if (stage.Started.IsEmpty()) // { // //stage.Started = DateTime.Now; // stage.Completed = DateTime.MinValue; // stage.PercentageComplete = 0.0F; // bComplete = false; // bFound = true; // } // else if (stage.Completed.IsEmpty()) // { // stage.Completed = DateTime.Now; // stage.PercentageComplete = 100.0F; // bFound = true; // } // } // //Completed = bComplete ? DateTime.Now : DateTime.MinValue; // bool bIsComplete = !Stages.Any(x => x.Completed.Equals(DateTime.MinValue)); // if (bIsComplete && Completed.Equals(DateTime.MinValue)) // Completed = DateTime.Now; // Stage = CurrentStage(); //} //public Boolean IsComplete() //{ // if ((!Issued.IsEmpty()) && (Stages != null)) // { // foreach (SetoutStage stage in Stages) // { // if (stage.Completed.IsEmpty()) // return false; // } // return true; // } // return false; //} //public String Status() //{ // if ((Stages == null) || (!Stages.Any())) // return "No Template!"; // if (Issued.IsEmpty()) // return "To Be Issued"; // var stage = GetCurrentStage(); // if (stage != null) // { // if (!Archived.IsEmpty()) // return "Cancelled"; // else // return String.Format("{0} ({1:F2}%)", stage.Name, stage.PercentageComplete); // } // return "Complete"; //} //public Guid CurrentStage() //{ // if (Issued.IsEmpty()) // return Guid.Empty; // SetoutStage stage = GetCurrentStage(); // if (stage != null) // return stage.SectionID; // return CoreUtils.FullGuid; //} //public SetoutStage GetCurrentStage() //{ // if ((!Issued.IsEmpty()) && (Stages != null)) // { // foreach (SetoutStage stage in Stages) // { // if (stage.Completed.IsEmpty()) // return stage; // } // } // return null; //} //public void SetStage(Guid id, bool complete = false) //{ // bool bFound = id == Guid.Empty; // Issued = (id == Guid.Empty) ? DateTime.MinValue : Issued.IsEmpty() ? DateTime.Now : Issued; // if (id == CoreUtils.FullGuid) // { // foreach (SetoutStage stage in Stages) // { // stage.Started = stage.Started.IsEmpty() ? DateTime.Now : stage.Started; // stage.Completed = stage.Completed.IsEmpty() ? DateTime.Now : stage.Completed; // stage.PercentageComplete = 100.0F; // Completed = stage.Completed; // } // } // else // { // //Completed = DateTime.MinValue; // foreach (SetoutStage stage in Stages) // { // if (stage.SectionID.Equals(id)) // { // bFound = true; // //stage.Started = stage.Started.IsEmpty() ? DateTime.Now : stage.Started; // stage.Completed = complete ? DateTime.Now : DateTime.MinValue; // stage.PercentageComplete = stage.Completed.IsEmpty() ? 0.0F : 100.0F; // } // else // { // if (!bFound) // { // // Stages Before this stage - Update Started and Completed if Empty // if (stage.Started.IsEmpty()) // stage.Started = DateTime.Now; // if (stage.Completed.IsEmpty()) // stage.Completed = DateTime.Now; // stage.PercentageComplete = 100.0F; // } // else // { // // Stages After This Stage - Blank out Started and Completed // stage.Started = DateTime.MinValue; // stage.Completed = DateTime.MinValue; // stage.PercentageComplete = 0.0F; // } // } // } // } // bool bIsComplete = !Stages.Any(x => x.Completed.Equals(DateTime.MinValue)); // if (bIsComplete && Completed.Equals(DateTime.MinValue)) // Completed = DateTime.Now; // Stage = CurrentStage(); //} #endregion } }