Инструменты пользователя

Инструменты сайта


sharixopen:knowledge:scenarios:order_create

Это старая версия документа!


Создание заказа через API: транзакция, ответ и внешние события

Область: ShariX Open, проверенный API-путь. Основание: опубликованные backend/tickets/webapp исходники от 29.10.2026. Фактический серверный сценарий этим source-анализом не выполнен.

Участники и предусловия

Интегратор или клиент вызывает POST /dbsynce/api/v1/orders/ установленной сборки ShariX Open. Маршрут создаётся в root core/urls.py → dbsynce.urls → apiviews/open_api.py при включённом DBSYNCE_OPEN_API_ENABLED. Не переносить этот endpoint автоматически на Platform.

OpenAPIBaseView допускает authenticated user либо HasAPIKey. Но создание использует request.user и предметные проверки заказчика/объектов: API key не является универсальной заменой actor. Инициатор должен иметь разрешённые основание заказа, тариф и связанные сущности. Self-order и корпоративный заказ имеют разные проверки; self-order нельзя одновременно оформить от организации.

Последовательность операции

  1. create_order_from_payload внутри transaction.atomic нормализует режим draft/place, self-order и доступные сущности. Проверяет заказчика, получателя/его снимок, время, количество, длительность и маршрут. Отсутствующий тариф или недоступное сочетание не обходят подбором произвольного ID.
  2. Создаётся Orders. Сохранённый order.pk назначает БД; чтение последней строки для вычисления нового ID не используется.
  3. Создаётся SERVICE_REQUEST Ticket: draft → TEMPLATE, place → BOOKED. Subscription-category принудительно создаётся как place; её entitlement нельзя отложить до произвольного будущего размещения.
  4. Ticket связывается с заказом; вызывается initialize_order_execution через зарегистрированный integration port. Наличие этого вызова не доказывает одинаковый набор Stage у всех сервисов.
  5. При place и заданном исполнителе вызывается ACTION_ASSIGN_CREATED. Отказ назначения добавляет предупреждение, а не обязательно отменяет созданный заказ. В частности, конфликт занятого исполнителя или незавершённые требования отличают запись заказа от успешного назначения.
  6. Внутри операции планируются события; после commit выполняются callbacks. Ticket wakeup — ticket.changed, а при каноническом переходе прежний owner получает ticket.moved. schedule_order_mobile_event перечитывает сохранённый заказ и предпринимает доставку мобильного события; транспортный отказ не равен откату уже committed заказа.
  7. HTTP view получает snapshot по order.pk и возвращает 201, success, message, warnings и order. Проверяется содержимое warnings и фактическое состояние, а не один код ответа.

BPMN: границы транзакции и ответа

Описательная схема isExecutable=false. Свёрнутый task создания раскрыт шагами выше; схема не является runtime-кодом и не заменяет Blockly алгоритмы последующих обработчиков.

Схема BPMN

Загрузка схемы…

