PurchaseOrderItemAllocation.cs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. using InABox.Core;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. namespace Comal.Classes
  7. {
  8. /// <summary>
  9. /// The <see cref="PurchaseOrderItemAllocation"/> is the way that we are allowing a single <see cref="PurchaseOrderItem"/> to, when received,
  10. /// have its stock distributed to multiple sources. The current idea is this:
  11. ///
  12. /// <list type="bullet">
  13. /// <item>
  14. /// The <see cref="PurchaseOrderItem"/> itself has a <see cref="PurchaseOrderItem.Job"/> and a <see cref="PurchaseOrderItem.Qty"/>.
  15. /// In most cases, this will be the target for received stock, and
  16. /// in this simple case, there are no POIAs. If the <see cref="PurchaseOrderItem.Job"/> is blank, it goes to general stock;
  17. /// otherwise, it goes to a specific allocation.
  18. /// </item>
  19. /// <item>
  20. /// If there are allocations, this cuts into the <see cref="PurchaseOrderItem.Qty"/>, such that after any allocations have been filled,
  21. /// the remainder of the stock goes to the <see cref="PurchaseOrderItem.Job"/>.
  22. /// If the allocations total more than <see cref="PurchaseOrderItem.Qty"/>, then a negative stock movement
  23. /// is registered against <see cref="PurchaseOrderItem.Job"/>.
  24. /// </item>
  25. /// <item>
  26. /// In the case of Dimension conversions (see <see cref="DimensionUnit.Conversion"/>), the quantity on the allocation is after the conversion has
  27. /// happened.<br/>
  28. /// This is important, because in this case, <b>there will be a discrepancy</b> between <see cref="PurchaseOrderItem.Qty"/> and the total
  29. /// of <see cref="Quantity"/>.
  30. /// <br/>
  31. /// As an example, suppose we are purchasing 2 boxes of 1000 screws. Then, the allocations are by numbers of screws, so that 800 might go to
  32. /// Job A, 600 to Job B and 600 to general stock. So the allocation quantities are the actual numbers that will be on the stock movements.
  33. /// </item>
  34. /// </list>
  35. /// </summary>
  36. [Caption("Allocation")]
  37. public class PurchaseOrderItemAllocation : Entity, IRemotable, IPersistent, ILicense<ProjectManagementLicense>
  38. , IOneToMany<JobRequisitionItem>, IOneToMany<Job>, IOneToMany<PurchaseOrderItem>
  39. {
  40. [EntityRelationship(DeleteAction.Cascade)]
  41. public PurchaseOrderItemLink Item { get; set; }
  42. [EntityRelationship(DeleteAction.Cascade)]
  43. [EditorSequence(1)]
  44. public JobLink Job { get; set; }
  45. private class JobRequisitionItemLookup : LookupDefinitionGenerator<JobRequisitionItem, PurchaseOrderItemAllocation>
  46. {
  47. public override Columns<PurchaseOrderItemAllocation> DefineFilterColumns()
  48. {
  49. return base.DefineFilterColumns().Add(x => x.Job.ID);
  50. }
  51. public override Filter<JobRequisitionItem>? DefineFilter(PurchaseOrderItemAllocation[] items)
  52. {
  53. return new Filter<JobRequisitionItem>(x => x.Job.ID).InList(items.ToArray(x => x.Job.ID));
  54. }
  55. }
  56. /// <summary>
  57. /// This may be an empty link. The interface is as such: if there is no JRI, then we are creating a reserve and allocation just against the job. If there is a JRI,
  58. /// then received stock is reserved and allocated for the JRI.
  59. /// </summary>
  60. [EntityRelationship(DeleteAction.Cascade)]
  61. [LookupDefinition(typeof(JobRequisitionItemLookup))]
  62. [EditorSequence(2)]
  63. public JobRequisitionItemLink JobRequisitionItem { get; set; }
  64. [EditorSequence(3)]
  65. public double Quantity { get; set; }
  66. protected override void DoPropertyChanged(string name, object? before, object? after)
  67. {
  68. base.DoPropertyChanged(name, before, after);
  69. if(name == $"{nameof(Job)}.{nameof(Job.ID)}")
  70. {
  71. JobRequisitionItem.ID = Guid.Empty;
  72. JobRequisitionItem.Clear();
  73. }
  74. }
  75. }
  76. public class PurchaseOrderItemAllocationJobLink : EntityLink<PurchaseOrderItemAllocation>
  77. {
  78. [NullEditor]
  79. public override Guid ID { get; set; }
  80. public LightJobLink Job { get; set; }
  81. public LightPurchaseOrderItemLink Item { get; set; }
  82. }
  83. }