コード例 #1
0
        private void OnCLEMHerdSummary(object sender, EventArgs e)
        {
            if (PaymentCalculationStyle == PayHiredLabourCalculationStyle.ByLabourUsedInTimeStep)
            {
                int    currentmonth = clock.Today.Month;
                double total        = 0;
                foreach (LabourType item in labour.Items.Where(a => a.Hired))
                {
                    // get days needed
                    double daysUsed = item.LabourAvailability.GetAvailability(currentmonth - 1) - item.AvailableDays;

                    // calculate rate and amount needed
                    double rate = item.PayRate();
                    total += (daysUsed * rate);
                }

                // take hire cost
                bankAccount.Remove(new ResourceRequest()
                {
                    Resource           = bankAccount,
                    ResourceType       = typeof(Finance),
                    AllowTransmutation = false,
                    Required           = total,
                    ResourceTypeName   = this.AccountName,
                    ActivityModel      = this,
                    Category           = TransactionCategory
                });
            }
        }
コード例 #2
0
        ///<inheritdoc/>
        public bool DoTransmute(ResourceRequest request, double shortfallPacketsNeeded, double requiredByActivities, ResourcesHolder holder, bool queryOnly)
        {
            switch (TransmuteStyle)
            {
            case TransmuteStyle.Direct:
                request.Required = shortfallPacketsNeeded * AmountPerPacket;
                break;

            case TransmuteStyle.UsePricing:
                request.Required = (shortfallPacketsNeeded * shortfallPricing.CurrentPrice) / transmutePricing.CurrentPrice;
                // check that sell whole packets are honoured
                if (transmutePricing.UseWholePackets)
                {
                    double pricingWholePacketAdjusted = Math.Ceiling(request.Required / transmutePricing.PacketSize) * transmutePricing.PacketSize;
                    request.Required = pricingWholePacketAdjusted;
                }
                break;

            default:
                break;
            }

            if (queryOnly)
            {
                return(request.Required + requiredByActivities <= TransmuteResourceType.Amount);
            }
            else
            {
                TransmuteResourceType.Remove(request);
                if (TransmuteStyle == TransmuteStyle.UsePricing && financeType != null)
                {
                    // add finance transaction to sell transmute
                    financeType.Add(request.Required * transmutePricing.CurrentPrice, request.ActivityModel, TransmuteResourceTypeName, request.Category);

                    // add finance transaction to buy shortfall
                    ResourceRequest financeRequest = new ResourceRequest()
                    {
                        Resource          = financeType,
                        Required          = shortfallPacketsNeeded * shortfallPacketSize * shortfallPricing.CurrentPrice,
                        RelatesToResource = request.ResourceTypeName,
                        ResourceType      = typeof(Finance),
                        ActivityModel     = request.ActivityModel,
                        Category          = request.Category,
                    };
                    financeType.Remove(financeRequest);
                }
            }
            return(true);
        }
コード例 #3
0
        private void OnEndOfMonth(object sender, EventArgs e)
        {
            FinanceType bankAccount = Resources.FinanceResource().GetFirst() as FinanceType;

            // make interest payments on bank accounts
            foreach (FinanceType accnt in Resources.FinanceResource().Children.Where(a => a.GetType() == typeof(FinanceType)))
            {
                if (accnt.Balance > 0)
                {
                    bankAccount.Add(accnt.Balance * accnt.InterestRatePaid / 1200, this.Name, "InterestPaid");
                }
                else
                {
                    bankAccount.Remove(Math.Abs(accnt.Balance) * accnt.InterestRateCharged / 1200, this.Name, "InterestCharged");
                }
            }
        }
コード例 #4
0
        private void OnWFAnimalBuy(object sender, EventArgs e)
        {
            RuminantHerd ruminantHerd = Resources.RuminantHerd();

            Finance     Accounts    = Resources.FinanceResource() as Finance;
            FinanceType bankAccount = Accounts.GetFirst() as FinanceType;

            var newRequests = ruminantHerd.PurchaseIndividuals.Where(a => a.BreedParams.Breed == BreedName).ToList();

            foreach (var newgroup in newRequests.GroupBy(a => a.SaleFlag))
            {
                double fundsAvailable = 100000000;
                if (bankAccount != null)
                {
                    fundsAvailable = bankAccount.FundsAvailable;
                }
                double cost = 0;
                foreach (var newind in newgroup)
                {
                    double value = 0;
                    if (newgroup.Key == Common.HerdChangeReason.SirePurchase)
                    {
                        value = BreedingSirePrice;
                    }
                    else
                    {
                        RuminantValue getvalue = PriceList.Where(a => a.Age < newind.Age).OrderBy(a => a.Age).LastOrDefault();
                        value = getvalue.PurchaseValue * ((getvalue.Style == Common.PricingStyleType.perKg) ? newind.Weight : 1.0);
                    }
                    if (cost + value <= fundsAvailable)
                    {
                        ruminantHerd.AddRuminant(newind);
                        cost += value;
                    }
                    else
                    {
                        break;
                    }
                }
                if (bankAccount != null)
                {
                    bankAccount.Remove(cost, this.Name, newgroup.Key.ToString());
                }
            }
        }
コード例 #5
0
        /// <summary>
        /// Method used to perform activity if it can occur as soon as resources are available.
        /// </summary>
        public override void DoActivity()
        {
            Status = ActivityStatus.NotNeeded;
            // take local equivalent of market from resource

            double provided = 0;

            if ((resourceToBuy as CLEMResourceTypeBase).MarketStoreExists)
            {
                // find resource entry in market if present and reduce
                ResourceRequest rr = ResourceRequestList.Where(a => a.Resource == (resourceToBuy as CLEMResourceTypeBase).EquivalentMarketStore).FirstOrDefault();
                provided = rr.Provided / this.FarmMultiplier;
            }
            else
            {
                provided = unitsCanAfford * price.PacketSize;
            }

            if (provided > 0)
            {
                resourceToBuy.Add(provided, this, "", "Purchase");
                Status = ActivityStatus.Success;
            }

            // make financial transactions
            if (bankAccount != null)
            {
                ResourceRequest payment = new ResourceRequest()
                {
                    AllowTransmutation          = false,
                    MarketTransactionMultiplier = this.FarmMultiplier,
                    Required          = provided / price.PacketSize * price.PricePerPacket,
                    ResourceType      = typeof(Finance),
                    ResourceTypeName  = bankAccount.Name,
                    Category          = "Purchase",
                    RelatesToResource = (resourceToBuy as CLEMModel).NameWithParent,
                    ActivityModel     = this
                };
                bankAccount.Remove(payment);
            }
        }