Исходник схемы
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_OrderCreateAPISource20261029" targetNamespace="urn:sharix:knowledge:handlers">
  <bpmn:process id="backend_Process_backend" name="ShariX Open: API создания заказа" isExecutable="false">
    <bpmn:documentation>{"notes": ["Схема свёрнута до границ HTTP/транзакции/событий. Ветви draft/place, subscription и назначения описаны рядом. Callback не гарантирует доставку. Аутентификация APIView предшествует операции; ошибка до commit откатывает её записи."], "sources": [{"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "models/orders.py", "repository": "sharix-open-backend", "sha256": "4a5dbbec8a62ed3ca933ae5494032ba2a8a4369c7c1ece4011c98755df23faf2"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/open_order_api.py", "repository": "sharix-open-backend", "sha256": "8950a4169a352db3d250c9e08f6de7a4fa2a31985a247541411e20bd224ca2b6"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/ticket_gen.py", "repository": "sharix-open-backend", "sha256": "7bdf92007916aec7e968a45f142e5f98fffb5dfe9b61ee7fcae3c65c826dfbde"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_actions.py", "repository": "sharix-open-backend", "sha256": "27ce243408a46f1b700d94bf78a25c68ef21d51078bb03627174e4a424d82ef0"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_permissions.py", "repository": "sharix-open-backend", "sha256": "9c1636daa80c4da68c3ae5cf347e279127d142eeff91e969559e8bd54ca3d81d"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/mobile_order_events.py", "repository": "sharix-open-backend", "sha256": "818b21d471b629dcae3d96ee089e0f83406a41d03ad36a6c4ddabdf8857f2e68"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/integration_ports.py", "repository": "sharix-open-backend", "sha256": "d079ec56e6709b29d7755e47d2a88d423235fe8eb1bf7a92851ae25d74bf1066"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "apiviews/open_api.py", "repository": "sharix-open-backend", "sha256": "cb8fdda304d29c2cc5c0fc938759a13c60022871b7b93d77883d521820021ad3"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "urls.py", "repository": "sharix-open-backend", "sha256": "61ffd2f0563291da2dcc9488a5443cb5e2c0395108740a6700034cfd90548158"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "signals.py", "repository": "sharix-open-tickets", "sha256": "39aad8690a2e7d35cebfb052127a8130a951cbb4eea316c4f767a0a59fc5fa7e"}]}</bpmn:documentation>
    <bpmn:laneSet id="backend_Lanes_backend">
      <bpmn:lane id="backend_Lane_api" name="HTTP и транзакционная операция">
        <bpmn:flowNodeRef>backend_start</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_create</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_commit</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_callbacks</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_response</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_error</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_classify</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_known</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_other</bpmn:flowNodeRef>
      </bpmn:lane>
    </bpmn:laneSet>
    <bpmn:startEvent id="backend_start" name="POST orders">
      <bpmn:outgoing>backend_Flow_0</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:serviceTask id="backend_create" name="Проверить и создать заказ (atomic)">
      <bpmn:incoming>backend_Flow_0</bpmn:incoming>
      <bpmn:outgoing>backend_Flow_1</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:serviceTask id="backend_commit" name="Commit: Order/Ticket/execution">
      <bpmn:incoming>backend_Flow_1</bpmn:incoming>
      <bpmn:outgoing>backend_Flow_2</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:serviceTask id="backend_callbacks" name="on_commit: отправить события">
      <bpmn:incoming>backend_Flow_2</bpmn:incoming>
      <bpmn:outgoing>backend_Flow_3</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:endEvent id="backend_response" name="201: snapshot и warnings">
      <bpmn:incoming>backend_Flow_3</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:boundaryEvent id="backend_error" name="Исключение" attachedToRef="backend_create" cancelActivity="true">
      <bpmn:outgoing>backend_Flow_4</bpmn:outgoing>
      <bpmn:errorEventDefinition />
    </bpmn:boundaryEvent>
    <bpmn:exclusiveGateway id="backend_classify" name="Тип отказа?">
      <bpmn:incoming>backend_Flow_4</bpmn:incoming>
      <bpmn:outgoing>backend_Flow_5</bpmn:outgoing>
      <bpmn:outgoing>backend_Flow_6</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:endEvent id="backend_known" name="ValidationError 400; PermissionDenied 403">
      <bpmn:incoming>backend_Flow_5</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:endEvent id="backend_other" name="Прочие исключения: нет гарантии ответа 400">
      <bpmn:incoming>backend_Flow_6</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="backend_Flow_0" sourceRef="backend_start" targetRef="backend_create" name="" />
    <bpmn:sequenceFlow id="backend_Flow_1" sourceRef="backend_create" targetRef="backend_commit" name="" />
    <bpmn:sequenceFlow id="backend_Flow_2" sourceRef="backend_commit" targetRef="backend_callbacks" name="" />
    <bpmn:sequenceFlow id="backend_Flow_3" sourceRef="backend_callbacks" targetRef="backend_response" name="" />
    <bpmn:sequenceFlow id="backend_Flow_4" sourceRef="backend_error" targetRef="backend_classify" name="" />
    <bpmn:sequenceFlow id="backend_Flow_5" sourceRef="backend_classify" targetRef="backend_known" name="Явно обработан" />
    <bpmn:sequenceFlow id="backend_Flow_6" sourceRef="backend_classify" targetRef="backend_other" name="Иной отказ" />
  </bpmn:process>
  <bpmn:collaboration id="Collaboration_OrderCreateAPISource20261029">
    <bpmn:participant id="backend_Pool_backend" name="ShariX Open: API создания заказа" processRef="backend_Process_backend" />
  </bpmn:collaboration>
  <bpmndi:BPMNDiagram id="Diagram_OrderCreateAPISource20261029">
    <bpmndi:BPMNPlane id="Plane_OrderCreateAPISource20261029" bpmnElement="Collaboration_OrderCreateAPISource20261029">
      <bpmndi:BPMNShape id="backend_DI_Pool_backend" bpmnElement="backend_Pool_backend" isHorizontal="true">
        <dc:Bounds x="0.0" y="0.0" width="1330" height="550" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_Lane_api" bpmnElement="backend_Lane_api" isHorizontal="true">
        <dc:Bounds x="30.0" y="0.0" width="1300" height="550" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_start" bpmnElement="backend_start">
        <dc:Bounds x="112.0" y="112.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_create" bpmnElement="backend_create">
        <dc:Bounds x="295.0" y="95.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_commit" bpmnElement="backend_commit">
        <dc:Bounds x="565.0" y="95.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_callbacks" bpmnElement="backend_callbacks">
        <dc:Bounds x="835.0" y="95.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_response" bpmnElement="backend_response">
        <dc:Bounds x="1152.0" y="112.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_error" bpmnElement="backend_error">
        <dc:Bounds x="402.0" y="147.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_classify" bpmnElement="backend_classify">
        <dc:Bounds x="345.0" y="265.0" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_known" bpmnElement="backend_known">
        <dc:Bounds x="682.0" y="272.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="backend_DI_other" bpmnElement="backend_other">
        <dc:Bounds x="352.0" y="432.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="backend_DI_Flow_0" bpmnElement="backend_Flow_0">
        <di:waypoint x="148.0" y="130.0" />
        <di:waypoint x="295.0" y="130.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="backend_DI_Flow_1" bpmnElement="backend_Flow_1">
        <di:waypoint x="445.0" y="130.0" />
        <di:waypoint x="565.0" y="130.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="backend_DI_Flow_2" bpmnElement="backend_Flow_2">
        <di:waypoint x="715.0" y="130.0" />
        <di:waypoint x="835.0" y="130.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="backend_DI_Flow_3" bpmnElement="backend_Flow_3">
        <di:waypoint x="985.0" y="130.0" />
        <di:waypoint x="1152.0" y="130.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="backend_DI_Flow_4" bpmnElement="backend_Flow_4">
        <di:waypoint x="420.0" y="183.0" />
        <di:waypoint x="420.0" y="225.0" />
        <di:waypoint x="370.0" y="225.0" />
        <di:waypoint x="370.0" y="265.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="backend_DI_Flow_5" bpmnElement="backend_Flow_5">
        <di:waypoint x="395.0" y="290.0" />
        <di:waypoint x="682.0" y="290.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="backend_DI_Flow_6" bpmnElement="backend_Flow_6">
        <di:waypoint x="370.0" y="315.0" />
        <di:waypoint x="370.0" y="432.0" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>

Отказы и повтор

Django ValidationError преобразуется view в 400, PermissionDenied — в 403. Исключение внутри atomic до commit отменяет её записи. Но callback после commit — другая граница: данные уже сохранены. Не объявлять атомарность БД гарантией exactly-once доставки сети или rollback внешних систем.

Неизвестный creation_mode вызывает ValueError, который эта view явно не ловит. Это зафиксированное ограничение, а не готовый исправленный ответ 400. Серверные ошибки также не следует описывать как обязательный отказ валидации.

Если клиент не получил ответ на POST, повторная отправка может создать второй заказ: в изученной операции не найден отдельный контракт client idempotency key. Сначала установить результат по доступным записям/истории и контексту запроса. Нельзя вычислить успех по максимальному ID или отправить создание ещё раз только из-за таймаута.

HTML-форма — отдельный путь

sharix_admin.views.order.OrderCreateView.form_valid не вызывает целиком create_order_from_payload: она собирает модель через OrderForm и выполняет собственный atomic блок, используя общие ticket/action/execution primitives. У неё есть дополнительные subscription/extension шаги. Поэтому изменение только API не доказывает исправление формы, и наоборот. Согласованность этих путей проверяют отдельными сценариями; не переписывают документацию так, будто общей orchestration уже достаточно.

Проверка при изменении

На предназначенной тестовой установке проверить допустимое создание и доступность snapshot; draft и place; запрет чужих объектов/корпоративного контекста; self-order; отказ назначения с сохранением заказа и предупреждением; rollback при ошибке execution; событие только после commit. HTTP-ошибки проверить отдельно, включая неизвестный mode. Для HTML повторить затронутый form-сценарий. Чтение чужого заказа и запись зеркальных полей через local endpoint не должны становиться обходным путём; известное расхождение OrdersLocal/order_synced описано отдельно.

Эта матрица — порядок приёмки изменения, не отчёт о якобы выполненных здесь runtime-тестах.

Связанные контракты

Проверенная исходная база: 29.10.2026

Проверены опубликованные исходники указанных ревизий. Это source-анализ; он не подтверждает применённую версию, конфигурацию или успешный сценарий конкретного сервера.

sharixopen/knowledge/scenarios/order_create.1793262621.txt.gz · Последнее изменение: — sx_knowledge_api_open

© 2022 ShariX