Это старая версия документа!
Содержание
SERVICE_REQUEST в TEMPLATE: черновик, действия клиента и напоминания
Область: ShariX Open. Обработчик: open_service_request_template, тип SERVICE_REQUEST (2), рабочий статус TEMPLATE (210). Опубликованный Python на 28.10.2026 побайтово совпадает с канонической генерацией его Blockly workspace. Выбранная версия на конкретном сервере проверяется отдельно.
Назначение и границы
Handler сопровождает уже существующий черновик заказа: принимает подходящее пользовательское намерение, проверяет срок автоматического закрытия, напоминает автору о размещении и освобождает worker до следующего прохода. Он не создаёт заказ и не выбирает исполнителя в фоне только из-за наличия черновика.
Пользовательское book/cancel обрабатывается до проверки срока закрытия. Успешное действие либо устаревший scope завершают этот проход. Если intent не найден или каноническое пользовательское действие отклонено, текущий проход продолжает обычную проверку черновика. Очерёдность важна: дата закрытия не является предварительным фильтром перед всеми пользовательскими намерениями этой стадии.
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)
Загрузка схемы…
Исходник схемы
<?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" 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>
<bpmndi:BPMNDiagram id="Diagram_service_template_logic">
<bpmndi:BPMNPlane id="Plane_service_template_logic" bpmnElement="Collaboration_service_template_logic">
<bpmndi:BPMNShape id="template_DI_Pool_template" bpmnElement="template_Pool_template" isHorizontal="true">
<dc:Bounds x="0.0" y="0.0" width="2310" height="1030" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_Lane_worker" bpmnElement="template_Lane_worker" isHorizontal="true">
<dc:Bounds x="30.0" y="0.0" width="2280" height="637.5" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_Lane_queue" bpmnElement="template_Lane_queue" isHorizontal="true">
<dc:Bounds x="30.0" y="637.5" width="2280" height="392.5" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_start" bpmnElement="template_start">
<dc:Bounds x="132.0" y="92.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_status" bpmnElement="template_status">
<dc:Bounds x="325.0" y="85.0" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_intent" bpmnElement="template_intent">
<dc:Bounds x="515.0" y="75.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_handled" bpmnElement="template_handled">
<dc:Bounds x="825.0" y="85.0" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_intent_end" bpmnElement="template_intent_end">
<dc:Bounds x="1092.0" y="92.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_stale" bpmnElement="template_stale">
<dc:Bounds x="275.0" y="275.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_stale_end" bpmnElement="template_stale_end">
<dc:Bounds x="572.0" y="292.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_context" bpmnElement="template_context">
<dc:Bounds x="775.0" y="275.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_found" bpmnElement="template_found">
<dc:Bounds x="1085.0" y="285.0" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_missing" bpmnElement="template_missing">
<dc:Bounds x="1092.0" y="492.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_due" bpmnElement="template_due">
<dc:Bounds x="1345.0" y="285.0" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_close" bpmnElement="template_close">
<dc:Bounds x="1555.0" y="275.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_close_end" bpmnElement="template_close_end">
<dc:Bounds x="2132.0" y="292.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_reason" bpmnElement="template_reason">
<dc:Bounds x="1295.0" y="475.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_reminder" bpmnElement="template_reminder">
<dc:Bounds x="1555.0" y="475.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_defer" bpmnElement="template_defer">
<dc:Bounds x="1815.0" y="475.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_intent_error" bpmnElement="template_intent_error">
<dc:Bounds x="622.0" y="127.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_context_error" bpmnElement="template_context_error">
<dc:Bounds x="882.0" y="327.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_close_error" bpmnElement="template_close_error">
<dc:Bounds x="1662.0" y="327.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_send_error" bpmnElement="template_send_error">
<dc:Bounds x="1662.0" y="527.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_retry" bpmnElement="template_retry">
<dc:Bounds x="2075.0" y="475.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_wait" bpmnElement="template_wait">
<dc:Bounds x="1345.0" y="775.0" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_timer" bpmnElement="template_timer">
<dc:Bounds x="1612.0" y="712.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_event" bpmnElement="template_event">
<dc:Bounds x="1612.0" y="912.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="template_DI_ready" bpmnElement="template_ready">
<dc:Bounds x="1815.0" y="765.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="template_DI_Flow_0" bpmnElement="template_Flow_0">
<di:waypoint x="168.0" y="110.0" />
<di:waypoint x="325.0" y="110.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_1" bpmnElement="template_Flow_1">
<di:waypoint x="375.0" y="110.0" />
<di:waypoint x="515.0" y="110.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_2" bpmnElement="template_Flow_2">
<di:waypoint x="350.0" y="135.0" />
<di:waypoint x="350.0" y="275.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_3" bpmnElement="template_Flow_3">
<di:waypoint x="425.0" y="310.0" />
<di:waypoint x="572.0" y="310.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_4" bpmnElement="template_Flow_4">
<di:waypoint x="665.0" y="110.0" />
<di:waypoint x="825.0" y="110.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_5" bpmnElement="template_Flow_5">
<di:waypoint x="875.0" y="110.0" />
<di:waypoint x="1092.0" y="110.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_6" bpmnElement="template_Flow_6">
<di:waypoint x="850.0" y="135.0" />
<di:waypoint x="850.0" y="275.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_7" bpmnElement="template_Flow_7">
<di:waypoint x="925.0" y="310.0" />
<di:waypoint x="1085.0" y="310.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_8" bpmnElement="template_Flow_8">
<di:waypoint x="1110.0" y="335.0" />
<di:waypoint x="1110.0" y="492.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_9" bpmnElement="template_Flow_9">
<di:waypoint x="1135.0" y="310.0" />
<di:waypoint x="1345.0" y="310.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_10" bpmnElement="template_Flow_10">
<di:waypoint x="1395.0" y="310.0" />
<di:waypoint x="1555.0" y="310.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_11" bpmnElement="template_Flow_11">
<di:waypoint x="1370.0" y="335.0" />
<di:waypoint x="1370.0" y="475.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_12" bpmnElement="template_Flow_12">
<di:waypoint x="1445.0" y="510.0" />
<di:waypoint x="1555.0" y="510.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_13" bpmnElement="template_Flow_13">
<di:waypoint x="1705.0" y="510.0" />
<di:waypoint x="1815.0" y="510.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_14" bpmnElement="template_Flow_14">
<di:waypoint x="1965.0" y="510.0" />
<di:waypoint x="2010.0" y="510.0" />
<di:waypoint x="2010.0" y="660.0" />
<di:waypoint x="1370.0" y="660.0" />
<di:waypoint x="1370.0" y="775.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_15" bpmnElement="template_Flow_15">
<di:waypoint x="2225.0" y="510.0" />
<di:waypoint x="2280.0" y="510.0" />
<di:waypoint x="2280.0" y="640.0" />
<di:waypoint x="1370.0" y="640.0" />
<di:waypoint x="1370.0" y="775.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_16" bpmnElement="template_Flow_16">
<di:waypoint x="658.0" y="145.0" />
<di:waypoint x="700.0" y="145.0" />
<di:waypoint x="700.0" y="590.0" />
<di:waypoint x="2150.0" y="590.0" />
<di:waypoint x="2150.0" y="475.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_17" bpmnElement="template_Flow_17">
<di:waypoint x="918.0" y="345.0" />
<di:waypoint x="960.0" y="345.0" />
<di:waypoint x="960.0" y="570.0" />
<di:waypoint x="2150.0" y="570.0" />
<di:waypoint x="2150.0" y="475.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_18" bpmnElement="template_Flow_18">
<di:waypoint x="1698.0" y="345.0" />
<di:waypoint x="1740.0" y="345.0" />
<di:waypoint x="2150.0" y="345.0" />
<di:waypoint x="2150.0" y="475.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_19" bpmnElement="template_Flow_19">
<di:waypoint x="1698.0" y="545.0" />
<di:waypoint x="1740.0" y="545.0" />
<di:waypoint x="1740.0" y="600.0" />
<di:waypoint x="2150.0" y="600.0" />
<di:waypoint x="2150.0" y="475.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_20" bpmnElement="template_Flow_20">
<di:waypoint x="1395.0" y="800.0" />
<di:waypoint x="1503.5" y="800.0" />
<di:waypoint x="1503.5" y="730.0" />
<di:waypoint x="1612.0" y="730.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_21" bpmnElement="template_Flow_21">
<di:waypoint x="1395.0" y="800.0" />
<di:waypoint x="1503.5" y="800.0" />
<di:waypoint x="1503.5" y="930.0" />
<di:waypoint x="1612.0" y="930.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_22" bpmnElement="template_Flow_22">
<di:waypoint x="1648.0" y="730.0" />
<di:waypoint x="1731.5" y="730.0" />
<di:waypoint x="1731.5" y="800.0" />
<di:waypoint x="1815.0" y="800.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_23" bpmnElement="template_Flow_23">
<di:waypoint x="1648.0" y="930.0" />
<di:waypoint x="1731.5" y="930.0" />
<di:waypoint x="1731.5" y="800.0" />
<di:waypoint x="1815.0" y="800.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_24" bpmnElement="template_Flow_24">
<di:waypoint x="1965.0" y="800.0" />
<di:waypoint x="2410.0" y="800.0" />
<di:waypoint x="2410.0" y="25.0" />
<di:waypoint x="350.0" y="25.0" />
<di:waypoint x="350.0" y="85.0" />
<bpmndi:BPMNLabel>
<dc:Bounds x="2120.0" y="5.0" width="180" height="26" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="template_DI_Flow_25" bpmnElement="template_Flow_25">
<di:waypoint x="1705.0" y="310.0" />
<di:waypoint x="2132.0" y="310.0" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi: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)
Загрузка схемы…
Исходник схемы
<?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_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>
<bpmndi:BPMNDiagram id="Diagram_service_template_external">
<bpmndi:BPMNPlane id="Plane_service_template_external" bpmnElement="Collaboration_service_template_external">
<bpmndi:BPMNShape id="person_DI_Pool_person" bpmnElement="person_Pool_person" isHorizontal="true">
<dc:Bounds x="0.0" y="0.0" width="920" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="person_DI_Lane_worker" bpmnElement="person_Lane_worker" isHorizontal="true">
<dc:Bounds x="30.0" y="0.0" width="890" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="person_DI_start" bpmnElement="person_start">
<dc:Bounds x="132.0" y="82.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="person_DI_send" bpmnElement="person_send">
<dc:Bounds x="375.0" y="65.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="person_DI_end" bpmnElement="person_end">
<dc:Bounds x="742.0" y="82.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="person_DI_Flow_0" bpmnElement="person_Flow_0">
<di:waypoint x="168.0" y="100.0" />
<di:waypoint x="375.0" y="100.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="person_DI_Flow_1" bpmnElement="person_Flow_1">
<di:waypoint x="525.0" y="100.0" />
<di:waypoint x="742.0" y="100.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="relay_DI_Pool_relay" bpmnElement="relay_Pool_relay" isHorizontal="true">
<dc:Bounds x="0.0" y="300.0" width="1220" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="relay_DI_Lane_worker" bpmnElement="relay_Lane_worker" isHorizontal="true">
<dc:Bounds x="30.0" y="300.0" width="1190" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="relay_DI_start" bpmnElement="relay_start">
<dc:Bounds x="132.0" y="382.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="relay_DI_acl" bpmnElement="relay_acl">
<dc:Bounds x="375.0" y="365.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="relay_DI_xmpp" bpmnElement="relay_xmpp">
<dc:Bounds x="685.0" y="365.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="relay_DI_end" bpmnElement="relay_end">
<dc:Bounds x="1042.0" y="382.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="relay_DI_Flow_0" bpmnElement="relay_Flow_0">
<di:waypoint x="168.0" y="400.0" />
<di:waypoint x="375.0" y="400.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="relay_DI_Flow_1" bpmnElement="relay_Flow_1">
<di:waypoint x="525.0" y="400.0" />
<di:waypoint x="685.0" y="400.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="relay_DI_Flow_2" bpmnElement="relay_Flow_2">
<di:waypoint x="835.0" y="400.0" />
<di:waypoint x="1042.0" y="400.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="handler_DI_Pool_handler" bpmnElement="handler_Pool_handler" isHorizontal="true">
<dc:Bounds x="0.0" y="650.0" width="1520" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="handler_DI_Lane_worker" bpmnElement="handler_Lane_worker" isHorizontal="true">
<dc:Bounds x="30.0" y="650.0" width="1490" height="200" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="handler_DI_start" bpmnElement="handler_start">
<dc:Bounds x="132.0" y="732.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="handler_DI_validate" bpmnElement="handler_validate">
<dc:Bounds x="375.0" y="715.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="handler_DI_queue" bpmnElement="handler_queue">
<dc:Bounds x="685.0" y="715.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="handler_DI_apply" bpmnElement="handler_apply">
<dc:Bounds x="985.0" y="715.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="handler_DI_end" bpmnElement="handler_end">
<dc:Bounds x="1342.0" y="732.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="handler_DI_Flow_0" bpmnElement="handler_Flow_0">
<di:waypoint x="168.0" y="750.0" />
<di:waypoint x="375.0" y="750.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="handler_DI_Flow_1" bpmnElement="handler_Flow_1">
<di:waypoint x="525.0" y="750.0" />
<di:waypoint x="685.0" y="750.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="handler_DI_Flow_2" bpmnElement="handler_Flow_2">
<di:waypoint x="835.0" y="750.0" />
<di:waypoint x="985.0" y="750.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="handler_DI_Flow_3" bpmnElement="handler_Flow_3">
<di:waypoint x="1135.0" y="750.0" />
<di:waypoint x="1342.0" y="750.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="backend_DI_Pool_backend" bpmnElement="backend_Pool_backend" isHorizontal="true">
<dc:Bounds x="0.0" y="1000.0" width="1800" height="380" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="backend_DI_Lane_worker" bpmnElement="backend_Lane_worker" isHorizontal="true">
<dc:Bounds x="30.0" y="1000.0" width="1770" height="380" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="backend_DI_start" bpmnElement="backend_start">
<dc:Bounds x="132.0" y="1082.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="backend_DI_check" bpmnElement="backend_check">
<dc:Bounds x="375.0" y="1065.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="backend_DI_decide" bpmnElement="backend_decide">
<dc:Bounds x="735.0" y="1075.0" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="backend_DI_save" bpmnElement="backend_save">
<dc:Bounds x="985.0" y="1065.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="backend_DI_wake" bpmnElement="backend_wake">
<dc:Bounds x="1285.0" y="1065.0" width="150" height="70" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="backend_DI_end" bpmnElement="backend_end">
<dc:Bounds x="1622.0" y="1082.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="backend_DI_reject" bpmnElement="backend_reject">
<dc:Bounds x="742.0" y="1262.0" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="backend_DI_Flow_0" bpmnElement="backend_Flow_0">
<di:waypoint x="168.0" y="1100.0" />
<di:waypoint x="375.0" y="1100.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="backend_DI_Flow_1" bpmnElement="backend_Flow_1">
<di:waypoint x="525.0" y="1100.0" />
<di:waypoint x="735.0" y="1100.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="backend_DI_Flow_2" bpmnElement="backend_Flow_2">
<di:waypoint x="785.0" y="1100.0" />
<di:waypoint x="985.0" y="1100.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="backend_DI_Flow_3" bpmnElement="backend_Flow_3">
<di:waypoint x="760.0" y="1125.0" />
<di:waypoint x="760.0" y="1262.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="backend_DI_Flow_4" bpmnElement="backend_Flow_4">
<di:waypoint x="1135.0" y="1100.0" />
<di:waypoint x="1285.0" y="1100.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="backend_DI_Flow_5" bpmnElement="backend_Flow_5">
<di:waypoint x="1435.0" y="1100.0" />
<di:waypoint x="1622.0" y="1100.0" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DI_Message_service_template_external_0" bpmnElement="Message_service_template_external_0">
<di:waypoint x="450" y="135" />
<di:waypoint x="450" y="245" />
<di:waypoint x="150" y="245" />
<di:waypoint x="150" y="382" />
<bpmndi:BPMNLabel>
<dc:Bounds x="170" y="215" width="260" height="42" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DI_Message_service_template_external_1" bpmnElement="Message_service_template_external_1">
<di:waypoint x="760" y="435" />
<di:waypoint x="760" y="590" />
<di:waypoint x="150" y="590" />
<di:waypoint x="150" y="732" />
<bpmndi:BPMNLabel>
<dc:Bounds x="190" y="555" width="260" height="42" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DI_Message_service_template_external_2" bpmnElement="Message_service_template_external_2">
<di:waypoint x="1060" y="785" />
<di:waypoint x="1060" y="940" />
<di:waypoint x="150" y="940" />
<di:waypoint x="150" y="1082" />
<bpmndi:BPMNLabel>
<dc:Bounds x="230" y="905" width="260" height="42" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="DI_Message_service_template_external_3" bpmnElement="Message_service_template_external_3">
<di:waypoint x="525" y="100" />
<di:waypoint x="1850" y="100" />
<di:waypoint x="1850" y="950" />
<di:waypoint x="75" y="950" />
<di:waypoint x="75" y="1100" />
<di:waypoint x="132" y="1100" />
<bpmndi:BPMNLabel>
<dc:Bounds x="1500" y="860" width="260" height="42" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi: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/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)
Загрузка схемы…
Исходник схемы
<?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 при анализе не исполнялся, бизнес-запросы к заказам не выполнялись. Изменение источников требует повторного сопоставления.
- sharix-open-handlers-examples / handlers/open_service_request_template.py — Git 76e0c693b628ed4a1fa34515a3f8abdff26149bb.
- sharix-open-handlers-examples / generated_handler_blocks/open_service_request_template.json — Git 76e0c693b628ed4a1fa34515a3f8abdff26149bb.
- sharix-open-handlers-examples / catalog.py — Git 76e0c693b628ed4a1fa34515a3f8abdff26149bb.
- sharix-open-handlers-backend / core/blockly_runtime.py — Git 50baf376e224d915a87d63240f3f339b3dda9afa.
- sharix-open-handlers-backend / core/requesters.py — Git 50baf376e224d915a87d63240f3f339b3dda9afa.
- sharix-open-handlers-backend / core/order_action_messages.py — Git 50baf376e224d915a87d63240f3f339b3dda9afa.
- sharix-open-handlers-backend / ticket_blockly_codegen.py — Git 50baf376e224d915a87d63240f3f339b3dda9afa.
- sharix-open-handlers-backend / ticket_codegen_contract.json — Git 50baf376e224d915a87d63240f3f339b3dda9afa.
- sharix-open-tickets / lib/tickets.py — Git fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14.
- sharix-open-tickets / api/handler_auth.py — Git fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14.
- sharix-open-tickets / signals.py — Git fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14.
- sharix-open-tickets / services/handler_wakeup.py — Git fd64704d7d9f01a5ec5b7b89cbc5afe5102b2c14.
- sharix-open-backend / apiviews/handler_order_workflow.py — Git 778a3280cee115ba0efe3fdff7b0e708b0c10093.
- sharix-open-backend / apiviews/open_api.py — Git 778a3280cee115ba0efe3fdff7b0e708b0c10093.
- sharix-open-backend / lib/order_handler_relay.py — Git 778a3280cee115ba0efe3fdff7b0e708b0c10093.
- sharix-open-backend / lib/handler_order_context.py — Git 778a3280cee115ba0efe3fdff7b0e708b0c10093.
- sharix-open-backend / lib/order_workflow_policy.py — Git 778a3280cee115ba0efe3fdff7b0e708b0c10093.
- sharix-open-backend / lib/order_actions.py — Git 778a3280cee115ba0efe3fdff7b0e708b0c10093.
- sharix-open-backend / lib/order_permissions.py — Git 778a3280cee115ba0efe3fdff7b0e708b0c10093.
- sharix-open-backend / urls.py — Git 778a3280cee115ba0efe3fdff7b0e708b0c10093.
Связанные материалы
Связанные материалы
- SERVICE_REQUEST в ACCEPTED: подготовка, подтверждение и платёжное ожидание business_processes · implemented
- SERVICE_REQUEST в ASSIGNED: раунд подтверждения и принятие назначения business_processes · implemented
- SERVICE_REQUEST в BOOKED: ожидание исполнителя и окно PENDING business_processes · implemented
- SERVICE_REQUEST в PENDING: партии кандидатов и назначение победителя business_processes · implemented
- SERVICE_REQUEST в PRE_START: начало выполнения и внешние действия business_processes · implemented
- SERVICE_REQUEST в PROCESS: этапы выполнения, завершение и подписка business_processes · implemented
- Материалы по аудитории glossary · not_applicable
- Материалы по назначению glossary · not_applicable
- Материалы по продукту и применимости glossary · not_applicable
- Темы и понятия базы знаний glossary · not_applicable
- Обработчики ShariX Open: Blockly, Python и выполнение modules · implemented
- Health, systemd, handlers и многократные установки reference · implemented
- Сценарии ShariX Open: выбор процесса и проверка результата use_cases · not_applicable