using System; using System.Linq; using System.Text; using System.Threading.Tasks; using Comal.Classes; using InABox.Core; using Xamarin.CommunityToolkit.ObjectModel; using Xamarin.Forms; using Xamarin.Forms.Xaml; namespace PRS.Mobile { public enum StockTakeStatus { Complete, InProgress, NotFound } public enum StockTakeResult { AllCorrect, AdjustmentsMade } public class StockTakeViewModel : BindableObject { public ObservableRangeCollection Images { get; private set; } public String Notes { get; set; } public StockTransactions Transactions { get; private set; } private StockLocationShell _location; public StockLocationShell Location { get => _location; set { if (Equals(value, _location)) return; _location = value; Holdings?.Refresh(true); CheckTransactions(); OnPropertyChanged(); } } public StockHoldingModel Holdings { get; private set; } public StockTakeViewModel() { Images = new(); Notes = ""; Transactions = new StockTransactions(); Transactions.CollectionChanged += (sender, args) => { CheckTransactions(); }; _location = new StockLocationShell(); Holdings = new StockHoldingModel(App.Data, () => new Filter(x => x.Location.ID).IsEqualTo(Location.ID)); Holdings.Transactions = Transactions; } private StockTakeStatus CalculateStatus() { var progress = Holdings.Count(x => x.LastStocktake >= Location.CurrentStocktake) + Transactions.Count; if (progress == Holdings.Items.Count) return StockTakeStatus.Complete; if (progress > 0) return StockTakeStatus.InProgress; return StockTakeStatus.NotFound; } public StockTakeStatus StocktakeStatus => CalculateStatus(); private StockTakeResult CalculateResult() { var adjustments = Transactions.Count(x => !CoreUtils.IsEffectivelyEqual(x.Source.Units, x.Quantity)); return adjustments > 0 ? StockTakeResult.AdjustmentsMade : StockTakeResult.AllCorrect; } public StockTakeResult StocktakeResult => CalculateResult(); public void CheckTransactions() { foreach (var transaction in Transactions.Where(x => x != null)) { if (Location.ID == transaction.Source?.LocationID || Location.ID == transaction.Target?.LocationID) { if (!Holdings.Any( x => x.ProductID == transaction.ProductID && String.Equals(x.DimensionsUnitSize ?? string.Empty, transaction.DimensionsUnitSize ?? string.Empty) && (x.LocationID == (transaction.Source?.LocationID ?? Guid.Empty) || x.LocationID == (transaction.Target?.LocationID ?? Guid.Empty)) && (x.StyleID == (transaction.Source?.StyleID ?? Guid.Empty) || x.StyleID == (transaction.Target?.StyleID ?? Guid.Empty)) && (x.JobID == (transaction.Source?.JobID ?? Guid.Empty) || x.JobID == (transaction.Target?.JobID ?? Guid.Empty)) )) { var holding = Holdings.CreateItem(); holding.ProductID = transaction.ProductID; holding.ProductCode = transaction.ProductCode; holding.ProductName = transaction.ProductName; Guid imageid = transaction.ImageID; if (imageid != Guid.Empty && transaction.Image !=null) Holdings.Images[imageid] = transaction.Image; holding.ImageID = imageid; holding.DimensionsUnitID = transaction.DimensionsUnitID; holding.DimensionsQuantity = transaction.DimensionsQuantity; holding.DimensionsLength = transaction.DimensionsLength; holding.DimensionsWidth = transaction.DimensionsWidth; holding.DimensionsHeight = transaction.DimensionsHeight; holding.DimensionsWeight = transaction.DimensionsWeight; holding.DimensionsUnitSize = transaction.DimensionsUnitSize; holding.DimensionsValue = transaction.DimensionsValue; holding.LocationID = transaction.Target.LocationID; holding.LocationCode = transaction.Target.LocationCode ?? string.Empty; holding.LocationDescription = transaction.Target.LocationDescription ?? string.Empty; holding.StyleID = transaction.Target.StyleID; holding.StyleCode = transaction.Target.StyleCode ?? string.Empty; holding.StyleDescription = transaction.Target.StyleDescription ?? string.Empty; holding.JobID = transaction.Target.JobID; holding.JobNumber = transaction.Target.JobNumber ?? string.Empty; holding.JobName = transaction.Target.JobName ?? string.Empty; holding.Transactions.Add(transaction); transaction.Source.Shell = holding; transaction.Target.Shell = holding; Holdings.CommitItem(holding); } } } } public Task Save(IProgress progress) { return Task.Run(() => { if (Location.Entity.IsChanged()) { progress.Report("Updating Location "); Location.Save("Updated from Mobile Device"); } progress.Report("Creating Stock Movement Batch"); var batchModel = new StockMovementBatchModel(App.Data, () => new Filter().None()); batchModel.Refresh(false); var batch = batchModel.AddItem(); batch.Type = StockMovementBatchType.Stocktake; batch.EmployeeID = App.Data.Me.ID; StringBuilder sb = new StringBuilder(); if (StocktakeStatus == StockTakeStatus.NotFound) sb.AppendLine("Location Not Found"); else { if (StocktakeStatus == StockTakeStatus.InProgress) sb.Append("Partially Counted"); else sb.Append("Stocktake Complete"); if (StocktakeResult == StockTakeResult.AllCorrect) sb.AppendLine(", All Correct"); else sb.AppendLine(", Adjustments made"); if (!String.IsNullOrWhiteSpace(Notes.Trim())) sb.AppendLine(Notes.Trim()); } // foreach (var holding in Holdings.Items) // { // if (!holding.Transactions.Any()) // { // if (sb.Length != 0) // sb.AppendLine().AppendLine("The following Products were not checked:"); // // var comps = new String[] // { // holding.ProductDisplay, // holding.DimensionsUnitSize, // holding.StyleID != Guid.Empty ? $"/ {holding.StyleDisplay}" : string.Empty, // holding.JobID != Guid.Empty ? $"(Job: {holding.JobNumber})" : string.Empty, // $": Qty {holding.Units:F2}" // }; // sb.AppendLine(String.Join(" ", comps.Where(x => !String.IsNullOrWhiteSpace(x)))); // } // } batch.Notes = sb.ToString(); batch.Save("Created on Mobile Device"); progress.Report($"Saving Transactions"); var movementModel = new StockMovementModel(App.Data, () => new Filter().None()); movementModel.Refresh(false); Transactions.ProcessTransactions(movementModel, batch.ID); progress.Report($"Creating {movementModel.Count()} Movements"); movementModel.Save("Created on Mobile Device"); progress.Report($"Saving {Images.Count} Images"); var batchimageModel = new StockMovementBatchDocumentModel(App.Data, () => new Filter().None()); batchimageModel.Refresh(false); var documentModel = new DocumentModel(App.Data, () => new Filter().None()); documentModel.Refresh(false); int i = 1; foreach (var image in Images) { progress.Report($"Saving {i}/{Images.Count} Images"); var document = documentModel.AddItem(); document.Data = image.Document.Data; document.FileName = image.Document.FileName; document.CRC = CoreUtils.CalculateCRC(image.Document.Data); document.TimeStamp = DateTime.Now; document.Save("Created on MobileDevice"); var batchImage = batchimageModel.AddItem(); { batchImage.BatchID = batch.ID; batchImage.DocumentID = document.ID; batchImage.Thumbnail = image.Thumbnail; } } progress.Report($"Updating Thumbnails"); batchimageModel.Save("Created on Mobile Device"); progress.Report($"Updating Stocktake Status"); if (StocktakeStatus == StockTakeStatus.Complete && !Location.CurrentStocktake.IsEmpty()) { Location.CurrentStocktake = DateTime.MinValue; Location.LastStocktake = DateTime.Now; Location.Save("StockTake Completed on mobile device"); } }); } } }