Эта страница описывает ежедневное завершение платежей по исполненным событиям: списание ранее захолдированных средств для выполненного заказа или снятие холда в пользу клиента.
При подтверждении оплаты FreedomPay создает платеж. После webhook заказ может перейти в funds_holded. Деньги остаются в холде до момента, когда дата исполнения события прошла.
После даты исполнения backend принимает одно из решений:
| Состояние события | Операция FreedomPay | Новый статус internal order |
|---|---|---|
done |
edit.payment.clearing на полную сумму заказа |
success |
| Любой другой статус | edit.payment.reverse |
canceled |
Clearing завершает платеж по сумме BaseInternalOrder.amount. Reverse снимает холд и возвращает доступность средств клиенту. Обрабатываются только заказы в статусе funds_holded.
Задача поддерживает четыре домена:
| Тип | Дата исполнения считается прошедшей, когда |
|---|---|
| Job | planning_start_time + planning_duration_time < now |
| Bringing | planning_bringing_time < local date |
| Contract | planning_contract_end_date < local date |
| Storage | receiving_time < now |
Для полей DateField событие обрабатывается начиная со следующей локальной даты. Для DateTimeField сравнение выполняется с текущим timezone-aware временем.
Наличие EventMoveRequest само по себе не исключает событие из расчета.
Таким образом, решение определяется фактической датой в event, а не наличием или историей запроса переноса.
Task:
event_flow.settle_due_events
Реализация:
event_flow.tasks.settle_due_events_task — Celery entrypoint;event_flow.settlements.settle_due_events — обход просроченных событий;event_flow.settlements.settle_event — атомарная обработка одного события;event_flow.services._payment_id — получение FreedomPay payment id из сохраненного create_payment response.Миграция event_flow.0002_daily_settlement_schedule создает включенную periodic task Daily settlement of due events с расписанием 02:00 UTC каждый день.
Проект использует django_celery_beat.schedulers.DatabaseScheduler, поэтому расписание управляется в Django admin:
/admin/.Periodic tasks.Daily settlement of due events.enabled.Не нужно добавлять это расписание в CELERY_BEAT_SCHEDULE или в код settings. Источник истины — база django-celery-beat.
funds_holded.success, после reverse — на canceled.select_for_update() блокирует event на время обработки и сериализует параллельные ручные/плановые запуски для одного события.FreedomPay response сохраняется в FreedomPayProviderResponse через общий механизм payment operations.
Ошибка FreedomPay или отсутствие payment_id обрабатывается на уровне отдельного события:
funds_holded;event_type и event_id.Task возвращает счетчики:
{
"paid": 2,
"released": 1,
"skipped": 0,
"errors": 1
}
paid — успешные clearing, released — успешные reverse, skipped — кандидаты, состояние которых изменилось до получения блокировки, errors — ожидаемые ошибки провайдера или отсутствующий payment id.
Перед включением в production:
default;/v5/g2g/edit;FreedomPayProviderResponse сохраняются для clearing/reverse.Для ручного запуска из Django shell:
from event_flow.tasks import settle_due_events_task
settle_due_events_task.delay()
Для синхронной диагностики без постановки в broker:
from event_flow.settlements import settle_due_events
result = settle_due_events()
Синхронный вызов выполняет реальные provider operations и не является dry run.
event_flow.tests.EventFlowTests проверяет:
done;funds_holded после ошибки провайдера.Запуск:
python manage.py test event_flow.tests