Browse Source

Resolving Stores Requi Page

Frank van den Bos 2 năm trước cách đây
mục cha
commit
b270dd598a

+ 126 - 0
prs.media/PRSDigital/Web Content.docx

@@ -0,0 +1,126 @@
+ Employee Planning
+--------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------
+Assigning staff to jobs in a construction company requires careful planning and consideration of a variety of factors. Here are some key steps to follow:
+  1. --------------------------------------------------------------------------------
+  Assess the project requirements: Before assigning staff to a job, it's important to assess the project requirements, including the scope of work, timeline, and budget. This will help determine the number and type of staff needed for the job.
+     1. --------------------------------------------------------------------------------
+     Project Planner
+     2. --------------------------------------------------------------------------------
+     Activity Budgets
+  2. --------------------------------------------------------------------------------
+  Identify staff skills and expertise: Once you know what the project requires, you can identify the skills and expertise needed from staff. Consider factors such as experience, qualifications, and certifications when making staffing decisions.
+     1. --------------------------------------------------------------------------------
+     Employee Qualifications
+     2. --------------------------------------------------------------------------------
+     Employee Teams
+  3. --------------------------------------------------------------------------------
+  Evaluate staff availability: Evaluate the availability of staff to ensure that they are able to work the required hours and days for the job. Consider other ongoing projects or commitments that may impact their availability.
+     1. --------------------------------------------------------------------------------
+     Employee Rostering
+     2. --------------------------------------------------------------------------------
+     Standard Leaves
+     3. --------------------------------------------------------------------------------
+     Leave Requests
+  4. --------------------------------------------------------------------------------
+  Make staffing decisions: Based on the above factors, make decisions on which staff members are best suited for each job. Consider factors such as workload balance, project timelines, and availability of resources.
+     1. --------------------------------------------------------------------------------
+     Daily Planner
+     2. --------------------------------------------------------------------------------
+     Employee Resource Planner
+     3. --------------------------------------------------------------------------------
+     Job resource Planner
+  5. --------------------------------------------------------------------------------
+  Communicate assignments: Once you have made staffing decisions, communicate the assignments clearly to staff members. Provide them with all necessary information about the job, including expectations, timelines, and requirements.
+     1. --------------------------------------------------------------------------------
+     PRS Mobile
+  6. --------------------------------------------------------------------------------
+  Monitor performance: Monitor the performance of staff members throughout the project to ensure that they are meeting expectations and that the job is progressing as planned. Make adjustments to staffing as needed to ensure success.
+     1. --------------------------------------------------------------------------------
+     PRS Mobile
+     2. --------------------------------------------------------------------------------
+     Digital Forms
+     3. --------------------------------------------------------------------------------
+     Daily Reports
+
+ Factory Management
+--------------------------------------------------------------------------------
+
+--------------------------------------------------------------------------------
+There are several advantages of using a factory management software package, including:
+  1. --------------------------------------------------------------------------------
+  Increased efficiency: A factory management software package can automate many processes, such as inventory management, production scheduling, and quality control, which can help to streamline operations and reduce manual labor.
+  2. --------------------------------------------------------------------------------
+  Improved accuracy: With a factory management software package, data is entered and processed automatically, which reduces the likelihood of errors that can occur when information is manually entered.
+  3. --------------------------------------------------------------------------------
+  Better decision-making: Factory management software can provide real-time data on production, inventory, and other key metrics, which can help managers make informed decisions more quickly and accurately.
+  4. --------------------------------------------------------------------------------
+  Cost savings: By automating processes, reducing errors, and improving efficiency, a factory management software package can help to reduce costs and increase profitability.
+  5. --------------------------------------------------------------------------------
+  Improved collaboration: A factory management software package can provide a centralized platform for collaboration between different departments and teams, which can help to improve communication and coordination.
+  6. --------------------------------------------------------------------------------
+  Better customer service: With real-time data on inventory and production, factory management software can help to improve customer service by providing accurate delivery estimates and reducing the likelihood of stockouts.
+--------------------------------------------------------------------------------
+Overall, a factory management software package can help to improve efficiency, accuracy, decision-making, collaboration, and customer service, while reducing costs and increasing profitability.
+
+ GPS Tracking
+Here are three key reasons why you should put GPS trackers on your company assets:
+  1. --------------------------------------------------------------------------------
+  Theft prevention: GPS trackers can deter theft of your company assets and help you recover them quickly in the event they are stolen. This can save you significant amounts of money in replacement costs and insurance premiums, as well as avoid any operational delays due to asset loss.
+  2. --------------------------------------------------------------------------------
+  Improved asset utilization: GPS tracking can help you optimize the use of your assets by providing valuable insights into how they are being used. You can identify underutilized assets, track usage patterns, and better allocate resources to improve efficiency and reduce costs.
+  3. --------------------------------------------------------------------------------
+  Real-time tracking: With GPS tracking, you can monitor the location and status of your assets in real-time, providing greater visibility and control over your operations. This can help you make better decisions, respond to emergencies more quickly, and better manage your resources for optimal performance.
+
+
+ Service Companies
+--------------------------------------------------------------------------------
+Service companies are always looking for ways to improve their efficiency and effectiveness, and one of the best ways to do so is by utilizing software designed specifically for their needs.
+--------------------------------------------------------------------------------
+Whether you're in the healthcare industry, hospitality, transportation, or any other service-based industry, software can help streamline your operations and boost your bottom line.
+--------------------------------------------------------------------------------
+With software for service companies, you can automate tedious tasks like scheduling, billing, and inventory management, freeing up valuable time for you and your team to focus on more important tasks.
+--------------------------------------------------------------------------------
+Additionally, software can help you track and analyze important data like customer satisfaction rates, employee productivity, and revenue streams, giving you invaluable insights into your business's performance and helping you make informed decisions about where to focus your resources.
+--------------------------------------------------------------------------------
+The benefits of software for service companies are clear, and the options available on the market today are more powerful and user-friendly than ever before. Don't wait to start improving your business - consider investing in software today and take your service company to the next level.
+
+ Manufacturing Businesses
+When looking for software for your manufacturing business, here are some key features you should consider:
+  1. --------------------------------------------------------------------------------
+  Production Planning and Scheduling: The software should have the ability to plan and schedule production, including the allocation of resources and materials.
+  2. --------------------------------------------------------------------------------
+  Inventory Management: The software should have the ability to manage inventory levels and track the movement of raw materials, work-in-progress and finished goods throughout the production process.
+  3. --------------------------------------------------------------------------------
+  Quality Control: The software should have the ability to manage quality control processes such as inspection, testing, and corrective action.
+  4. --------------------------------------------------------------------------------
+  Traceability: The software should have the ability to trace the movement of products and components throughout the production process, including their origin, production date, and any processing steps they went through.
+  5. --------------------------------------------------------------------------------
+  Reporting and Analytics: The software should have the ability to generate reports and analytics on production processes, inventory levels, quality control data, and other key performance indicators.
+  6. --------------------------------------------------------------------------------
+  Integration: The software should have the ability to integrate with other systems such as accounting and supply chain management systems.
+  7. --------------------------------------------------------------------------------
+  User Interface: The software should have a user-friendly interface that is easy to navigate and use.
+  8. --------------------------------------------------------------------------------
+  Scalability: The software should have the ability to scale with your business as it grows and expands.
+  9. --------------------------------------------------------------------------------
+  Security: The software should have robust security features to protect sensitive data and prevent unauthorized access.
+  10. --------------------------------------------------------------------------------
+  Customer Support: The software provider should offer reliable customer support to help you address any issues or questions that arise.
+
+ Kanban Based Task Tracking
+
+--------------------------------------------------------------------------------
+Introducing the most efficient way to track your tasks - Kanban-based task tracking!
+--------------------------------------------------------------------------------
+Are you tired of keeping track of your never-ending to-do list? Do you find yourself overwhelmed with the number of tasks you have to complete? Look no further than PRS Task tracking!
+--------------------------------------------------------------------------------
+PRS contains a  visual project management system that allows you to easily track the progress of your tasks. With PRS task tracking, you can quickly and easily organize your tasks into different categories or stages such as "to do," "in progress," and "done." This system makes it easy to see which tasks are a priority and which ones can wait.
+--------------------------------------------------------------------------------
+Our Kanban-based task tracking system is user-friendly, allowing you to easily drag and drop tasks into different categories as you complete them. You can also assign tasks to team members, set deadlines, and add notes or attachments to each task.
+--------------------------------------------------------------------------------
+By using Kanban-based task tracking, you can increase your productivity, reduce your stress levels, and stay on top of all your tasks. With a clear visualization of your workflow, you can quickly identify bottlenecks and make adjustments to keep your projects moving forward.
+--------------------------------------------------------------------------------
+Don't waste any more time trying to keep track of your tasks on a piece of paper or in a cluttered spreadsheet. Upgrade to PRS task tracking today and start seeing results!
+

