spectaxi

Конечный автомат заказа и платежа (MVP)

1) Цель

Переходы статусов по USER_SCENARIOS.md.

2) Состояния заказа

3) Возврат на поиск (пока не in_progress)

Пока заказ не в in_progress, срыв матча не хоронит заказ: тот же orders, статус published, клиент ищет другого. Полную отмену делает только клиент (или система / админ).

Возврат на поиск:

После in_progress заказ в published не возвращается.

4) Допустимые переходы

Нельзя:

Не меняют статус заказа (остаётся published):

409 INVALID_STATE_TRANSITION
409 ORDER_NO_LONGER_RELEVANT
409 CANCEL_NOT_ALLOWED
409 DISPUTE_NOT_ALLOWED
409 APPEAL_LIMIT_REACHED / 409 APPEAL_NOT_ALLOWED

4.1) Плановый заказ до даты начала

После «подтвердить условия» плановый заказ сразу in_progress, хотя работа начнётся в planned_start_at. До этого момента обе стороны могут отменить заказ с причиной (коды — как для awaiting_payment, CANCELLATION_REASONS.md), заказ → cancelled, холд при сделке возвращается. Отменил исполнитель — клиенту уведомление с «искать снова?».

С момента planned_start_at — только спор. У срочного заказа окна отмены нет.

4.2) Исполнитель не найден

Заказ в published без ожидающего кандидата автоматически отменяется системой:

cancelled_by_role = system, причины нет, штрафа нет, клиенту уведомление с «искать снова?».

5) Платёж (secure_deal)

Режим расчёта клиент выбирает на экране отправки запроса. secure_deal при выключенном secure_deal_enabled → 409 SECURE_DEAL_DISABLED.

Холд создаётся после «подтвердить условия», на awaiting_payment, когда клиент открыл оплату. Сумма всегда order_pricing.computed_amount, клиент сумму не передаёт. Пока клиент не создал платёж, у провайдера нет холда и нечего возвращать.

Истечение наших суток без оплаты → заказ published (поиск исполнителя), платёж cancelled, клиенту −3, без disputed и без cancelled заказа.

Правка деталей или отклонение партнёра на awaiting_payment: отменить pending / вернуть холд, если уже есть.

expires_at провайдера имеет смысл только при authorized. Тогда возврат холда провайдером → заказ disputed, ждём админа.

Открытый вопрос (срок холда). У провайдера холд живёт ограниченное время. Если работа длиннее (тариф month, большое количество day), холд истечёт раньше completed, и заказ уйдёт в disputed автоматически. Нужно проверить, позволяет ли ЮKassa задавать срок холда под заказ; до ответа ограничений на безопасную сделку по тарифу не вводим. Зафиксировано в PRODUCT_FOUNDATION.md, раздел 12.

Оба подтвердили completed (или автоподтверждение) — выплата (captured). После captured платформа больше не двигает деньги: админ в споре может только санкции (рейтинг, блокировка), не возврат и не повторную выплату.

Закрытие спора админом:

6) Кандидаты, версии, повтор

На один заказ не более одного кандидата notified. Статуса viewed нет: открытие из уведомления ничего не меняет. Принял — принял, отказал — отказал, не ответил за 5 минут — это отказ.

Статусы кандидата: notified, accepted, declined, auto_declined, expired, withdrawn, negotiation_rejected, terms_expired.

Повтор тому же исполнителю на этот заказ:

Первый ответ: response_deadline_at = notified_at + 5 минут. Плановый заказ — тот же таймер.

Подтверждение условий: terms_confirm_deadline_at = момент входа в in_negotiation + 1 сутки (сбрасывается при правке деталей). Не подтвердил — кандидат terms_expired, заказ published, исполнитель скрыт, исполнителю −3.

details_version начинается с 1 при переходе в in_negotiation. Правка заказчика: +1, order_pricing пересчитывается по текущим ставкам машины, исполнителю уведомление. «Подтвердить условия» передаёт details_version; несовпадение — 409 STALE_ORDER_DETAILS. Изменение ставок исполнителем на машине само по себе заказ не трогает.

order_assignment при «подтвердить условия». При возврате на поиск назначение снимается.

execution_confirmed_by_client_at / execution_confirmed_by_executor_at: когда оба не null — completed. Если один подтвердил, второй молчит 1 сутки — автоподтверждение. execution_confirm_deadline_at = время первого из двух подтверждений + 1 сутки; это внутренний таймер для автоприёмки, пользователю не показывается и к отзывам не относится. Если до истечения таймера открыт спор — таймер отменяется, заказ disputed.

Repeat: с cancelled; с completed после фиксации исполнения. С published после срыва матча repeat не нужен — это тот же заказ.

6.1) Несколько запросов одному исполнителю

Календаря занятости нет, поэтому одному исполнителю могут одновременно висеть запросы от разных клиентов (по одному ожидающему на каждый заказ). Флаг «принимаю срочные заказы» и автоотказ работают на уровне исполнителя, не отдельной машины.

Исполнитель принял срочный заказ:

Исполнитель принял плановый заказ — остальные запросы (срочные и плановые) не трогаем.

Штрафа за auto_declined нет. Флаг «принимаю срочные заказы» при этом не меняется: снимает и ставит его только сам исполнитель.

7) Диаграмма

stateDiagram-v2
    [*] --> draft: save_draft
    [*] --> published: send_request

    draft --> published: publish
    draft --> cancelled: discard_draft

    published --> in_negotiation: accept_request
    published --> cancelled: client_cancel_or_not_found

    in_negotiation --> published: reject_partner
    in_negotiation --> published: terms_timeout
    in_negotiation --> cancelled: client_cancel
    in_negotiation --> awaiting_payment: confirm_terms_secure
    in_negotiation --> in_progress: confirm_terms_direct

    awaiting_payment --> in_negotiation: client_edits_refund
    awaiting_payment --> published: reject_partner_or_unpaid
    awaiting_payment --> in_progress: hold_authorized
    awaiting_payment --> cancelled: client_cancel
    awaiting_payment --> disputed: authorized_hold_expired

    in_progress --> completed: both_confirm_execution
    in_progress --> disputed: open_dispute
    in_progress --> cancelled: planned_before_start

    completed --> disputed: dispute_or_appeal
    cancelled --> disputed: appeal

    disputed --> completed: admin_close
    disputed --> cancelled: admin_close
    disputed --> in_progress: admin_close

Отмена админом возможна из любого статуса, кроме completed (на диаграмме не показана).

8) Аудит

order_status_events: черновик, публикация, запрос, снятие, принять/отказ/автоотказ/таймаут, правки деталей, подтвердить условия, холд, возврат холда, таймаут неоплаты (возврат в поиск), отмена «исполнитель не найден», подтверждения исполнения, спор, апелляция, отмена (клиент / плановый до начала / админ).

Рейтинг — RATING_PLAN.md. Таймаут 5 минут и таймаут подтверждения условий: исполнителю −3. Неоплата: клиенту −3. Автоотказ, «исполнитель не найден», отмена админом: 0.

9) Feature-флаги