using Comal.Classes; using InABox.Clients; using InABox.Core; using Plugin.Media; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Xamarin.Forms; using Xamarin.Forms.Xaml; using XF.Material.Forms.UI.Dialogs; namespace comal.timesheets { [XamlCompilation(XamlCompilationOptions.Compile)] public partial class RecTransCompletion : ContentPage { public delegate void RecTransCompleted(); public event RecTransCompleted OnRecTransCompleted; List receivingShells = new List(); List originalHoldings = new List(); StockLocation issuingLocation = new StockLocation(); StockLocation receivingLocation = new StockLocation(); List stockMovements = new List(); Job receivingJob = new Job(); Dictionary imagesDocuments = new Dictionary(); List favourites = new List { "Issued to Cutting","Issued to Factory" , "Transferred For Painting", "Returned From Painting", "Received on PO", "Issued to Site" }; public RecTransCompletion(List _receivingShells, List _originalHoldings, StockLocation _issuingLocation, StockLocation _receivingLocation, Job _receivingJob) { InitializeComponent(); receivingShells = _receivingShells; issuingLocation = _issuingLocation; receivingLocation = _receivingLocation; originalHoldings = _originalHoldings; receivingJob = _receivingJob; AddFavButtons(); if (receivingLocation.ID != Guid.Empty) DownloadIssuingLocation(); } private void AddFavButtons() { foreach (string s in favourites) { Button button = new Button { Text = s, TextColor = Color.White, BackgroundColor = Color.FromHex("#15C7C1"), CornerRadius = 10, Margin = 2, FontAttributes = FontAttributes.Bold, VerticalOptions = LayoutOptions.Center, HorizontalOptions = LayoutOptions.Center, Padding = new Thickness(6, 3, 6, 3) }; button.Clicked += FavButton_Clicked; optionsFlexLayout.Children.Add(button); } } private void FavButton_Clicked(object sender, EventArgs e) { Button button = sender as Button; if (string.IsNullOrWhiteSpace(notesEdt.Text)) { notesEdt.Text = button.Text; } else { notesEdt.Text = notesEdt.Text + " " + button.Text; } } private async void DownloadIssuingLocation() { await Task.Run(() => { CoreTable table = new Client().Query ( new Filter(x => x.ID).IsEqualTo(issuingLocation.ID), new Columns(x => x.ID, x => x.Code, x => x.Description) ); issuingLocation = table.Rows.First().ToObject(); }); } private async void SaveBatch_Clicked(object sender, EventArgs e) { using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Saving")) { // Create a Stock Movement Batch - save and wait for return StockMovementBatch batch = new StockMovementBatch() { Notes = notesEdt.Text }; if (receivingLocation.ID != Guid.Empty) { batch.Type = StockMovementBatchType.Transfer; } else if (receivingJob.ID != Guid.Empty) { batch.Type = StockMovementBatchType.Issue; } new Client().Save(batch, "Created on mobile"); // Save photos - async, no wait needed SavePhotos(batch.ID); if (receivingLocation.ID != Guid.Empty) { CreateStockMovements(batch, true, false); //issuing CreateStockMovements(batch, false, true); //receiving } else if (receivingJob.ID != Guid.Empty) { CreateStockMovements(batch, true, false); //issuing only } Task.Run(() => { new Client().Save(stockMovements, "Updated from mobile device"); }); Device.BeginInvokeOnMainThread(async () => { saveBatchBtn.IsVisible = false; await DisplayAlert("Success", "Batch Saved", "OK"); OnRecTransCompleted?.Invoke(); Navigation.PopAsync(); }); } } private void CreateStockMovements(StockMovementBatch batch, bool issuing = false, bool receiving = false) { foreach (StockHoldingShell shell in receivingShells) { CreateStockMovement(shell, batch, issuing, receiving); } } private void CreateStockMovement(StockHoldingShell shell, StockMovementBatch batch, bool issuing = false, bool receiving = false, bool innerloop = false) { StockMovement movement = new StockMovement(); movement.Batch.ID = batch.ID; movement.Date = DateTime.Now; if (batch.Type == StockMovementBatchType.Transfer) movement.IsTransfer = true; movement.Notes = notesEdt.Text; movement.Dimensions.Unit.ID = shell.DimensionsUnitID; movement.Dimensions.Quantity = shell.DimensionsQuantity; movement.Dimensions.Length = shell.DimensionsLength; movement.Dimensions.Width = shell.DimensionsWidth; movement.Dimensions.Height = shell.DimensionsHeight; movement.Dimensions.Weight = shell.DimensionsWeight; movement.Dimensions.Unit.HasHeight = shell.DimensionsHasHeight; movement.Dimensions.Unit.HasLength = shell.DimensionsHasLength; movement.Dimensions.Unit.HasWidth = shell.DimensionsHasWidth; movement.Dimensions.Unit.HasWeight = shell.DimensionsHasWeight; movement.Dimensions.Unit.HasQuantity = shell.DimensionsHasQuantity; movement.Dimensions.Unit.Formula = shell.DimensionsUnitFormula; movement.Dimensions.Unit.Format = shell.DimensionsUnitFormat; movement.Dimensions.Unit.Code = shell.DimensionsUnitCode; movement.Dimensions.Unit.Description = shell.DimensionsUnitDescription; movement.Dimensions.UnitSize = shell.DimensionsUnitSize; movement.Dimensions.Value = shell.DimensionsValue; movement.Product.ID = shell.ProductID; movement.Product.Code = shell.Code; movement.Product.Name = shell.Name; movement.Employee.ID = GlobalVariables.EmpID; movement.Employee.Name = GlobalVariables.EmpName; if (issuing) { StockHoldingShell originalShell = originalHoldings.First(x => x.ID == shell.ID); movement.Style.ID = originalShell.StyleID; movement.Style.Code = originalShell.StyleCode; movement.Style.Description = originalShell.Finish; movement.Job.ID = originalShell.JobID; movement.Job.JobNumber = originalShell.JobNumber; movement.Job.Name = originalShell.JobName; if (innerloop) { movement.System = true; movement.Job.ID = receivingJob.ID; movement.Job.JobNumber = receivingJob.JobNumber; movement.Job.Name = receivingJob.Name; } movement.Location.ID = issuingLocation.ID; movement.Location.Code = issuingLocation.Code; movement.Location.Description = issuingLocation.Description; movement.Issued = shell.Units; //innerloop for creating extra system stock movements if needed when issuing if (receivingJob.ID != Guid.Empty && !innerloop) { if (originalShell.JobID != receivingJob.ID) { CreateStockMovement(shell, batch, false, true, true); CreateStockMovement(shell, batch, true, false, true); } } } else if (receiving) { StockHoldingShell originalShell = originalHoldings.First(x => x.ID == shell.ID); movement.Style.ID = shell.StyleID; movement.Style.Code = shell.StyleCode; movement.Style.Description = shell.Finish; movement.Job.ID = shell.JobID; movement.Job.JobNumber = shell.JobNumber; movement.Job.Name = shell.JobName; movement.Location.ID = receivingLocation.ID; movement.Location.Code = receivingLocation.Code; movement.Location.Description = receivingLocation.Description; movement.Received = shell.Units; if (receivingJob.ID != Guid.Empty && innerloop) { movement.Style.ID = originalShell.StyleID; movement.Style.Code = originalShell.StyleCode; movement.Style.Description = originalShell.Finish; movement.Job.ID = receivingJob.ID; movement.Job.JobNumber = receivingJob.JobNumber; movement.Job.Name = receivingJob.Name; movement.Location.ID = issuingLocation.ID; movement.Location.Code = issuingLocation.Code; movement.Location.Description = issuingLocation.Description; movement.System = true; } } stockMovements.Add(movement); } #region Photos private async void SavePhotos(Guid batchID) { await Task.Run(() => { new Client().Save(imagesDocuments.Values, ""); // Link the photos to the batch List stockMovementBatchDocuments = new List(); foreach (var doc in imagesDocuments.Values) { var smd = new StockMovementBatchDocument(); smd.EntityLink.ID = batchID; smd.DocumentLink.ID = doc.ID; smd.DocumentLink.FileName = doc.FileName; if (smd.EntityLink.ID != Guid.Empty) stockMovementBatchDocuments.Add(smd); } new Client().Save(stockMovementBatchDocuments, ""); }); } async void TakePhoto_Clicked(object sender, EventArgs e) { TakeAPhoto(); } async void ChooseImage_Clicked(object sender, EventArgs e) { ChooseAPhoto(); } private async void TakeAPhoto() { await CrossMedia.Current.Initialize(); if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported) { await DisplayAlert("No Camera", ":( No camera available.", "OK"); return; } String filename = String.Format("{0:yyyy-MM-dd HH:mm:ss.fff}.png", DateTime.Now); var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions { Name = filename, CompressionQuality = 10, PhotoSize = Plugin.Media.Abstractions.PhotoSize.Full }); if (file == null) return; using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Adding Photo")) { Image img = null; var memoryStream = new MemoryStream(); file.GetStream().CopyTo(memoryStream); var data = memoryStream.ToArray(); Document doc = new Document() { FileName = filename, Data = data, CRC = CoreUtils.CalculateCRC(data), TimeStamp = DateTime.Now }; ImageSource src = ImageSource.FromStream(() => new MemoryStream(data)); img = new Image(); img.HeightRequest = 150; img.WidthRequest = 150; img.Aspect = Aspect.AspectFit; img.Source = src; img.GestureRecognizers.Add(new TapGestureRecognizer { Command = new Command(OnTap), CommandParameter = src, NumberOfTapsRequired = 1 }); imagesDocuments.Add(img, doc); file.Dispose(); if (img != null) { Device.BeginInvokeOnMainThread(() => { ImageScroller.IsVisible = true; images.Children.Add(img); UpdateColours(); }); } } } private async void ChooseAPhoto() { await CrossMedia.Current.Initialize(); if (!CrossMedia.Current.IsPickPhotoSupported) { await DisplayAlert("No Library", ":( No Photo Library available.", "OK"); return; } var file = await CrossMedia.Current.PickPhotoAsync(new Plugin.Media.Abstractions.PickMediaOptions() { CompressionQuality = 10, PhotoSize = Plugin.Media.Abstractions.PhotoSize.Full }); if (file == null) return; using (await MaterialDialog.Instance.LoadingDialogAsync(message: "Adding Photo")) { Image img = null; var memoryStream = new MemoryStream(); file.GetStream().CopyTo(memoryStream); var data = memoryStream.ToArray(); Document doc = new Document() { FileName = Path.GetFileName(file.Path), Data = data, CRC = CoreUtils.CalculateCRC(data), TimeStamp = DateTime.Now }; ImageSource src = ImageSource.FromStream(() => new MemoryStream(data)); img = new Image(); img.HeightRequest = 150; img.WidthRequest = 150; img.Aspect = Aspect.AspectFit; img.Source = src; img.GestureRecognizers.Add(new TapGestureRecognizer { Command = new Command(OnTap), CommandParameter = src, NumberOfTapsRequired = 1 }); imagesDocuments.Add(img, doc); file.Dispose(); if (img != null) { Device.BeginInvokeOnMainThread(() => { ImageScroller.IsVisible = true; images.Children.Add(img); UpdateColours(); }); } } } private void OnTap(object obj) { ImageViewer viewer = new ImageViewer(obj as ImageSource); Navigation.PushAsync(viewer); viewer.ChooseDelete(); viewer.OnDeleteSelected += () => { Image img = imagesDocuments.Keys.First(x => x.Source.Equals(obj as ImageSource)); imagesDocuments.Remove(img); Device.BeginInvokeOnMainThread(() => { images.Children.Clear(); if (imagesDocuments.Count > 0) { foreach (Image image in imagesDocuments.Keys) { images.Children.Add(image); } } UpdateColours(); }); }; } #endregion #region Updating Screen private void NotesEdt_Changed(object sender, EventArgs e) { UpdateColours(); } private void UpdateColours() { if (photosFrame.BorderColor == Color.Red) { if (imagesDocuments.Values.Count > 0) { photosFrame.BorderColor = Color.Gray; } } if (!string.IsNullOrWhiteSpace(notesEdt.Text)) { if (notesFrame.BorderColor == Color.Red) { notesFrame.BorderColor = Color.Gray; } } else { notesFrame.BorderColor = Color.Red; } ShowSave(); } private void ShowSave() { if (notesFrame.BorderColor == Color.Gray && photosFrame.BorderColor == Color.Gray) { saveBatchBtn.IsVisible = true; } else { saveBatchBtn.IsVisible = false; } } #endregion } }