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

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


sharixopen:knowledge:scenarios:service_request_template

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


SERVICE_REQUEST в TEMPLATE: черновик, действия клиента и напоминания

Назначение: Сценарий процесса. Продукт: ShariX Open.

Для кого: Разработчик · Поддержка · Рецензент и приёмщик · Нейросеть.

Темы: Заказы → Создание и черновик · Заказы → Жизненный цикл · Обработчики → Runtime.

Область: ShariX Open. Обработчик: open_service_request_template, тип SERVICE_REQUEST (2), рабочий статус TEMPLATE (210). 31.10.2026 опубликованные исходники повторно получены из Git. Обе Python-копии заново сопоставлены с результатом генерации Blockly; проверены 11 исходников генераторов. Сам handler не исполнялся. Выбранную версию, конфигурацию и внешние подключения сервера проверяют отдельно.

Назначение и границы

Handler сопровождает существующий черновик:

  • принимает допустимое пользовательское намерение;
  • проверяет срок автоматического закрытия;
  • при необходимости напоминает автору о размещении;
  • освобождает worker до следующего прохода.

Новый заказ здесь не создаётся. Наличие черновика само по себе не запускает фоновый выбор исполнителя.

Приоритет действий в TEMPLATE:

  1. Сначала обработать разрешённый book/cancel.
  2. При успешном действии или stale scope завершить проход.
  3. Если intent отсутствует или каноническое действие отклонено — продолжить проверку черновика.
  4. Только затем проверить срок автоматического закрытия.

Дата закрытия не является предварительным фильтром перед всеми пользовательскими намерениями.

SERVICE_REQUEST не должен менять бизнес-состояние через универсальный ticket.transition: каталог TEMPLATE объявляет узкие order.context, order.apply_user_intent, order.close_template и необходимые read/notification возможности. Backend order actions проверяют актуальный заказ и его lifecycle.

BPMN имеют isExecutable=false. Wiki не исполняет процесс: runtime запускает выбранный проверенный Python, сгенерированный из Blockly. End event завершает показанный проход/операцию, а не гарантирует выполнение услуги.

Один проход и локальное ожидание (BPMN)

Схема BPMN

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