コード例 #6
0
        /// <summary>
        /// Method to determine resources required for this activity in the current month
        /// </summary>
        /// <returns>List of required resource requests</returns>
        public override List <ResourceRequest> GetResourcesNeededForActivity()
        {
            if (people is null | food is null)
            {
                return(null);
            }

            List <LabourType> peopleList = people.Items.Where(a => IncludeHiredLabour || a.Hired == false).ToList();

            peopleList.Select(a => a.FeedToTargetIntake == 0);

            // determine AEs to be fed
            double aE = peopleList.Sum(a => a.AdultEquivalent);

            if (aE <= 0)
            {
                return(null);
            }

            int daysInMonth = DateTime.DaysInMonth(Clock.Today.Year, Clock.Today.Month);

            // determine feed limits (max kg per AE per day * AEs * days)
            double intakeLimit = DailyIntakeLimit * aE * daysInMonth;

            // remove previous consumption
            double otherIntake = this.DailyIntakeOtherSources * aE * daysInMonth;

            otherIntake += peopleList.Sum(a => a.GetAmountConsumed());

            List <LabourActivityFeedTarget> labourActivityFeedTargets = this.FindAllChildren <LabourActivityFeedTarget>().Cast <LabourActivityFeedTarget>().ToList();

            // determine targets
            foreach (LabourActivityFeedTarget target in labourActivityFeedTargets)
            {
                // calculate target
                target.Target = target.TargetValue * aE * daysInMonth;

                // set initial level based on off store inputs
                target.CurrentAchieved = target.OtherSourcesValue * aE * daysInMonth;

                // calculate current level from previous intake this month (LabourActivityFeed)
                target.CurrentAchieved += people.GetDietaryValue(target.Metric, IncludeHiredLabour, true) * aE * daysInMonth;

                // add sources outside of this activity to peoples' diets
                if (target.OtherSourcesValue > 0)
                {
                    foreach (var person in peopleList)
                    {
                        LabourDietComponent outsideEat = new LabourDietComponent();
                        outsideEat.AddOtherSource(target.Metric, target.OtherSourcesValue * person.AdultEquivalent * daysInMonth);
                        person.AddIntake(outsideEat);
                    }
                }
            }

            // get max months before spoiling of all food stored (will be zero for non perishable food)
            int maxFoodAge = food.FindAllChildren <HumanFoodStoreType>().Cast <HumanFoodStoreType>().Max(a => a.Pools.Select(b => a.UseByAge - b.Age).DefaultIfEmpty(0).Max());

            // create list of all food parcels
            List <HumanFoodParcel> foodParcels = new List <HumanFoodParcel>();

            foreach (HumanFoodStoreType foodStore in food.FindAllChildren <HumanFoodStoreType>().Cast <HumanFoodStoreType>().ToList())
            {
                foreach (HumanFoodStorePool pool in foodStore.Pools)
                {
                    foodParcels.Add(new HumanFoodParcel()
                    {
                        FoodStore = foodStore,
                        Pool      = pool,
                        Expires   = ((foodStore.UseByAge == 0) ? maxFoodAge + 1: foodStore.UseByAge - pool.Age)
                    });
                }
            }

            foodParcels = foodParcels.OrderBy(a => a.Expires).ToList();

            // if a market exists add the available market produce to the list below that ordered above.
            // order market food by price ascending
            // this will include market available food in the decisions.
            // will need to purchase this food before taking it if cost associated.
            // We can check if the parent of the human food store used is a market and charge accordingly.

            // for each market
            List <HumanFoodParcel> marketFoodParcels = new List <HumanFoodParcel>();
            ResourcesHolder        resources         = Resources.FoundMarket.Resources;

            if (resources != null)
            {
                HumanFoodStore food = resources.HumanFoodStore();
                if (food != null)
                {
                    foreach (HumanFoodStoreType foodStore in food.FindAllChildren <HumanFoodStoreType>())
                    {
                        foreach (HumanFoodStorePool pool in foodStore.Pools)
                        {
                            marketFoodParcels.Add(new HumanFoodParcel()
                            {
                                FoodStore = foodStore,
                                Pool      = pool,
                                Expires   = ((foodStore.UseByAge == 0) ? maxFoodAge + 1 : foodStore.UseByAge - pool.Age)
                            });
                        }
                    }
                }
            }
            foodParcels.AddRange(marketFoodParcels.OrderBy(a => a.FoodStore.Price(PurchaseOrSalePricingStyleType.Purchase).PricePerPacket));

            double fundsAvailable = double.PositiveInfinity;

            if (bankAccount != null)
            {
                fundsAvailable = bankAccount.FundsAvailable;
            }

            int    parcelIndex = 0;
            double intake      = otherIntake;

            // start eating food from list from that about to expire first
            while (parcelIndex < foodParcels.Count)
            {
                foodParcels[parcelIndex].Proportion = 0;
                if (intake < intakeLimit & (labourActivityFeedTargets.Where(a => !a.TargetMet).Count() > 0 | foodParcels[parcelIndex].Expires == 0))
                {
                    // still able to eat and target not met or food about to expire this timestep
                    // reduce by amout that can be eaten
                    double propCanBeEaten = Math.Min(1, (intakeLimit - intake) / (foodParcels[parcelIndex].FoodStore.EdibleProportion * foodParcels[parcelIndex].Pool.Amount));
                    // reduce to target limits
                    double propToTarget = 1;
                    if (foodParcels[parcelIndex].Expires != 0)
                    {
                        // if the food is not going to spoil
                        // then adjust what can be eaten up to target otherwise allow over target consumption to avoid waste

                        LabourActivityFeedTarget targetUnfilled = labourActivityFeedTargets.Where(a => !a.TargetMet).FirstOrDefault();
                        if (targetUnfilled != null)
                        {
                            // calculate reduction to metric target
                            double metricneeded = Math.Max(0, targetUnfilled.Target - targetUnfilled.CurrentAchieved);
                            double amountneeded = metricneeded / foodParcels[parcelIndex].FoodStore.ConversionFactor(targetUnfilled.Metric);

                            propToTarget = Math.Min(1, amountneeded / (foodParcels[parcelIndex].FoodStore.EdibleProportion * foodParcels[parcelIndex].Pool.Amount));
                        }
                    }

                    foodParcels[parcelIndex].Proportion = Math.Min(propCanBeEaten, propToTarget);

                    // work out if there will be a cost limitation, only if a price structure exists for the resource
                    double propToPrice = 1;
                    if (foodParcels[parcelIndex].FoodStore.PricingExists(PurchaseOrSalePricingStyleType.Purchase))
                    {
                        ResourcePricing price = foodParcels[parcelIndex].FoodStore.Price(PurchaseOrSalePricingStyleType.Purchase);
                        double          cost  = (foodParcels[parcelIndex].Pool.Amount * foodParcels[parcelIndex].Proportion) / price.PacketSize * price.PricePerPacket;
                        if (cost > 0)
                        {
                            propToPrice = Math.Min(1, fundsAvailable / cost);
                            // remove cost from running check tally
                            fundsAvailable = Math.Max(0, fundsAvailable - (cost * propToPrice));

                            // real finance transactions will happen in the do activity as stuff is allocated
                            // there should not be shortfall as all the checks and reductions have happened here
                        }
                    }
                    foodParcels[parcelIndex].Proportion *= propToPrice;

                    // update intake
                    double newIntake = (foodParcels[parcelIndex].FoodStore.EdibleProportion * foodParcels[parcelIndex].Pool.Amount * foodParcels[parcelIndex].Proportion);
                    intake += newIntake;
                    // update metrics
                    foreach (LabourActivityFeedTarget target in labourActivityFeedTargets)
                    {
                        target.CurrentAchieved += newIntake * foodParcels[parcelIndex].FoodStore.ConversionFactor(target.Metric);
                    }
                }
                else if (intake >= intakeLimit && labourActivityFeedTargets.Where(a => !a.TargetMet).Count() > 1)
                {
                    // full but could still reach target with some substitution
                    // but can substitute to remove a previous target

                    // does the current parcel have better target values than any previous non age 0 pool of a different food type
                }
                else
                {
                    break;
                }
                parcelIndex++;
            }

            // fill resource requests
            List <ResourceRequest> requests = new List <ResourceRequest>();

            foreach (var item in foodParcels.GroupBy(a => a.FoodStore))
            {
                double amount = item.Sum(a => a.Pool.Amount * a.Proportion);
                if (amount > 0)
                {
                    double financeLimit = 1;
                    // if obtained from the market make financial transaction before taking
                    ResourcePricing price = item.Key.Price(PurchaseOrSalePricingStyleType.Sale);
                    if (bankAccount != null && item.Key.Parent.Parent.Parent == Market && price.PricePerPacket > 0)
                    {
                        // if shortfall reduce purchase
                        ResourceRequest marketRequest = new ResourceRequest
                        {
                            ActivityModel               = this,
                            Required                    = amount / price.PacketSize * price.PricePerPacket,
                            AllowTransmutation          = false,
                            Category                    = "Food purchase",
                            MarketTransactionMultiplier = 1
                        };
                        bankAccount.Remove(marketRequest);
                    }

                    requests.Add(new ResourceRequest()
                    {
                        Resource           = item.Key,
                        ResourceType       = typeof(HumanFoodStore),
                        AllowTransmutation = false,
                        Required           = amount * financeLimit,
                        ResourceTypeName   = item.Key.Name,
                        ActivityModel      = this,
                        Category           = "Consumption"
                    });
                }
            }

            // if still hungry and funds available, try buy food in excess of what stores (private or market) offered using transmutation if present.
            // This will force the market or private sources to purchase more food to meet demand if transmutation available.
            // if no market is present it will look to transmutating from its own stores if possible.
            // this means that other than a purchase from market (above) this activity doesn't need to worry about financial tranactions.
            if (intake < intakeLimit && (labourActivityFeedTargets.Where(a => !a.TargetMet).Count() > 0) && fundsAvailable > 0)
            {
                ResourcesHolder resourcesHolder = Resources;
                // if market is present point to market to find the resource
                if (Market != null)
                {
                    resourcesHolder = Market.FindChild <ResourcesHolder>();
                }

                // don't worry about money anymore. The over request will be handled by the transmutation.
                // move through specified purchase list
                foreach (LabourActivityFeedTargetPurchase purchase in this.FindAllChildren <LabourActivityFeedTargetPurchase>().Cast <LabourActivityFeedTargetPurchase>().ToList())
                {
                    HumanFoodStoreType foodtype = resourcesHolder.GetResourceItem(this, purchase.FoodStoreName, OnMissingResourceActionTypes.Ignore, OnMissingResourceActionTypes.Ignore) as HumanFoodStoreType;
                    if (foodtype != null && (foodtype.TransmutationDefined & intake < intakeLimit))
                    {
                        LabourActivityFeedTarget targetUnfilled = labourActivityFeedTargets.Where(a => !a.TargetMet).FirstOrDefault();
                        if (targetUnfilled != null)
                        {
                            // calculate reduction to metric target
                            double metricneeded = Math.Max(0, (targetUnfilled.Target - targetUnfilled.CurrentAchieved));
                            double amountneeded = metricneeded / foodtype.ConversionFactor(targetUnfilled.Metric);

                            if (intake + amountneeded > intakeLimit)
                            {
                                amountneeded = intakeLimit - intake;
                            }
                            double amountfood = amountneeded / foodtype.EdibleProportion;

                            // update intake
                            intake += amountfood;

                            // find in requests or create a new one
                            ResourceRequest foodRequestFound = requests.Find(a => a.Resource == foodtype) as ResourceRequest;
                            if (foodRequestFound is null)
                            {
                                requests.Add(new ResourceRequest()
                                {
                                    Resource           = foodtype,
                                    ResourceType       = typeof(HumanFoodStore),
                                    AllowTransmutation = true,
                                    Required           = amountfood,
                                    ResourceTypeName   = purchase.FoodStoreName.Split('.')[1],
                                    ActivityModel      = this,
                                    Category           = "Consumption"
                                });
                            }
                            else
                            {
                                foodRequestFound.Required          += amountneeded;
                                foodRequestFound.AllowTransmutation = true;
                            }
                        }
                    }
                }
                // NOTE: proportions of purchased food are not modified if the sum does not add up to 1 or some of the food types are not available.
            }

            return(requests);
        }
