示例#1
0
        public async Task <IActionResult> Edit(int id, [Bind("Id,Name")] LabourType labourType)
        {
            if (id != labourType.Id)
            {
                return(NotFound());
            }

            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(labourType);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!LabourTypeExists(labourType.Id))
                    {
                        return(NotFound());
                    }
                    else
                    {
                        throw;
                    }
                }
                return(RedirectToAction(nameof(Index)));
            }
            return(View(labourType));
        }
示例#2
0
        public async Task <IActionResult> Create([Bind("Id,Name")] LabourType labourType)
        {
            if (ModelState.IsValid)
            {
                _context.Add(labourType);
                await _context.SaveChangesAsync();

                return(RedirectToAction(nameof(Index)));
            }
            return(View(labourType));
        }
示例#3
0
 private void AddLabour(string name, Employee employee, LabourType labourType, string activity)
 {
     _dataContext.Labours.Add(new Labour
     {
         Start      = DateTime.Now.AddYears(-2),
         Name       = name,
         Employee   = employee,
         LabourType = labourType,
         Activity   = activity
     });
 }
示例#4
0
        /// <summary>
        /// Creates the a model for each Labour Type
        /// </summary>
        public IEnumerable <LabourType> GetLabourTypes(Labour parent)
        {
            List <LabourType> types = new List <LabourType>();

            int row = -1;

            foreach (string item in LabourSupply.RowNames)
            {
                row++;
                if (LabourSupply.GetData <string>(row, 0) != "0")
                {
                    // Finds the current demographic
                    string demo = LabourSupply.ExtraNames[row] + " " + LabourSupply.RowNames[row];

                    // Tries to find an age for the demographic, defaults to 20
                    int age = 20;
                    LabourAges.TryGetValue(demo, out age);

                    int gender = 0;
                    if (LabourSupply.RowNames[row].Contains("F"))
                    {
                        gender = 1;
                    }

                    LabourType type = new LabourType(parent)
                    {
                        Name        = demo,
                        InitialAge  = age,
                        Gender      = gender,
                        Individuals = LabourSupply.GetData <int>(row, 0)
                    };

                    types.Add(type);
                }
            }

            return(types.AsEnumerable());
        }
