Assignment.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. using System;
  2. using System.Linq;
  3. using System.Linq.Expressions;
  4. using InABox.Core;
  5. namespace Comal.Classes
  6. {
  7. /// <summary>
  8. /// An assignment represents an anticipated booking for an employee, much like a diary entry
  9. /// <exclude />
  10. /// </summary>
  11. [UserTracking("Assignments")]
  12. [Caption("Assignments")]
  13. public class Assignment : Entity, IPersistent, IRemotable, INumericAutoIncrement<Assignment>, IOneToMany<Employee>, IOneToMany<Job>,
  14. IOneToMany<Kanban>, ILicense<SchedulingControlLicense>, IJobActivity, IOneToMany<Invoice>, IJobScopedItem
  15. {
  16. [IntegerEditor(Editable = Editable.Hidden)]
  17. [EditorSequence(1)]
  18. public int Number { get; set; }
  19. [DateEditor]
  20. [EditorSequence(2)]
  21. [RequiredColumn]
  22. public DateTime Date { get; set; }
  23. [EntityRelationship(DeleteAction.Cascade)]
  24. [EditorSequence(3)]
  25. [RequiredColumn]
  26. public EmployeeLink EmployeeLink { get; set; }
  27. // [EntityRelationship(DeleteAction.Cascade)]
  28. // [EditorSequence(4)]
  29. // public EquipmentLink Equipment { get; set; }
  30. [TextBoxEditor]
  31. [EditorSequence(5)]
  32. public string Title { get; set; }
  33. [MemoEditor]
  34. [EditorSequence(6)]
  35. public string Description { get; set; }
  36. [EditorSequence(7)]
  37. public AssignmentActivityLink ActivityLink { get; set; }
  38. private class KanbanLookup : LookupDefinitionGenerator<Kanban, Assignment>
  39. {
  40. public override Filter<Kanban> DefineFilter(Assignment[] items)
  41. {
  42. if (items == null || !items.Any())
  43. return LookupFactory.DefineFilter<Kanban>();
  44. var employeeID = items.First().EmployeeLink.ID;
  45. // Open tasks which the employee of this assignment is an observer of.
  46. return Filter<Kanban>.Where(x => x.Closed).IsEqualTo(DateTime.MinValue)
  47. .And(x => x.ID).InQuery(Filter<KanbanSubscriber>.Where(x => x.Employee.ID).IsEqualTo(employeeID), x => x.Kanban.ID);
  48. }
  49. public override Columns<Assignment> DefineFilterColumns()
  50. => Columns.None<Assignment>().Add(x => x.EmployeeLink.ID);
  51. }
  52. [LookupDefinition(typeof(KanbanLookup))]
  53. [EditorSequence(8)]
  54. [EntityRelationship(DeleteAction.SetNull)]
  55. public KanbanLink Task { get; set; }
  56. [EditorSequence(9)]
  57. public JobLink JobLink { get; set; }
  58. private class JobITPLookup : LookupDefinitionGenerator<JobITP, Assignment>
  59. {
  60. public override Filter<JobITP> DefineFilter(Assignment[] items)
  61. {
  62. if (items.Length == 1)
  63. return Filter<JobITP>.Where(x => x.Job.ID).IsEqualTo(items.First().JobLink.ID);
  64. return LookupFactory.DefineFilter<JobITP>();
  65. }
  66. public override Columns<Assignment> DefineFilterColumns()
  67. => Columns.None<Assignment>().Add(x => x.JobLink.ID);
  68. }
  69. [LookupDefinition(typeof(JobITPLookup))]
  70. [EditorSequence(10)]
  71. public JobITPLink ITP { get; set; }
  72. [NullEditor]
  73. [Obsolete("Replaced with Actual.Start", true)]
  74. public TimeSpan Start { get; set; }
  75. [NullEditor]
  76. [Obsolete("Replaced with Actual.Duration", true)]
  77. public TimeSpan Duration { get; set; }
  78. [NullEditor]
  79. [Obsolete("Replaced with Actual.Finish", true)]
  80. public TimeSpan Finish { get; set; }
  81. [EditorSequence(11)]
  82. [CoreTimeEditor]
  83. public TimeBlock Booked { get; set; }
  84. [EditorSequence(12)]
  85. [CoreTimeEditor]
  86. public TimeBlock Actual { get; set; }
  87. [TimestampEditor]
  88. [RequiredColumn]
  89. [EditorSequence(13)]
  90. public DateTime Completed { get; set; }
  91. [Editable(Editable.Disabled)]
  92. [Comment("The duration this Assignment was treated as having for costing purposes")]
  93. [EditorSequence("Processing", 1)]
  94. public double CostedHours { get; set; }
  95. [CurrencyEditor]
  96. [Editable(Editable.Disabled)]
  97. [Comment("Cost of the Assignment; calculated from duration, overtime rules and the employee's hourly rate.")]
  98. [EditorSequence("Processing", 2)]
  99. public double Cost { get; set; }
  100. [EditorSequence("Processing", 3)]
  101. public ActualCharge Charge { get; set; }
  102. [TimestampEditor]
  103. [EditorSequence("Processing", 4)]
  104. public DateTime Processed { get; set; }
  105. [NullEditor]
  106. [EntityRelationship(DeleteAction.Cascade)]
  107. public LeaveRequestLink LeaveRequestLink { get; set; }
  108. [NullEditor]
  109. [EntityRelationship(DeleteAction.Cascade)]
  110. public DeliveryLink Delivery { get; set; }
  111. [NullEditor]
  112. [EntityRelationship(DeleteAction.SetNull)]
  113. public InvoiceLink Invoice { get; set; }
  114. [NullEditor]
  115. public MeetingDetails Meeting { get; set; }
  116. private class JobScopeLookup : LookupDefinitionGenerator<JobScope, Assignment>
  117. {
  118. public override Filter<JobScope> DefineFilter(Assignment[] items)
  119. {
  120. var item = items?.Length == 1 ? items[0] : null;
  121. if (item != null)
  122. return Filter<JobScope>.Where(x => x.Job.ID).IsEqualTo(item.JobLink.ID).And(x => x.Status.Approved).IsEqualTo(true);
  123. return Filter.None<JobScope>();
  124. }
  125. public override Columns<Assignment> DefineFilterColumns()
  126. => Columns.None<Assignment>().Add(x => x.JobLink.ID);
  127. }
  128. [LookupDefinition(typeof(JobScopeLookup))]
  129. public JobScopeLink JobScope { get; set; }
  130. public Expression<Func<Assignment, int>> AutoIncrementField()
  131. {
  132. return x => x.Number;
  133. }
  134. public Filter<Assignment> AutoIncrementFilter()
  135. {
  136. return null;
  137. }
  138. public int AutoIncrementDefault() => 1;
  139. public static TimeSpan EffectiveTime(TimeSpan actual, TimeSpan booked) => actual.Ticks != 0L ? actual : booked;
  140. public TimeSpan EffectiveStartTime()
  141. {
  142. return EffectiveTime(Actual.Start, Booked.Start);
  143. }
  144. public DateTime EffectiveStart()
  145. {
  146. return Date.Add(EffectiveStartTime());
  147. }
  148. public TimeSpan EffectiveFinishTime()
  149. {
  150. // If we have an actual finish, always use that
  151. // otherwise use EffectiveStart() + booked.duration
  152. return EffectiveTime(
  153. Actual.Finish,
  154. EffectiveTime(Actual.Start, Booked.Start)
  155. .Add(Booked.Duration)
  156. );
  157. }
  158. public DateTime EffectiveFinish()
  159. {
  160. return Date.Add(
  161. EffectiveFinishTime()
  162. );
  163. }
  164. static Assignment()
  165. {
  166. LinkedProperties.Register<Assignment, ActivityCharge, bool>(ass => ass.ActivityLink.Charge, chg => chg.Chargeable, ass => ass.Charge.Chargeable);
  167. Classes.JobScope.LinkScopeProperties<Assignment>();
  168. }
  169. }
  170. }