+ 11 - 34
prs.mobile/comal.timesheets/StoreRequis/StoreRequiConfirmationPage.xaml.cs

@@ -448,7 +448,7 @@ namespace comal.timesheets.StoreRequis
             new Client<Requisition>().Save(requisition, "Saved requi on mobile device");
         }
 
-        private void SaveItems()
+        private async void SaveItems()
         {
             Task.Run(() =>
             {
@@ -470,47 +470,24 @@ namespace comal.timesheets.StoreRequis
                 }
             });
             List<RequisitionItem> toSave = new List<RequisitionItem>();
-            foreach (StoreRequiItemShell requiItemShell in requiItems)
+            foreach (StoreRequiItemShell itemShell in requiItems)
             {
                 RequisitionItem item = new RequisitionItem();
                 item.RequisitionLink.ID = requisition.ID;
-                item.ID = requiItemShell.ID;
-                item.Product.ID = requiItemShell.ProductID;
-                item.Product.Code = requiItemShell.ProductCode;
-                item.Product.Name = requiItemShell.ProductName;
-                item.Location.ID = requiItemShell.LocationID;
-                item.Quantity = requiItemShell.Quantity;
-                item.Description = requiItemShell.ProductName;
-                item.Code = requiItemShell.ProductCode;
-                item.Job.ID = requiItemShell.JobID;
-                item.Style.ID = requiItemShell.StyleID;            
-
-                item.Picked = item.Picked == DateTime.MinValue ? DateTime.Now : item.Picked;
-
-                item.Dimensions.Unit.ID = requiItemShell.Dimensions.Unit.ID;
-                item.Dimensions.Unit.HasQuantity = requiItemShell.Dimensions.Unit.HasQuantity;
-                item.Dimensions.Unit.HasLength = requiItemShell.Dimensions.Unit.HasLength;
-                item.Dimensions.Unit.HasHeight = requiItemShell.Dimensions.Unit.HasHeight;
-                item.Dimensions.Unit.HasWeight = requiItemShell.Dimensions.Unit.HasWeight;
-                item.Dimensions.Unit.HasWidth = requiItemShell.Dimensions.Unit.HasWidth;
-
-                item.Dimensions.Quantity = requiItemShell.Dimensions.Quantity;
-                item.Dimensions.Length = requiItemShell.Dimensions.Length;
-                item.Dimensions.Height = requiItemShell.Dimensions.Height;
-                item.Dimensions.Weight = requiItemShell.Dimensions.Weight;
-                item.Dimensions.Width = requiItemShell.Dimensions.Width;
-
-                item.Dimensions.Unit.Format = requiItemShell.Dimensions.Unit.Format;
-                item.Dimensions.Unit.Formula = requiItemShell.Dimensions.Unit.Formula;
-
-                item.Dimensions.UnitSize = requiItemShell.Dimensions.UnitSize;
-
+                item.ID = itemShell.ID;
+                item.Product.ID = itemShell.ProductID;
+                item.Product.Code = itemShell.ProductCode;
+                item.Product.Name = itemShell.ProductName;
+                item.Location.ID = itemShell.HoldingID;
+                item.Quantity = itemShell.Quantity;
+                item.Description = item.Product.Name;
+                item.Code = item.Product.Code;
                 toSave.Add(item);
             }
             new Client<RequisitionItem>().Save(toSave, "Saved requi on mobile device");
         }
 