示例#5
0
        /// <summary>
        /// Method to determine available labour based on filters and take it if requested.
        /// </summary>
        /// <param name="request">Resource request details</param>
        /// <param name="removeFromResource">Determines if only calculating available labour or labour removed</param>
        /// <param name="callingModel">Model calling this method</param>
        /// <param name="resourceHolder">Location of resource holder</param>
        /// <param name="partialAction">Action on partial resources available</param>
        /// <returns></returns>
        public static double TakeLabour(ResourceRequest request, bool removeFromResource, IModel callingModel, ResourcesHolder resourceHolder, OnPartialResourcesAvailableActionTypes partialAction)
        {
            double            amountProvided = 0;
            double            amountNeeded   = request.Required;
            LabourFilterGroup current        = request.FilterDetails.OfType <LabourFilterGroup>().FirstOrDefault() as LabourFilterGroup;

            LabourRequirement lr;

            if (current != null)
            {
                if (current.Parent is LabourRequirement)
                {
                    lr = current.Parent as LabourRequirement;
                }
                else
                {
                    // coming from Transmutation request
                    lr = new LabourRequirement()
                    {
                        ApplyToAll       = false,
                        MaximumPerPerson = 1000,
                        MinimumPerPerson = 0
                    };
                }
            }
            else
            {
                lr = Apsim.Children(callingModel, typeof(LabourRequirement)).FirstOrDefault() as LabourRequirement;
            }

            int currentIndex = 0;

            if (current == null)
            {
                // no filtergroup provided so assume any labour
                current = new LabourFilterGroup();
            }

            request.ResourceTypeName = "Labour";
            ResourceRequest removeRequest = new ResourceRequest()
            {
                ActivityID         = request.ActivityID,
                ActivityModel      = request.ActivityModel,
                AdditionalDetails  = request.AdditionalDetails,
                AllowTransmutation = request.AllowTransmutation,
                Available          = request.Available,
                FilterDetails      = request.FilterDetails,
                Provided           = request.Provided,
                Reason             = request.Reason,
                Required           = request.Required,
                Resource           = request.Resource,
                ResourceType       = request.ResourceType,
                ResourceTypeName   = request.ResourceTypeName
            };

            // start with top most LabourFilterGroup
            while (current != null && amountProvided < amountNeeded)
            {
                List <LabourType> items = (resourceHolder.GetResourceGroupByType(request.ResourceType) as Labour).Items;
                items = items.Where(a => (a.LastActivityRequestID != request.ActivityID) || (a.LastActivityRequestID == request.ActivityID && a.LastActivityRequestAmount < lr.MaximumPerPerson)).ToList();
                items = items.Filter(current as Model);

                // search for people who can do whole task first
                while (amountProvided < amountNeeded && items.Where(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson) >= request.Required).Count() > 0)
                {
                    // get labour least available but with the amount needed
                    LabourType lt = items.Where(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson) >= request.Required).OrderBy(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson)).FirstOrDefault();

                    double amount = Math.Min(amountNeeded - amountProvided, lt.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson));

                    // limit to max allowed per person
                    amount = Math.Min(amount, lr.MaximumPerPerson);
                    // limit to min per person to do activity
                    if (amount < lr.MinimumPerPerson)
                    {
                        request.Reason = "Min labour limit";
                        return(amountProvided);
                    }

                    amountProvided        += amount;
                    removeRequest.Required = amount;
                    if (removeFromResource)
                    {
                        lt.LastActivityRequestID     = request.ActivityID;
                        lt.LastActivityRequestAmount = amount;
                        lt.Remove(removeRequest);
                        request.Provided += removeRequest.Provided;
                        request.Value    += request.Provided * lt.PayRate();
                    }
                }

                // if still needed and allow partial resource use.
                if (partialAction == OnPartialResourcesAvailableActionTypes.UseResourcesAvailable)
                {
                    if (amountProvided < amountNeeded)
                    {
                        // then search for those that meet criteria and can do part of task
                        foreach (LabourType item in items.Where(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson) >= 0).OrderByDescending(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson)))
                        {
                            if (amountProvided >= amountNeeded)
                            {
                                break;
                            }

                            double amount = Math.Min(amountNeeded - amountProvided, item.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumPerPerson));

                            // limit to max allowed per person
                            amount = Math.Min(amount, lr.MaximumPerPerson);

                            // limit to min per person to do activity
                            if (amount >= lr.MinimumPerPerson)
                            {
                                amountProvided        += amount;
                                removeRequest.Required = amount;
                                if (removeFromResource)
                                {
                                    if (item.LastActivityRequestID != request.ActivityID)
                                    {
                                        item.LastActivityRequestAmount = 0;
                                    }
                                    item.LastActivityRequestID      = request.ActivityID;
                                    item.LastActivityRequestAmount += amount;
                                    item.Remove(removeRequest);
                                    request.Provided += removeRequest.Provided;
                                    request.Value    += request.Provided * item.PayRate();
                                }
                            }
                            else
                            {
                                currentIndex = request.FilterDetails.Count;
                            }
                        }
                    }
                }
                currentIndex++;
                if (current.Children.OfType <LabourFilterGroup>().Count() > 0)
                {
                    current = current.Children.OfType <LabourFilterGroup>().FirstOrDefault();
                }
                else
                {
                    current = null;
                }
            }
            // report amount gained.
            return(amountProvided);
        }
