# form: заполнить анкету

> POST /v1/browser/form — несколько полей за один шаг, каждому виду поля свой способ, и сразу отправка

Источник: https://docs.parreq.com/browser-form/

Заполняет несколько полей за одно обращение и, если попросить, нажимает кнопку
отправки тем же шагом.

**Цена:** 1 кредит за шаг — независимо от того, сколько в нём полей. Работа тут
одна: страница собирается один раз, в конце.

## Зачем отдельная ручка

Анкета заказа в интернет-магазине — это имя, почта, телефон, город, способ
доставки, способ оплаты, примечание и две галочки согласия. Отдельными вызовами
`fill` это девять обращений, девять ответов со всей страницей и восемь пауз
между ними, каждая из которых приближает сессию к закрытию по простою.

Здесь поля идут подряд, **по порядку списка**. Порядок соблюдается намеренно:
витрины пересчитывают одно поле по другому, и «город» перед «улицей» — не
прихоть, а условие того, что улица вообще появится.

## Запрос

```bash cURL
curl -X POST "https://api.parreq.com/v1/browser/form" \
  -H "Authorization: Bearer pr_ВАШКЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{
        "session_id": "bs_9f2a41c7e8b0",
        "fields": [
          {"ref": "pq3-a1b2c", "value": "Иван Петров"},
          {"ref": "pq4-d3e4f", "value": "+375290001100"},
          {"ref": "pq7-g5h6i", "value": "Самовывоз"},
          {"ref": "pq9-j7k8l", "value": "да"}
        ],
        "submit": "pq12-m9n0o"
      }'
```

```python Python
res = requests.post(
    "https://api.parreq.com/v1/browser/form",
    headers={"Authorization": "Bearer pr_ВАШКЛЮЧ"},
    json={
        "session_id": session,
        "fields": [
            {"ref": fio,   "value": "Иван Петров"},
            {"ref": phone, "value": "+375290001100"},
            {"ref": pickup, "value": "да"},
            {"ref": offer, "value": "да"},
        ],
        "submit": order_button,
    },
    timeout=180,
).json()

for row in res["filled"]:
    print(row["ref"], "→", row.get("got", row.get("error")))
```

```javascript Node
const res = await fetch("https://api.parreq.com/v1/browser/form", {
  method: "POST",
  headers: {
    "Authorization": "Bearer pr_ВАШКЛЮЧ",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    session_id: session,
    fields: [
      { ref: fio, value: "Иван Петров" },
      { ref: phone, value: "+375290001100" },
      { ref: pickup, value: "да" },
    ],
    submit: orderButton,
  }),
}).then((r) => r.json());
```

## Параметры

- **`session_id`** (`string`, обязательно, body):
  Идентификатор сессии из `open`.

- **`fields`** (`array`, обязательно, body):
  Поля анкеты по порядку. Каждое — объект с `ref` и `value`. От одного до
  шестидесяти.

- **`submit`** (`string`, body):
  Ссылка на кнопку, которую нажать после заполнения. Пусто — анкета останется
  заполненной, но не отправленной.

- **`include`** (`string`, по умолчанию `buttons,fields`, body):
  Что вернуть после заполнения. Те же значения, что и в `open`.

## Что означает `value`