コード例 #7
0
        /// <inheritdoc/>
        public override List <ResourceRequest> GetResourcesNeededForActivity()
        {
            if (people is null | food is null)
            {
                return(null);
            }

            List <LabourType> peopleList = people.Items.Where(a => IncludeHiredLabour || a.Hired == false).ToList();

            peopleList.Select(a => { a.FeedToTargetIntake = 0; return(a); }).ToList();

            // determine AEs to be fed
            double aE = peopleList.Sum(a => a.TotalAdultEquivalents);

            if (aE <= 0)
            {
                return(null);
            }

            int daysInMonth = DateTime.DaysInMonth(clock.Today.Year, clock.Today.Month);

            // determine feed limits (max kg per AE per day * AEs * days)
            double intakeLimit = DailyIntakeLimit * aE * daysInMonth;

            // remove previous consumption
            double otherIntake = this.DailyIntakeOtherSources * aE * daysInMonth;

            otherIntake += peopleList.Sum(a => a.GetAmountConsumed());

            List <LabourActivityFeedTarget> labourActivityFeedTargets = this.FindAllChildren <LabourActivityFeedTarget>().ToList();

            // determine targets
            foreach (LabourActivityFeedTarget target in labourActivityFeedTargets)
            {
                // calculate target
                target.Target = target.TargetValue * aE * daysInMonth;

                // calculate target maximum
                target.TargetMaximum = target.TargetMaximumValue * aE * daysInMonth;

                // set initial level based on off store inputs
                target.CurrentAchieved = target.OtherSourcesValue * aE * daysInMonth;

                // calculate current level from previous intake this month (LabourActivityFeed)
                target.CurrentAchieved += people.GetDietaryValue(target.Metric, IncludeHiredLabour, false); // * aE; // * daysInMonth;

                // add sources outside of this activity to peoples' diets
                if (target.OtherSourcesValue > 0)
                {
                    foreach (var person in peopleList)
                    {
                        LabourDietComponent outsideEat = new LabourDietComponent();
                        // TODO: might need to add consumed here
                        outsideEat.AmountConsumed = this.DailyIntakeOtherSources * person.TotalAdultEquivalents * daysInMonth;
                        outsideEat.AddOtherSource(target.Metric, target.OtherSourcesValue * person.TotalAdultEquivalents * daysInMonth);
                        // track this consumption by people here.
                        person.AddIntake(outsideEat);
                        person.FeedToTargetIntake += outsideEat.AmountConsumed;
                    }
                }
            }

            // get max months before spoiling of all food stored (will be zero for non perishable food)
            int maxFoodAge = food.FindAllChildren <HumanFoodStoreType>().Max(a => a.Pools.Select(b => a.UseByAge - b.Age).DefaultIfEmpty(0).Max());

            // create list of all food parcels
            List <HumanFoodParcel> foodParcels = new List <HumanFoodParcel>();

            foreach (HumanFoodStoreType foodStore in food.FindAllChildren <HumanFoodStoreType>().ToList())
            {
                foreach (HumanFoodStorePool pool in foodStore.Pools.Where(a => a.Amount > 0))
                {
                    foodParcels.Add(new HumanFoodParcel()
                    {
                        FoodStore = foodStore,
                        Pool      = pool,
                        Expires   = ((foodStore.UseByAge == 0) ? maxFoodAge + 1: foodStore.UseByAge - pool.Age)
                    });
                }
            }

            foodParcels = foodParcels.OrderBy(a => a.Expires).ToList();

            // if a market exists add the available market produce to the list below that ordered above.
            // order market food by price ascending
            // this will include market available food in the decisions.
            // will need to purchase this food before taking it if cost associated.
            // We can check if the parent of the human food store used is a market and charge accordingly.

            // for each market
            List <HumanFoodParcel> marketFoodParcels = new List <HumanFoodParcel>();
            ResourcesHolder        resources         = Market?.Resources;

            if (resources != null)
            {
                HumanFoodStore food = resources.FindResourceGroup <HumanFoodStore>();
                if (food != null)
                {
                    foreach (HumanFoodStoreType foodStore in food.FindAllChildren <HumanFoodStoreType>())
                    {
                        foreach (HumanFoodStorePool pool in foodStore.Pools.Where(a => a.Amount > 0))
                        {
                            marketFoodParcels.Add(new HumanFoodParcel()
                            {
                                FoodStore = foodStore,
                                Pool      = pool,
                                Expires   = ((foodStore.UseByAge == 0) ? maxFoodAge + 1 : foodStore.UseByAge - pool.Age)
                            });
                        }
                    }
                }
            }
            foodParcels.AddRange(marketFoodParcels.OrderBy(a => a.FoodStore.Price(PurchaseOrSalePricingStyleType.Purchase).PricePerPacket));

            double fundsAvailable = double.PositiveInfinity;

            if (bankAccount != null)
            {
                fundsAvailable = bankAccount.FundsAvailable;
            }

            int    parcelIndex  = 0;
            double metricneeded = 0;
            double intake       = otherIntake;

            // start eating food from list from that about to expire first

            // food from household can be eaten up to target maximum
            // food from market can only be eaten up to target

            while (parcelIndex < foodParcels.Count)
            {
                foodParcels[parcelIndex].Proportion = 0;
                var isHousehold = foodParcels[parcelIndex].FoodStore.CLEMParentName == this.CLEMParentName;
                if (intake < intakeLimit & (labourActivityFeedTargets.Where(a => ((isHousehold)? !a.TargetMaximumAchieved: !a.TargetAchieved)).Count() > 0 | foodParcels[parcelIndex].Expires == 0))
                {
                    // still able to eat and target not met or food about to expire this timestep
                    // reduce by amout that can be eaten
                    double propCanBeEaten = Math.Min(1, (intakeLimit - intake) / (foodParcels[parcelIndex].FoodStore.EdibleProportion * foodParcels[parcelIndex].Pool.Amount));
                    // reduce to target limits
                    double propToTarget = 1;
                    if (foodParcels[parcelIndex].Expires != 0)
                    {
                        // if the food is not going to spoil
                        // then adjust what can be eaten up to target otherwise allow over target consumption to avoid waste

                        LabourActivityFeedTarget targetUnfilled = labourActivityFeedTargets.Where(a => ((isHousehold) ? !a.TargetMaximumAchieved : !a.TargetAchieved)).FirstOrDefault();
                        if (targetUnfilled != null)
                        {
                            // calculate reduction to metric target
                            metricneeded = Math.Max(0, (isHousehold ? targetUnfilled.TargetMaximum : targetUnfilled.Target) - targetUnfilled.CurrentAchieved);
                            double amountneeded = metricneeded / foodParcels[parcelIndex].FoodStore.ConversionFactor(targetUnfilled.Metric);

                            propToTarget = Math.Min(1, amountneeded / (foodParcels[parcelIndex].FoodStore.EdibleProportion * foodParcels[parcelIndex].Pool.Amount));
                        }
                    }

                    foodParcels[parcelIndex].Proportion = Math.Min(propCanBeEaten, propToTarget);

                    // work out if there will be a cost limitation, only if a price structure exists for the resource
                    // no charge for household consumption
                    double propToPrice = 1;
                    if (!isHousehold && foodParcels[parcelIndex].FoodStore.PricingExists(PurchaseOrSalePricingStyleType.Purchase))
                    {
                        ResourcePricing price = foodParcels[parcelIndex].FoodStore.Price(PurchaseOrSalePricingStyleType.Purchase);
                        double          cost  = (foodParcels[parcelIndex].Pool.Amount * foodParcels[parcelIndex].Proportion) / price.PacketSize * price.PricePerPacket;

                        // TODO: sell cattle based on selling groups till run out of cattle or meet shortfall
                        // adjust fundsAvailable with new money
                        // if cost > 0 and cost > funds available

                        if (cost > 0)
                        {
                            propToPrice = Math.Min(1, fundsAvailable / cost);
                            // remove cost from running check tally
                            fundsAvailable = Math.Max(0, fundsAvailable - (cost * propToPrice));

                            // real finance transactions will happen in the do activity as stuff is allocated
                            // there should not be shortfall as all the checks and reductions have happened here
                        }
                    }
                    foodParcels[parcelIndex].Proportion *= propToPrice;

                    // update intake
                    double newIntake = (foodParcels[parcelIndex].FoodStore.EdibleProportion * foodParcels[parcelIndex].Pool.Amount * foodParcels[parcelIndex].Proportion);
                    intake += newIntake;
                    // update metrics
                    foreach (LabourActivityFeedTarget target in labourActivityFeedTargets)
                    {
                        target.CurrentAchieved += newIntake * foodParcels[parcelIndex].FoodStore.ConversionFactor(target.Metric);
                    }
                }
                else if (intake >= intakeLimit && labourActivityFeedTargets.Where(a => ((isHousehold) ? !a.TargetMaximumAchieved : !a.TargetAchieved)).Count() > 1)
                {
                    // full but could still reach target with some substitution
                    // but can substitute to remove a previous target

                    // does the current parcel have better target values than any previous non age 0 pool of a different food type
                }
                else
                {
                    break;
                }
                parcelIndex++;
            }

            // fill resource requests
            List <ResourceRequest> requests = new List <ResourceRequest>();

            foreach (var item in foodParcels.GroupBy(a => a.FoodStore))
            {
                double amount = item.Sum(a => a.Pool.Amount * a.Proportion);
                if (amount > 0)
                {
                    double financeLimit = 1;
                    // if obtained from the market make financial transaction before taking
                    ResourcePricing price          = item.Key.Price(PurchaseOrSalePricingStyleType.Sale);
                    bool            marketIsSource = item.Key.Parent.Parent.Parent == Market;
                    if (bankAccount != null && marketIsSource && price.PricePerPacket > 0)
                    {
                        // finance transaction to buy food from market
                        ResourceRequest marketRequest = new ResourceRequest
                        {
                            ActivityModel               = this,
                            Required                    = amount / price.PacketSize * price.PricePerPacket,
                            AllowTransmutation          = false,
                            Category                    = $"{TransactionCategory}.PurchaseFood",
                            MarketTransactionMultiplier = 1,
                            RelatesToResource           = item.Key.NameWithParent
                        };
                        bankAccount.Remove(marketRequest);
                    }

                    // is this a market

                    requests.Add(new ResourceRequest()
                    {
                        Resource           = item.Key,
                        ResourceType       = typeof(HumanFoodStore),
                        AllowTransmutation = false,
                        Required           = amount * financeLimit,
                        ResourceTypeName   = item.Key.NameWithParent,
                        ActivityModel      = this,
                        Category           = $"{TransactionCategory}{(marketIsSource?".FromMarket":".FromHousehold")}"
                    });
                }
            }

            // if still hungry and funds available, try buy food in excess of what stores (private or market) offered using transmutation if present.
            // This will force the market or private sources to purchase more food to meet demand if transmutation available.
            // if no market is present it will look to transmutating from its own stores if possible.
            // this means that other than a purchase from market (above) this activity doesn't need to worry about financial tranactions.
            int testType = 0;

            // test is limited to 1 for now so only to metric target NOT intake limit as we use maximum and target values now
            while (testType < 1 && intake < intakeLimit && (labourActivityFeedTargets.Where(a => !a.TargetAchieved).Any()) && fundsAvailable > 0)
            {
                // don't worry about money anymore. The over request will be handled by the transmutation.
                // move through specified purchase list
                // 1. to assign based on energy
                // 2. if still need food assign based on intake still needed

                metricneeded = 0;
                LabourActivityFeedTarget targetUnfilled = labourActivityFeedTargets.Where(a => !a.TargetAchieved).FirstOrDefault();
                if (targetUnfilled != null)
                {
                    metricneeded = Math.Max(0, (targetUnfilled.Target - targetUnfilled.CurrentAchieved));
                    double amountToFull = intakeLimit - intake;

                    foreach (LabourActivityFeedTargetPurchase purchase in this.FindAllChildren <LabourActivityFeedTargetPurchase>())
                    {
                        HumanFoodStoreType foodtype = purchase.FoodStore;
                        if (purchase.ProportionToPurchase > 0 && foodtype != null && (foodtype.TransmutationDefined & intake < intakeLimit))
                        {
                            double amountEaten = 0;
                            if (testType == 0)
                            {
                                // metric target based on purchase proportion
                                amountEaten = metricneeded / foodtype.ConversionFactor(targetUnfilled.Metric) * purchase.ProportionToPurchase;
                            }
                            else
                            {
                                // amount to satisfy limited by proportion of purchases
                                amountEaten = amountToFull * purchase.ProportionToPurchase;
                            }

                            if (intake + amountEaten > intakeLimit)
                            {
                                amountEaten = intakeLimit - intake;
                            }

                            if (amountEaten > 0)
                            {
                                targetUnfilled.CurrentAchieved += amountEaten * foodtype.ConversionFactor(targetUnfilled.Metric);
                                double amountPurchased = amountEaten / foodtype.EdibleProportion;

                                // update intake.. needed is the amount edible, not the amount purchased.
                                intake += amountEaten;

                                // add financial transactions to purchase from market
                                // if obtained from the market make financial transaction before taking
                                ResourcePricing price = foodtype.Price(PurchaseOrSalePricingStyleType.Sale);
                                if (bankAccount != null)
                                {
                                    if (price.PricePerPacket > 0)
                                    {
                                        ResourceRequest marketRequest = new ResourceRequest
                                        {
                                            ActivityModel               = this,
                                            Required                    = amountPurchased / price.PacketSize * price.PricePerPacket,
                                            AllowTransmutation          = false,
                                            Category                    = "Import",
                                            MarketTransactionMultiplier = 1,
                                            RelatesToResource           = foodtype.NameWithParent
                                        };
                                        bankAccount.Remove(marketRequest);
                                    }
                                    else
                                    {
                                        string warn = $"No price set [{price.PricePerPacket}] for [r={foodtype.Name}] at time of transaction for [a={this.Name}]{Environment.NewLine}No financial transactions will occur.{Environment.NewLine}Ensure price is set or resource pricing file contains entries before this transaction or start of simulation.";
                                        Warnings.CheckAndWrite(warn, Summary, this, MessageType.Warning);
                                    }
                                }

                                // find in requests or create a new one
                                ResourceRequest foodRequestFound = requests.Find(a => a.Resource == foodtype);
                                if (foodRequestFound is null)
                                {
                                    requests.Add(new ResourceRequest()
                                    {
                                        Resource           = foodtype,
                                        ResourceType       = typeof(HumanFoodStore),
                                        AllowTransmutation = true,
                                        Required           = amountPurchased,
                                        ResourceTypeName   = purchase.FoodStoreName,
                                        ActivityModel      = this,
                                        Category           = $"{TransactionCategory}.FromImports"
                                    });
                                }
                                else
                                {
                                    foodRequestFound.Required          += amountPurchased;
                                    foodRequestFound.AllowTransmutation = true;
                                }
                            }
                        }
                    }
                    testType++;
                }
            }
            return(requests);
        }
