/// <summary> /// This is a recursive function. Each scenario is determined by working out 'fulfillment capabilities' starting at a particular supplier and then recurse through all other suppliers for 'unfulfilled' products /// </summary> /// <param name="purchaseRequirements"></param> /// <param name="suppliers"></param> /// <returns></returns> FulfillmentScenario Optimize(IEnumerable <PurchaseRequirement> purchaseRequirements, IEnumerable <Supplier> suppliers) { FulfillmentScenario optimalScenario = null; // workout a possible scenario starting from one carrier // could be done in paralel with Paralel.For foreach (Supplier supplier in suppliers) { FulfillmentScenario scenario = new FulfillmentScenario(); FulfillmentCapability fulfillmentCapability = DetermineFulfillmentCapability(supplier, purchaseRequirements); scenario.Add(fulfillmentCapability); // determine requirements current carrier could not fulfill IEnumerable <PurchaseRequirement> pendingRequirements = fulfillmentCapability.ProductsWithInsufficientStock.Concat(fulfillmentCapability.UnrecognizedProducts); // recuse through other carriers if current supplier unable to fulfill all requirements if (pendingRequirements.Count() > 0) { FulfillmentScenario residualFulfillmentScenario = Optimize(pendingRequirements, suppliers.Where(s => s.ID != supplier.ID)); scenario.Adopt(residualFulfillmentScenario); } // Determine if this scenario is the most optimal and keep track if (optimalScenario == null || scenario.TotalCost < optimalScenario.TotalCost) { optimalScenario = scenario; } } return(optimalScenario); }
/// <summary> /// Adds supplier fulfillment capability to scenario /// </summary> /// <param name="fulfillmentCapability"></param> /// <exception cref="DuplicateScenarioCapabilityException"></exception> public void Add(FulfillmentCapability fulfillmentCapability) { if (_supplierFulfillmentCapabilities.ContainsKey(fulfillmentCapability.Supplier.ID)) { throw new DuplicateScenarioCapabilityException(); } add(fulfillmentCapability); }
/// <summary> /// Update supplier fulfillment capability. Used when adding 'insufficient stock' items to existing supplier fulfillment capability (quote) /// </summary> /// <param name="fulfillmentCapability"></param> public void Replace(FulfillmentCapability fulfillmentCapability) { if (_supplierFulfillmentCapabilities.TryGetValue(fulfillmentCapability.Supplier.ID, out FulfillmentCapability original)) { _totalCost -= original.TotalCost; _supplierFulfillmentCapabilities.Remove(fulfillmentCapability.Supplier.ID); } add(fulfillmentCapability); }
/// <summary> /// Internal function to add fulfillment capability to list and keep track of total cost for scenario /// </summary> /// <param name="fulfillmentCapability"></param> void add(FulfillmentCapability fulfillmentCapability) { _supplierFulfillmentCapabilities.Add(fulfillmentCapability.Supplier.ID, fulfillmentCapability); _totalCost += fulfillmentCapability.TotalCost; }