{
  "openapi": "3.0.3",
  "info": {
    "title": "api/time-slots/terminals",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "/"
    },
    {
      "url": "https://api.ati.su"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "paths": {
    "/gw/timeslots/api/v1/terminal": {
      "post": {
        "operationId": "timeslots_v1_terminal_upsert",
        "description": "Без ненулевого id создаёт площадку, с id изменяет существующую. Доступно только владельцу неудалённого склада. warehouse нельзя изменить. schedule и contacts обязательны и полностью заменяют прежние значения. Отсутствующий warehouse_cargo_types очищает принимаемые типы грузов. Типы грузов должны принадлежать переданному складу. Расписание использует локальное время склада: начало раньше конца, один рабочий интервал на день; перерывы внутри рабочего интервала без пересечений. Идентификатор склада можно получить через GET /api/v1/warehouse.",
        "summary": "Создаёт или изменяет площадку склада.",
        "tags": [
          "Площадки"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TerminalUpsertRequestRequest"
              },
              "examples": {
                "CreateTerminal": {
                  "value": {
                    "warehouse": 101,
                    "name": "Ворота № 2",
                    "schedule": [
                      {
                        "day_of_week": "1",
                        "time_from": "08:00:00",
                        "time_to": "18:00:00"
                      }
                    ],
                    "contacts": []
                  },
                  "summary": "Создание площадки на своём складе",
                  "description": "Замените warehouse на result.warehouse.id созданного склада. Понедельник: 08:00–18:00 по местному времени склада."
                },
                "UpdateTerminal": {
                  "value": {
                    "id": 201,
                    "warehouse": 101,
                    "name": "Ворота № 2 — новое название",
                    "schedule": [
                      {
                        "day_of_week": "1",
                        "time_from": "08:00:00",
                        "time_to": "18:00:00"
                      }
                    ],
                    "contacts": []
                  },
                  "summary": "Изменение площадки",
                  "description": "Подставьте id из result.terminal.id, warehouse оставьте прежним. schedule и contacts заменяются полностью; отсутствие warehouse_cargo_types очищает типы площадки."
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TerminalUpsertResponse"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorListResponse"
                }
              }
            },
            "description": "Некорректные поля, расписание или нет доступа к складу."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Контекст пользователя отсутствует или некорректен."
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Площадка не найдена или недоступна пользователю."
          }
        }
      },
      "get": {
        "operationId": "timeslots_v1_terminal_list",
        "description": "terminals содержит площадки складов фирмы пользователя. partners_terminals — площадки чужих складов с принятой неудалённой связью со Справочниками фирмы. count учитывает только terminals. Пагинации и фильтров нет; порядок — от новых к старым. Удалённые площадки и площадки удалённых складов также могут присутствовать; проверяйте deleted. Полученный id используется для изменения или удаления площадки.",
        "summary": "Получает собственные и партнёрские площадки.",
        "tags": [
          "Площадки"
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TerminalsResponse"
                }
              }
            },
            "description": ""
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Контекст пользователя отсутствует или некорректен."
          }
        }
      },
      "delete": {
        "operationId": "timeslots_v1_terminal_delete",
        "description": "Только владелец склада может удалить его неудалённую площадку. Последнюю неудалённую площадку склада удалить нельзя. Площадка помечается удалённой, её расписание, контакты и связи с типами груза очищаются; брони сохраняются. HTTP 200 возможен при частичном или полном отказе: проверяйте result['200'] и result['400']. ID обрабатываются последовательно, повторы не удаляются. При ошибке размера ID обработка прерывается с 400, ранее выполненные удаления сохраняются. Числовые строки допустимы и возвращаются строками.",
        "summary": "Удаляет площадки склада.",
        "tags": [
          "Площадки"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TerminalDeleteRequestRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TerminalDeleteResponse"
                }
              }
            },
            "description": ""
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorListResponse"
                },
                "examples": {
                  "НекорректныйЗапрос": {
                    "value": {
                      "error": "bad_request",
                      "reason": "warehouse_ids должен быть списком"
                    },
                    "summary": "Некорректный запрос"
                  }
                }
              }
            },
            "description": "Некорректный список или размер ID."
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            },
            "description": "Контекст пользователя отсутствует или некорректен."
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "TerminalDeleteRequestRequest": {
        "type": "object",
        "description": "Список удаляемых площадок.",
        "properties": {
          "terminal_ids": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Идентификаторы удаляемых площадок; допускаются числовые строки.",
            "minItems": 1,
            "example": [
              1
            ]
          }
        },
        "required": [
          "terminal_ids"
        ]
      },
      "TerminalDeleteResponse": {
        "type": "object",
        "description": "Успешный ответ.",
        "properties": {
          "result": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TerminalDeleteResponseResult"
              }
            ],
            "description": "Результат выполнения запроса.",
            "example": {
              "200": [],
              "400": [],
              "500": []
            }
          },
          "ok": {
            "type": "boolean",
            "default": true,
            "description": "Признак успешного выполнения запроса.",
            "example": true
          }
        },
        "required": [
          "result"
        ]
      },
      "ErrorListResponse": {
        "type": "object",
        "description": "Ошибка запроса с подробностями по отдельным полям.",
        "properties": {
          "error": {
            "type": "string",
            "description": "Машиночитаемый код ошибки.",
            "example": "bad_request"
          },
          "reason": {
            "type": "string",
            "description": "Описание причины ошибки.",
            "example": "warehouse_ids должен быть списком"
          },
          "error_list": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "description": "Ошибки отдельных полей запроса.",
            "example": [
              {
                "error": "warehouse",
                "reason": "Обязательное поле."
              }
            ]
          }
        },
        "required": [
          "error",
          "reason"
        ]
      },
      "ErrorResponse": {
        "type": "object",
        "description": "Ошибка API: код и причина.",
        "properties": {
          "error": {
            "type": "string",
            "description": "Машиночитаемый код ошибки.",
            "example": "bad_request"
          },
          "reason": {
            "type": "string",
            "description": "Описание причины ошибки.",
            "example": "warehouse_ids должен быть списком"
          }
        },
        "required": [
          "error",
          "reason"
        ]
      },
      "TerminalsResponse": {
        "type": "object",
        "description": "Успешный ответ.",
        "properties": {
          "result": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TerminalsResponseResult"
              }
            ],
            "description": "Результат выполнения запроса.",
            "example": {
              "count": 1,
              "terminals": [],
              "partners_terminals": []
            }
          },
          "ok": {
            "type": "boolean",
            "default": true,
            "description": "Признак успешного выполнения запроса.",
            "example": true
          }
        },
        "required": [
          "result"
        ]
      },
      "TerminalUpsertRequestRequest": {
        "type": "object",
        "description": "Создание или изменение площадки склада.",
        "properties": {
          "schedule": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TerminalScheduleRequest"
            },
            "description": "Расписание площадки и перерывы. Один рабочий интервал на день; перерывы внутри него и не пересекаются.",
            "minItems": 1,
            "example": [
              {
                "day_of_week": "1",
                "time_from": "08:00:00",
                "time_to": "18:00:00",
                "is_break": false
              }
            ]
          },
          "contacts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TerminalContactRequest"
            },
            "description": "Контакты площадки; при изменении заменяются целиком, [] очищает список.",
            "example": []
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "title": "Название площадки",
            "maxLength": 280,
            "description": "Название площадки",
            "example": "string"
          },
          "loading_type": {
            "allOf": [
              {
                "$ref": "#/components/schemas/LoadingTypeEnum"
              }
            ],
            "description": "Тип загрузки\n\n* `any` - Любая\n* `up` - Сверху\n* `lateral` - Боковая",
            "title": "Тип загрузки",
            "example": "any"
          },
          "deleted": {
            "type": "boolean",
            "title": "Удален",
            "description": "Удален",
            "example": false
          },
          "is_test": {
            "type": "boolean",
            "title": "Тестовый",
            "description": "Тестовый",
            "example": false
          },
          "warehouse": {
            "type": "integer",
            "title": "Склад",
            "description": "Идентификатор склада. Источник: GET /gw/timeslots/api/v1/warehouse, поле result.warehouses[].id или result.partners_warehouses[].id. При создании склада: POST /gw/timeslots/api/v1/warehouse, поле result.warehouse.id. Используйте неудалённый склад, доступный для выбранной операции.",
            "example": 1
          },
          "warehouse_cargo_types": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid",
              "title": "Принимаемые типы грузов"
            },
            "title": "Принимаемые типы грузов",
            "description": "UUID типов груза из справочника склада, не числовые ID общего словаря грузов ATI. Уже назначенные площадкам типы доступны через GET /gw/timeslots/api/v1/terminal: result.terminals[].warehouse_cargo_types[].id или result.partners_terminals[].warehouse_cargo_types[].id. Это только типы выбранных площадок, не полный справочник склада. Используйте типы своего выбранного склада; если они не нужны, не передавайте поле. При изменении отсутствие поля или [] очищает типы площадки.",
            "example": []
          },
          "id": {
            "type": "integer",
            "description": "Идентификатор изменяемой площадки. Без id или с 0 создаётся новая.",
            "example": 1
          }
        },
        "required": [
          "contacts",
          "name",
          "schedule",
          "warehouse"
        ]
      },
      "TerminalUpsertResponse": {
        "type": "object",
        "description": "Успешный ответ.",
        "properties": {
          "result": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TerminalUpsertResponseResult"
              }
            ],
            "description": "Результат выполнения запроса.",
            "example": {
              "terminal": {
                "id": 1,
                "schedule": [],
                "contacts": [],
                "warehouse_cargo_types": [],
                "name": "string",
                "loading_type": "any",
                "date_creation": "2030-01-01T07:00:00Z",
                "date_modified": "2030-01-01T07:00:00Z",
                "deleted": false,
                "is_test": false,
                "warehouse": 1
              }
            }
          },
          "ok": {
            "type": "boolean",
            "default": true,
            "description": "Признак успешного выполнения запроса.",
            "example": true
          }
        },
        "required": [
          "result"
        ]
      },
      "TerminalDeleteResponseResult": {
        "type": "object",
        "description": "Результат выполнения запроса.",
        "properties": {
          "200": {
            "type": "array",
            "items": {},
            "description": "Успешно удалённые ID в исходном типе запроса (число или строка).",
            "example": []
          },
          "400": {
            "type": "array",
            "items": {},
            "description": "ID с ошибкой: объект не найден, недоступен или удаление запрещено.",
            "example": []
          },
          "500": {
            "type": "array",
            "items": {},
            "description": "ID с серверной ошибкой; текущая реализация возвращает пустой список.",
            "example": []
          }
        },
        "required": [
          "200",
          "400",
          "500"
        ]
      },
      "TerminalsResponseResult": {
        "type": "object",
        "description": "Результат выполнения запроса.",
        "properties": {
          "count": {
            "type": "integer",
            "minimum": 0,
            "description": "Количество собственных площадок.",
            "example": 1
          },
          "terminals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TerminalResponse"
            },
            "description": "Площадки собственных складов.",
            "example": []
          },
          "partners_terminals": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TerminalResponse"
            },
            "description": "Площадки партнёрских складов.",
            "example": []
          }
        },
        "required": [
          "count",
          "partners_terminals",
          "terminals"
        ]
      },
      "TerminalScheduleRequest": {
        "type": "object",
        "description": "Рабочий интервал или перерыв площадки в указанный день недели.",
        "properties": {
          "day_of_week": {
            "allOf": [
              {
                "$ref": "#/components/schemas/DayOfWeekEnum"
              }
            ],
            "description": "День недели\n\n* `1` - пн\n* `2` - вт\n* `3` - ср\n* `4` - чт\n* `5` - пт\n* `6` - сб\n* `7` - вс",
            "title": "День недели",
            "example": "1"
          },
          "time_from": {
            "type": "string",
            "format": "time",
            "title": "Время работы с",
            "description": "Начало интервала в локальном времени склада. На входе ЧЧ:ММ или ЧЧ:ММ:СС, на выходе ЧЧ:ММ:СС.",
            "example": "08:00:00"
          },
          "time_to": {
            "type": "string",
            "format": "time",
            "title": "Время работы по",
            "description": "Конец интервала в локальном времени склада. На входе ЧЧ:ММ или ЧЧ:ММ:СС, на выходе ЧЧ:ММ:СС.",
            "example": "18:00:00"
          },
          "is_break": {
            "type": "boolean",
            "nullable": true,
            "title": "Перерыв?",
            "description": "Перерыв?",
            "example": false
          }
        },
        "required": [
          "day_of_week",
          "time_from",
          "time_to"
        ]
      },
      "TerminalContactRequest": {
        "type": "object",
        "description": "Контактное лицо площадки.",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "title": "Имя",
            "maxLength": 255,
            "description": "Имя",
            "example": "string"
          },
          "phone": {
            "type": "string",
            "minLength": 1,
            "title": "Номер телефона",
            "maxLength": 26,
            "description": "Номер телефона",
            "example": "string"
          },
          "country_phone_id": {
            "type": "string",
            "minLength": 1,
            "title": "Код страны для телефона",
            "maxLength": 10,
            "description": "Код страны для телефона",
            "example": "string"
          }
        },
        "required": [
          "country_phone_id",
          "name",
          "phone"
        ]
      },
      "LoadingTypeEnum": {
        "enum": [
          "any",
          "up",
          "lateral"
        ],
        "type": "string",
        "description": "* `any` - Любая\n* `up` - Сверху\n* `lateral` - Боковая"
      },
      "TerminalUpsertResponseResult": {
        "type": "object",
        "description": "Результат выполнения запроса.",
        "properties": {
          "terminal": {
            "allOf": [
              {
                "$ref": "#/components/schemas/TerminalResponse"
              }
            ],
            "description": "Созданная или изменённая площадка.",
            "example": {
              "id": 1,
              "schedule": [],
              "contacts": [],
              "warehouse_cargo_types": [],
              "name": "string",
              "loading_type": "any",
              "date_creation": "2030-01-01T07:00:00Z",
              "date_modified": "2030-01-01T07:00:00Z",
              "deleted": false,
              "is_test": false,
              "warehouse": 1
            }
          }
        },
        "required": [
          "terminal"
        ]
      },
      "TerminalResponse": {
        "type": "object",
        "description": "Площадка склада с расписанием, контактами и типами грузов.",
        "properties": {
          "id": {
            "type": "integer",
            "readOnly": true,
            "description": "ID",
            "example": 1
          },
          "schedule": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TerminalScheduleRequest"
            },
            "readOnly": true,
            "description": "Расписание площадки; после удаления пустое.",
            "example": []
          },
          "contacts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TerminalContact"
            },
            "description": "Контакты площадки; при изменении заменяются целиком, [] очищает список.",
            "example": []
          },
          "warehouse_cargo_types": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WarehouseCargoTypesResponse"
            },
            "readOnly": true,
            "description": "Принимаемые типы грузов склада.",
            "example": []
          },
          "name": {
            "type": "string",
            "title": "Название площадки",
            "maxLength": 280,
            "description": "Название площадки",
            "example": "string"
          },
          "loading_type": {
            "allOf": [
              {
                "$ref": "#/components/schemas/LoadingTypeEnum"
              }
            ],
            "description": "Тип загрузки\n\n* `any` - Любая\n* `up` - Сверху\n* `lateral` - Боковая",
            "title": "Тип загрузки",
            "example": "any"
          },
          "date_creation": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "title": "Дата создания",
            "description": "Дата создания",
            "example": "2030-01-01T07:00:00Z"
          },
          "date_modified": {
            "type": "string",
            "format": "date-time",
            "readOnly": true,
            "title": "Дата редактирования",
            "description": "Дата редактирования",
            "example": "2030-01-01T07:00:00Z"
          },
          "deleted": {
            "type": "boolean",
            "title": "Удален",
            "description": "Удален",
            "example": false
          },
          "is_test": {
            "type": "boolean",
            "title": "Тестовый",
            "description": "Тестовый",
            "example": false
          },
          "warehouse": {
            "type": "integer",
            "title": "Склад",
            "description": "Идентификатор склада. Источник: GET /gw/timeslots/api/v1/warehouse, поле result.warehouses[].id или result.partners_warehouses[].id. При создании склада: POST /gw/timeslots/api/v1/warehouse, поле result.warehouse.id. Используйте неудалённый склад, доступный для выбранной операции.",
            "example": 1
          }
        },
        "required": [
          "contacts",
          "date_creation",
          "date_modified",
          "id",
          "name",
          "schedule",
          "warehouse",
          "warehouse_cargo_types"
        ]
      },
      "DayOfWeekEnum": {
        "enum": [
          "1",
          "2",
          "3",
          "4",
          "5",
          "6",
          "7"
        ],
        "type": "string",
        "description": "* `1` - пн\n* `2` - вт\n* `3` - ср\n* `4` - чт\n* `5` - пт\n* `6` - сб\n* `7` - вс"
      },
      "TerminalContact": {
        "type": "object",
        "description": "Контактное лицо площадки.",
        "properties": {
          "id": {
            "type": "integer",
            "readOnly": true,
            "description": "ID",
            "example": 1
          },
          "name": {
            "type": "string",
            "title": "Имя",
            "maxLength": 255,
            "description": "Имя",
            "example": "string"
          },
          "phone": {
            "type": "string",
            "title": "Номер телефона",
            "maxLength": 26,
            "description": "Номер телефона",
            "example": "string"
          },
          "country_phone_id": {
            "type": "string",
            "title": "Код страны для телефона",
            "maxLength": 10,
            "description": "Код страны для телефона",
            "example": "string"
          }
        },
        "required": [
          "country_phone_id",
          "id",
          "name",
          "phone"
        ]
      },
      "WarehouseCargoTypesResponse": {
        "type": "object",
        "description": "Тип груза, принимаемый складом, и его настройки.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "readOnly": true,
            "description": "Id",
            "example": "11111111-1111-4111-8111-111111111111"
          },
          "name": {
            "type": "string",
            "readOnly": true,
            "description": "Название типа груза на языке запроса.",
            "example": "string"
          },
          "approved_by_warehouse_owner": {
            "type": "boolean",
            "title": "Владелец склада начал принимать созданный кем то тип груза к себе на склад",
            "description": "Владелец склада начал принимать созданный кем то тип груза к себе на склад",
            "example": false
          },
          "type_id": {
            "type": "integer",
            "maximum": 2147483647,
            "minimum": -2147483648,
            "title": "Айдишник соответствующий общему словарю АТИ",
            "description": "Айдишник соответствующий общему словарю АТИ",
            "example": 1
          },
          "warehouse": {
            "type": "integer",
            "title": "Склад",
            "description": "Склад",
            "example": 1
          }
        },
        "required": [
          "id",
          "name",
          "type_id",
          "warehouse"
        ]
      }
    },
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Authorization: Bearer {authorizationToken}"
      }
    }
  }
}