コード例 #8
0
        /// <summary>
        /// Method used to perform activity if it can occur as soon as resources are available.
        /// </summary>
        public override void DoActivity()
        {
            this.Status = ActivityStatus.NotNeeded;

            // get labour shortfall
            double labourLimit = this.LabourLimitProportion;
            // get finance purchase shortfall
            double financeLimit = (spent - earned > 0) ? Math.Min(bankAccount.Amount, spent - earned) / (spent - earned) : 1;

            if (resourceList.Count() == 0)
            {
                if (currentEntries.Count > 0)
                {
                    this.Status = ActivityStatus.Warning;
                }
                return;
            }
            else
            {
                if (financeLimit < 1)
                {
                    ResourceRequest purchaseRequest = new ResourceRequest
                    {
                        ActivityModel      = this,
                        Required           = spent - earned,
                        Available          = bankAccount.Amount,
                        Provided           = bankAccount.Amount,
                        AllowTransmutation = false,
                        ResourceType       = typeof(Finance),
                        ResourceTypeName   = AccountName,
                        Category           = "External purchases"
                    };
                    ResourceRequestEventArgs rre = new ResourceRequestEventArgs()
                    {
                        Request = purchaseRequest
                    };
                    OnShortfallOccurred(rre);
                }

                if (financeLimit < 1 || labourLimit < 1)
                {
                    switch (OnPartialResourcesAvailableAction)
                    {
                    case OnPartialResourcesAvailableActionTypes.ReportErrorAndStop:
                        Summary.WriteWarning(this, $"Ensure resources are available or change OnPartialResourcesAvailableAction setting for activity [a={this.NameWithParent}]");
                        Status = ActivityStatus.Critical;
                        throw new ApsimXException(this, $"Insufficient resources [r={AccountName}] for activity [a={this.NameWithParent}]");

                    case OnPartialResourcesAvailableActionTypes.SkipActivity:
                        this.Status = ActivityStatus.Ignored;
                        return;

                    default:
                        break;
                    }
                    this.Status = ActivityStatus.Partial;
                }
                else
                {
                    this.Status = ActivityStatus.Success;
                }

                // loop through all resources to exchange and make transactions
                for (int i = 0; i < currentEntries.Count; i++)
                {
                    if (resourceList[i] is null)
                    {
                        this.Status = ActivityStatus.Warning;
                    }
                    else
                    {
                        // matching resource was found
                        double amount = Convert.ToDouble(currentEntries[i][fileResource.AmountColumnName], CultureInfo.InvariantCulture);
                        bool   isSale = (amount < 0);
                        amount = Math.Abs(amount);
                        ResourcePricing price = null;
                        if (bankAccount != null && !(resourceList[i] is FinanceType))
                        {
                            price = resourceList[i].Price((amount > 0 ? PurchaseOrSalePricingStyleType.Purchase : PurchaseOrSalePricingStyleType.Sale));
                        }
                        // transactions
                        if (isSale)
                        {
                            // sell, so limit to labour and amount available
                            amount = Math.Min(amount * labourLimit, resourceList[i].Amount);
                            if (amount > 0)
                            {
                                if (price != null)
                                {
                                    double packets = amount / price.PacketSize;
                                    if (price.UseWholePackets)
                                    {
                                        packets = Math.Truncate(packets);
                                        amount  = packets * price.PacketSize;
                                    }
                                    bankAccount.Add(packets * price.PricePerPacket, this, (resourceList[i] as CLEMModel).NameWithParent, "External output");
                                }
                                ResourceRequest sellRequest = new ResourceRequest
                                {
                                    ActivityModel      = this,
                                    Required           = amount,
                                    AllowTransmutation = false,
                                    Category           = "External output",
                                    RelatesToResource  = (resourceList[i] as CLEMModel).NameWithParent
                                };
                                resourceList[i].Remove(sellRequest);
                            }
                        }
                        else
                        {
                            // limit to labour and financial constraints as this is a purchase
                            amount *= Math.Min(labourLimit, financeLimit);
                            if (amount > 0)
                            {
                                if (price != null)
                                {
                                    // need to limit amount by financial constraints
                                    double packets = amount / price.PacketSize;
                                    if (price.UseWholePackets)
                                    {
                                        packets = Math.Truncate(packets);
                                    }
                                    amount = packets * price.PacketSize;
                                    ResourceRequest sellRequestDollars = new ResourceRequest
                                    {
                                        ActivityModel      = this,
                                        Required           = packets * price.PacketSize,
                                        AllowTransmutation = false,
                                        Category           = "External input",
                                        RelatesToResource  = (resourceList[i] as CLEMModel).NameWithParent
                                    };
                                    bankAccount.Remove(sellRequestDollars);
                                }
                                resourceList[i].Add(amount, this, (resourceList[i] as CLEMModel).NameWithParent, "External input");
                            }
                        }
                    }
                }
            }
        }