示例#6
0
        private string CreateHTML()
        {
            string htmlString = "<!DOCTYPE html>\n" +
                                "<html>\n<head>\n<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\" />\n<style>\n" +
                                "body {color: [FontColor]; max-width:1000px; font-size:1em; font-family: Segoe UI, Arial, sans-serif}" +
                                "table {border-collapse: collapse; font-size:0.8em; }" +
                                "table,th,td {border: 1px solid #aaaaaa; }" +
                                "table th {padding:3px; color:[HeaderFontColor]; vertical-align: bottom; text-align: center;}" +
                                "th span {-ms-writing-mode: tb-rl;-webkit-writing-mode: vertical-rl;writing-mode: vertical-rl;transform: rotate(180deg);white-space: nowrap;}" +
                                "table td {padding:3px; }" +
                                "td:nth-child(n+2) {text-align:center;}" +
                                "th:nth-child(1) {text-align:left;}" +
                                "th {background-color: Black !important; }" +
                                "tr:nth-child(2n+3) {background:[ResRowBack] !important;}" +
                                "tr:nth-child(2n+2) {background:[ResRowBack2] !important;}" +
                                "td.fill {background-color: #c1946c !important;}" +
                                "table.main {[TableBackground] }" +
                                "table.main tr td.disabled {color: [DisabledColour]; }" +
                                ".dot { margin:auto; display:block; height:20px; width:20px; line-height:20px; background-color:black; -moz-border-radius: 10px; border-radius: 10px; }" +
                                ".dot1 { background-color:#F5793A; }" +
                                ".dot2 { background-color:#A95AA1; }" +
                                ".dot3 { background-color:#85C0F9; }" +
                                ".dot4 { background-color:#0F2080; }" +
                                ".warningbanner {background-color:orange; border-radius:5px 5px 0px 0px; color:white; padding:5px; font-weight:bold }" +
                                ".warningcontent {background-color:[WarningBackground]; margin-bottom:20px; border-radius:0px 0px 5px 5px; border-color:orange; border-width:1px; border-style:none solid solid solid; padding:10px;}" +
                                ".messagebanner {background-color:CornflowerBlue; border-radius:5px 5px 0px 0px; color:white; padding:5px; font-weight:bold }" +
                                ".messagecontent {background-color:[MessageBackground]; margin-bottom:20px; border-radius:0px 0px 5px 5px; border-color:CornflowerBlue; border-width:1px; border-style:none solid solid solid; padding:10px;}" +
                                "li {margin-bottom:10px;}" +
                                "table.blank td {border: 0px none [GridColor]; }" +
                                "table.blank {border: 0px none #009999; border-collapse: collapse; }" +
                                "table th:first-child {text-align:left; }" +
                                "table th:nth-child(n+2) { /* Safari */ - webkit - transform: rotate(-90deg); /* Firefox */ -moz - transform: rotate(-90deg); /* IE */ -ms - transform: rotate(-90deg); /* Opera */ -o - transform: rotate(-90deg); /* Internet Explorer */ filter: progid: DXImageTransform.Microsoft.BasicImage(rotation = 3);  }" +
                                "table td:nth-child(n+2) { text-align:center; }" +
                                ".clearfix { overflow: auto; }" +
                                ".namediv { float:left; vertical-align:middle; }" +
                                ".typediv { float:right; vertical-align:middle; font-size:0.6em; }" +
                                ".holdermain {margin: 20px 0px 20px 0px}" +
                                ".defaultbanner {background-color:[ContDefaultBanner] !important; border-radius:5px 5px 0px 0px; color:white; padding:5px; font-weight:bold }" +
                                ".defaultcontent {background-color:[ContDefaultBack] !important; margin-bottom:20px; border-radius:0px 0px 5px 5px; border-color:[ContDefaultBanner]; border-width:1px; border-style:none solid solid solid; padding:10px;}" +
                                "@media print { body { -webkit - print - color - adjust: exact; }}" +
                                ".rotate {/* FF3.5+ */ -moz - transform: rotate(-90.0deg); /* Opera 10.5 */ -o - transform: rotate(-90.0deg); /* Saf3.1+, Chrome */ -webkit - transform: rotate(-90.0deg); /* IE6,IE7 */ filter: progid: DXImageTransform.Microsoft.BasicImage(rotation = 0.083); /* IE8 */ -ms - filter: \"progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083)\"; /* Standard */ transform: rotate(-90.0deg);} " +
                                "\n</style>\n</head>\n<body>";

            // Start building table
            // apply theme based settings
            if (!Utility.Configuration.Settings.DarkTheme)
            {
                // light theme
                htmlString = htmlString.Replace("[FontColor]", "#000000");
                htmlString = htmlString.Replace("[GridColor]", "Black");
                htmlString = htmlString.Replace("[WarningBackground]", "#FFFFFA");
                htmlString = htmlString.Replace("[MessageBackground]", "#FAFAFF");
                htmlString = htmlString.Replace("[DisabledColour]", "#cccccc");
                htmlString = htmlString.Replace("[TableBackground]", "background-color: white;");
                htmlString = htmlString.Replace("[ContDefaultBack]", "#FAFAFA");
                htmlString = htmlString.Replace("[ContDefaultBanner]", "#000");
                htmlString = htmlString.Replace("[HeaderFontColor]", "white");
            }
            else
            {
                // dark theme
                htmlString = htmlString.Replace("[FontColor]", "#E5E5E5");
                htmlString = htmlString.Replace("[GridColor]", "#888");
                htmlString = htmlString.Replace("[WarningBackground]", "rgba(255, 102, 0, 0.4)");
                htmlString = htmlString.Replace("[MessageBackground]", "rgba(100, 149, 237, 0.4)");
                htmlString = htmlString.Replace("[DisabledColour]", "#666666");
                htmlString = htmlString.Replace("[TableBackground]", "background-color: rgba(50, 50, 50, 0.5);");
                htmlString = htmlString.Replace("[ContDefaultBack]", "#282828");
                htmlString = htmlString.Replace("[ContDefaultBanner]", "#686868");
                htmlString = htmlString.Replace("[HeaderFontColor]", "#333333");
            }

            // get CLEM Zone
            IModel clem = model as IModel;

            while (!(clem is ZoneCLEM))
            {
                clem = clem.Parent;
            }

            using (StringWriter htmlWriter = new StringWriter())
            {
                htmlWriter.WriteLine(htmlString);
                htmlWriter.WriteLine("\n<span style=\"font-size:0.8em; font-weight:bold\">You will need to keep refreshing this page after changing settings and selecting the LabourAllocationsReport to see changes</span><br /><br />");

                htmlWriter.Write("\n<div class=\"clearfix defaultbanner\">");
                htmlWriter.Write($"<div class=\"namediv\">Labour allocation summary</div>");
                htmlWriter.Write($"<div class=\"typediv\">Details</div>");
                htmlWriter.Write("</div>");
                htmlWriter.Write("\n<div class=\"defaultcontent\">");
                htmlWriter.Write($"\n<div class=\"activityentry\">Summary last created on {DateTime.Now.ToShortDateString()} at {DateTime.Now.ToShortTimeString()}<br />");
                htmlWriter.WriteLine("\n</div>");
                htmlWriter.WriteLine("\n</div>");

                // Get Labour resources
                labour = clem.FindAllDescendants <Labour>().FirstOrDefault() as Labour;
                if (labour == null)
                {
                    htmlWriter.Write("No Labour supplied in resources");
                    htmlWriter.Write("\n</body>\n</html>");
                    return(htmlWriter.ToString());
                }

                numberLabourTypes = labour.FindAllChildren <LabourType>().Count();
                if (numberLabourTypes == 0)
                {
                    htmlWriter.Write("No Labour types supplied in Labour resource");
                    htmlWriter.Write("\n</body>\n</html>");
                    return(htmlWriter.ToString());
                }

                // create labour list
                labourList.Clear();
                foreach (LabourType lt in labour.FindAllChildren <LabourType>())
                {
                    var newLabour = new LabourType()
                    {
                        Parent      = labour,
                        Name        = lt.Name,
                        AgeInMonths = lt.InitialAge * 12,
                        Sex         = lt.Sex
                    };
                    IndividualAttribute att = new IndividualAttribute()
                    {
                        StoredValue = lt.Name
                    };
                    newLabour.Attributes.Add("Group", att);
                    labourList.Add(newLabour);
                }

                // get all parents of LabourRequirement
                validpAtt.AddRange(ReflectionUtilities.GetAttributes(typeof(LabourRequirement), typeof(ValidParentAttribute), false).Cast <ValidParentAttribute>().ToList());
                validpAtt.AddRange(ReflectionUtilities.GetAttributes(typeof(LabourRequirementNoUnitSize), typeof(ValidParentAttribute), false).Cast <ValidParentAttribute>().ToList());
                validpAtt.AddRange(ReflectionUtilities.GetAttributes(typeof(LabourRequirementSimple), typeof(ValidParentAttribute), false).Cast <ValidParentAttribute>().ToList());
                if (validpAtt.Count() == 0)
                {
                    htmlWriter.Write("No components allow Labour Requirements to be added");
                    htmlWriter.Write("\n</body>\n</html>");
                    return(htmlWriter.ToString());
                }

                // walk through all activities
                // check if LabourRequirement can be added
                ActivitiesHolder activities = clem.FindDescendant <ActivitiesHolder>();
                if (activities == null)
                {
                    htmlWriter.Write("Could not find an Activities Holder");
                    htmlWriter.Write("\n</body>\n</html>");
                    return(htmlWriter.ToString());
                }

                using (StringWriter tableHtml = new StringWriter())
                {
                    tableHtml.WriteLine("<table class=\"main\">");
                    tableHtml.Write("<tr><th>Activity</th>");
                    foreach (LabourType lt in labour.FindAllChildren <LabourType>())
                    {
                        tableHtml.Write($"<th><span>{lt.Name}</span></th>");
                    }

                    tableHtml.WriteLine("</tr>");
                    tableHtml.WriteLine(TableRowHTML(activities));
                    tableHtml.WriteLine("</table>");

                    htmlWriter.Write(tableHtml.ToString());
                }
                // add notes
                htmlWriter.WriteLine("\n<div class=\"holdermain\">");
                htmlWriter.Write("\n<div class=\"clearfix messagebanner\">");
                htmlWriter.Write("<div class=\"typediv\">" + "Notes" + "</div>");
                htmlWriter.Write("</div>");
                htmlWriter.WriteLine("\n<div class=\"messagecontent\">");
                htmlWriter.WriteLine("\n<ul>");
                htmlWriter.WriteLine("\n<li>Only activities capable of including a labour requirement are displayed.</li>");
                htmlWriter.WriteLine("\n<li>Activities with no labour requirement provided are displayed with grey text.</li>");
                htmlWriter.WriteLine("\n<li>Multiple rows of icons (circles) for a given activity show where more than one individual is required.</li>");
                htmlWriter.WriteLine("\n<li>The preferential allocation of labour is displayed in the following order:" +
                                     "<table class=\"blank\">" +
                                     "<tr><td><span class=\"dot dot1 \">" + "</span></td><td>1st preference</td></tr>" +
                                     "<tr><td><span class=\"dot dot2 \">" + "</span></td><td>2nd preference</td></tr>" +
                                     "<tr><td><span class=\"dot dot3 \">" + "</span></td><td>3rd preference</td></tr>" +
                                     "<tr><td><span class=\"dot dot4 \">" + "</span></td><td>4th+ preference</td></tr>" +
                                     "</table></li>");
                htmlWriter.WriteLine("\n</ul>");
                htmlWriter.Write("\n</div>");

                // aging note
                if (labour.AllowAging)
                {
                    htmlWriter.WriteLine("\n<div class=\"holdermain\">");
                    htmlWriter.WriteLine("\n<div class=\"clearfix warningbanner\">");
                    htmlWriter.Write("<div class=\"typediv\">" + "Warning" + "</div>");
                    htmlWriter.Write("</div>");
                    htmlWriter.Write("\n<div class=\"warningcontent\">");
                    htmlWriter.Write("\n<div class=\"activityentry\">As this simulation allows aging of individuals (see Labour) these allocations may change over the duration of the simulation. ");
                    htmlWriter.Write("\n</div>");
                    htmlWriter.WriteLine("\n</div>");
                }
                htmlWriter.Write("\n</body>\n</html>");
                return(htmlWriter.ToString());
            }
        }