-        private void SavePhotos()
+        private async void SavePhotos()
         {
             Task.Run(() =>
             {

+ 111 - 257
prs.mobile/comal.timesheets/StoreRequis/StoreRequiScannerPage.xaml.cs

@@ -1,17 +1,23 @@
-using comal.timesheets.StoreRequis;
-using Comal.Classes;
-using InABox.Clients;
-using InABox.Core;
-using System;
+using System;
 using System.Collections.Generic;
 using System.Linq;
-using System.Threading;
+using System.Text;
 using System.Threading.Tasks;
 using Xamarin.Essentials;
 using Xamarin.Forms;
+using ZXing;
+using ZXing;
+using Xamarin.Forms;
 using Xamarin.Forms.Xaml;
-using XF.Material.Forms.UI.Dialogs;
+using comal.timesheets.CustomControls;
+using Comal.Classes;
+using InABox.Core;
+using InABox.Clients;
+using System.Threading;
 using static comal.timesheets.RequiItems;
+using XF.Material.Forms.UI.Dialogs;
+using Plugin.SimpleAudioPlayer;
+using comal.timesheets.StoreRequis;
 
 namespace comal.timesheets
 {
@@ -19,7 +25,7 @@ namespace comal.timesheets
     public partial class StoreRequiScannerPage : ContentPage
     {
         #region Fields / Constructor
-        public delegate bool OnScanEvent(object sender, string barcode);
+        public delegate bool OnScanEvent(object sender, String barcode);
         public event OnScanEvent OnScan;
         List<StoreRequiItemShell> shells = new List<StoreRequiItemShell>();
         List<StoreRequiItemShell> oldShells = new List<StoreRequiItemShell>();
@@ -110,19 +116,15 @@ namespace comal.timesheets
                 requisition = new Client<Requisition>().Query(
                        new Filter<Requisition>(x => x.ID).IsEqualTo(requisition.ID)
                        ).Rows.FirstOrDefault().ToObject<Requisition>();
-
-                string notes = CheckNotes(requisition.Notes);
-
-                if (!string.IsNullOrWhiteSpace(requisition.Request) || !string.IsNullOrWhiteSpace(notes))
+                if (!string.IsNullOrWhiteSpace(requisition.Request))
                 {
                     StoreRequiItemShell shell1 = new StoreRequiItemShell()
                     {
                         IsNotes = true,
                         IsNotNotes = false,
+                        Summary = requisition.Request,
                         BorderColor = Color.FromHex("#9f4576")
                     };
-                    shell1.Summary = !string.IsNullOrWhiteSpace(requisition.Request) ? "REQUEST: " + requisition.Request + System.Environment.NewLine : "";
-                    shell1.Summary = shell1.Summary + notes;
                     shells.Insert(0, shell1);
                     containsNotes = true;
                 }
@@ -134,31 +136,38 @@ namespace comal.timesheets
                    (
                    new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(requisition.ID),
                    new Columns<RequisitionItem>(
-                       x => x.ID,
-                       x => x.Product.ID,
-                       x => x.Product.Name,
-                       x => x.Product.Code,
-                       x => x.Quantity,
-                       x => x.Location.ID,
-                       x => x.Location.Description,
-                       x => x.Picked
+                       x => x.ID, //0
+                       x => x.Product.ID, //1 
+                       x => x.Product.Name, //2
+                       x => x.Product.Code, //3
+                       x => x.Quantity, //4
+                       x => x.Location.ID, //5
+                       x => x.Location.Description //6
                        )
                    );
                 if (table.Rows.Any())
                 {
-                    Device.BeginInvokeOnMainThread(() => { saveBtn.IsVisible = true; });
-                    foreach (CoreRow row in table.Rows)
+                    Device.BeginInvokeOnMainThread(() =>{ saveBtn.IsVisible = true; });
+                        foreach (CoreRow row in table.Rows)
                     {
+                        List<object> list = row.Values;
+                        if (list[0] == null) { list[0] = Guid.Empty; }
+                        if (list[1] == null) { list[1] = Guid.Empty; }
+                        if (list[2] == null) { list[2] = ""; }
+                        if (list[3] == null) { list[3] = ""; }
+                        if (list[4] == null) { list[4] = 0.0; }
+                        if (list[5] == null) { list[5] = Guid.Empty; }
+                        if (list[6] == null) { list[6] = ""; }
+
                         StoreRequiItemShell shell = new StoreRequiItemShell()
                         {
-                            ID = row.Get<RequisitionItem, Guid>(x => x.ID),
-                            ProductID = row.Get<RequisitionItem, Guid>(x => x.Product.ID),
-                            ProductName = row.Get<RequisitionItem, string>(x => x.Product.Name),
-                            ProductCode = row.Get<RequisitionItem, string>(x => x.Product.Code),
-                            Quantity = row.Get<RequisitionItem, double>(x => x.Quantity),
-                            LocationID = row.Get<RequisitionItem, Guid>(x => x.Location.ID),
-                            LocationName = row.Get<RequisitionItem, string>(x => x.Location.Description),
-                            Picked = row.Get<RequisitionItem, DateTime>(x => x.Picked),
+                            ID = Guid.Parse(list[0].ToString()),
+                            ProductID = Guid.Parse(list[1].ToString()),
+                            ProductName = list[2].ToString(),
+                            ProductCode = list[3].ToString(),
+                            Quantity = double.Parse(list[4].ToString()),
+                            HoldingID = Guid.Parse(list[5].ToString()),
+                            LocationName = list[6].ToString(),
                         };
                         shells.Add(shell);
                         oldShells.Add(shell);
@@ -179,19 +188,6 @@ namespace comal.timesheets
             });
         }
 
-        private string CheckNotes(string[] notes)
-        {
-            string combinednotes = "----------" + System.Environment.NewLine + "NOTES: " + System.Environment.NewLine;
-            if (notes.Count() > 0)
-            {
-                foreach (var note in notes)
-                {
-                    combinednotes = combinednotes + note + System.Environment.NewLine;
-                }
-            }
-            return combinednotes;
-        }
-
         void ConfigDisplay()
         {
             loadingLbl.IsVisible = false;
@@ -296,28 +292,55 @@ namespace comal.timesheets
             return tuple;
         }
 
-        private void LoadProduct(Tuple<string, double> processedResultQtyTuple, string rawResult)
+        private async void LoadProduct(Tuple<string, double> processedResultQtyTuple, string rawResult)
         {
             Device.BeginInvokeOnMainThread(async () =>
             {
                 //lookup product in productshells cache
                 ProductShell product = GlobalVariables.ProductShells.Find(x => x.Code.Equals(processedResultQtyTuple.Item1));
 
+                string itemLocation = "";
+                Guid holdingID = Guid.Empty;
+
                 //lookup holding for product in holdings cache
                 try
                 {
-                    var list = CreateHoldingsList(product.ID);
-
-                    if (list.Count == 1) //one stockholding - auto choose holding
-                        AddStoreRequiItemShell(list.First(), product, rawResult, processedResultQtyTuple);
-
-                    else if (list.Count > 1)  //more than one stockholding - user choose shelf                    
-                        UserSelectFromList(list, product, rawResult, processedResultQtyTuple);
-
+                    List<HoldingsCacheShell> list = holdingsCache.Where(x => x.ProductID.Equals(product.ID)).ToList();
+                    if (list.Count == 1) //one stockholding - auto choose shelf
+                    {
+                        HoldingsCacheShell holding = list.First();
+                        itemLocation = holding.LocationName;
+                        holdingID = holding.ID;
+                    }
+                    else if (list.Count > 1)  //more than one stockholding - choose shelf
+                    {
+                        loading = true;
+                        Dictionary<string, Guid> holdingIDLocations = new Dictionary<string, Guid>();
+                        foreach (HoldingsCacheShell holding in list)
+                        {
+                            if (!holdingIDLocations.ContainsKey(holding.LocationName + " (Units: " + holding.Units + ")"))
+                            {
+                                holdingIDLocations.Add(holding.LocationName + " (Units: " + holding.Units + ")" + 
+                                    Environment.NewLine + "Style: " + holding.StyleDescription
+                                    + Environment.NewLine + "Job: " + holding.JobNumber
+                                    + Environment.NewLine + "Size: " + holding.DimensionsUnitSize, holding.ID);
+                            }
+                        }
+                        List<string> options = holdingIDLocations.Keys.ToList();
+                        ListSelectionPage page = new ListSelectionPage(options);
+                        page.OnSimpleListTapped += (s) => 
+                        {
+                            itemLocation = s;
+                            holdingID = holdingIDLocations[s];
+                        };
+                        Navigation.PushAsync(page);
+                    }
                     else if (list.Count == 0)
+                    {
                         DisplayAlert("No Holdings Found for Product", "", "OK");
-
-                    loading = false;
+                        loading = false;
+                        return;
+                    }
                 }
                 catch (Exception e)
                 {
@@ -325,170 +348,38 @@ namespace comal.timesheets
                     loading = false;
                     return;
                 }
-            });
-        }
-
-        private void UserSelectFromList(List<StoreRequiIHoldingShell> list, ProductShell product, string rawResult, Tuple<string, double> processedResultQtyTuple)
-        {
-            Dictionary<string, Guid> holdingLocationIDs = new Dictionary<string, Guid>();
-            foreach (StoreRequiIHoldingShell holding in list)
-            {
-                if (!holdingLocationIDs.ContainsKey(holding.LocationName))
-                    holdingLocationIDs.Add(holding.LocationName, holding.LocationID);
-            }
-            List<string> options = holdingLocationIDs.Keys.ToList();
-            ListSelectionPage page = new ListSelectionPage(options);
-            page.OnSimpleListTapped += (locationName) =>
-            {
-                AddStoreRequiItemShell(list.Find(x => x.LocationName == locationName), product, rawResult, processedResultQtyTuple);
-            };
-            Navigation.PushAsync(page);
-        }
-
-        private List<StoreRequiIHoldingShell> CreateHoldingsList(Guid productID)
-        {
-            List<StoreRequiIHoldingShell> list = new List<StoreRequiIHoldingShell>();
-
-            CoreTable table = DoHoldingsQuery(productID);
-
-            foreach (CoreRow row in table.Rows)
-            {
-                if (row.Get<StockHolding, double>(x => x.Units) == 0.0)
-                    continue;
-
-                list.Add(CreateHoldingShell(row));
-            }
-            return list;
-        }
-
-        private CoreTable DoHoldingsQuery(Guid productID)
-        {
-            return new Client<StockHolding>().Query(
-                new Filter<StockHolding>(x => x.Product.ID).IsEqualTo(productID),
-                new Columns<StockHolding>(
-                    x => x.ID,
-                    x => x.Product.ID,
-                    x => x.Location.ID,
-                    x => x.Location.Description,
-                    x => x.Units,
-                    x => x.Job.ID,
-                    x => x.Job.JobNumber,
-                    x => x.Job.Name,
-                    x => x.Style.ID,
-                    x => x.Style.Code,
-                    x => x.Style.Description,
-                    x => x.Dimensions.Unit.ID,
-                    x => x.Dimensions.Unit.HasQuantity,
-                    x => x.Dimensions.Unit.HasLength,
-                    x => x.Dimensions.Unit.HasHeight,
-                    x => x.Dimensions.Unit.HasWeight,
-                    x => x.Dimensions.Unit.HasWidth,
-                    x => x.Dimensions.Quantity,
-                    x => x.Dimensions.Length,
-                    x => x.Dimensions.Height,
-                    x => x.Dimensions.Weight,
-                    x => x.Dimensions.Width,
-                    x => x.Dimensions.Unit.Format,
-                    x => x.Dimensions.Unit.Formula,
-                    x => x.Dimensions.UnitSize
-                    )
-                );
-        }
-
-        private StoreRequiIHoldingShell CreateHoldingShell(CoreRow row)
-        {
-            StoreRequiIHoldingShell holding = new StoreRequiIHoldingShell()
-            {
-                ProductID = row.Get<StockHolding, Guid>(x => x.Product.ID),
-                LocationID = row.Get<StockHolding, Guid>(x => x.Location.ID),
-                LocationName = row.Get<StockHolding, string>(x => x.Location.Description),
-                Units = row.Get<StockHolding, double>(x => x.Units).ToString(),
-                JobID = row.Get<StockHolding, Guid>(x => x.Job.ID),
-                JobNumber = row.Get<StockHolding, string>(x => x.Job.JobNumber),
-                JobName = row.Get<StockHolding, string>(x => x.Job.Name),
-                StyleID = row.Get<StockHolding, Guid>(x => x.Style.ID),
-                StyleCode = row.Get<StockHolding, string>(x => x.Style.Code),
-                StyleDescription = row.Get<StockHolding, string>(x => x.Style.Description)
-            };
-
-            holding.Dimensions.Unit.ID = row.Get<StockHolding, Guid>(x => x.Dimensions.Unit.ID);
-            holding.Dimensions.Unit.HasQuantity = row.Get<StockHolding, bool>(x => x.Dimensions.Unit.HasQuantity);
-            holding.Dimensions.Unit.HasLength = row.Get<StockHolding, bool>(x => x.Dimensions.Unit.HasLength);
-            holding.Dimensions.Unit.HasHeight = row.Get<StockHolding, bool>(x => x.Dimensions.Unit.HasHeight);
-            holding.Dimensions.Unit.HasWeight = row.Get<StockHolding, bool>(x => x.Dimensions.Unit.HasWeight);
-            holding.Dimensions.Unit.HasWidth = row.Get<StockHolding, bool>(x => x.Dimensions.Unit.HasWidth);
-
-            holding.Dimensions.Quantity = row.Get<StockHolding, double>(x => x.Dimensions.Quantity);
-            holding.Dimensions.Length = row.Get<StockHolding, double>(x => x.Dimensions.Length);
-            holding.Dimensions.Height = row.Get<StockHolding, double>(x => x.Dimensions.Height);
-            holding.Dimensions.Weight = row.Get<StockHolding, double>(x => x.Dimensions.Weight);
-            holding.Dimensions.Width = row.Get<StockHolding, double>(x => x.Dimensions.Width);
-
-            holding.Dimensions.Unit.Format = row.Get<StockHolding, string>(x => x.Dimensions.Unit.Format);
-            holding.Dimensions.Unit.Formula = row.Get<StockHolding, string>(x => x.Dimensions.Unit.Formula);
-
-            holding.Dimensions.UnitSize = row.Get<StockHolding, string>(x => x.Dimensions.UnitSize);
-
-            holding.LocationName = holding.LocationName + " (Units: " + holding.Units + ")" +
-                   Environment.NewLine + "Style: " + holding.StyleDescription
-                   + Environment.NewLine + "Job: " + holding.JobNumber
-                   + Environment.NewLine + "Size: " + holding.Dimensions.UnitSize;
-
-            return holding;
-        }
 
-        private void AddStoreRequiItemShell(StoreRequiIHoldingShell holding, ProductShell product, string rawResult, Tuple<string, double> processedResultQtyTuple)
-        {
-            StoreRequiItemShell shell = new StoreRequiItemShell
-            {
-                ProductID = product.ID,
-                ProductName = product.Name,
-                ProductCode = product.Code,
-                Quantity = 1,
-                LocationID = holding.LocationID,
-                LocationName = holding.LocationName,
-                StyleID = holding.StyleID,
-                JobID = holding.StyleID
-            };
-            shell.Dimensions.Unit.ID = holding.Dimensions.Unit.ID;
-            shell.Dimensions.Unit.HasQuantity = holding.Dimensions.Unit.HasQuantity;
-            shell.Dimensions.Unit.HasLength = holding.Dimensions.Unit.HasLength;
-            shell.Dimensions.Unit.HasHeight = holding.Dimensions.Unit.HasHeight;
-            shell.Dimensions.Unit.HasWeight = holding.Dimensions.Unit.HasWeight;
-            shell.Dimensions.Unit.HasWidth = holding.Dimensions.Unit.HasWidth;
-
-            shell.Dimensions.Quantity = holding.Dimensions.Quantity;
-            shell.Dimensions.Length = holding.Dimensions.Length;
-            shell.Dimensions.Height = holding.Dimensions.Height;
-            shell.Dimensions.Weight = holding.Dimensions.Weight;
-            shell.Dimensions.Width = holding.Dimensions.Width;
-
-            shell.Dimensions.Unit.Format = holding.Dimensions.Unit.Format;
-            shell.Dimensions.Unit.Formula = holding.Dimensions.Unit.Formula;
-
-            shell.Dimensions.UnitSize = holding.Dimensions.UnitSize;
-
-            shells.Add(shell);
+                StoreRequiItemShell shell = new StoreRequiItemShell
+                {
+                    ProductID = product.ID,
+                    ProductName = product.Name,
+                    ProductCode = product.Code,
+                    Quantity = 1,
+                    HoldingID = holdingID,
+                    LocationName = itemLocation,
+                };
+                shells.Add(shell);
 
-            itemRowScannerRawResultPairs.Add(shell, rawResult);
-            itemRowScannerProcessedResultPairs.Add(shell, processedResultQtyTuple.Item1);
+                itemRowScannerRawResultPairs.Add(shell, rawResult);
+                itemRowScannerProcessedResultPairs.Add(shell, processedResultQtyTuple.Item1);
 
-            requiItemListView.ItemsSource = null;
-            requiItemListView.ItemsSource = shells;
+                requiItemListView.ItemsSource = null;
+                requiItemListView.ItemsSource = shells;
 
-            countLbl.IsVisible = true;
+                countLbl.IsVisible = true;
 
-            if (containsNotes)
-            {
-                countLbl.Text = "Number of items: " + (shells.Count - 1);
-            }
-            else
-            {
-                countLbl.Text = "Number of items: " + shells.Count;
-            }
+                if (containsNotes)
+                {
+                    countLbl.Text = "Number of items: " + (shells.Count - 1);
+                }
+                else
+                {
+                    countLbl.Text = "Number of items: " + shells.Count;
+                }
 
-            saveBtn.IsVisible = true;
-            loading = false;
+                saveBtn.IsVisible = true;
+                loading = false;
+            });
         }
         #endregion
 
@@ -532,7 +423,7 @@ namespace comal.timesheets
                         default:
                             return;
                     }
-                }
+                }               
             }
             else
                 Navigation.PopAsync();