コード例 #9
0
        private void OnCLEMAnimalSell(object sender, EventArgs e)
        {
            RuminantHerd ruminantHerd = Resources.RuminantHerd();

            int    trucks     = 0;
            double saleValue  = 0;
            double saleWeight = 0;
            int    head       = 0;
            double aESum      = 0;

            // get current untrucked list of animals flagged for sale
            List <Ruminant> herd = this.CurrentHerd(false).Where(a => a.SaleFlag != HerdChangeReason.None).OrderByDescending(a => a.Weight).ToList();

            if (trucking == null)
            {
                // no trucking just sell
                head = herd.Count();
                if (herd.Count() > 0)
                {
                    SetStatusSuccess();
                }
                foreach (var ind in herd)
                {
                    aESum      += ind.AdultEquivalent;
                    saleValue  += ind.BreedParams.ValueofIndividual(ind, PurchaseOrSalePricingStyleType.Sale);
                    saleWeight += ind.Weight;
                    ruminantHerd.RemoveRuminant(ind, this);
                }
            }
            else
            {
                // if sale herd > min loads before allowing sale
                if (herd.Select(a => a.Weight / 450.0).Sum() / trucking.Number450kgPerTruck >= trucking.MinimumTrucksBeforeSelling)
                {
                    // while truck to fill
                    while (herd.Select(a => a.Weight / 450.0).Sum() / trucking.Number450kgPerTruck > trucking.MinimumLoadBeforeSelling)
                    {
                        bool nonloaded = true;
                        trucks++;
                        double load450kgs = 0;
                        // while truck below carrying capacity load individuals
                        foreach (var ind in herd)
                        {
                            if (load450kgs + (ind.Weight / 450.0) <= trucking.Number450kgPerTruck)
                            {
                                nonloaded = false;
                                head++;
                                aESum      += ind.AdultEquivalent;
                                load450kgs += ind.Weight / 450.0;
                                saleValue  += ind.BreedParams.ValueofIndividual(ind, PurchaseOrSalePricingStyleType.Sale);
                                saleWeight += ind.Weight;
                                ruminantHerd.RemoveRuminant(ind, this);

                                //TODO: work out what to do with suckling calves still with mothers if mother sold.
                            }
                        }
                        if (nonloaded)
                        {
                            Summary.WriteWarning(this, String.Format("There was a problem loading the sale truck as sale individuals did not meet the loading criteria for breed [r={0}]", this.PredictedHerdBreed));
                            break;
                        }
                        herd = this.CurrentHerd(false).Where(a => a.SaleFlag != HerdChangeReason.None).OrderByDescending(a => a.Weight).ToList();
                    }
                    // create trucking emissions
                    if (trucks > 0)
                    {
                        SetStatusSuccess();
                    }
                    trucking.ReportEmissions(trucks, true);
                }
            }
            if (bankAccount != null && head > 0) //(trucks > 0 || trucking == null)
            {
                ResourceRequest expenseRequest = new ResourceRequest
                {
                    ActivityModel      = this,
                    AllowTransmutation = false
                };

                // calculate transport costs
                if (trucking != null)
                {
                    expenseRequest.Required = trucks * trucking.DistanceToMarket * trucking.CostPerKmTrucking;
                    expenseRequest.Reason   = "Transport sales";
                    bankAccount.Remove(expenseRequest);
                }

                foreach (RuminantActivityFee item in Apsim.Children(this, typeof(RuminantActivityFee)))
                {
                    switch (item.PaymentStyle)
                    {
                    case AnimalPaymentStyleType.Fixed:
                        expenseRequest.Required = item.Amount;
                        break;

                    case AnimalPaymentStyleType.perHead:
                        expenseRequest.Required = head * item.Amount;
                        break;

                    case AnimalPaymentStyleType.perAE:
                        expenseRequest.Required = aESum * item.Amount;
                        break;

                    case AnimalPaymentStyleType.ProportionOfTotalSales:
                        expenseRequest.Required = saleValue * item.Amount;
                        break;

                    default:
                        throw new Exception(String.Format("PaymentStyle ({0}) is not supported for ({1}) in ({2})", item.PaymentStyle, item.Name, this.Name));
                    }
                    expenseRequest.Reason = item.Name;
                    // uses bank account specified in the RuminantActivityFee
                    item.BankAccount.Remove(expenseRequest);
                }

                // add and remove from bank
                if (saleValue > 0)
                {
                    bankAccount.Add(saleValue, this, this.PredictedHerdName + " sales");
                }
            }
        }
