Skip to content

Refund coordinator

Что делает: ЮKassa webhook о refund-request’е → находит сделку в amoCRM по metadata → просит approval у owner’а (если > 10 000 ₽) → после approval’а обновляет сделку + создаёт задачу в 1С для бухгалтера оформить корректировку.

Production-safe: ни один refund не уходит в бухгалтерию без подтверждения человеком.

yookassa-shop-id
yookassa-secret-key
amocrm-token-main
amocrm-subdomain
onec-url
onec-username
onec-password
┌────────────────────┐
│ yookassa.webhook. │ event: refund.succeeded
│ trigger │
└────────┬───────────┘
│ {object: {id, amount, metadata.order_id, ...}}
┌────────────────────┐
│ amocrm.crm.list │ entity=leads,
│ │ filter by custom_field (order_id)
└────────┬───────────┘
│ {results: [{id: 12345, name: "...", ...}], _total_items: 1}
┌────────────────────┐
│ control.switch │ amount > 10000?
└────┬───────────┬───┘
│ yes │ no
↓ ↓
┌────────────┐ │
│ approval. │ │
│ request │ │
└────┬───────┘ │
│ approved │
└─────┬─────┘
┌────────────────────┐
│ amocrm.lead.update │ status_id = "refunded"
└────────┬───────────┘
┌────────────────────┐
│ onec.odata.create │ Document_КорректировкаРеализации
└────────────────────┘
events:
- refund.succeeded
token: "{{secrets.yookassa-webhook-token}}"
entity: leads
filter:
custom_fields_values:
- field_code: "ORDER_ID"
values: [{ value: "{{trigger.object.metadata.order_id}}" }]
limit: 1

Если нет сделки (list.results.length == 0) — fall’aем с alert’ом в Telegram / логом. Здесь для краткости не показываю.

3. control.switch на trigger.object.amount.value > 10000

Section titled “3. control.switch на trigger.object.amount.value > 10000”

Две ветки: approve-required (большой refund) и auto-approved (мелкий).

4a. approval.request (только для > 10 000 ₽)

Section titled “4a. approval.request (только для > 10 000 ₽)”
title: "Refund {{trigger.object.amount.value}} ₽ для сделки {{list.results.0.name}}"
body: |
Заказ: {{trigger.object.metadata.order_id}}
Клиент: {{list.results.0.name}}
Сумма refund'а: {{trigger.object.amount.value}} ₽
ЮKassa ID: {{trigger.object.id}}
amoCRM: https://{{secrets.amocrm-subdomain}}.amocrm.ru/leads/detail/{{list.results.0.id}}
assignedTo:
kind: role
role: owner
ttl: 172800 # 48 часов

Две выходные ветки: approved → шаг 5, rejected → terminal с telegram.message.send уведомлением что refund отклонён.

id: "{{list.results.0.id}}"
status_id: 23459 # ваш ID status'а «Возврат»
custom_fields_values:
- field_code: "REFUND_AMOUNT"
values: [{ value: "{{trigger.object.amount.value}}" }]
- field_code: "REFUND_AT"
values: [{ value: "{{run.startedAt}}" }]
entity: Document_КорректировкаРеализации
data:
Дата: "{{run.startedAt}}"
Номер: "REF-{{trigger.object.id}}"
Основание_Type: "StandardODATA.Document_РеализацияТоваровУслуг"
Основание_Key: "{{list.results.0.custom_fields_values.onec_realization_guid}}"
СуммаДокумента: "{{trigger.object.amount.value}}"
Комментарий: "Возврат по refund ID: {{trigger.object.id}}"

Если 1С автоматически проводит документ (зависит от настроек) — бухгалтер получит notification в 1С’овском messenger’е.

webhook → list → switch(auto) → update → create ~3 сек. Сделка в amoCRM закрыта, корректировка в 1С создана, всё без вмешательства людей.

webhook → list → switch(approval) → approval.request — дальше run в статусе awaiting_approval на /approvals.

Owner заходит в /approvals, видит карточку, жмёт Approve → amocrm.lead.update и onec.odata.create отрабатывают.

Если owner 48 часов не заметил — approval auto-expires, run падает в failed с reason TIMEOUT. Мы не коммитим рефанд в 1С без ручного подтверждения — safety-by-default.

Замените 10000 на expression с конфигурационной таблицей:

control.switch
condition: "trigger.object.amount.value > data_table.rows.get('config', 'refund_threshold')"

Тогда менять порог можно без редактирования workflow’а — через data-tables UI.

Alert в Telegram в параллель с approval’ом

Section titled “Alert в Telegram в параллель с approval’ом”

После approval.request добавьте telegram.message.send в параллельную ветку:

approval.request (...) ─┬─→ (approved) → amocrm.lead.update ...
└─→ telegram.message.send (нотификация что
ждёт approval'а, ссылка на /approvals)

Разные 1С-entities для разных продуктов

Section titled “Разные 1С-entities для разных продуктов”

Используйте control.switch по product-type перед onec.odata.create, или централизуйте routing в data-table’е (product_id → onec_entity).

Сделка в amoCRM не нашлась. Причины:

  • order_id в ЮKassa metadata не совпадает с ORDER_ID custom_field’ом в amoCRM (проверьте в обеих системах)
  • Сделка была удалена в amoCRM после оплаты
  • Сделка в другой pipeline’е; amocrm.crm.list не фильтрует по pipeline — уточните filter’ом если нужно

Добавьте control.switch на list.results.length и fallback-ветку, где шлёте alert в Telegram: «не смогли найти сделку для refund’а {id}, разберитесь вручную».

v1 не шлёт push-нотификаций. Владельцу нужно видеть /approvals страницу. Workaround — добавить telegram.message.send параллельно approval.request (см. Variations).

Типичный trigger: required reference-field не заполнен (Организация _Key, Контрагент_Key). В 1С каждая конфигурация имеет свои required-поля — смотрите $metadata или тело ошибки.

Refund приходит дважды (ЮKassa ретраит)

Section titled “Refund приходит дважды (ЮKassa ретраит)”

OPORA дедуп’ит по trigger.object.id — повторный run не создаётся, получите 200 OK + header X-Opora-Idempotent: true. Никаких ручных действий не нужно.