Исходник схемы
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:ns2="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:ns3="http://www.omg.org/spec/DD/20100524/DC" xmlns:ns4="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="Definitions_service_template_logic" targetNamespace="urn:sharix:knowledge:handlers">
  <bpmn:process id="template_Process_template" name="open_service_request_template: пользовательский intent, срок закрытия, напоминание" isExecutable="false">
    <bpmn:documentation>{"notes": ["Git built-in; BPMN isExecutable=false. Handler при генерации не исполняется.", "Дата закрытия считается runtime: planned_start + SERVICE_REQUEST_TEMPLATE_CLOSE_AFTER_START_SECONDS.", "Intent-очередь, дедупликация и reminder counters — в памяти, не durable delivery guarantee."], "sources": [{"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_service_request_template.py", "repository": "sharix-open-handlers-examples", "sha256": "a5e86f4580c8add4b05c6e58fa33306f5b4a2419d0951523afb996bff6e9e51b"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_service_request_template.json", "repository": "sharix-open-handlers-examples", "sha256": "6fb731e413f8fb8709e0b1e578a1da883c1d5a46ce291675114b32ec52619925"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "catalog.py", "repository": "sharix-open-handlers-examples", "sha256": "e3dcb72b7e620e2837adacd7af053f35b04cdff475789496d9c114e17d57dfde"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/blockly_runtime.py", "repository": "sharix-open-handlers-backend", "sha256": "3e222150cbff315077c6c9b160d46e59856cedf6d6591d213e958c63cb2f2428"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/requesters.py", "repository": "sharix-open-handlers-backend", "sha256": "965a348cea477722bbaf4c8c6b06023eb238b71664a332f7ea8c90bfe72ea808"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/order_action_messages.py", "repository": "sharix-open-handlers-backend", "sha256": "046c262c0aabb02104fefca4e887324f99df22731e7726063f614aaf8839ca5c"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "ticket_blockly_codegen.py", "repository": "sharix-open-handlers-backend", "sha256": "bce71eab622922f8dd0954222842349799b60e18a0ab6310cc3e5f305603661e"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "ticket_codegen_contract.json", "repository": "sharix-open-handlers-backend", "sha256": "0bfd2b0ebb07bd380ed3c867386536ab88ef7dfa6e13f1cd8c91d32bb02c1ae9"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "lib/tickets.py", "repository": "sharix-open-tickets", "sha256": "0d260c17947f9a186d07af2749159780e3c7354a95b4bafe9d67493663c96883"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/handler_auth.py", "repository": "sharix-open-tickets", "sha256": "ac76dc45aaa9742e5e1da0b98aae914bb2e287048d33e97b4a245a6997bc8425"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "signals.py", "repository": "sharix-open-tickets", "sha256": "39aad8690a2e7d35cebfb052127a8130a951cbb4eea316c4f767a0a59fc5fa7e"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "services/handler_wakeup.py", "repository": "sharix-open-tickets", "sha256": "c9fdc62a18301fd7c075395c697d5b1c738c77713aa71fcbb5ab097e173d98de"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "apiviews/handler_order_workflow.py", "repository": "sharix-open-backend", "sha256": "35624ded6e67110437a25dd07caef214a04251eb0136194ae939fa32fef17e84"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "apiviews/open_api.py", "repository": "sharix-open-backend", "sha256": "cb8fdda304d29c2cc5c0fc938759a13c60022871b7b93d77883d521820021ad3"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_handler_relay.py", "repository": "sharix-open-backend", "sha256": "e49a7876169403970d995af464357e2134af19a398372c55db2a5b40681d731e"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/handler_order_context.py", "repository": "sharix-open-backend", "sha256": "f3c0731e74d30dbe5e59bd53040a06ee108f14f7aad04771e65d741cffeb7179"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_workflow_policy.py", "repository": "sharix-open-backend", "sha256": "3266c6ecab490a0e19c8bbc02041387b86fe4b14068750e545ba9bde8bf51326"}, {"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": "urls.py", "repository": "sharix-open-backend", "sha256": "61ffd2f0563291da2dcc9488a5443cb5e2c0395108740a6700034cfd90548158"}]}</bpmn:documentation>
    <bpmn:laneSet id="template_Lanes_template">
      <bpmn:lane id="template_Lane_worker" name="Один проход канонического Python">
        <bpmn:flowNodeRef>template_start</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_status</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_intent</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_handled</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_intent_end</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_stale</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_stale_end</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_context</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_found</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_missing</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_due</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_close</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_close_end</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_reason</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_reminder</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_defer</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_intent_error</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_context_error</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_close_error</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_send_error</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_retry</bpmn:flowNodeRef>
      </bpmn:lane>
      <bpmn:lane id="template_Lane_queue" name="Планировщик: ожидание без занятого worker">
        <bpmn:flowNodeRef>template_wait</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_timer</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_event</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>template_ready</bpmn:flowNodeRef>
      </bpmn:lane>
    </bpmn:laneSet>
    <bpmn:startEvent id="template_start" name="Ticket готов к проходу">
      <bpmn:outgoing>template_Flow_0</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:exclusiveGateway id="template_status" name="Статус TEMPLATE?">
      <bpmn:incoming>template_Flow_0</bpmn:incoming>
      <bpmn:incoming>template_Flow_24</bpmn:incoming>
      <bpmn:outgoing>template_Flow_1</bpmn:outgoing>
      <bpmn:outgoing>template_Flow_2</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:serviceTask id="template_intent" name="Попробовать один доверенный book / cancel">
      <bpmn:documentation>Приоритет перед context/таймером. Backend заново проверяет actor и действие.</bpmn:documentation>
      <bpmn:incoming>template_Flow_1</bpmn:incoming>
      <bpmn:outgoing>template_Flow_4</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:exclusiveGateway id="template_handled" name="Успех или stale?">
      <bpmn:incoming>template_Flow_4</bpmn:incoming>
      <bpmn:outgoing>template_Flow_5</bpmn:outgoing>
      <bpmn:outgoing>template_Flow_6</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:endEvent id="template_intent_end" name="Локальный Ticket уже исключён">
      <bpmn:incoming>template_Flow_5</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:serviceTask id="template_stale" name="Убрать Ticket и комнату">
      <bpmn:incoming>template_Flow_2</bpmn:incoming>
      <bpmn:outgoing>template_Flow_3</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:endEvent id="template_stale_end" name="Прежний владелец освобождён">
      <bpmn:incoming>template_Flow_3</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:serviceTask id="template_context" name="Scoped API: загрузить текущий order context">
      <bpmn:incoming>template_Flow_6</bpmn:incoming>
      <bpmn:outgoing>template_Flow_7</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:exclusiveGateway id="template_found" name="Контекст найден?">
      <bpmn:incoming>template_Flow_7</bpmn:incoming>
      <bpmn:outgoing>template_Flow_8</bpmn:outgoing>
      <bpmn:outgoing>template_Flow_9</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:endEvent id="template_missing" name="404: локальная очистка">
      <bpmn:incoming>template_Flow_8</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:exclusiveGateway id="template_due" name="Наступил template_close_at?">
      <bpmn:incoming>template_Flow_9</bpmn:incoming>
      <bpmn:outgoing>template_Flow_10</bpmn:outgoing>
      <bpmn:outgoing>template_Flow_11</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:serviceTask id="template_close" name="Narrow order action: close-template">
      <bpmn:incoming>template_Flow_10</bpmn:incoming>
      <bpmn:outgoing>template_Flow_25</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:endEvent id="template_close_end" name="Локальный Ticket исключён">
      <bpmn:incoming>template_Flow_25</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:serviceTask id="template_reason" name="Причина awaiting_booking">
      <bpmn:incoming>template_Flow_11</bpmn:incoming>
      <bpmn:outgoing>template_Flow_12</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:sendTask id="template_reminder" name="Напоминание автору, если срок/лимит позволяют">
      <bpmn:incoming>template_Flow_12</bpmn:incoming>
      <bpmn:outgoing>template_Flow_13</bpmn:outgoing>
    </bpmn:sendTask>
    <bpmn:serviceTask id="template_defer" name="SERVICE_REQUEST_TEMPLATE_RECHECK_SECONDS">
      <bpmn:incoming>template_Flow_13</bpmn:incoming>
      <bpmn:outgoing>template_Flow_14</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:boundaryEvent id="template_intent_error" name="Ошибка API" attachedToRef="template_intent" cancelActivity="true">
      <bpmn:outgoing>template_Flow_16</bpmn:outgoing>
      <bpmn:errorEventDefinition />
    </bpmn:boundaryEvent>
    <bpmn:boundaryEvent id="template_context_error" name="Ошибка context API" attachedToRef="template_context" cancelActivity="true">
      <bpmn:outgoing>template_Flow_17</bpmn:outgoing>
      <bpmn:errorEventDefinition />
    </bpmn:boundaryEvent>
    <bpmn:boundaryEvent id="template_close_error" name="Ошибка закрытия" attachedToRef="template_close" cancelActivity="true">
      <bpmn:outgoing>template_Flow_18</bpmn:outgoing>
      <bpmn:errorEventDefinition />
    </bpmn:boundaryEvent>
    <bpmn:boundaryEvent id="template_send_error" name="Ошибка отправки" attachedToRef="template_reminder" cancelActivity="true">
      <bpmn:outgoing>template_Flow_19</bpmn:outgoing>
      <bpmn:errorEventDefinition />
    </bpmn:boundaryEvent>
    <bpmn:serviceTask id="template_retry" name="processing_error + общий defer">
      <bpmn:incoming>template_Flow_16</bpmn:incoming>
      <bpmn:incoming>template_Flow_17</bpmn:incoming>
      <bpmn:incoming>template_Flow_18</bpmn:incoming>
      <bpmn:incoming>template_Flow_19</bpmn:incoming>
      <bpmn:outgoing>template_Flow_15</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:eventBasedGateway id="template_wait" name="Что наступило раньше?">
      <bpmn:incoming>template_Flow_14</bpmn:incoming>
      <bpmn:incoming>template_Flow_15</bpmn:incoming>
      <bpmn:outgoing>template_Flow_20</bpmn:outgoing>
      <bpmn:outgoing>template_Flow_21</bpmn:outgoing>
    </bpmn:eventBasedGateway>
    <bpmn:intermediateCatchEvent id="template_timer" name="Наступил локальный срок defer">
      <bpmn:incoming>template_Flow_20</bpmn:incoming>
      <bpmn:outgoing>template_Flow_22</bpmn:outgoing>
      <bpmn:timerEventDefinition>
        <bpmn:timeDate xsi:type="bpmn:tFormalExpression">deferred_until</bpmn:timeDate>
      </bpmn:timerEventDefinition>
    </bpmn:intermediateCatchEvent>
    <bpmn:intermediateCatchEvent id="template_event" name="Новая ревизия / разрешённый intent">
      <bpmn:incoming>template_Flow_21</bpmn:incoming>
      <bpmn:outgoing>template_Flow_23</bpmn:outgoing>
      <bpmn:messageEventDefinition />
    </bpmn:intermediateCatchEvent>
    <bpmn:serviceTask id="template_ready" name="Сделать Ticket готовым к проходу">
      <bpmn:incoming>template_Flow_22</bpmn:incoming>
      <bpmn:incoming>template_Flow_23</bpmn:incoming>
      <bpmn:outgoing>template_Flow_24</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:sequenceFlow id="template_Flow_0" sourceRef="template_start" targetRef="template_status" name="" />
    <bpmn:sequenceFlow id="template_Flow_1" sourceRef="template_status" targetRef="template_intent" name="Да" />
    <bpmn:sequenceFlow id="template_Flow_2" sourceRef="template_status" targetRef="template_stale" name="Нет" />
    <bpmn:sequenceFlow id="template_Flow_3" sourceRef="template_stale" targetRef="template_stale_end" name="" />
    <bpmn:sequenceFlow id="template_Flow_4" sourceRef="template_intent" targetRef="template_handled" name="" />
    <bpmn:sequenceFlow id="template_Flow_5" sourceRef="template_handled" targetRef="template_intent_end" name="Да" />
    <bpmn:sequenceFlow id="template_Flow_6" sourceRef="template_handled" targetRef="template_context" name="Нет" />
    <bpmn:sequenceFlow id="template_Flow_7" sourceRef="template_context" targetRef="template_found" name="" />
    <bpmn:sequenceFlow id="template_Flow_8" sourceRef="template_found" targetRef="template_missing" name="Нет (404)" />
    <bpmn:sequenceFlow id="template_Flow_9" sourceRef="template_found" targetRef="template_due" name="Да" />
    <bpmn:sequenceFlow id="template_Flow_10" sourceRef="template_due" targetRef="template_close" name="Да" />
    <bpmn:sequenceFlow id="template_Flow_11" sourceRef="template_due" targetRef="template_reason" name="Нет" />
    <bpmn:sequenceFlow id="template_Flow_12" sourceRef="template_reason" targetRef="template_reminder" name="" />
    <bpmn:sequenceFlow id="template_Flow_13" sourceRef="template_reminder" targetRef="template_defer" name="" />
    <bpmn:sequenceFlow id="template_Flow_14" sourceRef="template_defer" targetRef="template_wait" name="" />
    <bpmn:sequenceFlow id="template_Flow_15" sourceRef="template_retry" targetRef="template_wait" name="" />
    <bpmn:sequenceFlow id="template_Flow_16" sourceRef="template_intent_error" targetRef="template_retry" name="" />
    <bpmn:sequenceFlow id="template_Flow_17" sourceRef="template_context_error" targetRef="template_retry" name="" />
    <bpmn:sequenceFlow id="template_Flow_18" sourceRef="template_close_error" targetRef="template_retry" name="" />
    <bpmn:sequenceFlow id="template_Flow_19" sourceRef="template_send_error" targetRef="template_retry" name="" />
    <bpmn:sequenceFlow id="template_Flow_20" sourceRef="template_wait" targetRef="template_timer" name="" />
    <bpmn:sequenceFlow id="template_Flow_21" sourceRef="template_wait" targetRef="template_event" name="" />
    <bpmn:sequenceFlow id="template_Flow_22" sourceRef="template_timer" targetRef="template_ready" name="" />
    <bpmn:sequenceFlow id="template_Flow_23" sourceRef="template_event" targetRef="template_ready" name="" />
    <bpmn:sequenceFlow id="template_Flow_24" sourceRef="template_ready" targetRef="template_status" name="Новый проход" />
    <bpmn:sequenceFlow id="template_Flow_25" sourceRef="template_close" targetRef="template_close_end" name="Успех / stale" />
  </bpmn:process>
  <bpmn:collaboration id="Collaboration_service_template_logic">
    <bpmn:participant id="template_Pool_template" name="open_service_request_template: пользовательский intent, срок закрытия, напоминание" processRef="template_Process_template" />
  </bpmn:collaboration>
  <ns2:BPMNDiagram id="Diagram_service_template_logic">
    <ns2:BPMNPlane id="Plane_service_template_logic" bpmnElement="Collaboration_service_template_logic">
      <ns2:BPMNShape id="template_DI_Pool_template" bpmnElement="template_Pool_template" isHorizontal="true">
        <ns3:Bounds x="0.0" y="0.0" width="2450.0" height="1030.0" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_Lane_worker" bpmnElement="template_Lane_worker" isHorizontal="true">
        <ns3:Bounds x="30.0" y="0.0" width="2420.0" height="637.5" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_Lane_queue" bpmnElement="template_Lane_queue" isHorizontal="true">
        <ns3:Bounds x="30.0" y="637.5" width="2420.0" height="392.5" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_start" bpmnElement="template_start">
        <ns3:Bounds x="132.0" y="92.0" width="36" height="36" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_status" bpmnElement="template_status">
        <ns3:Bounds x="325.0" y="85.0" width="50" height="50" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_intent" bpmnElement="template_intent">
        <ns3:Bounds x="515.0" y="75.0" width="150" height="70" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_handled" bpmnElement="template_handled">
        <ns3:Bounds x="825.0" y="85.0" width="50" height="50" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_intent_end" bpmnElement="template_intent_end">
        <ns3:Bounds x="1092.0" y="92.0" width="36" height="36" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_stale" bpmnElement="template_stale">
        <ns3:Bounds x="275.0" y="275.0" width="150" height="70" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_stale_end" bpmnElement="template_stale_end">
        <ns3:Bounds x="572.0" y="292.0" width="36" height="36" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_context" bpmnElement="template_context">
        <ns3:Bounds x="775.0" y="275.0" width="150" height="70" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_found" bpmnElement="template_found">
        <ns3:Bounds x="1085.0" y="285.0" width="50" height="50" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_missing" bpmnElement="template_missing">
        <ns3:Bounds x="1092.0" y="492.0" width="36" height="36" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_due" bpmnElement="template_due">
        <ns3:Bounds x="1345.0" y="285.0" width="50" height="50" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_close" bpmnElement="template_close">
        <ns3:Bounds x="1555.0" y="275.0" width="150" height="70" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_close_end" bpmnElement="template_close_end">
        <ns3:Bounds x="2132.0" y="292.0" width="36" height="36" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_reason" bpmnElement="template_reason">
        <ns3:Bounds x="1295.0" y="475.0" width="150" height="70" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_reminder" bpmnElement="template_reminder">
        <ns3:Bounds x="1555.0" y="475.0" width="150" height="70" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_defer" bpmnElement="template_defer">
        <ns3:Bounds x="1815.0" y="475.0" width="150" height="70" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_intent_error" bpmnElement="template_intent_error">
        <ns3:Bounds x="622.0" y="127.0" width="36" height="36" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_context_error" bpmnElement="template_context_error">
        <ns3:Bounds x="882.0" y="327.0" width="36" height="36" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_close_error" bpmnElement="template_close_error">
        <ns3:Bounds x="1662.0" y="327.0" width="36" height="36" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_send_error" bpmnElement="template_send_error">
        <ns3:Bounds x="1662.0" y="527.0" width="36" height="36" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_retry" bpmnElement="template_retry">
        <ns3:Bounds x="2075.0" y="475.0" width="150" height="70" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_wait" bpmnElement="template_wait">
        <ns3:Bounds x="1345.0" y="775.0" width="50" height="50" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_timer" bpmnElement="template_timer">
        <ns3:Bounds x="1612.0" y="712.0" width="36" height="36" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_event" bpmnElement="template_event">
        <ns3:Bounds x="1612.0" y="912.0" width="36" height="36" />
      </ns2:BPMNShape>
      <ns2:BPMNShape id="template_DI_ready" bpmnElement="template_ready">
        <ns3:Bounds x="1815.0" y="765.0" width="150" height="70" />
      </ns2:BPMNShape>
      <ns2:BPMNEdge id="template_DI_Flow_0" bpmnElement="template_Flow_0">
        <ns4:waypoint x="168.0" y="110.0" />
        <ns4:waypoint x="325.0" y="110.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_1" bpmnElement="template_Flow_1">
        <ns4:waypoint x="375.0" y="110.0" />
        <ns4:waypoint x="515.0" y="110.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_2" bpmnElement="template_Flow_2">
        <ns4:waypoint x="350.0" y="135.0" />
        <ns4:waypoint x="350.0" y="275.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_3" bpmnElement="template_Flow_3">
        <ns4:waypoint x="425.0" y="310.0" />
        <ns4:waypoint x="572.0" y="310.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_4" bpmnElement="template_Flow_4">
        <ns4:waypoint x="665.0" y="110.0" />
        <ns4:waypoint x="825.0" y="110.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_5" bpmnElement="template_Flow_5">
        <ns4:waypoint x="875.0" y="110.0" />
        <ns4:waypoint x="1092.0" y="110.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_6" bpmnElement="template_Flow_6">
        <ns4:waypoint x="850.0" y="135.0" />
        <ns4:waypoint x="850.0" y="275.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_7" bpmnElement="template_Flow_7">
        <ns4:waypoint x="925.0" y="310.0" />
        <ns4:waypoint x="1085.0" y="310.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_8" bpmnElement="template_Flow_8">
        <ns4:waypoint x="1110.0" y="335.0" />
        <ns4:waypoint x="1110.0" y="492.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_9" bpmnElement="template_Flow_9">
        <ns4:waypoint x="1135.0" y="310.0" />
        <ns4:waypoint x="1345.0" y="310.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_10" bpmnElement="template_Flow_10">
        <ns4:waypoint x="1395.0" y="310.0" />
        <ns4:waypoint x="1555.0" y="310.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_11" bpmnElement="template_Flow_11">
        <ns4:waypoint x="1370.0" y="335.0" />
        <ns4:waypoint x="1370.0" y="475.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_12" bpmnElement="template_Flow_12">
        <ns4:waypoint x="1445.0" y="510.0" />
        <ns4:waypoint x="1555.0" y="510.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_13" bpmnElement="template_Flow_13">
        <ns4:waypoint x="1705.0" y="510.0" />
        <ns4:waypoint x="1815.0" y="510.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_14" bpmnElement="template_Flow_14">
        <ns4:waypoint x="1965.0" y="510.0" />
        <ns4:waypoint x="2010.0" y="510.0" />
        <ns4:waypoint x="2010.0" y="660.0" />
        <ns4:waypoint x="1370.0" y="660.0" />
        <ns4:waypoint x="1370.0" y="775.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_15" bpmnElement="template_Flow_15">
        <ns4:waypoint x="2225.0" y="510.0" />
        <ns4:waypoint x="2280.0" y="510.0" />
        <ns4:waypoint x="2280.0" y="640.0" />
        <ns4:waypoint x="1370.0" y="640.0" />
        <ns4:waypoint x="1370.0" y="775.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_16" bpmnElement="template_Flow_16">
        <ns4:waypoint x="658.0" y="145.0" />
        <ns4:waypoint x="700.0" y="145.0" />
        <ns4:waypoint x="700.0" y="590.0" />
        <ns4:waypoint x="2150.0" y="590.0" />
        <ns4:waypoint x="2150.0" y="475.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_17" bpmnElement="template_Flow_17">
        <ns4:waypoint x="918.0" y="345.0" />
        <ns4:waypoint x="960.0" y="345.0" />
        <ns4:waypoint x="960.0" y="570.0" />
        <ns4:waypoint x="2150.0" y="570.0" />
        <ns4:waypoint x="2150.0" y="475.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_18" bpmnElement="template_Flow_18">
        <ns4:waypoint x="1698.0" y="345.0" />
        <ns4:waypoint x="1740.0" y="345.0" />
        <ns4:waypoint x="2150.0" y="345.0" />
        <ns4:waypoint x="2150.0" y="475.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_19" bpmnElement="template_Flow_19">
        <ns4:waypoint x="1698.0" y="545.0" />
        <ns4:waypoint x="1740.0" y="545.0" />
        <ns4:waypoint x="1740.0" y="600.0" />
        <ns4:waypoint x="2150.0" y="600.0" />
        <ns4:waypoint x="2150.0" y="475.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_20" bpmnElement="template_Flow_20">
        <ns4:waypoint x="1395.0" y="800.0" />
        <ns4:waypoint x="1503.5" y="800.0" />
        <ns4:waypoint x="1503.5" y="730.0" />
        <ns4:waypoint x="1612.0" y="730.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_21" bpmnElement="template_Flow_21">
        <ns4:waypoint x="1395.0" y="800.0" />
        <ns4:waypoint x="1503.5" y="800.0" />
        <ns4:waypoint x="1503.5" y="930.0" />
        <ns4:waypoint x="1612.0" y="930.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_22" bpmnElement="template_Flow_22">
        <ns4:waypoint x="1648.0" y="730.0" />
        <ns4:waypoint x="1731.5" y="730.0" />
        <ns4:waypoint x="1731.5" y="800.0" />
        <ns4:waypoint x="1815.0" y="800.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_23" bpmnElement="template_Flow_23">
        <ns4:waypoint x="1648.0" y="930.0" />
        <ns4:waypoint x="1731.5" y="930.0" />
        <ns4:waypoint x="1731.5" y="800.0" />
        <ns4:waypoint x="1815.0" y="800.0" />
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_24" bpmnElement="template_Flow_24">
        <ns4:waypoint x="1965.0" y="800.0" />
        <ns4:waypoint x="2410.0" y="800.0" />
        <ns4:waypoint x="2410.0" y="25.0" />
        <ns4:waypoint x="350.0" y="25.0" />
        <ns4:waypoint x="350.0" y="85.0" />
        <ns2:BPMNLabel>
          <ns3:Bounds x="2120.0" y="5.0" width="180" height="26" />
        </ns2:BPMNLabel>
      </ns2:BPMNEdge>
      <ns2:BPMNEdge id="template_DI_Flow_25" bpmnElement="template_Flow_25">
        <ns4:waypoint x="1705.0" y="310.0" />
        <ns4:waypoint x="2132.0" y="310.0" />
      </ns2:BPMNEdge>
    </ns2:BPMNPlane>
  </ns2:BPMNDiagram>