コード例 #10
0
        private void OnCLEMAnimalSell(object sender, EventArgs e)
        {
            Status = ActivityStatus.NoTask;

            int    trucks     = 0;
            double saleValue  = 0;
            double saleWeight = 0;
            int    head       = 0;
            double aESum      = 0;

            // only perform this activity if timing ok, or selling required as a result of forces destock
            List <Ruminant> herd = new List <Ruminant>();

            if (this.TimingOK || this.CurrentHerd(false).Where(a => a.SaleFlag == HerdChangeReason.DestockSale).Any())
            {
                this.Status = ActivityStatus.NotNeeded;
                // get current untrucked list of animals flagged for sale
                herd = this.CurrentHerd(false).Where(a => a.SaleFlag != HerdChangeReason.None).OrderByDescending(a => a.Weight).ToList();
            }

            // no individuals to sell
            if (herd.Count == 0)
            {
                return;
            }

            List <Ruminant> soldIndividuals = new List <Ruminant>();

            if (trucking == null)
            {
                // no trucking just sell
                SetStatusSuccess();
                foreach (var ind in herd)
                {
                    aESum += ind.AdultEquivalent;
                    var pricing = ind.BreedParams.ValueofIndividual(ind, PurchaseOrSalePricingStyleType.Sale);
                    if (pricing != null)
                    {
                        saleValue += pricing.CalculateValue(ind);
                    }

                    saleWeight += ind.Weight;
                    soldIndividuals.Add(ind);
                    HerdResource.RemoveRuminant(ind, this);
                    head++;
                }
            }
            else
            {
                // if sale herd > min loads before allowing sale
                if (herd.Select(a => a.Weight / 450.0).Sum() / trucking.Number450kgPerTruck >= trucking.MinimumTrucksBeforeSelling)
                {
                    // while truck to fill
                    while (herd.Select(a => a.Weight / 450.0).Sum() / trucking.Number450kgPerTruck > trucking.MinimumLoadBeforeSelling)
                    {
                        bool nonloaded = true;
                        trucks++;
                        double load450kgs = 0;
                        // while truck below carrying capacity load individuals
                        foreach (var ind in herd)
                        {
                            if (load450kgs + (ind.Weight / 450.0) <= trucking.Number450kgPerTruck)
                            {
                                nonloaded = false;
                                head++;
                                aESum      += ind.AdultEquivalent;
                                load450kgs += ind.Weight / 450.0;
                                var pricing = ind.BreedParams.ValueofIndividual(ind, PurchaseOrSalePricingStyleType.Sale);
                                if (pricing != null)
                                {
                                    saleValue += pricing.CalculateValue(ind);
                                }
                                saleWeight += ind.Weight;
                                soldIndividuals.Add(ind);
                                HerdResource.RemoveRuminant(ind, this);

                                //TODO: work out what to do with suckling calves still with mothers if mother sold.
                            }
                        }
                        if (nonloaded)
                        {
                            Summary.WriteWarning(this, String.Format("There was a problem loading the sale truck as sale individuals did not meet the loading criteria for breed [r={0}]", this.PredictedHerdBreed));
                            break;
                        }
                        herd = this.CurrentHerd(false).Where(a => a.SaleFlag != HerdChangeReason.None).OrderByDescending(a => a.Weight).ToList();
                    }
                    // create trucking emissions
                    trucking.ReportEmissions(trucks, true);
                    // if sold all
                    Status = (this.CurrentHerd(false).Where(a => a.SaleFlag != HerdChangeReason.None).Count() == 0) ? ActivityStatus.Success : ActivityStatus.Warning;
                }
            }

            if (bankAccount != null && head > 0) //(trucks > 0 || trucking == null)
            {
                ResourceRequest expenseRequest = new ResourceRequest
                {
                    ActivityModel      = this,
                    AllowTransmutation = false
                };

                // calculate transport costs
                if (trucking != null)
                {
                    expenseRequest.Required = trucks * trucking.DistanceToMarket * trucking.CostPerKmTrucking;
                    expenseRequest.Category = trucking.TransactionCategory;
                    bankAccount.Remove(expenseRequest);
                }

                // perform payments by transaction grouping
                // uses a list of individuals that were taken from the herd

                // calculate aEsum and saleValue form the above list for use below
                // currently done above but can be shifted to calc from grouped indiv

                // add and remove from bank
                if (saleValue > 0)
                {
                    //bankAccount.Add(saleValue, this, this.PredictedHerdName, TransactionCategory);
                    var groupedIndividuals = HerdResource.SummarizeIndividualsByGroups(soldIndividuals, PurchaseOrSalePricingStyleType.Sale);
                    foreach (var item in groupedIndividuals)
                    {
                        foreach (var item2 in item.RuminantTypeGroup)
                        {
                            bankAccount.Add(item2.TotalPrice, this, item.RuminantTypeName, $"{TransactionCategory}.{item2.GroupName}");
                        }
                    }
                }

                // perform activity fee payments
                foreach (RuminantActivityFee item in this.FindAllChildren <RuminantActivityFee>())
                {
                    switch (item.PaymentStyle)
                    {
                    case AnimalPaymentStyleType.Fixed:
                        expenseRequest.Required = item.Amount;
                        break;

                    case AnimalPaymentStyleType.perHead:
                        expenseRequest.Required = head * item.Amount;
                        break;

                    case AnimalPaymentStyleType.perAE:
                        expenseRequest.Required = aESum * item.Amount;
                        break;

                    case AnimalPaymentStyleType.ProportionOfTotalSales:
                        expenseRequest.Required = saleValue * item.Amount;
                        break;

                    default:
                        throw new Exception(String.Format("PaymentStyle [{0}] is not supported for [{1}] in [{2}]", item.PaymentStyle, item.Name, this.Name));
                    }
                    expenseRequest.Category = item.TransactionCategory;
                    // uses bank account specified in the RuminantActivityFee
                    item.BankAccount.Remove(expenseRequest);
                }
            }
        }