@@ -546,32 +437,6 @@ namespace comal.timesheets
             Navigation.PushAsync(page);
         }
 
-        private async void RequiItem_Tapped(object sender, EventArgs e)
-        {
-            var shell = requiItemListView.SelectedItem as StoreRequiItemShell;
-            if (shell == null) return;
-
-            await RequiItemTappedAsync(shell);
-        }
-
-        private async Task RequiItemTappedAsync(StoreRequiItemShell shell)
-        {
-            string pickstatus = shell.Picked == DateTime.MinValue ? "not picked" : "picked (" + shell.Picked.ToString("dd MMM yy") + ")";
-            string options = shell.Picked == DateTime.MinValue ? ". Mark as Picked?" : ". Remove Picked status?";
-
-            string chosenOption = await DisplayActionSheet("Line is " + pickstatus + options, "Cancel", null, "Yes", "No");
-
-            if (chosenOption != "Yes")
-                return;
-
-            shell.Picked = shell.Picked == DateTime.MinValue ? DateTime.Today : DateTime.MinValue;
-            shell.Colour = shell.Picked == DateTime.MinValue ? Color.Default : Color.FromHex("#8fbc8f");
-
-            requiItemListView.ItemsSource = null;
-            requiItemListView.ItemsSource = shells;
-        }
-
-
         void ReduceQtyBtn_Clicked(object sender, EventArgs e)
         {
             var shell = ((TappedEventArgs)e).Parameter as StoreRequiItemShell;
@@ -610,8 +475,7 @@ namespace comal.timesheets
         void IncreaseQtyBtn_Clicked(object sender, EventArgs e)
         {
             var shell = ((TappedEventArgs)e).Parameter as StoreRequiItemShell;
-            if (shell == null)
-                return;
+            if (shell == null) return;
 
             shell.Quantity++;
             requiItemListView.ItemsSource = null;
@@ -643,24 +507,19 @@ namespace comal.timesheets
         #endregion
     }
 
-    [DoNotPersist]
-    public class StoreRequiItemShell : Entity
+    public class StoreRequiItemShell
     {
+        public Guid ID { get; set; }
         public Guid ProductID { get; set; }
         public string ProductCode { get; set; }
         public string ProductName { get; set; }
         public string LocationName { get; set; }
         public double Quantity { get; set; }
-        public Guid LocationID { get; set; }
+        public Guid HoldingID { get; set; }
         public Color BorderColor { get; set; }
         public bool IsNotes { get; set; }
         public bool IsNotNotes { get; set; }
         public string Summary { get; set; }
-        public DateTime Picked { get; set; }
-        public Color Colour { get; set; }
-        public Guid JobID { get; set; }
-        public Guid StyleID { get; set; }
-        public StockDimensions Dimensions { get; set; }
         public StoreRequiItemShell()
         {
             ProductID = Guid.Empty;
@@ -669,15 +528,10 @@ namespace comal.timesheets
             LocationName = "";
             Quantity = 0;
             ID = Guid.Empty;
-            LocationID = Guid.Empty;
+            HoldingID = Guid.Empty;
             BorderColor = Color.FromHex("#15C7C1");
             IsNotes = false;
             IsNotNotes = true;
-            Picked = DateTime.MinValue;
-            Colour = Color.Default;
-            JobID = Guid.Empty;
-            StyleID = Guid.Empty;
-            Dimensions = new StockDimensions(() => this);
         }
     }
 }

