Skip to main content

Overview

This example demonstrates retail store scheduling where a mix of full-time and part-time employees must cover varying demand throughout the week. The solution optimizes coverage during peak hours while respecting student schedules, availability preferences, and fair hour distribution.
This example showcases demand-based staffing, part-time availability windows, skill-based register assignments, and workload fairness across diverse employee types.

Business Scenario

A retail store manages:
  • 15 employees (5 full-time, 10 part-time including students)
  • Variable demand: quiet mornings, busy afternoons, peak weekends
  • Different roles: cashier, floor, stock, supervisor
  • Part-time constraints: students available only evenings/weekends
  • Fair distribution of desirable weekend shifts
  • Minimum 2 supervisors during peak hours

Complete Implementation

  • Request
  • Solution
  • Analysis
{
  "employees": [
    {
      "name": "Alex-FT",
      "skills": [
        { "name": "supervisor", "level": 5 },
        { "name": "cashier", "level": 5 },
        { "name": "floor", "level": 4 }
      ],
      "availability": [
        "2024-04-01T00:00:00/2024-04-07T23:59:59"
      ],
      "wage": 22
    },
    {
      "name": "Beth-FT",
      "skills": [
        { "name": "supervisor", "level": 4 },
        { "name": "cashier", "level": 5 },
        { "name": "stock", "level": 3 }
      ],
      "availability": [
        "2024-04-01T00:00:00/2024-04-07T23:59:59"
      ],
      "wage": 21
    },
    {
      "name": "Carlos-PT",
      "skills": [
        { "name": "cashier", "level": 3 },
        { "name": "floor", "level": 4 }
      ],
      "availability": [
        "2024-04-01T16:00:00/2024-04-01T22:00:00",
        "2024-04-02T16:00:00/2024-04-02T22:00:00",
        "2024-04-03T16:00:00/2024-04-03T22:00:00",
        "2024-04-06T09:00:00/2024-04-06T22:00:00",
        "2024-04-07T09:00:00/2024-04-07T22:00:00"
      ],
      "preference": ["weekend-floor-pm"],
      "wage": 15
    },
    {
      "name": "Diana-PT",
      "skills": [
        { "name": "cashier", "level": 4 },
        { "name": "floor", "level": 2 }
      ],
      "availability": [
        "2024-04-01T08:00:00/2024-04-01T14:00:00",
        "2024-04-02T08:00:00/2024-04-02T14:00:00",
        "2024-04-03T08:00:00/2024-04-03T14:00:00",
        "2024-04-04T08:00:00/2024-04-04T14:00:00",
        "2024-04-05T08:00:00/2024-04-05T14:00:00"
      ],
      "wage": 14
    },
    {
      "name": "Evan-Student",
      "skills": [
        { "name": "cashier", "level": 2 },
        { "name": "stock", "level": 3 }
      ],
      "availability": [
        "2024-04-01T17:00:00/2024-04-01T22:00:00",
        "2024-04-03T17:00:00/2024-04-03T22:00:00",
        "2024-04-05T17:00:00/2024-04-05T22:00:00",
        "2024-04-06T10:00:00/2024-04-06T22:00:00",
        "2024-04-07T10:00:00/2024-04-07T18:00:00"
      ],
      "wage": 12
    }
  ],
  "shifts": [
    {
      "name": "mon-open",
      "from": "2024-04-01T08:00:00",
      "to": "2024-04-01T14:00:00",
      "skills": [{ "name": "cashier" }],
      "min": 2,
      "max": 3,
      "tags": [{ "name": "MORNING" }, { "name": "WEEKDAY" }],
      "priority": 3
    },
    {
      "name": "mon-peak",
      "from": "2024-04-01T14:00:00",
      "to": "2024-04-01T20:00:00",
      "skills": [{ "name": "cashier" }],
      "min": 4,
      "max": 5,
      "tags": [{ "name": "AFTERNOON" }, { "name": "PEAK" }, { "name": "WEEKDAY" }],
      "priority": 1
    },
    {
      "name": "mon-close",
      "from": "2024-04-01T18:00:00",
      "to": "2024-04-01T22:00:00",
      "skills": [{ "name": "floor" }],
      "min": 2,
      "max": 3,
      "tags": [{ "name": "EVENING" }, { "name": "WEEKDAY" }],
      "priority": 2
    },
    {
      "name": "mon-supervisor",
      "from": "2024-04-01T12:00:00",
      "to": "2024-04-01T20:00:00",
      "skills": [{ "name": "supervisor" }],
      "min": 1,
      "max": 2,
      "tags": [{ "name": "SUPERVISOR" }, { "name": "WEEKDAY" }],
      "priority": 1
    },
    {
      "name": "sat-peak",
      "from": "2024-04-06T10:00:00",
      "to": "2024-04-06T18:00:00",
      "skills": [{ "name": "cashier" }],
      "min": 5,
      "max": 6,
      "tags": [{ "name": "WEEKEND" }, { "name": "PEAK" }],
      "priority": 1
    },
    {
      "name": "weekend-floor-pm",
      "from": "2024-04-06T14:00:00",
      "to": "2024-04-06T22:00:00",
      "skills": [{ "name": "floor" }],
      "min": 3,
      "max": 4,
      "tags": [{ "name": "WEEKEND" }, { "name": "PEAK" }],
      "priority": 1
    },
    {
      "name": "sun-all-day",
      "from": "2024-04-07T10:00:00",
      "to": "2024-04-07T18:00:00",
      "skills": [{ "name": "cashier" }],
      "min": 4,
      "max": 5,
      "tags": [{ "name": "WEEKEND" }],
      "priority": 1
    }
  ],
  "rules": [
    {
      "constraint": "COUNTER",
      "type": "HOURS_WORKED",
      "min": 32,
      "max": 40,
      "period": { "duration": "P7D" }
    },
    {
      "constraint": "COUNTER",
      "type": "WORKING_DAYS",
      "max": 5,
      "period": { "duration": "P7D" }
    },
    {
      "constraint": "SEQUENCE",
      "type": "WORKING_DAYS",
      "max": 6
    }
  ],
  "demands": [
    {
      "name": "peak-coverage",
      "from": "2024-04-06T12:00:00",
      "to": "2024-04-06T18:00:00",
      "min": 8,
      "max": 10
    }
  ],
  "requirements": [
    {
      "shifts": ["mon-peak", "sat-peak", "sun-all-day"],
      "skill": "supervisor",
      "value": 2
    }
  ],
  "fairnessBuckets": [
    {
      "employees": ["Carlos-PT", "Diana-PT", "Evan-Student"],
      "shifts": ["sat-peak", "weekend-floor-pm", "sun-all-day"],
      "period": {
        "from": "2024-04-01",
        "to": "2024-04-30"
      }
    }
  ],
  "options": {
    "hardAvailability": true,
    "partialPlanning": false,
    "penaliseZeroHours": true
  },
  "weights": {
    "availability": "100hard",
    "unassigned": "50medium",
    "wages": "3soft",
    "pref": "5medium"
  }
}