コード例 #11
0
        private void OnWFAnimalSell(object sender, EventArgs e)
        {
            RuminantHerd ruminantHerd = Resources.RuminantHerd();

            Finance     Accounts    = Resources.FinanceResource() as Finance;
            FinanceType bankAccount = Accounts.GetFirst() as FinanceType;

            int    trucks     = 0;
            double saleValue  = 0;
            double saleWeight = 0;
            int    head       = 0;

            // get current untrucked list of animals flagged for sale
            List <Ruminant> herd = ruminantHerd.Herd.Where(a => a.SaleFlag != Common.HerdChangeReason.None & a.Breed == BreedName).OrderByDescending(a => a.Weight).ToList();

            // if sale herd > min loads before allowing sale
            if (herd.Select(a => a.Weight / 450.0).Sum() / Number450kgPerTruck >= MinimumTrucksBeforeSelling)
            {
                // while truck to fill
                while (herd.Select(a => a.Weight / 450.0).Sum() / Number450kgPerTruck > MinimumLoadBeforeSelling)
                {
                    bool nonloaded = true;
                    trucks++;
                    double load450kgs = 0;
                    // while truck below carrying capacity load individuals
                    foreach (var ind in herd)
                    {
                        if (load450kgs + (ind.Weight / 450.0) <= Number450kgPerTruck)
                        {
                            nonloaded = false;
                            head++;
                            load450kgs += ind.Weight / 450.0;
                            RuminantValue getvalue = PriceList.Where(a => a.Age < ind.Age).OrderBy(a => a.Age).LastOrDefault();
                            saleValue  += getvalue.SellValue * ((getvalue.Style == Common.PricingStyleType.perKg) ? ind.Weight : 1.0);
                            saleWeight += ind.Weight;
                            ruminantHerd.RemoveRuminant(ind);
                        }
                    }
                    if (nonloaded)
                    {
                        Summary.WriteWarning(this, String.Format("There was a problem loading the sale truck as sale individuals did not meet the loading criteria for breed {0}", BreedName));
                        break;
                    }
                    herd = ruminantHerd.Herd.Where(a => a.SaleFlag != Common.HerdChangeReason.None & a.Breed == BreedName).OrderByDescending(a => a.Weight).ToList();
                }

                if (trucks > 0 & bankAccount != null)
                {
                    // calculate transport costs
                    double transportCost = trucks * DistanceToMarket * CostPerKmTrucking;
                    bankAccount.Remove(transportCost, this.Name, "Transport");
                    // calculate MLA fees
                    double mlaCost = head * MLAFees;
                    bankAccount.Remove(mlaCost, this.Name, "R&DFee");
                    // calculate yard fees
                    double yardCost = head * YardFees;
                    bankAccount.Remove(yardCost, this.Name, "YardCosts");
                    // calculate commission
                    double commissionCost = saleValue * SalesCommission;
                    bankAccount.Remove(commissionCost, this.Name, "SalesCommission");

                    // add and remove from bank
                    bankAccount.Add(saleValue, this.Name, "Sales");
                }
            }
        }