Зависит от того, что за поле — смотрите `field` в [списке
элементов](https://docs.parreq.com/browser-elements).

| `field` | Что писать в `value` |
|---|---|
| `text`, `tel`, `email`, `password`, `number`, `textarea` | текст; вводится посимвольно |
| `select` | подпись пункта: `"Самовывоз"`. Совпадение сперва точное, потом по вхождению |
| `radio`, `checkbox` | `да` — выбрать, `нет` — снять |

> **Внимание.**
>   Радиокнопку снять нельзя: её отменяет только выбор соседней в той же группе.
>   На `нет` она честно останется выбранной, и это будет видно в `got` — вместо
>   того, чтобы сделать вид, что сняли.
>
>   Уже выбранный переключатель повторным `да` не трогается. Иначе анкета,
>   заполненная дважды, оказалась бы пустой.

## Ответ

```json
{
  "filled": [
    {"ref": "pq3-a1b2c", "value": "Иван Петров", "typed": 11, "got": "Иван Петров"},
    {"ref": "pq4-d3e4f", "value": "+375290001100", "typed": 13, "got": "+375 (29) 000-11-00"},
    {"ref": "pq7-g5h6i", "value": "да", "typed": 0, "got": "да"},
    {"ref": "pq8-x0y1z", "value": "мимо", "error": "поля pq8-x0y1z нет на странице…"}
  ],
  "submitted": "pq12-m9n0o",
  "settled": {"settled": true, "reason": "страница догрузилась…"},
  "credits": 1
}
```

- **`filled[].got`** (`string`):
  Что оказалось в поле **на самом деле**. Сверяйте с `value`: маска ввода,
  `maxlength` и обработчик на странице могли его переписать. В примере выше
  телефон уехал в поле цифрами, а вернулся в маске — это нормально, и агент
  должен видеть именно возвращённое.

- **`filled[].typed`** (`integer`):
  Сколько знаков набрано. У списка и переключателя — ноль: вводом там дело не
  решается.

- **`filled[].error`** (`string`):
  Почему поле не заполнилось. Промах по одному полю **не отменяет остальных**:
  анкета, заполненная на пять шестых, полезнее пустой, а какое поле не легло —
  видно здесь.

- **`submitted`** (`string`):
  Какая кнопка нажата. Приходит, только если `submit` был задан и нажатие
  прошло; иначе на её месте `submit_error`.

## Оформление заказа целиком

Живой пример: один дешёвый товар, самовывоз, оплата при получении.

```python
# 1. Товар в корзину
page = browser_open("https://shop.example/catalog/lenta/")
to_cart = ref_of(page, "В корзину")
browser_click(session, to_cart)

# 2. К оформлению
page = browser_open("https://shop.example/order/")

# 3. Покупатель — одним шагом, и сразу «Продолжить»
page = browser_form(session, [
    {"ref": ref_of(page, "Ф.И.О."),   "value": "Иван Петров"},
    {"ref": ref_of(page, "E-Mail"),   "value": "ivan@example.com"},
    {"ref": ref_of(page, "Телефон"),  "value": "+375290001100"},
    {"ref": ref_of(page, "Продолжая, вы соглашаетесь с публичной офертой"),
     "value": "да"},
], submit=ref_of(page, "Продолжить"))

# 4. Способы доставки и оплаты появляются только после шага «Покупатель»
page = browser_click(session, ref_of(page, "Изменить"))

# 5. Самовывоз, оплата при получении, примечание — и отправка
page = browser_form(session, [
    {"ref": ref_of(page, "Самовывоз"),          "value": "да"},
    {"ref": ref_of(page, "Наличными, картой"),  "value": "да"},
    {"ref": ref_of(page, "Комментарии к заказу:"), "value": "самовывоз со склада"},
], submit=ref_of(page, "Оформить заказ"))
```

> **Примечание.**
>   Разделы анкеты открываются по очереди: способы доставки и оплаты на витринах
>   Битрикса появляются в разметке только после того, как заполнен покупатель.
>   Поэтому шагов два, а не один, и `ref` для второго берутся из ответа первого —
>   ссылки предыдущего списка после перерисовки уже не действуют.

## Частые отказы

| Код | Что делать |
|---|---|
| `element_not_found` | Поле или кнопка исчезли после перерисовки — возьмите свежий `elements` |
| `element_disabled` | Поле отключено: скорее всего, ждёт заполнения другого |
| `option_not_found` | В списке нет такого пункта; доступные перечислены в сообщении |
| `session_not_found` | Сессия закрылась — откройте новую |

Отказ по одному полю приходит в его строке `filled[].error` и шаг не отменяет.
Отказ по сессии — общий, и тогда `filled` не приходит вовсе.

## Дальше

**[Элементы и ссылки](https://docs.parreq.com/browser-elements)**
    Что такое `field`, `group`, `checked` и `options`.

**[fill](https://docs.parreq.com/browser-fill)**
    Одно поле, когда оно и вправду одно.
