Supplier SLA Performance — Lead Time and Reliability

Supplier SLA Performance — Lead Time and Reliability

Supplier performance analysis tracks whether vendors deliver on time, within promised lead times, and how their reliability affects your inventory position.


1. Actual vs Promised Lead Time per Supplier

SELECT
    sup.name                        AS supplier,
    sup.lead_time_days              AS promised_lead_days,
    sup.reliability_score,
    COUNT(po.id)                    AS total_orders,
    COUNT(po.id) FILTER (WHERE po.received_at IS NOT NULL) AS received_orders,
    ROUND((AVG(
        CASE WHEN po.received_at IS NOT NULL THEN
            DATE_PART('day', po.received_at - po.ordered_at)
        END
    ))::NUMERIC, 1)                           AS avg_actual_lead_days,
    ROUND((AVG(
        CASE WHEN po.received_at IS NOT NULL THEN
            DATE_PART('day', po.received_at - po.ordered_at) - sup.lead_time_days
        END
    ))::NUMERIC, 1)                           AS avg_delay_days
FROM lg_suppliers sup
LEFT JOIN lg_purchase_orders po ON po.supplier_id = sup.id
GROUP BY sup.id, sup.name, sup.lead_time_days, sup.reliability_score
ORDER BY avg_delay_days DESC NULLS LAST;

What This Returns

supplier                | promised_lead_days | avg_actual_lead_days | avg_delay_days
------------------------+--------------------+----------------------+----------------
Epsilon Goods           |                 25 |                 30.1 |            5.1
Delta Parts Co          |                 18 |                 21.3 |            3.3
Alpha Manufacturing     |                 21 |                 23.8 |            2.8
...

2. On-Time Delivery Rate by Supplier

SELECT
    sup.name,
    COUNT(po.id) FILTER (WHERE po.received_at IS NOT NULL) AS delivered,
    COUNT(po.id) FILTER (WHERE po.received_at IS NOT NULL
        AND po.received_at::DATE <= po.expected_at)        AS on_time,
    COUNT(po.id) FILTER (WHERE po.received_at IS NOT NULL
        AND po.received_at::DATE > po.expected_at)         AS late,
    ROUND((100.0 *
        COUNT(po.id) FILTER (WHERE po.received_at IS NOT NULL
            AND po.received_at::DATE <= po.expected_at)
        / NULLIF(COUNT(po.id) FILTER (WHERE po.received_at IS NOT NULL), 0))::NUMERIC, 1) AS otd_rate_pct
FROM lg_suppliers sup
LEFT JOIN lg_purchase_orders po ON po.supplier_id = sup.id
GROUP BY sup.name
ORDER BY otd_rate_pct DESC;

3. Supplier Performance Score Card

Combine multiple metrics into a composite score:

WITH metrics AS (
    SELECT
        sup.id,
        sup.name,
        sup.reliability_score,
        ROUND((AVG(
            CASE WHEN po.received_at IS NOT NULL THEN
                DATE_PART('day', po.received_at - po.ordered_at) - sup.lead_time_days
            END
        ))::NUMERIC, 1) AS avg_delay,
        ROUND((100.0 *
            COUNT(po.id) FILTER (WHERE po.received_at IS NOT NULL
                AND po.received_at::DATE <= po.expected_at)
            / NULLIF(COUNT(po.id) FILTER (WHERE po.received_at IS NOT NULL), 0))::NUMERIC, 1) AS otd_pct
    FROM lg_suppliers sup
    LEFT JOIN lg_purchase_orders po ON po.supplier_id = sup.id
    GROUP BY sup.id, sup.name, sup.reliability_score
)
SELECT
    name,
    reliability_score,
    avg_delay,
    otd_pct,
    ROUND(((reliability_score * 40)
        + (otd_pct / 100.0 * 40)
        + GREATEST(0, (10 - COALESCE(avg_delay, 0)) / 10.0 * 20))::NUMERIC, 1) AS composite_score
FROM metrics
ORDER BY composite_score DESC;

4. Cost of Late Deliveries

Late deliveries often force expensive spot purchases. Estimate the cost impact:

SELECT
    sup.name,
    COUNT(po.id) FILTER (WHERE po.received_at::DATE > po.expected_at) AS late_orders,
    SUM(po.quantity * po.unit_cost)
        FILTER (WHERE po.received_at::DATE > po.expected_at)           AS late_order_value_usd,
    ROUND((AVG(po.received_at::DATE - po.expected_at)
        FILTER (WHERE po.received_at::DATE > po.expected_at))::NUMERIC, 1)       AS avg_lateness_days
FROM lg_suppliers sup
JOIN lg_purchase_orders po ON po.supplier_id = sup.id
WHERE po.received_at IS NOT NULL
GROUP BY sup.name
ORDER BY late_order_value_usd DESC NULLS LAST;

Key Takeaway

Always compare actual lead time against the promised lead time rather than measuring absolute delivery speed — a supplier that always delivers in 30 days is more reliable than one that promises 5 days but regularly takes 15. The composite score pattern (weighted sum of normalised metrics) is directly reusable for vendor scorecards, employee performance reviews, and customer health scores.