Перейти к содержанию

Финансы, курсы и тарифы

Баланс клиента и леджер

У клиента два независимых счёта (client_balance_accounts): RUB и CNY. Оплаты заказов — в CNY.

RUR → RUB и новые денежные возможности

Код рублёвой валюты унифицирован: RURRUB (миграция unify_rur_to_rub). Добавлены: овердрафт клиента (clients.overdraft_limit — баланс может уходить в минус в пределах лимита), пополнение баланса вне заказа (standalone top-up: topup_requests.order_id стал nullable + currency + note), валюта доп. услуг (agent_rate_settings.services_currency), снимок курсов на отгрузке (shipments.currency_rates).

Все движения средств идут через LedgerService — единственную точку с lockForUpdate (атомарность). Каждое движение пишется в balance_ops со знаком и остатком после операции (balance_after), со ссылками на заказ/отгрузку/счёт.

flowchart LR
    Top[Пополнение баланса] --> Bal[Баланс клиента ¥]
    Bal -->|«Оплатить с баланса»| Order[Заказ → Выкуп]
    Bal -->|оплата доставки| Ship[Отгрузка → Оплачена]

Платёжный флоу

Оплата ≠ списание в заказ

Это ключевое решение. Подтверждение реквизитов пополняет общий баланс, а не списывает в конкретный заказ.

  1. Посредник выдаёт реквизиты/счёт (invoices): карта (payment_cards, номер шифруется) / наличные / платёжный агент. Короткий код для просмотра без логина — requisite_codes (/r/{code}).
  2. Клиент отметил «оплачено» → посредник «Реквизиты оплачены» → ConfirmInvoicePaid пополняет общий ¥-баланс клиента (topUpFromInvoice).
  3. Клиент жмёт «Оплатить с баланса»PayOrderFromBalance: если баланс ≥ суммы заказа → списание + снимок расчёта + переход await_pay → buyout.
  4. Не хватает → «Запросить пополнение» (на любую сумму) → запись topup_requests (pendingfulfilled) + сообщение посреднику; после подтверждения — пополнение общего баланса.

Мультивалютные счёта

У invoices добавлены base_currency / pay_currency / auto_convert — счёт может выставляться в одной валюте, а оплачиваться в другой с авто-конвертацией. Клиент может сменить валюту счёта (orders.invoice-currency). Валюта клиента — clients.currency.

Комиссия

CommissionService — ступенчатая комиссия по тарифу клиента (client_tariffs / client_subtariffs / client_tariff_steps):

  • ступени from_cny → pct (ладдер);
  • особая ставка первого заказа (first_order_pct), включается флагом first_order_commission_enabled;
  • подтариф выбирается по сайту товара (подтариф, чьи сайты покрывают сайт; иначе «Основной»).

Курсы валют

Курс посредника rates (₽ за 1 ¥), value через RateService::effectiveValue($agent, ?$amountCny):

Режим / источник Поведение
manual Фиксированное значение
auto + cbr Курс ЦБ РФ × (1 + наценка markup_pct)
auto + bestchange Средний курс топ-N обменников × (1 + наценка)
Ладдер (rate_steps, kind=order) Ступенчатый курс по сумме заказа

Ладдеры стали мультивалютными: у rate_steps добавлены from_cur/to_cur (валютная пара ступени), а у agent_rate_settingsdelivery_base (базовая валюта доставки). Это позволяет вести курсы не только ¥→₽.

Дополнительно agent_rate_settings: курс usd_rub, кросс usd_cny, режим приёма (self/bestchange), срок действия курса, тексты о доставке. В шапке кабинета — три виджета: $ → ₽, 元 От {курс}, $ → 元.

Источники курсов

  • ЦБ РФ (CbrRateService): парсит XML_daily.asp, берёт CNY и USD за один запрос. Команда rates:fetch-cbr (ежечасно), кэш cbr:CNY:RUB / cbr:USD:RUB.
  • bestchange (BestchangeService): курсы обменников и сами обменники, средний курс топ-N «проверенных» под лимит. Команда bestchange:fetch (каждые 15 мин).

Мультивалютность

  • currencies — справочник валют; agent_currencies — валюты посредника + основная (is_main).
  • Внутренний учёт в ¥/$, клиент видит суммы в display_currency (валюта страны).
  • Конвертация — CurrencyService по курсам посредника.

СРМ-тарифы посредника

Посредник платит за пользование платформой (crm_tariffs): месячная плата, лимит сотрудников, бесплатные заказы/товары, плата за превышение.

  • agent_invoices — счета СРМ (пополнение agents.balance_cny); подтверждает админ.
  • crm_charges — аудит списаний: subscription (месячная плата), over_order, over_item, renew_downgrade. order_id уникален для over_* (анти-дубль).
  • Команда crm:renew-tariffs — авто-продление ежедневно в 03:00.

Пополнение Alipay/WeChat

wallet_topupsдоп.услуга, не влияет на баланс: клиент создаёт заявку (система + кошелёк + сумма), передаёт деньги вне системы, посредник помечает «оплачено». Отдельная история пополнений.