using Comal.Classes; using Comal.Stores; using InABox.Core; using System.Collections.Generic; using System.Linq; using System.Text; using System; using InABox.Database; namespace PRSStores; using HoldingDictionary = Dictionary<(Guid product, Guid style, Guid location, Guid job, StockDimensions dimensions), StockHolding>; public class StockMovementStore : BaseStore { // These will be initialised in BeforeSave HoldingDictionary holdingData = null!; StockMovement[] mvtData = null!; HashSet currentIDs = new(); protected override void BeforeSave(IEnumerable entities) { foreach(var entity in entities) { // Calling base BeforeSave so that it doesn't call our other BeforeSave method. base.BeforeSave(entity); } currentIDs = entities.Select(x => x.ID).Where(x => x != Guid.Empty).ToHashSet(); mvtData = StockHoldingStore.LoadMovementData(this, currentIDs.ToArray()); holdingData = StockHoldingStore.LoadStockHoldings(this, mvtData); StockHoldingStore.ModifyHoldings(mvtData, holdingData, StockHoldingStore.Action.Decrease); foreach(var sm in entities) { if(sm.Job.HasOriginalValue(x => x.ID) && sm.Job.ID != Guid.Empty && sm.JobScope.ID == Guid.Empty) { // If we have updated the Job.ID to a non-empty value, we should // update the JobScope to the default job scope for that job. var scopeID = Guid.Empty; if(sm.ID != Guid.Empty) { // It's possible that the JobScope ID just wasn't passed up, if // this entity already exists; hence, we shall load the scopeID // from the database just in case. scopeID = Provider.Query( new Filter(x => x.ID).IsEqualTo(sm.ID), Columns.None().Add(x => x.JobScope.ID)) .Rows.FirstOrDefault()?.Get(x => x.JobScope.ID) ?? Guid.Empty; } if(scopeID == Guid.Empty) { // No scope has been assigned; however, we have a job, so we // load the default scope for the job. sm.JobScope.ID = Provider.Query( new Filter(x => x.ID).IsEqualTo(sm.Job.ID), Columns.None().Add(x => x.DefaultScope.ID)) .Rows.FirstOrDefault()?.Get(x => x.DefaultScope.ID) ?? Guid.Empty; } } } } protected override void BeforeSave(StockMovement sm) { BeforeSave(CoreUtils.One(sm)); } protected override void AfterSave(IEnumerable entities) { // Find all movements that weren't loaded in BeforeSave - i.e., they are new stock movements. var newIDs = entities.Select(x => x.ID).Where(x => !currentIDs.Contains(x)).ToArray(); // Grab the data for these movements. var newMvts = StockHoldingStore.LoadMovementData(this, newIDs); // Load all the stock holdings for these movements, but only if we haven't loaded them already. StockHoldingStore.LoadStockHoldings(this, newMvts, holdingData); // Add the new movement data to our data. Note that the above line does the same for holdings. mvtData = mvtData.Concatenate(newMvts); // Update the Relevant StockHolding with the details of this movement StockHoldingStore.ModifyHoldings(mvtData, holdingData, StockHoldingStore.Action.Increase); StockHoldingStore.SaveHoldings(this, holdingData); foreach(var sm in entities) { // Update the Job requisition item status (if applicable) if (sm.JobRequisitionItem.ID != Guid.Empty) JobRequisitionItemStore.UpdateStatus( this, sm.JobRequisitionItem.ID, sm.HasOriginalValue(x=>x.ID) ? JobRequisitionItemAction.Created : JobRequisitionItemAction.Updated ); } foreach(var entity in entities) { // Calling base AfterSave so that it doesn't call our other AfterSave method. base.AfterSave(entity); } } protected override void AfterSave(StockMovement sm) { AfterSave(CoreUtils.One(sm)); } protected override void BeforeDelete(StockMovement entity) { base.BeforeDelete(entity); // We need to do this in before delete, because otherwise we wont have // the data that we need to pull to properly update the stockholdings StockHoldingStore.UpdateStockHolding(this, entity.ID,StockHoldingStore.Action.Decrease); // Now let's pull the requisition ID, so that we can clean this up // properly in AfterDelete() entity.JobRequisitionItem.ID = Provider.Query( new Filter(x => x.ID).IsEqualTo(entity.ID), Columns.None().Add(x => x.JobRequisitionItem.ID) ).Rows .FirstOrDefault()? .Get(x => x.JobRequisitionItem.ID) ?? Guid.Empty; } protected override void AfterDelete(StockMovement sm) { if (sm.JobRequisitionItem.ID != Guid.Empty) JobRequisitionItemStore.UpdateStatus(this, sm.JobRequisitionItem.ID, JobRequisitionItemAction.Deleted); base.AfterDelete(sm); } }