Рассмотрим задачу планирования работы медсестры в отделении конкретной больницы. Ежедневно работают три смены по 12 часов, начиная с 7, 13 и 19 часов. Горизонт планирования составляет четыре дня, начиная с 01 мая 2023 г., всего 12 смен. В эти смены могут быть назначены четыре дипломированные медсестры, с целью иметь в отделении две медсестры в любой момент времени. Требование о покрытии является обязательным.
Всем медсестрам необходимо отдыхать между сменами не менее 12 часов (720 минут) и они могут работать не более 36 часов (2160 минут) в течение указанного горизонта планирования. Эти ограничения имеют соответственно высокий и средний приоритет.
Несколько смен в день
Три смены в день представлены как три независимые смены. Например, смены за первый день (из четырех дней) на локации «отдел» представлены как:
{
"shifts": [{
"id": "2023-05-01 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
}
}, {
"id": "2023-05-01 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 1
}
}, {
"id": "2023-05-01 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
}
},
...
]
}
Пример с 12 сменами (четыре дня по три смены в день)
{
"shifts": [{
"id": "2023-05-01 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
}
}, {
"id": "2023-05-01 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 1
}
}, {
"id": "2023-05-01 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
}
}, {
"id": "2023-05-02 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 19
}
}, {
"id": "2023-05-02 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 1
}
}, {
"id": "2023-05-02 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 7
}
}, {
"id": "2023-05-03 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 19
}
}, {
"id": "2023-05-03 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 1
}
}, {
"id": "2023-05-03 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 7
}
}, {
"id": "2023-05-04 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 19
}
}, {
"id": "2023-05-04 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 1
}
}, {
"id": "2023-05-04 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
}
}]
}
Отдых между сменами
Чтобы представить отдых между сменами для сотрудника, используйте поле minimumRestMinutes
из ограничения планирования . Время начала и окончания ограничения используется для определения того, какие смены следует учитывать, и поэтому должно соответствовать горизонту планирования, перекрываясь со всеми сменами. Время отдыха указывается в минутах (720), а приоритет PRIORITY_HIGH
, как указано выше. Первая медсестра (по имени Адам) представлена как:
{
"employees": [{
"id": "Adam",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}]
}
}
Максимальное время работы
Максимальное количество времени, в течение которого сотрудник может работать, также представлено ограничением планирования с использованием поля maximumMinutes
. Максимальное время работы в этом примере составляет 2160 минут. Время начала и окончания ограничения должно соответствовать всему горизонту планирования. Соответствующее представление первой медсестры (Адама) можно обновить до:
{
"employees": [{
"id": "Adam",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}
}
Пример со всеми четырьмя сотрудниками
{
"employees": [{
"id": "Adam",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "Grace",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "James",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "Alonso",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}]
}
Страхование дипломированных медсестер
Охват двух дипломированных медсестер в любой момент времени представлен требованием о покрытии . В частности, roleRequirements
заполняется одним требованием роли , для которого roleId
имеет значение «Registered Nurse», targetEmployeeCount
имеет значение 2, а priority
установлен на PRIORITY_MANDATORY
. Время начала и окончания действия страхового покрытия должно совпадать в каждую смену. В поле locationId
установлено значение «department», поэтому учитываются только смены, происходящие в этом месте.
{
"coverageRequirements": [{
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"locationId": "department",
"roleRequirements": [{
"roleId": "Registered Nurse",
"targetEmployeeCount": 2,
"priority": "PRIORITY_MANDATORY"
}]
}],
"roleIds": ["Registered Nurse"],
"locationIds": ["department"]
}
Пример полного запроса
{
"employees": [{
"id": "Adam",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "Grace",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "James",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}, {
"id": "Alonso",
"roleIds": ["Registered Nurse"],
"schedulingConstraints": [{
"priority": "PRIORITY_HIGH",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"minimumRestMinutes": 720
}, {
"priority": "PRIORITY_MEDIUM",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"maximumMinutes": 2160
}]
}],
"shifts": [{
"id": "2023-05-01 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
}
}, {
"id": "2023-05-01 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 1
}
}, {
"id": "2023-05-01 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
}
}, {
"id": "2023-05-02 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 19
}
}, {
"id": "2023-05-02 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 1
}
}, {
"id": "2023-05-02 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 2,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 7
}
}, {
"id": "2023-05-03 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 19
}
}, {
"id": "2023-05-03 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 1
}
}, {
"id": "2023-05-03 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 3,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 7
}
}, {
"id": "2023-05-04 7hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 19
}
}, {
"id": "2023-05-04 13hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 13
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 1
}
}, {
"id": "2023-05-04 19hr",
"locationId": "department",
"startDateTime": {
"year": 2023,
"month": 5,
"day": 4,
"hours": 19
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
}
}],
"coverageRequirements": [{
"startDateTime": {
"year": 2023,
"month": 5,
"day": 1,
"hours": 7
},
"endDateTime": {
"year": 2023,
"month": 5,
"day": 5,
"hours": 7
},
"locationId": "department",
"roleRequirements": [{
"roleId": "Registered Nurse",
"targetEmployeeCount": 2,
"priority": "PRIORITY_MANDATORY"
}]
}],
"roleIds": ["Registered Nurse"],
"locationIds": ["department"]
}
Пример ответа
Ответ решателя содержит распределение медсестер по сменам и статус процедуры оптимизации. Например, смены, назначенные первому сотруднику, возвращаются как:
{
"solutionStatus": "OPTIMAL",
"shiftAssignments": [
{
"employeeId": "Adam",
"shiftId": "2023-05-01 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-02 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-03 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-04 7hr",
"roleId": "Registered Nurse"
},
... ]
}
Пример полного ответа
{
"solutionStatus": "OPTIMAL",
"shiftAssignments": [
{
"employeeId": "Adam",
"shiftId": "2023-05-01 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-02 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-03 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Adam",
"shiftId": "2023-05-04 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Grace",
"shiftId": "2023-05-01 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Grace",
"shiftId": "2023-05-02 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Grace",
"shiftId": "2023-05-03 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Grace",
"shiftId": "2023-05-04 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "James",
"shiftId": "2023-05-01 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "James",
"shiftId": "2023-05-02 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "James",
"shiftId": "2023-05-03 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "James",
"shiftId": "2023-05-04 19hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Alonso",
"shiftId": "2023-05-01 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Alonso",
"shiftId": "2023-05-02 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Alonso",
"shiftId": "2023-05-03 7hr",
"roleId": "Registered Nurse"
},
{
"employeeId": "Alonso",
"shiftId": "2023-05-04 7hr",
"roleId": "Registered Nurse"
}
]
}