using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using Comal.Classes; using H.Pipes.Extensions; using InABox.Core; using PRSClasses; using Syncfusion.Windows.Tools.Controls; namespace Comal.Stores { internal class RequisitionStore : BaseStore { 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(Requisition entity, Expression> property) { // 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 (!entity.HasOriginalValue(property)) { Log("NeedsUpdating() return false - {0} has not changed", property.ToString()); return false; } return true; } private bool LoadRequisitionItems(Requisition entity, ref IEnumerable requisitionitems) { if (requisitionitems == null) requisitionitems = Provider.Query( new Filter(x => x.RequisitionLink.ID).IsEqualTo(entity.ID) ).Rows.Select(x => x.ToObject()); return requisitionitems.Any(); } private bool LoadDeliveryItems(Requisition entity, ref IEnumerable deliveryitems) { if (deliveryitems == null) deliveryitems = Provider.Query( new Filter(x => x.RequisitionLink.ID).IsEqualTo(entity.ID), new Columns(x => x.ID, x => x.DeliveredDate) ).Rows.Select(x => x.ToObject()); return deliveryitems.Any(); } #region TakenBy private void UpdateTakenBy(Requisition entity, ref IEnumerable items, ref IEnumerable deliveryitems) { Log("UpdateTakenBy() - starting"); if (!NeedsUpdating(entity, x => x.TakenBy)) 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().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); IEnumerable requisitionitems = null; IEnumerable deliveryitems = null; UpdateDeliveryItems(entity, ref requisitionitems, ref deliveryitems); UpdateTakenBy(entity, ref requisitionitems, ref deliveryitems); UpdateStockBatches(entity, ref requisitionitems); UpdateTrackingKanban(entity, e => { if (!entity.Archived.Equals(DateTime.MinValue) || entity.TakenBy.IsValid()) return KanbanCategory.Complete; if (entity.Delivery.IsValid()) { if (entity.Delivery.Completed != DateTime.MinValue) { return KanbanCategory.Complete; } } if (!entity.Filled.Equals(DateTime.MinValue)) return KanbanCategory.Waiting; if (Provider.Query( new Filter(x => x.RequisitionLink.ID).IsEqualTo(entity.ID), new Columns(x => x.ID) ).Rows.Any() ) return KanbanCategory.InProgress; return KanbanCategory.Open; }); } protected override void BeforeDelete(Requisition entity) { UnlinkTrackingKanban(entity); } #region Delivery Items private void CreateDeliveryItems(Requisition entity, ref IEnumerable requisitionitems, ref IEnumerable deliveryitems) { if (!LoadRequisitionItems(entity, ref requisitionitems)) { Log("CreateDeliveryItems() - no requisition items to update"); return; } var updates = new List(); foreach (var item in requisitionitems) updates.Add(item.CreateDeliveryItem(entity)); if (updates.Any()) FindSubStore().Save(updates, "Requisition [Filled] flag has been set"); deliveryitems = updates; } private void ClearDeliveryItems(Requisition entity, ref IEnumerable deliveryitems) { if (!LoadDeliveryItems(entity, ref deliveryitems)) { Log("ClearDeliveryItems() - no delivery items to update"); return; } if (deliveryitems.Any()) FindSubStore().Delete(deliveryitems, "Requisition [Filled] flag has been cleared"); deliveryitems = new List(); } private void UpdateDeliveryItems(Requisition entity, ref IEnumerable requisitionitems, ref IEnumerable deliveryitems) { Log("UpdateDeliveryItems() - starting"); if (!NeedsUpdating(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 void CreateStockMovement(List updates, Guid employeeid, DateTime date, Guid batchid, Guid productid, Guid locationid, Guid styleid, Guid jobid, double qty, IDimensions dimensions, Guid txnid, bool system, string note) { var movement = new StockMovement(); movement.Batch.ID = batchid; movement.Product.ID = productid; movement.Location.ID = locationid; movement.Style.ID = styleid; movement.Job.ID = jobid; movement.Issued = qty < 0.0F ? Math.Abs(qty) : 0.0F; movement.Received = qty > 0.0F ? qty : 0.0F; movement.Qty = qty; movement.Units = qty; movement.Dimensions.CopyFrom(dimensions); movement.System = system; movement.Transaction = txnid; movement.Notes = note; movement.Date = date; movement.Employee.ID = employeeid; updates.Add(movement); } private void CreateStockBatch(Requisition entity, ref IEnumerable items) { LoadRequisitionItems(entity, ref items); if (!items.Any()) { 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().Save(batch, ""); var updates = new List(); foreach (var item in items) { var locationid = item.Location.ID; var productid = item.Product.ID; var styleid = item.Style.ID; var unitsize = item.Dimensions.UnitSize; var jobid = entity.JobLink.ID; var holdings = Provider.Query( new Filter(x => x.Location.ID).IsEqualTo(locationid) .And(x => x.Product.ID).IsEqualTo(productid) .And(x => x.Style.ID).IsEqualTo(styleid) .And(x => x.Dimensions.UnitSize).IsEqualTo(unitsize) ); var holdingrow = holdings.Rows.FirstOrDefault(r => r.Get(c => c.Job.ID).Equals(jobid)); if (holdingrow == null) holdingrow = holdings.Rows.FirstOrDefault(r => r.Get(c => c.Job.ID).Equals(Guid.Empty)); if (holdingrow == null) holdingrow = holdings.Rows.FirstOrDefault(); Guid holdingjobid = holdingrow != null ? holdingrow.Get(c => c.Job.ID) : Guid.Empty; var qty = item.Quantity; var dimensions = item.Product.Dimensions; var txnid = Guid.Empty; if (jobid != holdingjobid) { txnid = Guid.NewGuid(); CreateStockMovement(updates, entity.Employee.ID, DateTime.Now, batch.ID, productid, locationid, styleid, holdingjobid, 0.0F - qty, dimensions, txnid, true, string.Format("Requisition #{0} Internal Transfer", entity.Number)); CreateStockMovement(updates, entity.Employee.ID, DateTime.Now, batch.ID, productid, locationid, styleid, jobid, qty, dimensions, txnid, true, string.Format("Requisition #{0} Internal Transfer", entity.Number)); } CreateStockMovement(updates, entity.Employee.ID, DateTime.Now, batch.ID, productid, locationid, styleid, jobid, 0.0F - qty, dimensions, txnid, false, string.Format("Requisition #{0}", entity.Number)); } FindSubStore().Save(updates, ""); } private void ClearStockBatch(Requisition entity) { Log("ClearStockBatch()"); var batches = Provider.Query( new Filter(x => x.Requisition.ID).IsEqualTo(entity.ID), new Columns(x => x.ID) ).Rows.Select(x => x.ToObject()); if (batches.Any()) FindSubStore().Delete(batches, ""); } private void UpdateStockBatches(Requisition entity, ref IEnumerable items) { Log("UpdateStockBatch() - starting"); if (!NeedsUpdating(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 } }