Key Retail Features

Part-Time Availability Windows

Handle complex availability patterns:
{
  "employees": [{
    "name": "Student-Worker",
    "availability": [
      "2024-04-01T17:00:00/2024-04-01T22:00:00",
      "2024-04-06T09:00:00/2024-04-06T22:00:00",
      "2024-04-07T09:00:00/2024-04-07T18:00:00"
    ]
  }]
}

Peak Hour Demands

Ensure adequate staffing during busy periods:
{
  "demands": [
    {
      "name": "saturday-rush",
      "from": "2024-04-06T12:00:00",
      "to": "2024-04-06T18:00:00",
      "min": 8,
      "max": 10
    }
  ]
}

Shift Priority for Coverage

Prioritize critical shifts:
{
  "shifts": [
    {
      "name": "peak-cashier",
      "priority": 1,
      "min": 4
    },
    {
      "name": "morning-stock",
      "priority": 3,
      "min": 1
    }
  ]
}
Priority 1 shifts are filled first. Use lower priority (higher numbers) for shifts that can be understaffed if needed.

Weekend Shift Fairness

Distribute desirable weekend shifts fairly:
{
  "fairnessBuckets": [
    {
      "employees": ["Part-Timer-1", "Part-Timer-2", "Part-Timer-3"],
      "shifts": ["saturday-pm", "sunday-am", "sunday-pm"],
      "period": { "from": "2024-04-01", "to": "2024-04-30" }
    }
  ]
}

Common Retail Patterns

{
  "shifts": [
    { "name": "am-shift", "from": "08:00", "to": "12:00" },
    { "name": "pm-shift", "from": "16:00", "to": "22:00" }
  ],
  "rules": [
    {
      "constraint": "COUNTER",
      "type": "WORKING_SHIFT_TYPE",
      "tags": ["SPLIT"],
      "max": 2,
      "period": { "duration": "P7D" }
    }
  ]
}
{
  "shifts": [{
    "name": "holiday-extra",
    "from": "2024-12-20T10:00:00",
    "to": "2024-12-20T22:00:00",
    "min": 8,
    "max": 12,
    "tags": [{ "name": "HOLIDAY" }]
  }],
  "options": { "partialPlanning": true }
}
{
  "shifts": [
    {
      "name": "opener",
      "from": "07:00",
      "to": "15:00",
      "skills": [{ "name": "key-holder" }],
      "min": 1,
      "max": 1
    },
    {
      "name": "closer",
      "from": "14:00",
      "to": "22:00",
      "skills": [{ "name": "key-holder" }],
      "min": 1,
      "max": 1
    }
  ]
}
{
  "employees": [{
    "name": "Flexible-Worker",
    "skills": [
      { "name": "cashier", "level": 3 },
      { "name": "floor", "level": 3 },
      { "name": "stock", "level": 2 }
    ]
  }],
  "weights": {
    "softSkills": "5soft"
  }
}