示例#7
0
        private string CreateMarkdown()
        {
            using (StringWriter markdownString = new StringWriter())
            {
                // Start building table
                IModel clem = model.FindAncestor <ZoneCLEM>() as IModel;

                // Get Labour resources
                labour = clem.FindAllDescendants <Labour>().FirstOrDefault() as Labour;
                if (labour == null)
                {
                    markdownString.Write("No Labour supplied in resources");
                    return(markdownString.ToString());
                }

                numberLabourTypes = labour.FindAllChildren <LabourType>().Count();
                if (numberLabourTypes == 0)
                {
                    markdownString.Write("No Labour types supplied in Labour resource");
                    return(markdownString.ToString());
                }

                labourList.Clear();
                foreach (LabourType lt in labour.FindAllChildren <LabourType>())
                {
                    var newLabour = new LabourType()
                    {
                        Parent      = labour,
                        Name        = lt.Name,
                        AgeInMonths = lt.InitialAge * 12,
                        Sex         = lt.Sex
                    };
                    IndividualAttribute att = new IndividualAttribute()
                    {
                        StoredValue = lt.Name
                    };
                    newLabour.Attributes.Add("Group", att);
                    labourList.Add(newLabour);
                }

                // get all parents of LabourRequirement
                validpAtt.AddRange(ReflectionUtilities.GetAttributes(typeof(LabourRequirement), typeof(ValidParentAttribute), false).Cast <ValidParentAttribute>().ToList());
                validpAtt.AddRange(ReflectionUtilities.GetAttributes(typeof(LabourRequirementNoUnitSize), typeof(ValidParentAttribute), false).Cast <ValidParentAttribute>().ToList());
                validpAtt.AddRange(ReflectionUtilities.GetAttributes(typeof(LabourRequirementSimple), typeof(ValidParentAttribute), false).Cast <ValidParentAttribute>().ToList());
                if (validpAtt.Count() == 0)
                {
                    markdownString.Write("No components allow Labour Requirements to be added");
                    return(markdownString.ToString());
                }

                // walk through all activities
                // check if LabourRequirement can be added
                ActivitiesHolder activities = clem.FindAllDescendants <ActivitiesHolder>().FirstOrDefault() as ActivitiesHolder;
                if (activities == null)
                {
                    markdownString.Write("Could not find an Activities Holder");
                    return(markdownString.ToString());
                }

                using (StringWriter tableHeader = new StringWriter())
                {
                    using (StringWriter tableSpacer = new StringWriter())
                    {
                        tableHeader.Write("| Activity");
                        tableSpacer.Write("| :---");
                        foreach (LabourType lt in labour.FindAllChildren <LabourType>())
                        {
                            tableHeader.Write(" | " + lt.Name.Replace("_", " "));
                            tableSpacer.Write(" | :---:");
                        }
                        tableHeader.Write(" |  \n");
                        tableSpacer.Write(" |  \n");

                        markdownString.Write(tableHeader.ToString());
                        markdownString.Write(tableSpacer.ToString());
                    }
                }
                markdownString.Write(TableRowMarkdown(activities));

                // add notes
                markdownString.Write("  \n***  \n");
                markdownString.Write("Notes  \n");
                markdownString.Write("-  Only activities capable of including a labour requirement are displayed.  \n");
                markdownString.Write("-  Activities with no labour requirement provided are displayed with italic text.  \n");
                markdownString.Write("-  Multiple rows for a given activity show where more than one individual is required.  \n");
                markdownString.Write("-  The preferential allocation of labour is identified from 1 (1st) to 5 (5th, max levels displayed)  \n");

                // aging note
                if (labour.AllowAging)
                {
                    markdownString.Write("  \n***  \n");
                    markdownString.Write("Warnings  \n");
                    markdownString.Write("-  As this simulation allows aging of individuals (see Labour) these allocations may change over the duration of the simulation.");
                }

                markdownString.Write("  \n***  \n");
                return(markdownString.ToString());
            }
        }
