123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- using Comal.Classes;
- using InABox.Clients;
- using InABox.Core;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using InABox.Mobile;
- using Syncfusion.SfImageEditor.XForms;
- using Xamarin.CommunityToolkit.Extensions;
- using Xamarin.CommunityToolkit.UI.Views;
- using Xamarin.Essentials;
- using Xamarin.Forms;
- using Xamarin.Forms.Xaml;
- using XF.Material.Forms.UI.Dialogs;
- using Location = InABox.Core.Location;
- using LogType = InABox.Core.LogType;
- using TextAlignment = Xamarin.Forms.TextAlignment;
- namespace PRS.Mobile
- {
- public class StockLocationStatusConverter : AbstractConverter<StockLocationShell, string>
- {
- protected override string? Convert(StockLocationShell? value, object? parameter = null)
- {
- return value != null
- ? $"{value.LocationType}, {(value.Active ? "Active" : "Inactive")}"
- : "";
- }
- }
- public class StockHoldingShellColorConverter : AbstractConverter<StockHoldingShell, Color>
- {
- public DateTime CurrentStockTake { get; set; } = DateTime.MinValue;
- protected override Color Convert(StockHoldingShell? value, object? parameter = null)
- {
- var count = value?.Transactions.Aggregate(0, (agg, trans) => agg += 1) ?? 0;
-
- var prevcounted = !CurrentStockTake.IsEmpty() && (value?.LastStocktake ?? DateTime.MinValue) >= CurrentStockTake;
-
- return count > 0 || prevcounted
- ? Color.LightGreen
- : Color.Orange;
- }
- }
-
- public class StockHoldingShellAdjustmentConverter : AbstractConverter<StockHoldingShell, String>
- {
-
- public DateTime CurrentStockTake { get; set; } = DateTime.MinValue;
- protected override String Convert(StockHoldingShell? value, object? parameter = null)
- {
- var basevalue = value?.Units ?? 0.0d;
- var count = value?.Transactions.Aggregate(0, (agg, trans) => agg += 1) ?? 0;
- var quantity = value?.Transactions.Aggregate(0.0d, (agg, trans) => agg += trans.Quantity) ?? 0.0d;
-
- var prevcounted = !CurrentStockTake.IsEmpty() && (value?.LastStocktake ?? DateTime.MinValue) >= CurrentStockTake;
-
- return count == 0
- ? prevcounted
- ? "ALREADY\nCOUNTED"
- : "NOT\nCHECKED"
- : quantity.IsEffectivelyEqual(basevalue)
- ? "CORRECT\nQUANTITY"
- : quantity < basevalue
- ? $"{basevalue-quantity:F2}\nSHORT"
- : $"{quantity-basevalue:F2}\nOVER";
- }
- }
-
- public class StockHoldingShellBalanceConverter : AbstractConverter<StockHoldingShell, String>
- {
- protected override String Convert(StockHoldingShell? value, object? parameter = null)
- {
- var basevalue = value?.Units ?? 0.0d;
- var count = value?.Transactions.Aggregate(0, (agg, trans) => agg += 1) ?? 0;
- var quantity = value?.Transactions.Aggregate(0.0d, (agg, trans) => agg += trans.Quantity) ?? 0.0d;
- return count == 0 || quantity.IsEffectivelyEqual(basevalue)
- ? $"{basevalue:F2}"
- : $"{quantity:F2}";
- }
- }
-
- [XamlCompilation(XamlCompilationOptions.Compile)]
- public partial class StocktakeModule : MobilePage
- {
- private bool _isNewStockTake = true;
-
- public StocktakeModule(Guid locationid)
- {
- InitializeComponent();
-
- if (locationid != Guid.Empty)
- {
- App.Data.StockLocations.Refresh(false);
- var location = App.Data.StockLocations.FirstOrDefault(x => x.ID == locationid);
- ViewModel.Location = location ?? new StockLocationShell();
- Title = $"Stock Take: {ViewModel.Location.Description}";
- }
- else
- ViewModel.Location = new StockLocationShell();
- _isNewStockTake = ViewModel.Location.CurrentStocktake.IsEmpty();
- _stockHoldingShellColorConverter.CurrentStockTake = ViewModel.Location.CurrentStocktake;
- _stockHoldingShellAdjustmentConverter.CurrentStockTake = ViewModel.Location.CurrentStocktake;
- }
-
- protected override async Task<bool> OnBackButtonClicked()
- {
- bool result = true;
- if (ViewModel.Location.ID != Guid.Empty && ViewModel.Transactions.Any())
- result = await DisplayAlert("Stocktake in progress",
- "This Stocktake is not complete.\nAre you sure you wish to close it?", "No", "Yes") == false;
- if (result && _isNewStockTake && !ViewModel.Location.CurrentStocktake.IsEmpty())
- {
- ViewModel.Location.CurrentStocktake = DateTime.MinValue;
- ViewModel.Location.Save("Stocktake cancelled by user");
- }
-
- return result;
- }
- private void Holding_Clicked(object sender, EventArgs e)
- {
-
- if (ViewModel.Location.ID == Guid.Empty)
- {
- DisplayAlert("ERROR", "Please select a Location!", "OK");
- return;
- }
-
- if ((sender as MobileCard)?.BindingContext is StockHoldingShell shell)
- {
- var transaction = ViewModel.Transactions.FirstOrDefault(x => x.Source.Shell == shell);
- if (transaction == null)
- {
- transaction = new StockTransaction(StockTransactionType.StockTake, shell, shell);
- transaction.Allocations = shell.Allocations.Select(x => new StockTransactionAllocation()
- {
- ID = x.ID,
- Description = x.Description,
- Quantity = x.Quantity,
- Maximum = double.MaxValue
- }
- ).ToArray();
- }
- var popup = new StockTakeEdit(transaction);
- popup.TransactionSaved += (o,e) =>
- {
- if (ViewModel.Location.CurrentStocktake.IsEmpty())
- {
- ViewModel.Location.CurrentStocktake = DateTime.Now;
- ViewModel.Location.Save("Stocktake marked as started on mobile device");
- }
-
- if (shell.Parent.Transactions != null && !shell.Parent.Transactions.Contains(transaction))
- shell.Parent.Transactions?.Add(transaction);
- shell.ProductID = transaction.ProductID;
- shell.ProductCode = transaction.ProductCode;
- shell.ProductName = transaction.ProductName;
-
- var imageid = transaction.ImageID;
- if (imageid != Guid.Empty)
- shell.Parent.Images[imageid] = transaction.Image;
- shell.ImageID = imageid;
- shell.DimensionsUnitID = transaction.DimensionsUnitID;
- shell.DimensionsHeight = transaction.DimensionsHeight;
- shell.DimensionsWidth = transaction.DimensionsWidth;
- shell.DimensionsLength = transaction.DimensionsLength;
- shell.DimensionsQuantity = transaction.DimensionsQuantity;
- shell.DimensionsValue = transaction.DimensionsValue;
- shell.DimensionsUnitSize = transaction.DimensionsUnitSize;
- _holdings.ItemsSource = null;
- _holdings.ItemsSource = ViewModel.Holdings.Items;
- };
- Navigation.PushAsync(popup);
- }
- }
-
- private async void TakePhoto_Clicked(object sender, EventArgs args)
- {
- try
- {
- MobileDocument file = await MobileDocument.From(PhotoUtils.CreateCameraOptions());
- if (file?.Data?.Any() == true)
- ViewModel.Images.Add(
- new StockTransactionImage(
- file,
- MobileUtils.ImageTools.CreateThumbnail(file.Data, 256, 256)
- )
- );
- }
- catch (Exception e)
- {
- await MaterialDialog.Instance.AlertAsync(e.Message, "ERROR");
- }
- }
- private async void PickPhoto_Clicked(object sender, EventArgs args)
- {
- try
- {
- MobileDocument file = await MobileDocument.From(PhotoUtils.CreatePhotoLibraryOptions());
- if (file?.Data?.Any() == true)
- ViewModel.Images.Add(
- new StockTransactionImage(
- file,
- MobileUtils.ImageTools.CreateThumbnail(file.Data, 256, 256)
- )
- );
- }
- catch (Exception e)
- {
- await MaterialDialog.Instance.AlertAsync(e.Message, "ERROR");
- }
- }
- private void Image_Clicked(object sender, EventArgs e)
- {
- if ((sender as MobileCard)?.BindingContext is StockTransactionImage image)
- {
- ShowPopup(() =>
- {
- var editor = new SfImageEditor()
- {
- Source = ImageSource.FromStream(() => new MemoryStream(image.Document.Data)),
- BackgroundColor = Color.Transparent,
- };
- editor.ToolbarSettings.HeaderToolbarHeight = 0;
-
- editor.ImageEdited += (o, args) =>
- {
- // Trigger the Dispatcher to allow the edit to complete before saving
- // Otherwise the autosaved image is one edit behind the editor itself
- Dispatcher.BeginInvokeOnMainThread(() => editor.Save());
- };
-
- editor.ImageSaving += (o, args) =>
- {
- using (var ms = new MemoryStream())
- {
- args.Stream.CopyTo(ms);
- image.Document.Data = ms.GetBuffer();
- image.Thumbnail = MobileUtils.ImageTools.CreateThumbnail(image.Document.Data, 256, 256);
- }
- args.Cancel = true;
- };
-
- return editor;
- });
- }
- }
- private async void Save_Clicked(object sender, MobileMenuButtonClickedEventArgs args)
- {
- if (!ViewModel.Holdings.Any() && !ViewModel.Transactions.Any() &&
- ViewModel.Location.LocationType == StockLocationType.Transient)
- {
- if (await MaterialDialog.Instance.ConfirmAsync("This location is empty!\nMark it as Inactive?",
- "Empty Location") == true)
- {
- using(var dialog = await MaterialDialog.Instance.LoadingDialogAsync(message: "Closing Location"))
- {
- ViewModel.Location.Active = false;
- ViewModel.Location.Save("Closed by Mobile Device");
- Navigation.PopAsync();
- return;
- }
- }
- }
-
- if (ViewModel.Holdings.Any()
- && !ViewModel.Transactions.Any())
- {
- await DisplayAlert("Error", "There are no transactions to save!", "OK");
- return;
- }
- if (ViewModel.Holdings.Any()
- && !ViewModel.Images.Any())
- {
- await DisplayAlert("Error", "Please provide at least one photo.", "OK");
- return;
- }
-
- if (await DisplayAlert("Confirm", "Save StockTake Batch?", "OK", "CANCEL") == true)
- {
- using(var dialog = await MaterialDialog.Instance.LoadingDialogAsync(message: "Saving Data"))
- {
- Progress<String> progress = new Progress<string>((s) => dialog.MessageText = s);
- await ViewModel.Save(progress);
- }
- Navigation.PopAsync();
- }
-
- }
- private async void AddHolding_Clicked(object sender, MobileMenuButtonClickedEventArgs args)
- {
- if (ViewModel.Location.ID == Guid.Empty)
- {
- DisplayAlert("ERROR", "Please select a Location!", "OK");
- return;
- }
- var holding = ViewModel.Holdings.CreateItem();
- holding.LocationID = ViewModel.Location.ID;
- holding.LocationCode = ViewModel.Location.Code;
- holding.LocationDescription = ViewModel.Location.Description;
- var transaction = new StockTransaction(StockTransactionType.StockTake, holding, holding);
- transaction.Allocations = new StockTransactionAllocation[]
- {
- new StockTransactionAllocation()
- {
- ID = Guid.Empty,
- Description = "General Stock",
- Quantity = 0.0F,
- Maximum = double.MaxValue
- }
- };
-
- var popup = new StockTakeEdit(transaction);
- popup.TransactionSaved += (o,e) =>
- {
- transaction.Source.JobID = transaction.Target.JobID;
- transaction.Source.JobNumber = transaction.Target.JobNumber;
- transaction.Source.JobName = transaction.Target.JobName;
-
- transaction.Source.StyleID = transaction.Target.StyleID;
- transaction.Source.StyleCode = transaction.Target.StyleCode;
- transaction.Source.StyleDescription = transaction.Target.StyleDescription;
- transaction.Source.Units = transaction.Target.Units;
-
- ViewModel.Transactions.Add(transaction);
- _holdings.ItemsSource = null;
- _holdings.ItemsSource = ViewModel.Holdings.Items;
- };
- Navigation.PushAsync(popup);
- }
- private void ChangeArea_Clicked(object sender, MobileButtonClickEventArgs args)
- {
- ShowPopup(
- () => SelectionView.Execute<StockAreaShell>(
- (columns) =>
- {
-
- columns.Add(new MobileGridTextColumn<StockAreaShell>()
- {
- Column = x => x.Code,
- Width = GridLength.Auto,
- Caption = "Code",
- Alignment = TextAlignment.Start
- });
-
- columns.Add(new MobileGridTextColumn<StockAreaShell>()
- {
- Column = x => x.Description, Width = GridLength.Star, Caption = "Description",
- Alignment = TextAlignment.Start
- });
-
- },
- (refresh) =>
- {
- App.Data.StockAreas.Refresh(true);
- return App.Data.StockAreas.Where(x => x.Active);
- },
- (areas) =>
- {
- ViewModel.Location.AreaID = areas?.FirstOrDefault()?.ID ?? Guid.Empty;
- ViewModel.Location.AreaCode = areas?.FirstOrDefault()?.Code ?? string.Empty;
- ViewModel.Location.AreaDescription = areas?.FirstOrDefault()?.Description ?? string.Empty;
- ViewModel.Location.WarehouseID = areas?.FirstOrDefault()?.WarehouseID ?? Guid.Empty;
- ViewModel.Location.WarehouseCode = areas?.FirstOrDefault()?.WarehouseCode ?? string.Empty;
- ViewModel.Location.WarehouseDescription = areas?.FirstOrDefault()?.WarehouseDescription ?? string.Empty;
- DismissPopup();
- }
- )
- );
- }
- private void ToggleActive_Clicked(object sender, MobileButtonClickEventArgs args)
- {
- ViewModel.Location.Active = !ViewModel.Location.Active;
- }
- }
- }
|