</bpmn:definitions>

В своём статусе handler извлекает одно разрешённое для TEMPLATE намерение book или cancel. При отсутствии завершённого действия он загружает scoped order context. Ticket должен иметь единственный связанный Orders: отсутствие/неоднозначность — конфликт API, а не произвольный выбор заказа. 404 из-за устаревшего Ticket scope запрашивает локальную очистку.

Для template_close_at runtime берёт timing.planned_start и прибавляет SERVICE_REQUEST_TEMPLATE_CLOSE_AFTER_START_SECONDS. При достигнутой границе вызывается узкое действие close-template. Успех/stale исключают Ticket из текущей очереди; backend-отказ, ошибка HTTP или некорректный ответ этого close-вызова дают общий retry, а не штатную ветвь успешного ожидания.

До границы handler записывает локальную причину awaiting_booking, вызывает условное напоминание и назначает defer по SERVICE_REQUEST_TEMPLATE_RECHECK_SECONDS. Пустой reason у defer использует сохранённую локальную причину. Worker во время ожидания свободен.

Два внешних пути действий пользователя (BPMN)

Схема BPMN

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

Исходник схемы
<?xml version="1.0" encoding="UTF-8"?>
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:ns1="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:ns2="http://www.omg.org/spec/DD/20100524/DC" xmlns:ns3="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_service_template_external" targetNamespace="urn:sharix:knowledge:handlers">
  <bpmn:process id="person_Process_person" name="Автор / личный клиент заказа с доступным действием" isExecutable="false">
    <bpmn:documentation>{"notes": ["Git built-in; BPMN isExecutable=false. Handler при генерации не исполняется.", "Дата закрытия считается runtime: planned_start + SERVICE_REQUEST_TEMPLATE_CLOSE_AFTER_START_SECONDS.", "Intent-очередь, дедупликация и reminder counters — в памяти, не durable delivery guarantee.", "202 означает только relay acceptance. Канонический action имеет собственное решение.", "Прямой actions API также существует и запускает ту же доменную операцию без handler-intent очереди."], "sources": [{"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_service_request_template.py", "repository": "sharix-open-handlers-examples", "sha256": "a5e86f4580c8add4b05c6e58fa33306f5b4a2419d0951523afb996bff6e9e51b"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_service_request_template.json", "repository": "sharix-open-handlers-examples", "sha256": "6fb731e413f8fb8709e0b1e578a1da883c1d5a46ce291675114b32ec52619925"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "catalog.py", "repository": "sharix-open-handlers-examples", "sha256": "e3dcb72b7e620e2837adacd7af053f35b04cdff475789496d9c114e17d57dfde"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/blockly_runtime.py", "repository": "sharix-open-handlers-backend", "sha256": "3e222150cbff315077c6c9b160d46e59856cedf6d6591d213e958c63cb2f2428"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/requesters.py", "repository": "sharix-open-handlers-backend", "sha256": "965a348cea477722bbaf4c8c6b06023eb238b71664a332f7ea8c90bfe72ea808"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/order_action_messages.py", "repository": "sharix-open-handlers-backend", "sha256": "046c262c0aabb02104fefca4e887324f99df22731e7726063f614aaf8839ca5c"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "ticket_blockly_codegen.py", "repository": "sharix-open-handlers-backend", "sha256": "bce71eab622922f8dd0954222842349799b60e18a0ab6310cc3e5f305603661e"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "ticket_codegen_contract.json", "repository": "sharix-open-handlers-backend", "sha256": "0bfd2b0ebb07bd380ed3c867386536ab88ef7dfa6e13f1cd8c91d32bb02c1ae9"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "lib/tickets.py", "repository": "sharix-open-tickets", "sha256": "0d260c17947f9a186d07af2749159780e3c7354a95b4bafe9d67493663c96883"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/handler_auth.py", "repository": "sharix-open-tickets", "sha256": "ac76dc45aaa9742e5e1da0b98aae914bb2e287048d33e97b4a245a6997bc8425"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "signals.py", "repository": "sharix-open-tickets", "sha256": "39aad8690a2e7d35cebfb052127a8130a951cbb4eea316c4f767a0a59fc5fa7e"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "services/handler_wakeup.py", "repository": "sharix-open-tickets", "sha256": "c9fdc62a18301fd7c075395c697d5b1c738c77713aa71fcbb5ab097e173d98de"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "apiviews/handler_order_workflow.py", "repository": "sharix-open-backend", "sha256": "35624ded6e67110437a25dd07caef214a04251eb0136194ae939fa32fef17e84"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "apiviews/open_api.py", "repository": "sharix-open-backend", "sha256": "cb8fdda304d29c2cc5c0fc938759a13c60022871b7b93d77883d521820021ad3"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_handler_relay.py", "repository": "sharix-open-backend", "sha256": "e49a7876169403970d995af464357e2134af19a398372c55db2a5b40681d731e"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/handler_order_context.py", "repository": "sharix-open-backend", "sha256": "f3c0731e74d30dbe5e59bd53040a06ee108f14f7aad04771e65d741cffeb7179"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_workflow_policy.py", "repository": "sharix-open-backend", "sha256": "3266c6ecab490a0e19c8bbc02041387b86fe4b14068750e545ba9bde8bf51326"}, {"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": "urls.py", "repository": "sharix-open-backend", "sha256": "61ffd2f0563291da2dcc9488a5443cb5e2c0395108740a6700034cfd90548158"}]}</bpmn:documentation>
    <bpmn:laneSet id="person_Lanes_person">
      <bpmn:lane id="person_Lane_worker" name="Выбор пользовательского действия">
        <bpmn:flowNodeRef>person_start</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>person_send</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>person_end</bpmn:flowNodeRef>
      </bpmn:lane>
    </bpmn:laneSet>
    <bpmn:startEvent id="person_start" name="Решение разместить или отменить черновик">
      <bpmn:outgoing>person_Flow_0</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:sendTask id="person_send" name="Отправить book / cancel через разрешённый API">
      <bpmn:incoming>person_Flow_0</bpmn:incoming>
      <bpmn:outgoing>person_Flow_1</bpmn:outgoing>
    </bpmn:sendTask>
    <bpmn:endEvent id="person_end" name="Следить за фактическим результатом">
      <bpmn:incoming>person_Flow_1</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="person_Flow_0" sourceRef="person_start" targetRef="person_send" name="" />
    <bpmn:sequenceFlow id="person_Flow_1" sourceRef="person_send" targetRef="person_end" name="" />
  </bpmn:process>
  <bpmn:process id="relay_Process_relay" name="handler-intents API и доверенный XMPP relay" isExecutable="false">
    <bpmn:documentation>{"notes": ["Git built-in; BPMN isExecutable=false. Handler при генерации не исполняется.", "Дата закрытия считается runtime: planned_start + SERVICE_REQUEST_TEMPLATE_CLOSE_AFTER_START_SECONDS.", "Intent-очередь, дедупликация и reminder counters — в памяти, не durable delivery guarantee.", "202 означает только relay acceptance. Канонический action имеет собственное решение.", "Прямой actions API также существует и запускает ту же доменную операцию без handler-intent очереди."], "sources": [{"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_service_request_template.py", "repository": "sharix-open-handlers-examples", "sha256": "a5e86f4580c8add4b05c6e58fa33306f5b4a2419d0951523afb996bff6e9e51b"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_service_request_template.json", "repository": "sharix-open-handlers-examples", "sha256": "6fb731e413f8fb8709e0b1e578a1da883c1d5a46ce291675114b32ec52619925"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "catalog.py", "repository": "sharix-open-handlers-examples", "sha256": "e3dcb72b7e620e2837adacd7af053f35b04cdff475789496d9c114e17d57dfde"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/blockly_runtime.py", "repository": "sharix-open-handlers-backend", "sha256": "3e222150cbff315077c6c9b160d46e59856cedf6d6591d213e958c63cb2f2428"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/requesters.py", "repository": "sharix-open-handlers-backend", "sha256": "965a348cea477722bbaf4c8c6b06023eb238b71664a332f7ea8c90bfe72ea808"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/order_action_messages.py", "repository": "sharix-open-handlers-backend", "sha256": "046c262c0aabb02104fefca4e887324f99df22731e7726063f614aaf8839ca5c"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "ticket_blockly_codegen.py", "repository": "sharix-open-handlers-backend", "sha256": "bce71eab622922f8dd0954222842349799b60e18a0ab6310cc3e5f305603661e"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "ticket_codegen_contract.json", "repository": "sharix-open-handlers-backend", "sha256": "0bfd2b0ebb07bd380ed3c867386536ab88ef7dfa6e13f1cd8c91d32bb02c1ae9"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "lib/tickets.py", "repository": "sharix-open-tickets", "sha256": "0d260c17947f9a186d07af2749159780e3c7354a95b4bafe9d67493663c96883"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/handler_auth.py", "repository": "sharix-open-tickets", "sha256": "ac76dc45aaa9742e5e1da0b98aae914bb2e287048d33e97b4a245a6997bc8425"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "signals.py", "repository": "sharix-open-tickets", "sha256": "39aad8690a2e7d35cebfb052127a8130a951cbb4eea316c4f767a0a59fc5fa7e"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "services/handler_wakeup.py", "repository": "sharix-open-tickets", "sha256": "c9fdc62a18301fd7c075395c697d5b1c738c77713aa71fcbb5ab097e173d98de"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "apiviews/handler_order_workflow.py", "repository": "sharix-open-backend", "sha256": "35624ded6e67110437a25dd07caef214a04251eb0136194ae939fa32fef17e84"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "apiviews/open_api.py", "repository": "sharix-open-backend", "sha256": "cb8fdda304d29c2cc5c0fc938759a13c60022871b7b93d77883d521820021ad3"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_handler_relay.py", "repository": "sharix-open-backend", "sha256": "e49a7876169403970d995af464357e2134af19a398372c55db2a5b40681d731e"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/handler_order_context.py", "repository": "sharix-open-backend", "sha256": "f3c0731e74d30dbe5e59bd53040a06ee108f14f7aad04771e65d741cffeb7179"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_workflow_policy.py", "repository": "sharix-open-backend", "sha256": "3266c6ecab490a0e19c8bbc02041387b86fe4b14068750e545ba9bde8bf51326"}, {"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": "urls.py", "repository": "sharix-open-backend", "sha256": "61ffd2f0563291da2dcc9488a5443cb5e2c0395108740a6700034cfd90548158"}]}</bpmn:documentation>
    <bpmn:laneSet id="relay_Lanes_relay">
      <bpmn:lane id="relay_Lane_worker" name="Авторизация и передача, без изменения заказа">
        <bpmn:flowNodeRef>relay_start</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>relay_acl</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>relay_xmpp</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>relay_end</bpmn:flowNodeRef>
      </bpmn:lane>
    </bpmn:laneSet>
    <bpmn:startEvent id="relay_start" name="Запрос handler-intent">
      <bpmn:outgoing>relay_Flow_0</bpmn:outgoing>
      <bpmn:messageEventDefinition />
    </bpmn:startEvent>
    <bpmn:serviceTask id="relay_acl" name="Проверить user, доступный action и текущий handler">
      <bpmn:incoming>relay_Flow_0</bpmn:incoming>
      <bpmn:outgoing>relay_Flow_1</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:sendTask id="relay_xmpp" name="order.action.intent с actor и event_id">
      <bpmn:incoming>relay_Flow_1</bpmn:incoming>
      <bpmn:outgoing>relay_Flow_2</bpmn:outgoing>
    </bpmn:sendTask>
    <bpmn:endEvent id="relay_end" name="HTTP 202: запрос передан">
      <bpmn:incoming>relay_Flow_2</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="relay_Flow_0" sourceRef="relay_start" targetRef="relay_acl" name="" />
    <bpmn:sequenceFlow id="relay_Flow_1" sourceRef="relay_acl" targetRef="relay_xmpp" name="" />
    <bpmn:sequenceFlow id="relay_Flow_2" sourceRef="relay_xmpp" targetRef="relay_end" name="" />
  </bpmn:process>
  <bpmn:process id="handler_Process_handler" name="TEMPLATE handler: доверенный источник, очередь и применение intent" isExecutable="false">
    <bpmn:documentation>{"notes": ["Git built-in; BPMN isExecutable=false. Handler при генерации не исполняется.", "Дата закрытия считается runtime: planned_start + SERVICE_REQUEST_TEMPLATE_CLOSE_AFTER_START_SECONDS.", "Intent-очередь, дедупликация и reminder counters — в памяти, не durable delivery guarantee.", "202 означает только relay acceptance. Канонический action имеет собственное решение.", "Прямой actions API также существует и запускает ту же доменную операцию без handler-intent очереди."], "sources": [{"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_service_request_template.py", "repository": "sharix-open-handlers-examples", "sha256": "a5e86f4580c8add4b05c6e58fa33306f5b4a2419d0951523afb996bff6e9e51b"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_service_request_template.json", "repository": "sharix-open-handlers-examples", "sha256": "6fb731e413f8fb8709e0b1e578a1da883c1d5a46ce291675114b32ec52619925"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "catalog.py", "repository": "sharix-open-handlers-examples", "sha256": "e3dcb72b7e620e2837adacd7af053f35b04cdff475789496d9c114e17d57dfde"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/blockly_runtime.py", "repository": "sharix-open-handlers-backend", "sha256": "3e222150cbff315077c6c9b160d46e59856cedf6d6591d213e958c63cb2f2428"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/requesters.py", "repository": "sharix-open-handlers-backend", "sha256": "965a348cea477722bbaf4c8c6b06023eb238b71664a332f7ea8c90bfe72ea808"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/order_action_messages.py", "repository": "sharix-open-handlers-backend", "sha256": "046c262c0aabb02104fefca4e887324f99df22731e7726063f614aaf8839ca5c"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "ticket_blockly_codegen.py", "repository": "sharix-open-handlers-backend", "sha256": "bce71eab622922f8dd0954222842349799b60e18a0ab6310cc3e5f305603661e"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "ticket_codegen_contract.json", "repository": "sharix-open-handlers-backend", "sha256": "0bfd2b0ebb07bd380ed3c867386536ab88ef7dfa6e13f1cd8c91d32bb02c1ae9"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "lib/tickets.py", "repository": "sharix-open-tickets", "sha256": "0d260c17947f9a186d07af2749159780e3c7354a95b4bafe9d67493663c96883"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/handler_auth.py", "repository": "sharix-open-tickets", "sha256": "ac76dc45aaa9742e5e1da0b98aae914bb2e287048d33e97b4a245a6997bc8425"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "signals.py", "repository": "sharix-open-tickets", "sha256": "39aad8690a2e7d35cebfb052127a8130a951cbb4eea316c4f767a0a59fc5fa7e"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "services/handler_wakeup.py", "repository": "sharix-open-tickets", "sha256": "c9fdc62a18301fd7c075395c697d5b1c738c77713aa71fcbb5ab097e173d98de"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "apiviews/handler_order_workflow.py", "repository": "sharix-open-backend", "sha256": "35624ded6e67110437a25dd07caef214a04251eb0136194ae939fa32fef17e84"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "apiviews/open_api.py", "repository": "sharix-open-backend", "sha256": "cb8fdda304d29c2cc5c0fc938759a13c60022871b7b93d77883d521820021ad3"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_handler_relay.py", "repository": "sharix-open-backend", "sha256": "e49a7876169403970d995af464357e2134af19a398372c55db2a5b40681d731e"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/handler_order_context.py", "repository": "sharix-open-backend", "sha256": "f3c0731e74d30dbe5e59bd53040a06ee108f14f7aad04771e65d741cffeb7179"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_workflow_policy.py", "repository": "sharix-open-backend", "sha256": "3266c6ecab490a0e19c8bbc02041387b86fe4b14068750e545ba9bde8bf51326"}, {"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": "urls.py", "repository": "sharix-open-backend", "sha256": "61ffd2f0563291da2dcc9488a5443cb5e2c0395108740a6700034cfd90548158"}]}</bpmn:documentation>
    <bpmn:laneSet id="handler_Lanes_handler">
      <bpmn:lane id="handler_Lane_worker" name="Процессная память, затем scoped action API">
        <bpmn:flowNodeRef>handler_start</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>handler_validate</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>handler_queue</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>handler_apply</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>handler_end</bpmn:flowNodeRef>
      </bpmn:lane>
    </bpmn:laneSet>
    <bpmn:startEvent id="handler_start" name="Получен XMPP intent">
      <bpmn:outgoing>handler_Flow_0</bpmn:outgoing>
      <bpmn:messageEventDefinition />
    </bpmn:startEvent>
    <bpmn:serviceTask id="handler_validate" name="Проверить relay/stage/schema и дубликат event">
      <bpmn:incoming>handler_Flow_0</bpmn:incoming>
      <bpmn:outgoing>handler_Flow_1</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:serviceTask id="handler_queue" name="Поставить intent, снять defer">
      <bpmn:incoming>handler_Flow_1</bpmn:incoming>
      <bpmn:outgoing>handler_Flow_2</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:sendTask id="handler_apply" name="В проходе: apply-user-intent с actor">
      <bpmn:incoming>handler_Flow_2</bpmn:incoming>
      <bpmn:outgoing>handler_Flow_3</bpmn:outgoing>
    </bpmn:sendTask>
    <bpmn:endEvent id="handler_end" name="Ждать канонический ответ">
      <bpmn:incoming>handler_Flow_3</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="handler_Flow_0" sourceRef="handler_start" targetRef="handler_validate" name="" />
    <bpmn:sequenceFlow id="handler_Flow_1" sourceRef="handler_validate" targetRef="handler_queue" name="" />
    <bpmn:sequenceFlow id="handler_Flow_2" sourceRef="handler_queue" targetRef="handler_apply" name="" />
    <bpmn:sequenceFlow id="handler_Flow_3" sourceRef="handler_apply" targetRef="handler_end" name="" />
  </bpmn:process>
  <bpmn:process id="backend_Process_backend" name="Backend order actions: окончательные права, состояние, платёжные hooks" isExecutable="false">
    <bpmn:documentation>{"notes": ["Git built-in; BPMN isExecutable=false. Handler при генерации не исполняется.", "Дата закрытия считается runtime: planned_start + SERVICE_REQUEST_TEMPLATE_CLOSE_AFTER_START_SECONDS.", "Intent-очередь, дедупликация и reminder counters — в памяти, не durable delivery guarantee.", "202 означает только relay acceptance. Канонический action имеет собственное решение.", "Прямой actions API также существует и запускает ту же доменную операцию без handler-intent очереди."], "sources": [{"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_service_request_template.py", "repository": "sharix-open-handlers-examples", "sha256": "a5e86f4580c8add4b05c6e58fa33306f5b4a2419d0951523afb996bff6e9e51b"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_service_request_template.json", "repository": "sharix-open-handlers-examples", "sha256": "6fb731e413f8fb8709e0b1e578a1da883c1d5a46ce291675114b32ec52619925"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "catalog.py", "repository": "sharix-open-handlers-examples", "sha256": "e3dcb72b7e620e2837adacd7af053f35b04cdff475789496d9c114e17d57dfde"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/blockly_runtime.py", "repository": "sharix-open-handlers-backend", "sha256": "3e222150cbff315077c6c9b160d46e59856cedf6d6591d213e958c63cb2f2428"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/requesters.py", "repository": "sharix-open-handlers-backend", "sha256": "965a348cea477722bbaf4c8c6b06023eb238b71664a332f7ea8c90bfe72ea808"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/order_action_messages.py", "repository": "sharix-open-handlers-backend", "sha256": "046c262c0aabb02104fefca4e887324f99df22731e7726063f614aaf8839ca5c"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "ticket_blockly_codegen.py", "repository": "sharix-open-handlers-backend", "sha256": "bce71eab622922f8dd0954222842349799b60e18a0ab6310cc3e5f305603661e"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "ticket_codegen_contract.json", "repository": "sharix-open-handlers-backend", "sha256": "0bfd2b0ebb07bd380ed3c867386536ab88ef7dfa6e13f1cd8c91d32bb02c1ae9"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "lib/tickets.py", "repository": "sharix-open-tickets", "sha256": "0d260c17947f9a186d07af2749159780e3c7354a95b4bafe9d67493663c96883"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/handler_auth.py", "repository": "sharix-open-tickets", "sha256": "ac76dc45aaa9742e5e1da0b98aae914bb2e287048d33e97b4a245a6997bc8425"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "signals.py", "repository": "sharix-open-tickets", "sha256": "39aad8690a2e7d35cebfb052127a8130a951cbb4eea316c4f767a0a59fc5fa7e"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "services/handler_wakeup.py", "repository": "sharix-open-tickets", "sha256": "c9fdc62a18301fd7c075395c697d5b1c738c77713aa71fcbb5ab097e173d98de"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "apiviews/handler_order_workflow.py", "repository": "sharix-open-backend", "sha256": "35624ded6e67110437a25dd07caef214a04251eb0136194ae939fa32fef17e84"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "apiviews/open_api.py", "repository": "sharix-open-backend", "sha256": "cb8fdda304d29c2cc5c0fc938759a13c60022871b7b93d77883d521820021ad3"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_handler_relay.py", "repository": "sharix-open-backend", "sha256": "e49a7876169403970d995af464357e2134af19a398372c55db2a5b40681d731e"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/handler_order_context.py", "repository": "sharix-open-backend", "sha256": "f3c0731e74d30dbe5e59bd53040a06ee108f14f7aad04771e65d741cffeb7179"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_workflow_policy.py", "repository": "sharix-open-backend", "sha256": "3266c6ecab490a0e19c8bbc02041387b86fe4b14068750e545ba9bde8bf51326"}, {"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": "urls.py", "repository": "sharix-open-backend", "sha256": "61ffd2f0563291da2dcc9488a5443cb5e2c0395108740a6700034cfd90548158"}]}</bpmn:documentation>
    <bpmn:laneSet id="backend_Lanes_backend">
      <bpmn:lane id="backend_Lane_worker" name="Каноническое бизнес-действие">
        <bpmn:flowNodeRef>backend_start</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_check</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_decide</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_save</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_wake</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_end</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>backend_reject</bpmn:flowNodeRef>
      </bpmn:lane>
    </bpmn:laneSet>
    <bpmn:startEvent id="backend_start" name="Запрос от handler либо прямой actions API">
      <bpmn:outgoing>backend_Flow_0</bpmn:outgoing>
      <bpmn:messageEventDefinition />
    </bpmn:startEvent>
    <bpmn:serviceTask id="backend_check" name="Проверить actor/права; заблокировать актуальный заказ">
      <bpmn:incoming>backend_Flow_0</bpmn:incoming>
      <bpmn:outgoing>backend_Flow_1</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:exclusiveGateway id="backend_decide" name="Действие разрешено?">
      <bpmn:incoming>backend_Flow_1</bpmn:incoming>
      <bpmn:outgoing>backend_Flow_2</bpmn:outgoing>
      <bpmn:outgoing>backend_Flow_3</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:serviceTask id="backend_save" name="book→BOOKED (+назначение), cancel→CLOSED">
      <bpmn:documentation>book может блокироваться платёжным hook; уже выбранный provider назначается после успешного BOOK.</bpmn:documentation>
      <bpmn:incoming>backend_Flow_2</bpmn:incoming>
      <bpmn:outgoing>backend_Flow_4</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:sendTask id="backend_wake" name="После commit: authoritative статус и wakeup">
      <bpmn:incoming>backend_Flow_4</bpmn:incoming>
      <bpmn:outgoing>backend_Flow_5</bpmn:outgoing>
    </bpmn:sendTask>
    <bpmn:endEvent id="backend_end" name="Действие выполнено">
      <bpmn:incoming>backend_Flow_5</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:endEvent id="backend_reject" name="Отказ: не считать заказ размещённым">
      <bpmn:incoming>backend_Flow_3</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:sequenceFlow id="backend_Flow_0" sourceRef="backend_start" targetRef="backend_check" name="" />
    <bpmn:sequenceFlow id="backend_Flow_1" sourceRef="backend_check" targetRef="backend_decide" name="" />
    <bpmn:sequenceFlow id="backend_Flow_2" sourceRef="backend_decide" targetRef="backend_save" name="Да" />
    <bpmn:sequenceFlow id="backend_Flow_3" sourceRef="backend_decide" targetRef="backend_reject" name="Нет" />
    <bpmn:sequenceFlow id="backend_Flow_4" sourceRef="backend_save" targetRef="backend_wake" name="" />
    <bpmn:sequenceFlow id="backend_Flow_5" sourceRef="backend_wake" targetRef="backend_end" name="" />
  </bpmn:process>
  <bpmn:collaboration id="Collaboration_service_template_external">
    <bpmn:participant id="person_Pool_person" name="Автор / личный клиент заказа с доступным действием" processRef="person_Process_person" />
    <bpmn:participant id="relay_Pool_relay" name="handler-intents API и доверенный XMPP relay" processRef="relay_Process_relay" />
    <bpmn:participant id="handler_Pool_handler" name="TEMPLATE handler: доверенный источник, очередь и применение intent" processRef="handler_Process_handler" />
    <bpmn:participant id="backend_Pool_backend" name="Backend order actions: окончательные права, состояние, платёжные hooks" processRef="backend_Process_backend" />
    <bpmn:messageFlow id="Message_service_template_external_0" sourceRef="person_send" targetRef="relay_start" name="Путь handler-intents" />
    <bpmn:messageFlow id="Message_service_template_external_1" sourceRef="relay_xmpp" targetRef="handler_start" name="Доверенная передача, не commit заказа" />
    <bpmn:messageFlow id="Message_service_template_external_2" sourceRef="handler_apply" targetRef="backend_start" name="Scoped apply-user-intent; actor проверяется повторно" />
    <bpmn:messageFlow id="Message_service_template_external_3" sourceRef="person_send" targetRef="backend_start" name="Альтернатива: прямой actions API" />
  </bpmn:collaboration>
  <ns1:BPMNDiagram id="Diagram_service_template_external">
    <ns1:BPMNPlane id="Plane_service_template_external" bpmnElement="Collaboration_service_template_external">
      <ns1:BPMNShape id="person_DI_Pool_person" bpmnElement="person_Pool_person" isHorizontal="true">
        <ns2:Bounds x="0.0" y="0.0" width="920" height="200" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="person_DI_Lane_worker" bpmnElement="person_Lane_worker" isHorizontal="true">
        <ns2:Bounds x="30.0" y="0.0" width="890" height="200" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="person_DI_start" bpmnElement="person_start">
        <ns2:Bounds x="132.0" y="82.0" width="36" height="36" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="person_DI_send" bpmnElement="person_send">
        <ns2:Bounds x="375.0" y="65.0" width="150" height="70" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="person_DI_end" bpmnElement="person_end">
        <ns2:Bounds x="742.0" y="82.0" width="36" height="36" />
      </ns1:BPMNShape>
      <ns1:BPMNEdge id="person_DI_Flow_0" bpmnElement="person_Flow_0">
        <ns3:waypoint x="168.0" y="100.0" />
        <ns3:waypoint x="375.0" y="100.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="person_DI_Flow_1" bpmnElement="person_Flow_1">
        <ns3:waypoint x="525.0" y="100.0" />
        <ns3:waypoint x="742.0" y="100.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNShape id="relay_DI_Pool_relay" bpmnElement="relay_Pool_relay" isHorizontal="true">
        <ns2:Bounds x="0.0" y="300.0" width="1220" height="200" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="relay_DI_Lane_worker" bpmnElement="relay_Lane_worker" isHorizontal="true">
        <ns2:Bounds x="30.0" y="300.0" width="1190" height="200" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="relay_DI_start" bpmnElement="relay_start">
        <ns2:Bounds x="132.0" y="382.0" width="36" height="36" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="relay_DI_acl" bpmnElement="relay_acl">
        <ns2:Bounds x="375.0" y="365.0" width="150" height="70" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="relay_DI_xmpp" bpmnElement="relay_xmpp">
        <ns2:Bounds x="685.0" y="365.0" width="150" height="70" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="relay_DI_end" bpmnElement="relay_end">
        <ns2:Bounds x="1042.0" y="382.0" width="36" height="36" />
      </ns1:BPMNShape>
      <ns1:BPMNEdge id="relay_DI_Flow_0" bpmnElement="relay_Flow_0">
        <ns3:waypoint x="168.0" y="400.0" />
        <ns3:waypoint x="375.0" y="400.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="relay_DI_Flow_1" bpmnElement="relay_Flow_1">
        <ns3:waypoint x="525.0" y="400.0" />
        <ns3:waypoint x="685.0" y="400.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="relay_DI_Flow_2" bpmnElement="relay_Flow_2">
        <ns3:waypoint x="835.0" y="400.0" />
        <ns3:waypoint x="1042.0" y="400.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNShape id="handler_DI_Pool_handler" bpmnElement="handler_Pool_handler" isHorizontal="true">
        <ns2:Bounds x="0.0" y="650.0" width="1520" height="200" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="handler_DI_Lane_worker" bpmnElement="handler_Lane_worker" isHorizontal="true">
        <ns2:Bounds x="30.0" y="650.0" width="1490" height="200" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="handler_DI_start" bpmnElement="handler_start">
        <ns2:Bounds x="132.0" y="732.0" width="36" height="36" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="handler_DI_validate" bpmnElement="handler_validate">
        <ns2:Bounds x="375.0" y="715.0" width="150" height="70" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="handler_DI_queue" bpmnElement="handler_queue">
        <ns2:Bounds x="685.0" y="715.0" width="150" height="70" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="handler_DI_apply" bpmnElement="handler_apply">
        <ns2:Bounds x="985.0" y="715.0" width="150" height="70" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="handler_DI_end" bpmnElement="handler_end">
        <ns2:Bounds x="1342.0" y="732.0" width="36" height="36" />
      </ns1:BPMNShape>
      <ns1:BPMNEdge id="handler_DI_Flow_0" bpmnElement="handler_Flow_0">
        <ns3:waypoint x="168.0" y="750.0" />
        <ns3:waypoint x="375.0" y="750.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="handler_DI_Flow_1" bpmnElement="handler_Flow_1">
        <ns3:waypoint x="525.0" y="750.0" />
        <ns3:waypoint x="685.0" y="750.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="handler_DI_Flow_2" bpmnElement="handler_Flow_2">
        <ns3:waypoint x="835.0" y="750.0" />
        <ns3:waypoint x="985.0" y="750.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="handler_DI_Flow_3" bpmnElement="handler_Flow_3">
        <ns3:waypoint x="1135.0" y="750.0" />
        <ns3:waypoint x="1342.0" y="750.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNShape id="backend_DI_Pool_backend" bpmnElement="backend_Pool_backend" isHorizontal="true">
        <ns2:Bounds x="0.0" y="1000.0" width="1890.0" height="380" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="backend_DI_Lane_worker" bpmnElement="backend_Lane_worker" isHorizontal="true">
        <ns2:Bounds x="30.0" y="1000.0" width="1860.0" height="380" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="backend_DI_start" bpmnElement="backend_start">
        <ns2:Bounds x="132.0" y="1082.0" width="36" height="36" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="backend_DI_check" bpmnElement="backend_check">
        <ns2:Bounds x="375.0" y="1065.0" width="150" height="70" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="backend_DI_decide" bpmnElement="backend_decide">
        <ns2:Bounds x="735.0" y="1075.0" width="50" height="50" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="backend_DI_save" bpmnElement="backend_save">
        <ns2:Bounds x="985.0" y="1065.0" width="150" height="70" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="backend_DI_wake" bpmnElement="backend_wake">
        <ns2:Bounds x="1285.0" y="1065.0" width="150" height="70" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="backend_DI_end" bpmnElement="backend_end">
        <ns2:Bounds x="1622.0" y="1082.0" width="36" height="36" />
      </ns1:BPMNShape>
      <ns1:BPMNShape id="backend_DI_reject" bpmnElement="backend_reject">
        <ns2:Bounds x="742.0" y="1262.0" width="36" height="36" />
      </ns1:BPMNShape>
      <ns1:BPMNEdge id="backend_DI_Flow_0" bpmnElement="backend_Flow_0">
        <ns3:waypoint x="168.0" y="1100.0" />
        <ns3:waypoint x="375.0" y="1100.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="backend_DI_Flow_1" bpmnElement="backend_Flow_1">
        <ns3:waypoint x="525.0" y="1100.0" />
        <ns3:waypoint x="735.0" y="1100.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="backend_DI_Flow_2" bpmnElement="backend_Flow_2">
        <ns3:waypoint x="785.0" y="1100.0" />
        <ns3:waypoint x="985.0" y="1100.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="backend_DI_Flow_3" bpmnElement="backend_Flow_3">
        <ns3:waypoint x="760.0" y="1125.0" />
        <ns3:waypoint x="760.0" y="1262.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="backend_DI_Flow_4" bpmnElement="backend_Flow_4">
        <ns3:waypoint x="1135.0" y="1100.0" />
        <ns3:waypoint x="1285.0" y="1100.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="backend_DI_Flow_5" bpmnElement="backend_Flow_5">
        <ns3:waypoint x="1435.0" y="1100.0" />
        <ns3:waypoint x="1622.0" y="1100.0" />
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="DI_Message_service_template_external_0" bpmnElement="Message_service_template_external_0">
        <ns3:waypoint x="450" y="135" />
        <ns3:waypoint x="450" y="245" />
        <ns3:waypoint x="150" y="245" />
        <ns3:waypoint x="150" y="382" />
        <ns1:BPMNLabel>
          <ns2:Bounds x="170" y="215" width="260" height="42" />
        </ns1:BPMNLabel>
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="DI_Message_service_template_external_1" bpmnElement="Message_service_template_external_1">
        <ns3:waypoint x="760" y="435" />
        <ns3:waypoint x="760" y="590" />
        <ns3:waypoint x="150" y="590" />
        <ns3:waypoint x="150" y="732" />
        <ns1:BPMNLabel>
          <ns2:Bounds x="190" y="555" width="260" height="42" />
        </ns1:BPMNLabel>
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="DI_Message_service_template_external_2" bpmnElement="Message_service_template_external_2">
        <ns3:waypoint x="1060" y="785" />
        <ns3:waypoint x="1060" y="940" />
        <ns3:waypoint x="150" y="940" />
        <ns3:waypoint x="150" y="1082" />
        <ns1:BPMNLabel>
          <ns2:Bounds x="230" y="905" width="260" height="42" />
        </ns1:BPMNLabel>
      </ns1:BPMNEdge>
      <ns1:BPMNEdge id="DI_Message_service_template_external_3" bpmnElement="Message_service_template_external_3">
        <ns3:waypoint x="525" y="100" />
        <ns3:waypoint x="1850" y="100" />
        <ns3:waypoint x="1850" y="950" />
        <ns3:waypoint x="75" y="950" />
        <ns3:waypoint x="75" y="1100" />
        <ns3:waypoint x="132" y="1100" />
        <ns1:BPMNLabel>
          <ns2:Bounds x="1500" y="860" width="260" height="42" />
        </ns1:BPMNLabel>
      </ns1:BPMNEdge>
    </ns1:BPMNPlane>
  </ns1:BPMNDiagram>
