JobScope.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Linq.Expressions;
  5. using System.Security;
  6. using InABox.Clients;
  7. using InABox.Core;
  8. namespace Comal.Classes
  9. {
  10. public class JobScopeInvoiceExTax : CoreAggregate<JobScope, InvoiceLine, double>
  11. {
  12. public override Expression<Func<InvoiceLine, double>> Aggregate => x => x.ExTax;
  13. public override AggregateCalculation Calculation => AggregateCalculation.Sum;
  14. public override Dictionary<Expression<Func<InvoiceLine, object>>, Expression<Func<JobScope, object>>> Links =>
  15. new Dictionary<Expression<Func<InvoiceLine, object>>, Expression<Func<JobScope, object>>>()
  16. {
  17. { InvoiceLine => InvoiceLine.Scope.ID, JobPrice => JobPrice.ID }
  18. };
  19. }
  20. public class JobScopeInvoiceTax : CoreAggregate<JobScope, InvoiceLine, double>
  21. {
  22. public override Expression<Func<InvoiceLine, double>> Aggregate => x => x.Tax;
  23. public override AggregateCalculation Calculation => AggregateCalculation.Sum;
  24. public override Dictionary<Expression<Func<InvoiceLine, object>>, Expression<Func<JobScope, object>>> Links =>
  25. new Dictionary<Expression<Func<InvoiceLine, object>>, Expression<Func<JobScope, object>>>()
  26. {
  27. { InvoiceLine => InvoiceLine.Scope.ID, JobPrice => JobPrice.ID }
  28. };
  29. }
  30. public class JobScopeInvoiceIncTax : CoreAggregate<JobScope, InvoiceLine, double>
  31. {
  32. public override Expression<Func<InvoiceLine, double>> Aggregate => x => x.IncTax;
  33. public override AggregateCalculation Calculation => AggregateCalculation.Sum;
  34. public override Dictionary<Expression<Func<InvoiceLine, object>>, Expression<Func<JobScope, object>>> Links =>
  35. new Dictionary<Expression<Func<InvoiceLine, object>>, Expression<Func<JobScope, object>>>()
  36. {
  37. { InvoiceLine => InvoiceLine.Scope.ID, JobPrice => JobPrice.ID }
  38. };
  39. }
  40. public class JobScopeUninvoicedExTax : IFormula<JobScope, double>
  41. {
  42. public Expression<Func<JobScope, double>> Value => x => x.ExTax;
  43. public Expression<Func<JobScope, double>>[] Modifiers => new Expression<Func<JobScope, double>>[] { x => x.InvoiceExTax };
  44. public FormulaOperator Operator => FormulaOperator.Subtract;
  45. public FormulaType Type => FormulaType.Virtual;
  46. }
  47. public class JobScopeActivityCost : CoreAggregate<JobScope, JobScopeActivity, double>
  48. {
  49. public override Expression<Func<JobScopeActivity, double>> Aggregate => x => x.Cost;
  50. public override AggregateCalculation Calculation => AggregateCalculation.Sum;
  51. public override Dictionary<Expression<Func<JobScopeActivity, object?>>, Expression<Func<JobScope, object?>>> Links =>
  52. new Dictionary<Expression<Func<JobScopeActivity, object>>, Expression<Func<JobScope, object>>>()
  53. {
  54. { JobScopeActivity => JobScopeActivity.Scope.ID, JobScope => JobScope.ID }
  55. };
  56. }
  57. public class JobScopeActivitySell : CoreAggregate<JobScope, JobScopeActivity, double>
  58. {
  59. public override Expression<Func<JobScopeActivity, double>> Aggregate => x => x.Sell;
  60. public override AggregateCalculation Calculation => AggregateCalculation.Sum;
  61. public override Dictionary<Expression<Func<JobScopeActivity, object?>>, Expression<Func<JobScope, object?>>> Links =>
  62. new Dictionary<Expression<Func<JobScopeActivity, object>>, Expression<Func<JobScope, object>>>()
  63. {
  64. { JobScopeActivity => JobScopeActivity.Scope.ID, JobScope => JobScope.ID }
  65. };
  66. }
  67. public class JobScopeCostCentreCost : CoreAggregate<JobScope, JobScopeCostCentre, double>
  68. {
  69. public override Expression<Func<JobScopeCostCentre, double>> Aggregate => x => x.Cost;
  70. public override AggregateCalculation Calculation => AggregateCalculation.Sum;
  71. public override Dictionary<Expression<Func<JobScopeCostCentre, object?>>, Expression<Func<JobScope, object?>>> Links =>
  72. new Dictionary<Expression<Func<JobScopeCostCentre, object>>, Expression<Func<JobScope, object>>>()
  73. {
  74. { JobScopeCostCentre => JobScopeCostCentre.Scope.ID, JobScope => JobScope.ID }
  75. };
  76. }
  77. public class JobScopeCostCentreSell : CoreAggregate<JobScope, JobScopeCostCentre, double>
  78. {
  79. public override Expression<Func<JobScopeCostCentre, double>> Aggregate => x => x.Sell;
  80. public override AggregateCalculation Calculation => AggregateCalculation.Sum;
  81. public override Dictionary<Expression<Func<JobScopeCostCentre, object?>>, Expression<Func<JobScope, object?>>> Links =>
  82. new Dictionary<Expression<Func<JobScopeCostCentre, object>>, Expression<Func<JobScope, object>>>()
  83. {
  84. { JobScopeCostCentre => JobScopeCostCentre.Scope.ID, JobScope => JobScope.ID }
  85. };
  86. }
  87. public interface IJobScopedItem
  88. {
  89. JobLink JobLink { get; set; }
  90. JobScopeLink JobScope { get; set; }
  91. }
  92. [UserTracking(typeof(Job))]
  93. public class JobScope : Entity, IRemotable, IPersistent, ITaxable, IStringAutoIncrement<JobScope>, ILicense<ProjectManagementLicense>
  94. {
  95. [NullEditor]
  96. public InternalJobLink Job { get; set; }
  97. [EnumLookupEditor(typeof(JobScopeType), Visible = Visible.Default)]
  98. [EditorSequence(1)]
  99. public JobScopeType Type { get; set; } = JobScopeType.Variation;
  100. [CodeEditor(Visible = Visible.Default, Editable = Editable.Enabled)]
  101. [EditorSequence(2)]
  102. public string Number { get; set; }
  103. [MemoEditor(Visible = Visible.Default)]
  104. [EditorSequence(3)]
  105. public string Description { get; set; }
  106. [EditorSequence(4)]
  107. [TextBoxEditor]
  108. public string SourceRef{ get; set; }
  109. private class JobScopeLookup : LookupDefinitionGenerator<JobScope, JobScope>
  110. {
  111. public override Filter<JobScope> DefineFilter(JobScope[] items)
  112. {
  113. if (items?.Any() != true)
  114. return Filter.None<JobScope>();
  115. var data = Client.Query(
  116. Filter<JobScope>.Where(x =>x.Job.ID).IsEqualTo(items.First().Job.ID),
  117. Columns.None<JobScope>().Add(x => x.ID).Add(x => x.Parent.ID));
  118. var nodes = new CoreTreeNodes<Guid>(Guid.Empty);
  119. nodes.Load<JobScope>(data, x => x.ID, x => x.Parent.ID);
  120. var exclusions = items.SelectMany(x => nodes.GetChildren(x.ID)).ToArray();
  121. var ids = exclusions.Select(x => x.ID).ToArray();
  122. return Filter<JobScope>.Where(x =>x.Job.ID).IsEqualTo(items.First().Job.ID).And(x => x.ID).NotInList(ids);
  123. }
  124. public override Columns<JobScope> DefineFilterColumns()
  125. => Columns.None<JobScope>().Add(x => x.ID).Add(x => x.Parent.ID).Add(x => x.Number);
  126. }
  127. [LookupDefinition(typeof(JobScopeLookup))]
  128. [EditorSequence(4)]
  129. public JobScopeLink Parent { get; set; }
  130. private class MaterialsCostAggregate : ComplexFormulaGenerator<JobScope, double>
  131. {
  132. public override IComplexFormulaNode<JobScope, double> GetFormula()
  133. => Aggregate<JobScopeCostCentre>(AggregateCalculation.Sum, x => x.Property(p => p.Cost))
  134. .WithLink(x => x.Scope.ID, x => x.ID);
  135. }
  136. [ComplexFormula(typeof(MaterialsCostAggregate))]
  137. [EditorSequence(5)]
  138. [CurrencyEditor(Summary = Summary.Sum, Visible = Visible.Optional, Editable = Editable.Hidden)]
  139. public double MaterialsCost { get; set; }
  140. private class MaterialsSellAggregate : ComplexFormulaGenerator<JobScope, double>
  141. {
  142. public override IComplexFormulaNode<JobScope, double> GetFormula()
  143. => Aggregate<JobScopeCostCentre>(AggregateCalculation.Sum, x => x.Property(p => p.Sell))
  144. .WithLink(x => x.Scope.ID, x => x.ID);
  145. }
  146. [ComplexFormula(typeof(MaterialsSellAggregate))]
  147. [EditorSequence(6)]
  148. [CurrencyEditor(Summary = Summary.Sum, Visible = Visible.Optional, Editable = Editable.Hidden)]
  149. public double MaterialsSell { get; set; }
  150. private class MaterialsMarginFormula : ComplexFormulaGenerator<JobScope, double>
  151. {
  152. public override IComplexFormulaNode<JobScope, double> GetFormula() =>
  153. Formula(
  154. FormulaOperator.Divide,
  155. Formula(
  156. FormulaOperator.Multiply,
  157. Formula(
  158. FormulaOperator.Subtract,
  159. Property(x=>x.MaterialsSell),
  160. Property(c => c.MaterialsCost)
  161. ),
  162. Constant(100.0F)
  163. ),
  164. Property(c=>c.MaterialsSell)
  165. );
  166. }
  167. [ComplexFormula(typeof(MaterialsMarginFormula))]
  168. [EditorSequence(7)]
  169. [DoubleEditor(Visible = Visible.Optional, Editable = Editable.Hidden)]
  170. public double MaterialMargin { get; set; }
  171. private class MaterialsMarkupFormula : ComplexFormulaGenerator<JobScope, double>
  172. {
  173. public override IComplexFormulaNode<JobScope, double> GetFormula() =>
  174. Formula(
  175. FormulaOperator.Divide,
  176. Formula(
  177. FormulaOperator.Multiply,
  178. Formula(
  179. FormulaOperator.Subtract,
  180. Property(x=>x.MaterialsSell),
  181. Property(c => c.MaterialsCost)
  182. ),
  183. Constant(100.0F)
  184. ),
  185. Property(c=>c.MaterialsCost)
  186. );
  187. }
  188. [ComplexFormula(typeof(MaterialsMarkupFormula))]
  189. [EditorSequence(8)]
  190. [DoubleEditor(Visible = Visible.Optional, Editable = Editable.Hidden)]
  191. public double MaterialMarkup { get; set; }
  192. private class LabourCostAggregate : ComplexFormulaGenerator<JobScope, double>
  193. {
  194. public override IComplexFormulaNode<JobScope, double> GetFormula()
  195. => Aggregate<JobScopeActivity>(AggregateCalculation.Sum, x => x.Property(p => p.Cost))
  196. .WithLink(x => x.Scope.ID, x => x.ID);
  197. }
  198. [ComplexFormula(typeof(LabourCostAggregate))]
  199. [EditorSequence(9)]
  200. [CurrencyEditor(Summary = Summary.Sum, Visible = Visible.Optional, Editable = Editable.Hidden)]
  201. public double LabourCost { get; set; }
  202. private class LabourSellAggregate : ComplexFormulaGenerator<JobScope, double>
  203. {
  204. public override IComplexFormulaNode<JobScope, double> GetFormula()
  205. => Aggregate<JobScopeActivity>(AggregateCalculation.Sum, x => x.Property(p => p.Sell))
  206. .WithLink(x => x.Scope.ID, x => x.ID);
  207. }
  208. [ComplexFormula(typeof(LabourSellAggregate))]
  209. [EditorSequence(10)]
  210. [CurrencyEditor(Summary = Summary.Sum, Visible = Visible.Optional, Editable = Editable.Hidden)]
  211. public double LabourSell { get; set; }
  212. private class LabourMarginFormula : ComplexFormulaGenerator<JobScope, double>
  213. {
  214. public override IComplexFormulaNode<JobScope, double> GetFormula() =>
  215. Formula(
  216. FormulaOperator.Divide,
  217. Formula(
  218. FormulaOperator.Multiply,
  219. Formula(
  220. FormulaOperator.Subtract,
  221. Property(x=>x.LabourSell),
  222. Property(c => c.LabourCost)
  223. ),
  224. Constant(100.0F)
  225. ),
  226. Property(c=>c.LabourSell)
  227. );
  228. }
  229. [ComplexFormula(typeof(LabourMarginFormula))]
  230. [EditorSequence(11)]
  231. [DoubleEditor(Visible = Visible.Optional, Editable = Editable.Hidden)]
  232. public double LabourMargin { get; set; }
  233. private class LabourMarkupFormula : ComplexFormulaGenerator<JobScope, double>
  234. {
  235. public override IComplexFormulaNode<JobScope, double> GetFormula() =>
  236. Formula(
  237. FormulaOperator.Divide,
  238. Formula(
  239. FormulaOperator.Multiply,
  240. Formula(
  241. FormulaOperator.Subtract,
  242. Property(x=>x.LabourSell),
  243. Property(c => c.LabourCost)
  244. ),
  245. Constant(100.0F)
  246. ),
  247. Property(c=>c.LabourCost)
  248. );
  249. }
  250. [ComplexFormula(typeof(LabourMarkupFormula))]
  251. [EditorSequence(12)]
  252. [DoubleEditor(Visible = Visible.Optional, Editable = Editable.Hidden)]
  253. public double LabourMarkup { get; set; }
  254. [CurrencyEditor(Summary = Summary.Sum, Visible = Visible.Default)]
  255. [EditorSequence(13)]
  256. public double ExTax { get; set; }
  257. [EditorSequence(14)]
  258. public TaxCodeLink TaxCode { get; set; }
  259. [CurrencyEditor(Summary = Summary.Sum, Visible = Visible.Optional)]
  260. [EditorSequence(15)]
  261. public double IncTax { get; set; }
  262. [EditorSequence(16)]
  263. public JobScopeStatusLink Status { get; set; }
  264. private class InvoiceExTaxAggregate : ComplexFormulaGenerator<JobScope, double>
  265. {
  266. public override IComplexFormulaNode<JobScope, double> GetFormula()
  267. => Aggregate<InvoiceLine>(AggregateCalculation.Sum, x => x.Property(p => p.ExTax))
  268. .WithLink(x => x.Scope.ID, x => x.ID);
  269. }
  270. [ComplexFormula(typeof(LabourSellAggregate))]
  271. [Aggregate(typeof(JobScopeInvoiceExTax))]
  272. [EditorSequence(17)]
  273. [CurrencyEditor(Visible = Visible.Default, Editable = Editable.Hidden, Summary = Summary.Sum)]
  274. public double InvoiceExTax { get; set; }
  275. [Aggregate(typeof(JobScopeInvoiceTax))]
  276. [EditorSequence(18)]
  277. [CurrencyEditor(Visible = Visible.Optional, Editable = Editable.Hidden, Summary = Summary.Sum)]
  278. public double InvoiceTax { get; set; }
  279. [Aggregate(typeof(JobScopeInvoiceIncTax))]
  280. [EditorSequence(19)]
  281. [CurrencyEditor(Visible = Visible.Optional, Editable = Editable.Hidden, Summary = Summary.Sum)]
  282. public double InvoiceIncTax { get; set; }
  283. [Formula(typeof(JobScopeUninvoicedExTax))]
  284. [EditorSequence(20)]
  285. [CurrencyEditor(Visible = Visible.Optional, Editable = Editable.Hidden, Summary = Summary.Sum)]
  286. public double UninvoiceIncTax { get; set; }
  287. private class MaterialsExTaxFormula : ComplexFormulaGenerator<JobScope, double>
  288. {
  289. public override IComplexFormulaNode<JobScope, double> GetFormula() =>
  290. Formula(FormulaOperator.Subtract,
  291. Aggregate<StockMovement>(AggregateCalculation.Sum, x => x.Property(x => x.Value))
  292. .WithFilter(
  293. Filter<StockMovement>.Where(x => x.Type).IsEqualTo(StockMovementType.Issue))
  294. .WithLink(x => x.JobScope.ID, x => x.ID));
  295. }
  296. [CurrencyEditor(Visible = Visible.Optional, Editable = Editable.Hidden, Summary = Summary.Sum)]
  297. [ComplexFormula(typeof(MaterialsExTaxFormula))]
  298. public double MaterialsExTax { get; set; }
  299. private class UninvoicedMaterial : ComplexFormulaGenerator<JobScope, double>
  300. {
  301. public override IComplexFormulaNode<JobScope, double> GetFormula() =>
  302. Formula(FormulaOperator.Subtract,
  303. Aggregate<StockMovement>(AggregateCalculation.Sum, x => x.Property(x => x.Value))
  304. .WithFilter(
  305. Filter<StockMovement>.Where(x => x.Invoice.ID).IsEqualTo(Guid.Empty)
  306. .And(x => x.Type).IsEqualTo(StockMovementType.Issue))
  307. .WithLink(x => x.JobScope.ID, x => x.ID));
  308. }
  309. [CurrencyEditor(Visible = Visible.Optional, Editable = Editable.Hidden, Summary = Summary.Sum)]
  310. [ComplexFormula(typeof(UninvoicedMaterial))]
  311. public double UninvoicedMaterialsExTax { get; set; }
  312. public Expression<Func<JobScope, string>> AutoIncrementField() => x => x.Number;
  313. public Filter<JobScope> AutoIncrementFilter() => Filter<JobScope>.Where(x => x.Job.ID).IsEqualTo(Job.ID);
  314. public String AutoIncrementPrefix() => "";
  315. public string AutoIncrementFormat() => "{0:D3}";
  316. public int AutoIncrementDefault() => 0;
  317. [NullEditor]
  318. public double TaxRate { get; set; }
  319. [NullEditor(Summary = Summary.Sum, Visible = Visible.Optional)]
  320. public double Tax { get; set; }
  321. static JobScope()
  322. {
  323. LinkedProperties.Register<JobScope, TaxCodeLink, double>(x=>x.TaxCode, x => x.Rate, x => x.TaxRate);
  324. }
  325. public static void LinkScopeProperties<TScoped>() where TScoped : class, IJobScopedItem
  326. {
  327. LinkedProperties.Register<TScoped, JobScopeLink, Guid>(ass => ass.JobLink.DefaultScope, scope => scope.ID, ass => ass.JobScope.ID);
  328. LinkedProperties.Register<TScoped, JobScopeLink, String>(ass => ass.JobLink.DefaultScope, scope => scope.Number, ass => ass.JobScope.Number);
  329. LinkedProperties.Register<TScoped, JobScopeLink, String>(ass => ass.JobLink.DefaultScope, scope => scope.Description, ass => ass.JobScope.Description);
  330. }
  331. }
  332. }