| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 | 
							- using System.Collections.Generic;
 
- using System.Linq;
 
- using System.Linq.Expressions;
 
- using Comal.Classes;
 
- using InABox.Core;
 
- using System;
 
- using NPOI.Util;
 
- namespace Comal.Stores
 
- {
 
-     internal class RequisitionStore : BaseStore<Requisition>
 
-     {
 
-         private readonly bool _debug = true;
 
-         private void Log(string format, params object[] values)
 
-         {
 
-             if (_debug)
 
-                 Logger.Send(LogType.Information, UserID, string.Format("- RequisitionStore:" + format, values));
 
-         }
 
-         private bool NeedsUpdating<TObject, T>(Requisition entity, TObject obj, Expression<Func<TObject, T>> property)
 
-             where TObject : BaseObject
 
-         {
 
-             // If this is a new Requisition, we don't need to do anything
 
-             if (entity.HasOriginalValue(x => x.ID))
 
-             {
 
-                 var originalid = entity.GetOriginalValue(x => x.ID);
 
-                 if (originalid == Guid.Empty)
 
-                 {
 
-                     Log("NeedsUpdating() return false - original id is empty");
 
-                     return false;
 
-                 }
 
-             }
 
-             // if the Property has not changed, we don't need to do anything
 
-             if (!obj.HasOriginalValue(property))
 
-             {
 
-                 Log("NeedsUpdating() return false - {0} has not changed", property.ToString());
 
-                 return false;
 
-             }
 
-             return true;
 
-         }
 
-         private bool LoadRequisitionItems(Requisition entity, ref IList<RequisitionItem> requisitionitems)
 
-         {
 
-             requisitionitems ??= Provider.Query(
 
-                     new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(entity.ID),
 
-                     Columns.None<RequisitionItem>().Add(x => x.ID)
 
-                         .Add(x => x.Description)
 
-                         .Add(x => x.Quantity)
 
-                         .Add(x => x.Code)
 
-                         .Add(x => x.Location.ID)
 
-                         .Add(x => x.Style.ID)
 
-                         .Add(x => x.Product.ID)
 
-                         .Add(x => x.Product.NonStock)
 
-                         .Add(x => x.SourceJRI.ID)
 
-                         .Add(x => x.JobRequisitionItem.ID)
 
-                         .Add(x =>x.JobLink.ID)
 
-                         .AddDimensionsColumns(x => x.Dimensions, Dimensions.ColumnsType.Local)
 
-                         .Add(x => x.ActualQuantity)
 
-                         .AddSubColumns(x => x.Charge, Columns.All<ActualCharge>())
 
-                         .Add(x => x.JobScope.ID)
 
-                         .AddDimensionsColumns(x => x.Product.DefaultInstance.Dimensions, Dimensions.ColumnsType.Local)
 
-                 ).ToList<RequisitionItem>();
 
-             return requisitionitems.Any();
 
-         }
 
-         private bool LoadDeliveryItems(Requisition entity, ref IList<DeliveryItem> deliveryitems)
 
-         {
 
-             deliveryitems ??= Provider.Query(
 
-                     new Filter<DeliveryItem>(x => x.RequisitionLink.ID).IsEqualTo(entity.ID),
 
-                     Columns.None<DeliveryItem>().Add(x => x.ID, x => x.DeliveredDate)
 
-                 ).ToList<DeliveryItem>();
 
-             return deliveryitems.Any();
 
-         }
 
-         #region TakenBy
 
-         private void UpdateTakenBy(Requisition entity, ref IList<RequisitionItem> items, ref IList<DeliveryItem> deliveryitems)
 
-         {
 
-             Log("UpdateTakenBy() - starting");
 
-             if (!NeedsUpdating(entity, entity.TakenBy, x => x.ID))
 
-                 return;
 
-             if (!LoadDeliveryItems(entity, ref deliveryitems))
 
-             {
 
-                 Log("UpdateTakenBy() - no delivery items to update");
 
-                 return;
 
-             }
 
-             foreach (var deliveryitem in deliveryitems)
 
-                 if (entity.TakenBy.IsValid() && deliveryitem.DeliveredDate.IsEmpty())
 
-                 {
 
-                     Log("UpdateTakenBy() - Setting DeliveryDate");
 
-                     deliveryitem.DeliveredDate = DateTime.Now;
 
-                 }
 
-                 else if (!entity.TakenBy.IsValid() && !deliveryitem.DeliveredDate.IsEmpty())
 
-                 {
 
-                     Log("UpdateTakenBy() - Clearing DeliveryDate");
 
-                     deliveryitem.DeliveredDate = DateTime.MinValue;
 
-                 }
 
-             var updates = deliveryitems.Where(x => x.IsChanged());
 
-             if (updates.Any())
 
-                 FindSubStore<DeliveryItem>().Save(updates,
 
-                     entity.TakenBy.IsValid() ? "Requisition taken by " + entity.TakenBy.Code : "Requisition [TakenBy] has been cleared");
 
-             Log("UpdateTakenBy() - done");
 
-         }
 
-         #endregion
 
-         protected override void BeforeSave(Requisition entity)
 
-         {
 
-             base.BeforeSave(entity);
 
-             if (entity.TakenBy.IsValid() || entity.Delivery.Completed != DateTime.MinValue || entity.Delivery.Delivered != DateTime.MinValue)
 
-             {
 
-                 if (entity.Archived.IsEmpty())
 
-                     entity.Archived = DateTime.Now;
 
-             }
 
-             else
 
-             {
 
-                 if (!entity.Archived.IsEmpty())
 
-                     entity.Archived = DateTime.MinValue;
 
-             }
 
-         }
 
-         protected override void AfterSave(Requisition entity)
 
-         {
 
-             base.AfterSave(entity);
 
-             IList<RequisitionItem> requisitionitems = null;
 
-             IList<DeliveryItem> deliveryitems = null;
 
-             
 
-             UpdateDeliveryItems(entity, ref requisitionitems, ref deliveryitems);
 
-             UpdateTakenBy(entity, ref requisitionitems, ref deliveryitems);
 
-             UpdateStockBatches(entity, ref requisitionitems);
 
-             UpdateTrackingKanban<RequisitionKanban, Requisition, RequisitionLink>(entity, e =>
 
-             {
 
-                 if (!entity.Archived.Equals(DateTime.MinValue) || entity.TakenBy.IsValid())
 
-                     return KanbanStatus.Complete;
 
-                 if (entity.Delivery.IsValid())
 
-                 {
 
-                     if (entity.Delivery.Completed != DateTime.MinValue)
 
-                     {
 
-                         return KanbanStatus.Complete;
 
-                     }
 
-                 }
 
-                 if (!entity.Filled.Equals(DateTime.MinValue))
 
-                     return KanbanStatus.Waiting;
 
-                 if (Provider.Query(
 
-                         new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(entity.ID),
 
-                         Columns.None<RequisitionItem>().Add(x => x.ID)
 
-                     ).Rows.Any()
 
-                    )
 
-                     return KanbanStatus.InProgress;
 
-                 return KanbanStatus.Open;
 
-             });
 
-         }
 
-         
 
-         protected override void BeforeDelete(Requisition entity)
 
-         {
 
-             UnlinkTrackingKanban<RequisitionKanban, Requisition, RequisitionLink>(entity);
 
-         }
 
-         
 
-         #region Delivery Items
 
-         private void CreateDeliveryItems(Requisition entity, ref IList<RequisitionItem> requisitionitems,
 
-             ref IList<DeliveryItem> deliveryitems)
 
-         {
 
-             if (!LoadRequisitionItems(entity, ref requisitionitems))
 
-             {
 
-                 Log("CreateDeliveryItems() - no requisition items to update");
 
-                 return;
 
-             }
 
-             var updates = new List<DeliveryItem>();
 
-             foreach (var item in requisitionitems)
 
-                 updates.Add(item.CreateDeliveryItem(entity));
 
-             if (updates.Any())
 
-                 FindSubStore<DeliveryItem>().Save(updates, "Requisition [Filled] flag has been set");
 
-             deliveryitems = updates;
 
-         }
 
-         private void ClearDeliveryItems(Requisition entity, ref IList<DeliveryItem> deliveryitems)
 
-         {
 
-             if (!LoadDeliveryItems(entity, ref deliveryitems))
 
-             {
 
-                 Log("ClearDeliveryItems() - no delivery items to update");
 
-                 return;
 
-             }
 
-             if (deliveryitems.Any())
 
-                 FindSubStore<DeliveryItem>().Delete(deliveryitems, "Requisition [Filled] flag has been cleared");
 
-             deliveryitems = new List<DeliveryItem>();
 
-         }
 
-         private void UpdateDeliveryItems(Requisition entity, ref IList<RequisitionItem> requisitionitems,
 
-             ref IList<DeliveryItem> deliveryitems)
 
-         {
 
-             Log("UpdateDeliveryItems() - starting");
 
-             if (!NeedsUpdating(entity, entity, x => x.Filled))
 
-             {
 
-                 Log("UpdateDeliveryItems() - NeedsUpdate() return false");
 
-                 return;
 
-             }
 
-             var oldfilled = entity.GetOriginalValue(x => x.Filled);
 
-             var newfilled = entity.Filled;
 
-             // Gone from Blank to Filled -> Create a Batch
 
-             if (oldfilled.IsEmpty() && !newfilled.IsEmpty())
 
-             {
 
-                 Log("UpdateDeliveryItems() - Filled has been set");
 
-                 ClearDeliveryItems(entity, ref deliveryitems);
 
-                 CreateDeliveryItems(entity, ref requisitionitems, ref deliveryitems);
 
-             }
 
-             // Gone from Filled to Blank -> Clear Out the Batch
 
-             else if (newfilled.IsEmpty() && !oldfilled.IsEmpty())
 
-             {
 
-                 Log("UpdateDeliveryItems() - Filled has been cleared");
 
-                 ClearDeliveryItems(entity, ref deliveryitems);
 
-             }
 
-             // Do nothing - filled flag has been updated, not set or cleared
 
-             Log("UpdateDeliveryItems() - done");
 
-         }
 
-         #endregion
 
-         #region StockMovements
 
-         private StockMovement CreateStockMovement(IEmployee employee, DateTime date, IStockMovementBatch batch, IProduct product, IStockLocation location,
 
-             IProductStyle style, IJob? job, IJobRequisitionItem? jri, IDimensions dimensions, Guid txnid, ActualCharge charge, JobScopeLink scope, bool system, string note)
 
-         {
 
-             var movement = new StockMovement();
 
-             movement.Batch.ID = batch.ID;
 
-             movement.Product.ID = product.ID;
 
-             movement.Location.ID = location.ID;
 
-             movement.Style.ID = style.ID;
 
-             movement.Job.ID = job?.ID ?? Guid.Empty;
 
-             movement.JobRequisitionItem.ID = jri?.ID ?? Guid.Empty;
 
-             movement.Dimensions.CopyFrom(dimensions);
 
-             movement.Charge.CopyFrom(charge);
 
-             movement.JobScope.CopyFrom(scope);
 
-             movement.System = system;
 
-             movement.Transaction = txnid;
 
-             movement.Notes = note;
 
-             movement.Date = date;
 
-             movement.Employee.ID = employee.ID;
 
-             return movement;
 
-         }
 
-         private void CreateStockBatch(Requisition entity, ref IList<RequisitionItem> items)
 
-         {
 
-             if(!LoadRequisitionItems(entity, ref items))
 
-             {
 
-                 Log("CreateStockBatch() - no items to update!");
 
-                 return;
 
-             }
 
-             var batch = new StockMovementBatch
 
-             {
 
-                 Type = StockMovementBatchType.Issue,
 
-                 TimeStamp = entity.Filled,
 
-                 Notes = string.Format("Requisition #{0}", entity.Number)
 
-             };
 
-             batch.Employee.ID = entity.Employee.ID;
 
-             batch.Requisition.ID = entity.ID;
 
-             FindSubStore<StockMovementBatch>().Save(batch, "");
 
-             var updates = new List<StockMovement>();
 
-             foreach (var item in items)
 
-             {
 
-                 if (item.Product.NonStock) continue;
 
-                 var holdingQty = 0.0;
 
-                 var dimensions = item.Dimensions;
 
-                 
 
-                 if(item.JobLink.ID != Guid.Empty)
 
-                 {
 
-                     var holdings = Provider.Query<StockHolding>(
 
-                         new Filter<StockHolding>(x => x.Location.ID).IsEqualTo(item.Location.ID)
 
-                             .And(x => x.Product.ID).IsEqualTo(item.Product.ID)
 
-                             .And(x => x.Style.ID).IsEqualTo(item.Style.ID)
 
-                             .And(x => x.Dimensions).DimensionEquals(item.Dimensions)
 
-                             .And(x => x.Job.ID).IsEqualTo(item.JobLink.ID),
 
-                         Columns.None<StockHolding>().Add(x => x.Units)
 
-                     );
 
-                     holdingQty = holdings.Rows.FirstOrDefault()?.Get<StockHolding, double>(x => x.Units) ?? 0.0;
 
-                 }
 
-                 var qty = item.ActualQuantity;
 
-                 var timestamp = entity.Filled;
 
-                 var txnid = Guid.NewGuid();
 
-                 if (holdingQty.IsEffectivelyLessThan(qty))
 
-                 {
 
-                     // Don't pull more than the required quantity, meaning if the holding is negative, it will remain negative.
 
-                     var extraRequired = qty - Math.Max(0.0,holdingQty); 
 
-                     
 
-                     // We're going to redirect this general stock direct to the target job, so reduce the amount required from the selected holding
 
-                     qty = holdingQty; 
 
-                     
 
-                     // We don't have enough stock in this case, so transfer the necessary stock from general. We don't check for quantity in general stock,
 
-                     // but instead will let general stock go negative if not enough. Obviously we have the stock, because its being sent to site. So if we do
 
-                     // get negatives, it means probably our number are wrong I think.
 
-                     // Transfer the necessary balance from General Stock...
 
-                     var from = CreateStockMovement(entity.Employee, timestamp, batch, item.Product, item.Location, item.Style, null, null,
 
-                         dimensions, txnid, item.Charge, item.JobScope, true, $"Requisition #{entity.Number} Internal Transfer");
 
-                     from.Issued = extraRequired;
 
-                     from.Type = StockMovementType.TransferOut;
 
-                     timestamp = timestamp.AddTicks(1);
 
-                     // ... to the job -  note this is the final (entity) job/JRI, not the holding job/JRI
 
-                     var to = CreateStockMovement(entity.Employee, timestamp, batch, item.Product, item.Location, item.Style, entity.JobLink, item.SourceJRI, dimensions, txnid, item.Charge, item.JobScope, true,
 
-                         $"Requisition #{entity.Number} Internal Transfer");
 
-                     to.Received = extraRequired;
 
-                     to.Type = StockMovementType.TransferIn;
 
-                     timestamp = timestamp.AddTicks(1);
 
-                     updates.Add(from);
 
-                     updates.Add(to);
 
-                     // Now we have a full qty in the job holding, and we can issue to site.
 
-                 }
 
-                 
 
-                 // if we have to change either job or JRI
 
-                 if (!qty.IsEffectivelyEqual(0.0) && (entity.JobLink.ID != item.JobLink.ID || item.JobRequisitionItem.ID != item.SourceJRI.ID))
 
-                 {
 
-                     // Transfer from the item job to the requisition job
 
-                     var from = CreateStockMovement(entity.Employee, timestamp, batch, item.Product, item.Location, item.Style, item.JobLink, item.JobRequisitionItem,
 
-                         dimensions, txnid, item.Charge, item.JobScope, true, $"Requisition #{entity.Number} Internal Transfer");
 
-                     from.Issued = qty;
 
-                     from.Type = StockMovementType.TransferOut;
 
-                     timestamp = timestamp.AddTicks(1);
 
-                     // ... to the job.
 
-                     var to = CreateStockMovement(entity.Employee, timestamp, batch, item.Product, item.Location, item.Style, entity.JobLink, item.SourceJRI, dimensions, txnid, item.Charge, item.JobScope, true,
 
-                         $"Requisition #{entity.Number} Internal Transfer");
 
-                     to.Received = qty;
 
-                     to.Type = StockMovementType.TransferIn;
 
-                     timestamp = timestamp.AddTicks(1);
 
-                     updates.Add(from);
 
-                     updates.Add(to);
 
-                     
 
-                 }
 
-                 var mvt = CreateStockMovement(entity.Employee, timestamp, batch, item.Product, item.Location, item.Style, entity.JobLink, item.SourceJRI, dimensions, txnid, item.Charge, item.JobScope,
 
-                     false,
 
-                     $"Requisition #{entity.Number}");
 
-                 
 
-                 // Now we can issue to full original quantity to the entity job :-)
 
-                 mvt.Issued = item.ActualQuantity;
 
-                 mvt.Type = StockMovementType.Issue;
 
-                 updates.Add(mvt);
 
-                 
 
-             }
 
-             FindSubStore<StockMovement>().Save(updates, "");
 
-         }
 
-         private void ClearStockBatch(Requisition entity)
 
-         {
 
-             Log("ClearStockBatch()");
 
-             var batches = Provider.Query(
 
-                 new Filter<StockMovementBatch>(x => x.Requisition.ID).IsEqualTo(entity.ID),
 
-                 Columns.None<StockMovementBatch>().Add(x => x.ID)
 
-             ).Rows.Select(x => x.ToObject<StockMovementBatch>());
 
-             if (batches.Any())
 
-                 FindSubStore<StockMovementBatch>().Delete(batches, "");
 
-         }
 
-         private void UpdateStockBatches(Requisition entity, ref IList<RequisitionItem> items)
 
-         {
 
-             Log("UpdateStockBatch() - starting");
 
-             if (!NeedsUpdating(entity, entity, x => x.StockUpdated))
 
-                 return;
 
-             var oldupdate = entity.GetOriginalValue(x => x.StockUpdated);
 
-             var newupdate = entity.StockUpdated;
 
-             // Gone from Blank to Updated -> Create a Batch
 
-             if (oldupdate.IsEmpty() && !newupdate.IsEmpty())
 
-             {
 
-                 Log("UpdateStockBatch() - creating batch");
 
-                 ClearStockBatch(entity);
 
-                 CreateStockBatch(entity, ref items);
 
-             }
 
-             // Gone from Updated to Blank -> Clear Out the Batch
 
-             else if (newupdate.IsEmpty() && !oldupdate.IsEmpty())
 
-             {
 
-                 Log("UpdateStockBatch() - clearing batch");
 
-                 ClearStockBatch(entity);
 
-             }
 
-             // Do nothing - Updated flag has been updated, not set or cleared
 
-             Log("UpdateStockBatch() - done");
 
-         }
 
-         #endregion
 
-     }
 
- }
 
 
  |