</bpmn:definitions>

На service API v1 существуют два разных входа:

  • orders/{id}/handler-intents/ — аутентифицированное намерение через доверенный web→XMPP relay. Ответ 202 «Запрос передан обработчику» подтверждает передачу, а не изменение заказа.
  • orders/{id}/actions/ — прямое каноническое действие с request.user, объектной областью и доменными проверками. Этот путь не ставит intent в память TEMPLATE handler; после commit смена статуса будит/освобождает соответствующих владельцев через обычные Ticket-события.

В relay для TEMPLATE доступны book/cancel по фактическим правам пользователя; subscription-access заказы не получают этот набор интерактивных действий. Текущий user_is_order_client проверяет автора заказа либо пользователя личного Client. Одно название LDAP-группы или статус «клиент платформы» не заменяют связь пользователя с этим заказом ShariX Open.

Relay определяет handler по Ticket.status и передаёт:

  • actor user ID и JID;
  • event ID;
  • order ID и ticket ID;
  • стадию;
  • сообщение order.action.intent.

Relay сам заказ не меняет. Runtime принимает intent от настроенного доверенного relay JID с transport=web_relay, проверяет структуру/стадию, отсекает известный event ID и ставит намерение в память процесса. Произвольное XMPP-сообщение не разрешает размещение заказа.