+ 346 - 0
prs.mobile/comal.timesheets/StoreRequis/StoreRequisMainPage.xaml.cs

@@ -0,0 +1,346 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Xamarin.Essentials;
+using Xamarin.Forms;
+using ZXing;
+using ZXing;
+using Xamarin.Forms;
+using Xamarin.Forms.Xaml;
+using comal.timesheets.CustomControls;
+using Comal.Classes;
+using InABox.Core;
+using InABox.Clients;
+using System.Threading;
+using static comal.timesheets.RequiItems;
+
+namespace comal.timesheets.StoreRequis
+{
+    [XamlCompilation(XamlCompilationOptions.Compile)]
+    public partial class StoreRequisMainPage : ContentPage
+    {
+
+        public delegate bool OnScanEvent(object sender, String barcode);
+
+        public event OnScanEvent OnScan;
+
+        Dictionary<StoreRequiItem, string> itemRowScannerRawResultPairs;
+
+        Dictionary<StoreRequiItem, string> itemRowScannerProcessedResultPairs;
+
+        Dictionary<int, StoreRequiItem> idItemRowPairs;
+
+        bool choosingLocation;
+
+        Requisition requisition;
+
+        bool newRequisition;
+
+        int count;
+
+        int itemsCount;
+
+        #region Constructor, appearing and disappearing
+
+        public StoreRequisMainPage(Guid _requiID)
+        {
+            InitializeComponent();
+            var options = new ZXing.Mobile.MobileBarcodeScanningOptions()
+            {
+                PossibleFormats = new List<ZXing.BarcodeFormat>() { ZXing.BarcodeFormat.QR_CODE },
+                AutoRotate = false,
+                TryInverted = true,
+                TryHarder = true,
+            };
+            _scanView.Options = options;
+            _scanView.IsAnalyzing = false;
+            _scanView.IsScanning = true;
+            _scanView.OnScanResult += ScanView_OnScanResult;
+            count = 0;
+            choosingLocation = false;
+            itemRowScannerRawResultPairs = new Dictionary<StoreRequiItem, string>();
+            itemRowScannerProcessedResultPairs = new Dictionary<StoreRequiItem, string>();
+            idItemRowPairs = new Dictionary<int, StoreRequiItem>();
+
+            RequiItems.NewRequisitionRows = new List<StoreRequiItem>();
+            RequiItems.OldRequisitionItems = new List<RequisitionItem>();
+
+            if (_requiID != Guid.Empty)
+            {
+                Title = "Loading";
+                requisition = new Requisition();
+                requisition.ID = _requiID;
+                LoadExistingRequi();
+            }
+            else
+            {
+                Title = "Scan Items";
+                newRequisition = true;
+                requisition = new Requisition();
+            }
+        }
+        private async void LoadExistingRequi()
+        {
+            await Task.Run(() =>
+            {
+                requisition = new Client<Requisition>().Query(
+                    new Filter<Requisition>(x => x.ID).IsEqualTo(requisition.ID)
+                    ).Rows.FirstOrDefault().ToObject<Requisition>();
+                if (!string.IsNullOrWhiteSpace(requisition.Request))
+                {
+                    Label notesLbl = new Label()
+                    {
+                        Text = requisition.Request,
+                        Margin = 0,
+                        Padding = 0
+                    };
+                    
+                    
+                    Device.BeginInvokeOnMainThread(() =>
+                    {
+                        requestFrame.Content = notesLbl;
+                        requestFrame.IsVisible = true;
+                    });
+                }
+
+                if (RequiItems.OldRequisitionItems.Count > 0)
+                    RequiItems.OldRequisitionItems.Clear();
+                CoreTable table = new Client<RequisitionItem>().Query
+                    (
+                    new Filter<RequisitionItem>(x => x.RequisitionLink.ID).IsEqualTo(requisition.ID)
+                    );
+                if (table.Rows.Any())
+                {
+                    foreach (CoreRow row in table.Rows)
+                    {
+                        RequisitionItem requisitionItem = row.ToObject<RequisitionItem>();
+                        LoadProduct(new Tuple<string, double>(requisitionItem.Product.Code, requisitionItem.Quantity), requisitionItem.Product.Code, requisitionItem);
+                        RequiItems.OldRequisitionItems.Add(requisitionItem);
+                    }
+                }
+                Device.BeginInvokeOnMainThread(() =>
+                {
+                    Title = "Scan Items";
+                });
+
+            });
+        }
+
+        protected override void OnAppearing()
+        {
+            base.OnAppearing();
+            _scanView.IsAnalyzing = true;
+        }
+
+        protected override void OnDisappearing()
+        {
+            _scanView.IsAnalyzing = false;
+            base.OnDisappearing();
+        }
+
+        #endregion
+
+        #region Scan Complete and process results
+        private void ScanView_OnScanResult(ZXing.Result result)
+        {
+            Device.BeginInvokeOnMainThread(() =>
+            {
+                if (!choosingLocation)
+                {
+                    if (RequiItems.HoldingsLoaded)
+                    {
+                        bool bOK = true;
+                        if (OnScan != null)
+                            bOK = OnScan(this, result.Text);
+                        if (bOK)
+                        {
+                            if (!itemRowScannerRawResultPairs.Values.Contains(result.Text))
+                            {
+                                if (!itemRowScannerProcessedResultPairs.Values.Contains(result.Text))
+                                {
+                                    Vibration.Vibrate();
+                                    string rawResult = result.Text;
+                                    Tuple<string, double> tuple = ProcessResult(result.Text);
+                                    LoadProduct(tuple, rawResult, new RequisitionItem());
+                                }
+                            }
+                        }
+                    }
+                }
+            });
+        }
+
+        private Tuple<string, double> ProcessResult(string result)
+        {
+            double qty = 1;
+            if (result.Contains("*"))
+            {
+                try
+                {
+                    int i = result.IndexOf("*");
+                    string remainder = result.Substring(i);
+                    result = result.Remove(i);                    
+                    string s1 = remainder.Substring(1);
+                    qty = Convert.ToDouble(s1);
+                }
+                catch { }
+            }
+            Tuple<string, double> tuple = new Tuple<string, double>(result, qty);
+            return tuple;
+        }
+
+        private void LoadProduct(Tuple<string, double> processedResultQtyTuple, string rawResult, RequisitionItem requisitionItem)
+        {
+            Device.BeginInvokeOnMainThread(async () =>
+            {
+                //lookup product in productshells cache
+                ProductShell product = GlobalVariables.ProductShells.Find(x => x.Code.Equals(processedResultQtyTuple.Item1));
+
+                //lookup holding for product in holdings cache
+                //List<HoldingsCacheShell> list = new List<HoldingsCacheShell>();
+                string itemLocation = "";
+                Guid holdingID = Guid.Empty;
+
+                if (requisitionItem.ID == Guid.Empty)
+                {
+                    try
+                    {
+                        List<HoldingsCacheShell> list = holdingsCache.Where(x => x.ProductID.Equals(product.ID)).ToList();
+                        if (list.Count == 1) //one stockholding - auto choose shelf
+                        {
+                            HoldingsCacheShell holding = list.First();
+                            itemLocation = holding.LocationName;
+                            holdingID = holding.ID;
+                        }
+                        else if (list.Count > 1)  //more than one stockholding - choose shelf
+                        {
+                            choosingLocation = true;
+                            Dictionary<string, Guid> holdingIDLocations = new Dictionary<string, Guid>();
+                            foreach (HoldingsCacheShell holding in list)
+                            {
+                                if (!holdingIDLocations.ContainsKey(holding.LocationName + " (Qty: " + holding.Units + ")"))
+                                {
+                                    holdingIDLocations.Add(holding.LocationName + " (Qty: " + holding.Units + ")", holding.ID);
+                                }
+                            }
+                            string[] array = holdingIDLocations.Keys.ToArray();
+                            string chosenOption = await DisplayActionSheet("Choose Location", "Cancel", null, array);
+                            if (chosenOption != null && chosenOption != "Cancel")
+                            {
+                                itemLocation = chosenOption;
+                                holdingID = holdingIDLocations[chosenOption];
+                            }
+                            else
+                                return;
+                        }
+                        else if (list.Count == 0)
+                        {
+                            DisplayAlert("No Holdings Found for Product", "", "OK");
+                            return;
+                        }
+                    }
+                    catch(Exception e)
+                    {
+                        DisplayAlert("Error", e.Message, "OK");
+                        return;
+                    }
+                }
+                else
+                {
+                    itemLocation = requisitionItem.Location.Description;
+                    holdingID = requisitionItem.Location.ID;
+                }
+
+                StoreRequiItem storeRequiItem = new StoreRequiItem(product, processedResultQtyTuple.Item2, itemLocation, holdingID) //default qty is 1
+                {
+                    ID = count,
+                };
+                storeRequiItem.RequiItemID = requisitionItem.ID;
+                storeRequiItem.OnZeroSelected += StoreRequiItem_OnZeroSelected;
+                storeRequiItem.OnParseError += OnParseError;
+
+                idItemRowPairs.Add(count, storeRequiItem);
+                itemRowScannerRawResultPairs.Add(storeRequiItem, rawResult);
+                itemRowScannerProcessedResultPairs.Add(storeRequiItem, processedResultQtyTuple.Item1);
+                itemRowsFlexlayout.Children.Add(storeRequiItem);
+                count++;
+                itemsCount++;
+                Title = "Store Requis (" + itemsCount + ")";
+                choosingLocation = false;
+                itemsScroller.ScrollToAsync(storeRequiItem, ScrollToPosition.Center, true);
+            });
+        }
+        #endregion
+
+        #region Buttons Pressed
+        private void Add_Clicked(object sender, EventArgs e)
+        {
+            if (GlobalVariables.ProductsLoaded)
+            {
+                ProductList products = new ProductList(GlobalVariables.ProductShells, true);
+                products.OnProductSelected += ()=> 
+                {
+                    Tuple<string, double> tuple = new Tuple<string, double>(products.SelectedProduct.Code, 1);
+
+                    LoadProduct(new Tuple<string, double>(products.SelectedProduct.Code, 1), products.SelectedProduct.Code, new RequisitionItem());
+                };
+                Navigation.PushAsync(products);
+            }
+        }
+
+        private void NextBtn_Clicked(object sender, EventArgs e)
+        {
+            if (RequiItems.NewRequisitionRows.Count > 0)
+                RequiItems.NewRequisitionRows.Clear();
+
+            if (idItemRowPairs.Count > 0)
+            {
+                //RequiItems.NewRequisitionRows = idItemRowPairs.Values.ToList();
+                //StoreRequiConfirmationPage storeRequiConfirmationPage = new StoreRequiConfirmationPage(requisition);
+                //storeRequiConfirmationPage.OnSaveSelected += () => { Navigation.PopAsync(); };
+                //Navigation.PushAsync(storeRequiConfirmationPage);
+            }
+            else
+            {
+                DisplayAlert("Alert", "Please add items", "Cancel");
+            }
+        }
+        private async void StoreRequiItem_OnZeroSelected(int ID)
+        {
+            string chosenOption = await DisplayActionSheet("Remove Item?", "Cancel", null, "Yes", "No");
+            switch (chosenOption)
+            {
+                case "Cancel":
+                    return;
+                    break;
+                case "No":
+                    return;
+                    break;
+                case "Yes":
+                    break;
+                default:
+                    return;
+                    break;
+            }
+            StoreRequiItem storeRequiItem = idItemRowPairs[ID];
+            itemRowsFlexlayout.Children.Remove(storeRequiItem);
+            idItemRowPairs.Remove(ID);
+            itemRowScannerRawResultPairs.Remove(storeRequiItem);
+            itemRowScannerProcessedResultPairs.Remove(storeRequiItem);
+            itemsCount--;
+            Title = "Store Requis (" + itemsCount + ")";
+        }
+
+        private async void OnParseError()
+        {
+            DisplayAlert("Error", "Enter only numbers", "OK");
+        }
+
+        #endregion
+
+
+
+    }
+}