示例#8
0
        /// <summary>
        /// Method to determine available labour based on filters and take it if requested.
        /// </summary>
        /// <param name="request">Resource request details</param>
        /// <param name="removeFromResource">Determines if only calculating available labour or labour removed</param>
        /// <param name="callingModel">Model calling this method</param>
        /// <param name="resourceHolder">Location of resource holder</param>
        /// <param name="partialAction">Action on partial resources available</param>
        /// <returns></returns>
        public static double TakeLabour(ResourceRequest request, bool removeFromResource, IModel callingModel, ResourcesHolder resourceHolder, OnPartialResourcesAvailableActionTypes partialAction)
        {
            double            amountProvided = 0;
            double            amountNeeded   = request.Required;
            LabourFilterGroup current        = request.FilterDetails.OfType <LabourFilterGroup>().FirstOrDefault();

            LabourRequirement lr;

            if (current != null)
            {
                if (current.Parent is LabourRequirement)
                {
                    lr = current.Parent as LabourRequirement;
                }
                else
                {
                    // coming from Transmutation request
                    lr = new LabourRequirement()
                    {
                        LimitStyle       = LabourLimitType.AsDaysRequired,
                        ApplyToAll       = false,
                        MaximumPerGroup  = 10000,
                        MaximumPerPerson = 1000,
                        MinimumPerPerson = 0
                    }
                };
            }
            else
            {
                lr = callingModel.FindAllChildren <LabourRequirement>().FirstOrDefault();
            }

            lr.CalculateLimits(amountNeeded);
            amountNeeded     = Math.Min(amountNeeded, lr.MaximumDaysPerGroup);
            request.Required = amountNeeded;
            // may need to reduce request here or shortfalls will be triggered

            int currentIndex = 0;

            if (current == null)
            {
                // no filtergroup provided so assume any labour
                current = new LabourFilterGroup();
            }

            request.ResourceTypeName = "Labour";
            ResourceRequest removeRequest = new ResourceRequest()
            {
                ActivityID         = request.ActivityID,
                ActivityModel      = request.ActivityModel,
                AdditionalDetails  = request.AdditionalDetails,
                AllowTransmutation = request.AllowTransmutation,
                Available          = request.Available,
                FilterDetails      = request.FilterDetails,
                Provided           = request.Provided,
                Category           = request.Category,
                RelatesToResource  = request.RelatesToResource,
                Required           = request.Required,
                Resource           = request.Resource,
                ResourceType       = request.ResourceType,
                ResourceTypeName   = (request.Resource is null? "":(request.Resource as CLEMModel).NameWithParent)
            };

            // start with top most LabourFilterGroup
            while (current != null && amountProvided < amountNeeded)
            {
                IEnumerable <LabourType> items = resourceHolder.FindResource <Labour>().Items;
                items = items.Where(a => (a.LastActivityRequestID != request.ActivityID) || (a.LastActivityRequestID == request.ActivityID && a.LastActivityRequestAmount < lr.MaximumDaysPerPerson));
                items = current.Filter(items);

                // search for people who can do whole task first
                while (amountProvided < amountNeeded && items.Where(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson) >= request.Required).Any())
                {
                    // get labour least available but with the amount needed
                    LabourType lt = items.Where(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson) >= request.Required).OrderBy(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson)).FirstOrDefault();

                    double amount = Math.Min(amountNeeded - amountProvided, lt.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson));

                    // limit to max allowed per person
                    amount = Math.Min(amount, lr.MaximumDaysPerPerson);
                    // limit to min per person to do activity
                    if (amount < lr.MinimumPerPerson)
                    {
                        request.Category = "Min labour limit";
                        return(amountProvided);
                    }

                    amountProvided        += amount;
                    removeRequest.Required = amount;
                    if (removeFromResource)
                    {
                        lt.LastActivityRequestID     = request.ActivityID;
                        lt.LastActivityRequestAmount = amount;
                        lt.Remove(removeRequest);
                        request.Provided += removeRequest.Provided;
                        request.Value    += request.Provided * lt.PayRate();
                    }
                }

                // if still needed and allow partial resource use.
                if (partialAction == OnPartialResourcesAvailableActionTypes.UseResourcesAvailable)
                {
                    if (amountProvided < amountNeeded)
                    {
                        // then search for those that meet criteria and can do part of task
                        foreach (LabourType item in items.Where(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson) >= 0).OrderByDescending(a => a.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson)))
                        {
                            if (amountProvided >= amountNeeded)
                            {
                                break;
                            }

                            double amount = Math.Min(amountNeeded - amountProvided, item.LabourCurrentlyAvailableForActivity(request.ActivityID, lr.MaximumDaysPerPerson));

                            // limit to max allowed per person
                            amount = Math.Min(amount, lr.MaximumDaysPerPerson);

                            // limit to min per person to do activity
                            if (amount >= lr.MinimumDaysPerPerson)
                            {
                                amountProvided        += amount;
                                removeRequest.Required = amount;
                                if (removeFromResource)
                                {
                                    if (item.LastActivityRequestID != request.ActivityID)
                                    {
                                        item.LastActivityRequestAmount = 0;
                                    }
                                    item.LastActivityRequestID      = request.ActivityID;
                                    item.LastActivityRequestAmount += amount;
                                    item.Remove(removeRequest);
                                    request.Provided += removeRequest.Provided;
                                    request.Value    += request.Provided * item.PayRate();
                                }
                            }
                            else
                            {
                                currentIndex = request.FilterDetails.Count;
                            }
                        }
                    }
                }
                currentIndex++;
                var currentFilterGroups = current.FindAllChildren <LabourFilterGroup>();
                if (currentFilterGroups.Any())
                {
                    current = currentFilterGroups.FirstOrDefault();
                }
                else
                {
                    current = null;
                }
            }
            // report amount gained.
            return(amountProvided);
        }