При применении intent backend заново проверяет активного actor, соответствие переданного JID, текущий связанный заказ и права канонического действия. Очередь и дедупликация runtime находятся в памяти: это не durable гарантия исполнения при рестарте и не exactly-once подтверждение. После 202 нужно смотреть фактический результат/статус заказа, а не считать размещение уже выполненным.

Размещение и отмена

book проверяет право клиента, вызывает платёжный hook перед размещением и при разрешении переводит заказ в BOOKED. Платёжное условие может заблокировать переход. Если в черновике уже выбран provider, после успешного BOOK выполняется каноническое назначение существующему исполнителю; поэтому конечная стадия может оказаться дальше BOOKED, а не всегда оставаться именно в нём. Неудача назначения отражается в результате отдельно от уже успешного размещения.

cancel из TEMPLATE ведёт в CLOSED, а не в CANCELLED. Для BOOKED политика отмены другая; нельзя механически переносить её на черновик. Оба входа используют доменные действия, а не прямую запись Ticket.status.

Срок автоматического закрытия

Плановое начало берётся из корректного Orders.time_start через read-only order context. Если его нет, runtime не считает template_close_at достигнутым; одного возраста Ticket для автоматического закрытия недостаточно. Некорректная дата контрольной проверки логируется и не считается достигнутой.