コード例 #12
0
ファイル: Transmute.cs プロジェクト: lie112/ApsimX
        ///<inheritdoc/>
        public bool DoTransmute(ResourceRequest request, double shortfall, double requiredByActivities, ResourcesHolder holder, bool queryOnly)
        {
            double transPackets     = 0;
            double shortfallPackets = shortfall / shortfallPacketSize;

            switch (TransmuteStyle)
            {
            case TransmuteStyle.Direct:
                if ((Parent as Transmutation).UseWholePackets)
                {
                    shortfallPackets = Math.Ceiling(shortfallPackets);
                }
                request.Required = shortfallPackets * AmountPerPacket;
                break;

            case TransmuteStyle.UsePricing:
                if (shortfallPricing.CurrentPrice > 0)
                {
                    if (transmutePricing.CurrentPrice == 0)
                    {
                        // no value of transmute resource
                        request.Required = 0;
                    }
                    else
                    {
                        if (shortfallWholePackets)
                        {
                            shortfallPackets = Math.Ceiling(shortfallPackets);
                        }
                        request.Required = shortfallPackets * shortfallPricing.CurrentPrice;

                        if (transmutePricing != shortfallPricing && transmutePricing.UseWholePackets)
                        {
                            transPackets = shortfall / transmutePricing.PacketSize;
                            if (transmutePricing.UseWholePackets)
                            {
                                transPackets = Math.Ceiling(transPackets);
                            }
                        }
                    }
                }
                break;

            default:
                break;
            }

            if (queryOnly)
            {
                return(request.Required + requiredByActivities <= TransmuteResourceType.Amount);
            }
            else
            {
                if (TransmuteStyle == TransmuteStyle.UsePricing && !(TransmuteResourceType is FinanceType))
                {
                    // add finance transaction to sell transmute
                    financeType.Add(transPackets * transmutePricing.CurrentPrice, request.ActivityModel, TransmuteResourceTypeName, request.Category);

                    // add finance transaction to buy shortfall
                    ResourceRequest financeRequest = new ResourceRequest()
                    {
                        Resource          = financeType,
                        Required          = shortfallPackets * shortfallPricing.CurrentPrice,
                        RelatesToResource = request.ResourceTypeName,
                        ResourceType      = typeof(Finance),
                        ActivityModel     = request.ActivityModel,
                        Category          = request.Category,
                    };
                    financeType.Remove(financeRequest);
                }
                else
                {
                    TransmuteResourceType.Remove(request);
                }
            }
            return(true);
        }
コード例 #13
0
        ///<inheritdoc/>
        public bool DoTransmute(ResourceRequest request, double shortfallPacketsNeeded, double requiredByActivities, ResourcesHolder holder, bool queryOnly)
        {
            double needed = 0;

            switch (TransmuteStyle)
            {
            case TransmuteStyle.Direct:
                needed = shortfallPacketSize * AmountPerPacket;
                break;

            case TransmuteStyle.UsePricing:
                needed = shortfallPacketsNeeded * shortfallPricing.CurrentPrice;
                break;

            default:
                break;
            }

            // walk through herd based on filters and take those needed to achieve exchange

            double available = 0;

            foreach (var group in groupings)
            {
                foreach (var ind in group.Filter((ResourceGroup as RuminantHerd).Herd.Where(a => !a.ReadyForSale)))
                {
                    switch (TransmuteStyle)
                    {
                    case TransmuteStyle.Direct:
                        switch (DirectExhangeStyle)
                        {
                        case PricingStyleType.perHead:
                            available += 1;
                            break;

                        case PricingStyleType.perKg:
                            available += ind.Weight;
                            break;

                        case PricingStyleType.perAE:
                            available += ind.AdultEquivalent;
                            break;

                        default:
                            break;
                        }
                        break;

                    case TransmuteStyle.UsePricing:
                        available += ind.BreedParams.ValueofIndividual(ind, PurchaseOrSalePricingStyleType.Sale)?.CurrentPrice ?? 0;
                        break;

                    default:
                        break;
                    }

                    if (!queryOnly)
                    {
                        // remove individual from herd immediately
                        (ResourceGroup as RuminantHerd).Herd.Remove(ind);
                    }

                    if (available >= needed)
                    {
                        if (queryOnly)
                        {
                            return(true);
                        }
                        break;
                    }
                }
            }

            if (!queryOnly)
            {
                if (TransmuteStyle == TransmuteStyle.UsePricing && financeType != null)
                {
                    // finance transaction from sale of animals
                    financeType.Add(available, request.ActivityModel, TransmuteResourceTypeName, request.Category);

                    // finance transaction from purchase of shortfall
                    ResourceRequest financeRequest = new ResourceRequest()
                    {
                        Resource          = financeType,
                        Required          = shortfallPacketsNeeded * shortfallPacketSize * shortfallPricing.CurrentPrice,
                        RelatesToResource = request.ResourceTypeName,
                        ResourceType      = typeof(Finance),
                        ActivityModel     = request.ActivityModel,
                        Category          = request.Category,
                    };
                    financeType.Remove(financeRequest);
                }
            }
            return(true);
        }