/// <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);
    }
Exemplo n.º 2
0
    /// <summary>
    /// Add supplier fulfillment capabilities from another scenario
    /// </summary>
    /// <param name="scenario"></param>
    public void Adopt(FulfillmentScenario scenario)
    {
        if (scenario == null)
        {
            return;
        }

        foreach (KeyValuePair <int, FulfillmentCapability> fulfillmentCapability in scenario._supplierFulfillmentCapabilities)
        {
            add(fulfillmentCapability.Value);
        }
    }
    /// <summary>
    /// Optimization works by working out all possible purchase order combination scenarios and then selecting cheapest scenario
    /// </summary>
    /// <param name="purchaseRequirements"></param>
    /// <returns>List of purchase order based on requirements</returns>
    public IEnumerable <PurchaseOrder> Optimize(IEnumerable <PurchaseRequirement> purchaseRequirements)
    {
        /* Assumptions:
         * - Optimal purchase orders account for shipping cost of each supplier
         * - Each PurchaseRequirement must be fulfilled within one purchase order
         * - Only Physical product requires shipping
         * - Service type product does not require stock in hand
         * - Shipping cost is not applicable if a purchase order does not include any Physical product
         * - "Background" specifies "‘Optimal’ in this case means the cheapest set of suppliers that have sufficient stock", which means product without sufficient stock is included in an order based on cheapest price best effort, e.g. through supplier with cheapest cost + shipping difference
         * - Product without stock at any supplier should tehnically be returned with list of purchase orders within a different model which is never specified or mentioned anywhere and therefore ignored
         * - PurchaseRequirement with quantity '0' is not included in any order
         * - Three suppliers had the same ID in the test data, which was assumed to be mistake and changed
         */

        // determine best ordering scenario, not taking insufficient quantity product into consideration
        FulfillmentScenario optimalScenario = Optimize(purchaseRequirements, _suppliers.Values);

        if (optimalScenario == null)
        {
            return(null);
        }

        # region Include products with insufficient stock in one order