Закрытие разрешает handler-side сравнение времени. Сам backend close_template_order_as_handler проверяет доверенный handler context и актуальную стадию TEMPLATE, затем выполняет канонический CLOSED; он не пересчитывает временную границу. Поэтому корректная выбранная версия Python и её именованные настройки являются частью контракта этой политики, а не только оформлением страницы.

При гонке пользовательского book и автоматического close backend работает с актуальным состоянием под блокировкой. Устаревший локальный снимок не должен компенсироваться обратной сменой статуса. Уже committed действие и доставка wakeup — разные операции; потеря XMPP-события восстанавливается scoped periodic reconciliation.

Условие и лимит напоминания (BPMN)

Схема 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_service_template_reminder" targetNamespace="urn:sharix:knowledge:handlers">
  <bpmn:process id="reminder_Process_reminder" name="send_template_reminder: условное личное уведомление автора" isExecutable="false">
    <bpmn:documentation>{"notes": ["Git built-in; BPMN isExecutable=false. Handler при генерации не исполняется.", "Дата закрытия считается runtime: planned_start + SERVICE_REQUEST_TEMPLATE_CLOSE_AFTER_START_SECONDS.", "Intent-очередь, дедупликация и reminder counters — в памяти, не durable delivery guarantee.", "Лимит напоминаний сохранён только в памяти процесса; restart его сбрасывает."], "sources": [{"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "handlers/open_service_request_template.py", "repository": "sharix-open-handlers-examples", "sha256": "a5e86f4580c8add4b05c6e58fa33306f5b4a2419d0951523afb996bff6e9e51b"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "generated_handler_blocks/open_service_request_template.json", "repository": "sharix-open-handlers-examples", "sha256": "6fb731e413f8fb8709e0b1e578a1da883c1d5a46ce291675114b32ec52619925"}, {"commit": "76e0c693b628ed4a1fa34515a3f8abdff26149bb", "path": "catalog.py", "repository": "sharix-open-handlers-examples", "sha256": "e3dcb72b7e620e2837adacd7af053f35b04cdff475789496d9c114e17d57dfde"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/blockly_runtime.py", "repository": "sharix-open-handlers-backend", "sha256": "3e222150cbff315077c6c9b160d46e59856cedf6d6591d213e958c63cb2f2428"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/requesters.py", "repository": "sharix-open-handlers-backend", "sha256": "965a348cea477722bbaf4c8c6b06023eb238b71664a332f7ea8c90bfe72ea808"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "core/order_action_messages.py", "repository": "sharix-open-handlers-backend", "sha256": "046c262c0aabb02104fefca4e887324f99df22731e7726063f614aaf8839ca5c"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "ticket_blockly_codegen.py", "repository": "sharix-open-handlers-backend", "sha256": "bce71eab622922f8dd0954222842349799b60e18a0ab6310cc3e5f305603661e"}, {"commit": "50baf376e224d915a87d63240f3f339b3dda9afa", "path": "ticket_codegen_contract.json", "repository": "sharix-open-handlers-backend", "sha256": "0bfd2b0ebb07bd380ed3c867386536ab88ef7dfa6e13f1cd8c91d32bb02c1ae9"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "lib/tickets.py", "repository": "sharix-open-tickets", "sha256": "0d260c17947f9a186d07af2749159780e3c7354a95b4bafe9d67493663c96883"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "api/handler_auth.py", "repository": "sharix-open-tickets", "sha256": "ac76dc45aaa9742e5e1da0b98aae914bb2e287048d33e97b4a245a6997bc8425"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "signals.py", "repository": "sharix-open-tickets", "sha256": "39aad8690a2e7d35cebfb052127a8130a951cbb4eea316c4f767a0a59fc5fa7e"}, {"commit": "fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14", "path": "services/handler_wakeup.py", "repository": "sharix-open-tickets", "sha256": "c9fdc62a18301fd7c075395c697d5b1c738c77713aa71fcbb5ab097e173d98de"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "apiviews/handler_order_workflow.py", "repository": "sharix-open-backend", "sha256": "35624ded6e67110437a25dd07caef214a04251eb0136194ae939fa32fef17e84"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "apiviews/open_api.py", "repository": "sharix-open-backend", "sha256": "cb8fdda304d29c2cc5c0fc938759a13c60022871b7b93d77883d521820021ad3"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_handler_relay.py", "repository": "sharix-open-backend", "sha256": "e49a7876169403970d995af464357e2134af19a398372c55db2a5b40681d731e"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/handler_order_context.py", "repository": "sharix-open-backend", "sha256": "f3c0731e74d30dbe5e59bd53040a06ee108f14f7aad04771e65d741cffeb7179"}, {"commit": "778a3280cee115ba0efe3fdff7b0e708b0c10093", "path": "lib/order_workflow_policy.py", "repository": "sharix-open-backend", "sha256": "3266c6ecab490a0e19c8bbc02041387b86fe4b14068750e545ba9bde8bf51326"}, {"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": "urls.py", "repository": "sharix-open-backend", "sha256": "61ffd2f0563291da2dcc9488a5443cb5e2c0395108740a6700034cfd90548158"}]}</bpmn:documentation>
    <bpmn:laneSet id="reminder_Lanes_reminder">
      <bpmn:lane id="reminder_Lane_worker" name="Локальные часы и защищённый API получателя">
        <bpmn:flowNodeRef>reminder_start</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>reminder_date</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>reminder_old</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>reminder_repeat</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>reminder_text</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>reminder_warning</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>reminder_append</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>reminder_send</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>reminder_sent</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>reminder_remember</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>reminder_end</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>reminder_skip</bpmn:flowNodeRef>
        <bpmn:flowNodeRef>reminder_bad_date</bpmn:flowNodeRef>
      </bpmn:lane>
    </bpmn:laneSet>
    <bpmn:startEvent id="reminder_start" name="Вызов из ожидающего TEMPLATE">
      <bpmn:outgoing>reminder_Flow_0</bpmn:outgoing>
    </bpmn:startEvent>
    <bpmn:serviceTask id="reminder_date" name="Разобрать Ticket.created_at">
      <bpmn:incoming>reminder_Flow_0</bpmn:incoming>
      <bpmn:outgoing>reminder_Flow_1</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:exclusiveGateway id="reminder_old" name="Возраст ≥ REMINDER_INTERVAL?">
      <bpmn:incoming>reminder_Flow_1</bpmn:incoming>
      <bpmn:outgoing>reminder_Flow_2</bpmn:outgoing>
      <bpmn:outgoing>reminder_Flow_3</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:exclusiveGateway id="reminder_repeat" name="Ещё не отправляли или интервал прошёл?">
      <bpmn:incoming>reminder_Flow_2</bpmn:incoming>
      <bpmn:outgoing>reminder_Flow_4</bpmn:outgoing>
      <bpmn:outgoing>reminder_Flow_5</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:serviceTask id="reminder_text" name="Сформировать сообщение о черновике">
      <bpmn:incoming>reminder_Flow_4</bpmn:incoming>
      <bpmn:outgoing>reminder_Flow_6</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:exclusiveGateway id="reminder_warning" name="Наступило close_at − WARNING?">
      <bpmn:incoming>reminder_Flow_6</bpmn:incoming>
      <bpmn:outgoing>reminder_Flow_7</bpmn:outgoing>
      <bpmn:outgoing>reminder_Flow_8</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:serviceTask id="reminder_append" name="Добавить дату автоматического закрытия">
      <bpmn:incoming>reminder_Flow_7</bpmn:incoming>
      <bpmn:outgoing>reminder_Flow_9</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:sendTask id="reminder_send" name="Защищённый creator API → XMPP">
      <bpmn:incoming>reminder_Flow_8</bpmn:incoming>
      <bpmn:incoming>reminder_Flow_9</bpmn:incoming>
      <bpmn:outgoing>reminder_Flow_10</bpmn:outgoing>
    </bpmn:sendTask>
    <bpmn:exclusiveGateway id="reminder_sent" name="Есть получатель и отправка?">
      <bpmn:incoming>reminder_Flow_10</bpmn:incoming>
      <bpmn:outgoing>reminder_Flow_11</bpmn:outgoing>
      <bpmn:outgoing>reminder_Flow_13</bpmn:outgoing>
    </bpmn:exclusiveGateway>
    <bpmn:serviceTask id="reminder_remember" name="Сохранить last_sent_at в памяти">
      <bpmn:incoming>reminder_Flow_11</bpmn:incoming>
      <bpmn:outgoing>reminder_Flow_12</bpmn:outgoing>
    </bpmn:serviceTask>
    <bpmn:endEvent id="reminder_end" name="Напоминание учтено">
      <bpmn:incoming>reminder_Flow_12</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:endEvent id="reminder_skip" name="Без напоминания; обычное ожидание продолжается">
      <bpmn:incoming>reminder_Flow_3</bpmn:incoming>
      <bpmn:incoming>reminder_Flow_5</bpmn:incoming>
      <bpmn:incoming>reminder_Flow_13</bpmn:incoming>
      <bpmn:incoming>reminder_Flow_14</bpmn:incoming>
    </bpmn:endEvent>
    <bpmn:boundaryEvent id="reminder_bad_date" name="Нет / неверная дата" attachedToRef="reminder_date" cancelActivity="true">
      <bpmn:outgoing>reminder_Flow_14</bpmn:outgoing>
      <bpmn:errorEventDefinition />
    </bpmn:boundaryEvent>
    <bpmn:sequenceFlow id="reminder_Flow_0" sourceRef="reminder_start" targetRef="reminder_date" name="" />
    <bpmn:sequenceFlow id="reminder_Flow_1" sourceRef="reminder_date" targetRef="reminder_old" name="" />
    <bpmn:sequenceFlow id="reminder_Flow_2" sourceRef="reminder_old" targetRef="reminder_repeat" name="Да" />
    <bpmn:sequenceFlow id="reminder_Flow_3" sourceRef="reminder_old" targetRef="reminder_skip" name="Нет" />
    <bpmn:sequenceFlow id="reminder_Flow_4" sourceRef="reminder_repeat" targetRef="reminder_text" name="Да" />
    <bpmn:sequenceFlow id="reminder_Flow_5" sourceRef="reminder_repeat" targetRef="reminder_skip" name="Нет" />
    <bpmn:sequenceFlow id="reminder_Flow_6" sourceRef="reminder_text" targetRef="reminder_warning" name="" />
    <bpmn:sequenceFlow id="reminder_Flow_7" sourceRef="reminder_warning" targetRef="reminder_append" name="Да" />
    <bpmn:sequenceFlow id="reminder_Flow_8" sourceRef="reminder_warning" targetRef="reminder_send" name="Нет / нет planned_start" />
    <bpmn:sequenceFlow id="reminder_Flow_9" sourceRef="reminder_append" targetRef="reminder_send" name="" />
    <bpmn:sequenceFlow id="reminder_Flow_10" sourceRef="reminder_send" targetRef="reminder_sent" name="" />
    <bpmn:sequenceFlow id="reminder_Flow_11" sourceRef="reminder_sent" targetRef="reminder_remember" name="Да" />
    <bpmn:sequenceFlow id="reminder_Flow_12" sourceRef="reminder_remember" targetRef="reminder_end" name="" />
    <bpmn:sequenceFlow id="reminder_Flow_13" sourceRef="reminder_sent" targetRef="reminder_skip" name="Нет" />
    <bpmn:sequenceFlow id="reminder_Flow_14" sourceRef="reminder_bad_date" targetRef="reminder_skip" name="" />
  </bpmn:process>
  <bpmn:collaboration id="Collaboration_service_template_reminder">
    <bpmn:participant id="reminder_Pool_reminder" name="send_template_reminder: условное личное уведомление автора" processRef="reminder_Process_reminder" />
  </bpmn:collaboration>
  <bpmndi:BPMNDiagram id="Diagram_service_template_reminder">
    <bpmndi:BPMNPlane id="Plane_service_template_reminder" bpmnElement="Collaboration_service_template_reminder">
      <bpmndi:BPMNShape id="reminder_DI_Pool_reminder" bpmnElement="reminder_Pool_reminder" isHorizontal="true">
        <dc:Bounds x="0.0" y="0.0" width="2730" height="610" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_Lane_worker" bpmnElement="reminder_Lane_worker" isHorizontal="true">
        <dc:Bounds x="30.0" y="0.0" width="2700" height="610" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_start" bpmnElement="reminder_start">
        <dc:Bounds x="132.0" y="92.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_date" bpmnElement="reminder_date">
        <dc:Bounds x="345.0" y="75.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_old" bpmnElement="reminder_old">
        <dc:Bounds x="675.0" y="85.0" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_repeat" bpmnElement="reminder_repeat">
        <dc:Bounds x="955.0" y="85.0" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_text" bpmnElement="reminder_text">
        <dc:Bounds x="1185.0" y="75.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_warning" bpmnElement="reminder_warning">
        <dc:Bounds x="1515.0" y="85.0" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_append" bpmnElement="reminder_append">
        <dc:Bounds x="1725.0" y="75.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_send" bpmnElement="reminder_send">
        <dc:Bounds x="1725.0" y="275.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_sent" bpmnElement="reminder_sent">
        <dc:Bounds x="2035.0" y="285.0" width="50" height="50" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_remember" bpmnElement="reminder_remember">
        <dc:Bounds x="2245.0" y="275.0" width="150" height="70" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_end" bpmnElement="reminder_end">
        <dc:Bounds x="2552.0" y="292.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_skip" bpmnElement="reminder_skip">
        <dc:Bounds x="962.0" y="492.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape id="reminder_DI_bad_date" bpmnElement="reminder_bad_date">
        <dc:Bounds x="452.0" y="127.0" width="36" height="36" />
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_0" bpmnElement="reminder_Flow_0">
        <di:waypoint x="168.0" y="110.0" />
        <di:waypoint x="345.0" y="110.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_1" bpmnElement="reminder_Flow_1">
        <di:waypoint x="495.0" y="110.0" />
        <di:waypoint x="675.0" y="110.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_2" bpmnElement="reminder_Flow_2">
        <di:waypoint x="725.0" y="110.0" />
        <di:waypoint x="955.0" y="110.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_3" bpmnElement="reminder_Flow_3">
        <di:waypoint x="725.0" y="110.0" />
        <di:waypoint x="820.0" y="110.0" />
        <di:waypoint x="820.0" y="440.0" />
        <di:waypoint x="980.0" y="440.0" />
        <di:waypoint x="980.0" y="492.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_4" bpmnElement="reminder_Flow_4">
        <di:waypoint x="1005.0" y="110.0" />
        <di:waypoint x="1185.0" y="110.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_5" bpmnElement="reminder_Flow_5">
        <di:waypoint x="980.0" y="135.0" />
        <di:waypoint x="980.0" y="492.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_6" bpmnElement="reminder_Flow_6">
        <di:waypoint x="1335.0" y="110.0" />
        <di:waypoint x="1515.0" y="110.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_7" bpmnElement="reminder_Flow_7">
        <di:waypoint x="1565.0" y="110.0" />
        <di:waypoint x="1725.0" y="110.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_8" bpmnElement="reminder_Flow_8">
        <di:waypoint x="1565.0" y="110.0" />
        <di:waypoint x="1660.0" y="110.0" />
        <di:waypoint x="1660.0" y="240.0" />
        <di:waypoint x="1800.0" y="240.0" />
        <di:waypoint x="1800.0" y="275.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_9" bpmnElement="reminder_Flow_9">
        <di:waypoint x="1800.0" y="145.0" />
        <di:waypoint x="1800.0" y="275.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_10" bpmnElement="reminder_Flow_10">
        <di:waypoint x="1875.0" y="310.0" />
        <di:waypoint x="2035.0" y="310.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_11" bpmnElement="reminder_Flow_11">
        <di:waypoint x="2085.0" y="310.0" />
        <di:waypoint x="2245.0" y="310.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_12" bpmnElement="reminder_Flow_12">
        <di:waypoint x="2395.0" y="310.0" />
        <di:waypoint x="2552.0" y="310.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_13" bpmnElement="reminder_Flow_13">
        <di:waypoint x="2085.0" y="310.0" />
        <di:waypoint x="2180.0" y="310.0" />
        <di:waypoint x="2180.0" y="440.0" />
        <di:waypoint x="980.0" y="440.0" />
        <di:waypoint x="980.0" y="492.0" />
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge id="reminder_DI_Flow_14" bpmnElement="reminder_Flow_14">
        <di:waypoint x="488.0" y="145.0" />
        <di:waypoint x="530.0" y="145.0" />
        <di:waypoint x="530.0" y="440.0" />
        <di:waypoint x="980.0" y="440.0" />
        <di:waypoint x="980.0" y="492.0" />
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</bpmn:definitions>

Условия напоминания:

  • первая отправка не раньше Ticket.created_at + SERVICE_REQUEST_TEMPLATE_REMINDER_INTERVAL_SECONDS;
  • последующие отправки учитывают последнюю успешную отправку в памяти процесса и тот же интервал;
  • при отсутствующем или неверном created_at helper пишет диагностику и пропускает напоминание.

Невозможность определить возраст для напоминания сама по себе не закрывает черновик.

Если есть planned_start и наступило close_at − SERVICE_REQUEST_TEMPLATE_CLOSE_WARNING_SECONDS, в сообщение добавляется дата автоматического закрытия. Она форматируется в локальной временной зоне runtime; не следует автоматически считать её часовой зоной пользователя. Напоминание не является гарантированным предварительным уведомлением: интервалы, фактические проходы, реквизиты и доступность XMPP влияют на отправку.

Получатель автора определяется защищённым creator-notification API. Если нет реквизитов/получателя либо API-ответ не позволяет отправить сообщение, helper возвращает false и не фиксирует успешный send; обычное ожидание продолжается. Исключение самой отправки попадает в общий retry. Успешный вызов send не доказывает прочтение человеком.

Счётчик последней отправки хранится в памяти и сбрасывается после рестарта. Нет durable verification ack; повтор после рестарта возможен. Вызывать это механизмом «однократного уведомления» было бы неверно.

Настройки и восстановление

Назначение Каноническое имя
Повтор прохода черновика SERVICE_REQUEST_TEMPLATE_RECHECK_SECONDS
Возраст/интервал напоминаний SERVICE_REQUEST_TEMPLATE_REMINDER_INTERVAL_SECONDS
Закрытие после планового начала SERVICE_REQUEST_TEMPLATE_CLOSE_AFTER_START_SECONDS
Окно текста предупреждения SERVICE_REQUEST_TEMPLATE_CLOSE_WARNING_SECONDS
Общий retry исключения DEFERRED_TICKET_RECHECK_SECONDS, причина processing_error
Сверка состава очереди INTERVAL_TIME_BD_REQ

Загрузка общего order context также читает именованные параметры таймингов соседних стадий; ошибочная обязательная настройка может остановить проход ещё до напоминания. Реальные значения сервера здесь не предполагаются.

Defer в памяти освобождает worker; срок означает готовность, не точное время запуска. Новая authoritative revision либо допустимый queued intent могут сделать Ticket готовым раньше; дубликат снимка не сбрасывает обычное ожидание. При рестарте состояние заказа перечитывается из backend, а память intent/reminder не заменяет persisted результат. Ошибка scoped списка не равна подтверждённой пустой очереди.

Диагностика

При диагностике различать:

  • 202 от relay и фактическое выполнение пользовательского действия;
  • извлечённый intent и доменный результат book/cancel;
  • фактическую стадию Orders/Ticket и доставку wakeup;
  • для автоматического закрытия — planned_start, именованный offset и выбранный runtime;
  • для напоминания — created_at, последний send в памяти, warning window, получателя и транспорт.

Одна открытая страница черновика не доказывает исполнения пользовательского запроса.

Проверенные источники

Git SHA/SHA-256 и параметры моделей закреплены в metadata и documentation BPMN. Handler при анализе не исполнялся, бизнес-запросы к заказам не выполнялись. Изменение источников требует повторного сопоставления.

Связанные материалы

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

© 2022 ShariX