Настройка частичного возврата средств на 1С-Битрикс
Частичный возврат — ситуация технически сложнее полного: нужно вернуть не всю сумму платежа, а только часть, при этом корректно пересчитать чек (если подключена фискализация), обновить статусы заказа и товарных позиций в Битрикс. Ошибки здесь дорогостоящие: неправильный чек возврата — основание для штрафа от налоговой.
Где выполняется частичный возврат
Частичный возврат инициируется магазином через API платёжной системы. Покупатель обращается в поддержку, менеджер обрабатывает возврат в административной панели Битрикс — либо через стандартный интерфейс (если модуль поддерживает), либо через кастомный обработчик.
API возврата: примеры
Тинькофф:
$params = [
'TerminalKey' => TINKOFF_TERMINAL,
'PaymentId' => $externalPaymentId, // ID платежа в Тинькофф
'Amount' => (int)($refundAmount * 100), // копейки
];
$params['Token'] = tinkoffSign($params, TINKOFF_SECRET);
$result = tinkoffPost('/v2/Cancel', $params);
// result['Status'] === 'REFUNDED' — успешный возврат
ЮКасса:
use YooKassa\Client;
$client = new Client();
$client->setAuth($shopId, $secretKey);
$refund = $client->createRefund([
'payment_id' => $externalPaymentId,
'amount' => [
'value' => number_format($refundAmount, 2, '.', ''),
'currency' => 'RUB',
],
'description' => 'Возврат позиции: ' . $itemName,
'receipt' => $refundReceiptData, // обязателен при подключённой кассе
], uniqid('', true));
Чек возврата (54-ФЗ)
Если подключена онлайн-касса, частичный возврат требует передачи чека возврата в ОФД. Структура чека возврата идентична исходному, но:
-
typeдокумента:refund(в АТОЛ),payment_refund(в ЮКасса) - В чек включаются только возвращаемые позиции с возвращаемыми суммами
- Сумма позиций в чеке должна точно совпадать с суммой возврата
// Пример чека возврата для ЮКасса
$refundReceiptData = [
'customer' => ['email' => $buyer->getEmail()],
'items' => [],
];
foreach ($refundItems as $item) {
$refundReceiptData['items'][] = [
'description' => $item['name'],
'quantity' => $item['quantity'],
'amount' => [
'value' => number_format($item['price'] * $item['quantity'], 2, '.', ''),
'currency' => 'RUB',
],
'vat_code' => $item['vat_code'],
'payment_subject' => 'commodity',
'payment_mode' => 'full_payment',
];
}
// Проверяем: сумма позиций === сумма возврата
$itemsTotal = array_sum(array_column(
array_map(fn($i) => ['sum' => $i['price'] * $i['quantity']], $refundItems),
'sum'
));
assert(abs($itemsTotal - $refundAmount) < 0.01, 'Расхождение суммы чека!');
Обновление статусов в Битрикс
После успешного возврата нужно обновить состояние в модуле Sale:
// Частичный возврат — не ставим оплату как "возвращена" полностью
// Только записываем сумму возврата и обновляем статус товарной позиции
$payment = $order->getPaymentCollection()->getItemById($paymentId);
$payment->setField('PS_STATUS_MESSAGE',
'Частичный возврат ' . $refundAmount . ' руб. от ' . date('d.m.Y')
);
// Обновляем статус возвращённых товарных позиций
foreach ($refundItems as $refundItem) {
$basketItem = getBasketItemById($order, $refundItem['basket_id']);
if ($basketItem) {
$basketItem->setField('CUSTOM_PRICE', 'Y');
// Или создаём отдельную запись в истории возвратов
}
}
$order->save();
Кейс: магазин одежды, возврат части заказа
Покупатель заказал 3 позиции на 8 400 руб. Одна позиция не подошла по размеру — возврат 2 100 руб. Через стандартный интерфейс Битрикс возврат не проходил: модуль Тинькофф поддерживал только полный возврат.
Решение: кастомный обработчик возвратов в /local/. Менеджер выбирает позиции для возврата → PHP-скрипт формирует чек возврата, вызывает /v2/Cancel с частичной суммой, фиксирует результат в пользовательском поле заказа. Время разработки: 3 дня.
Сроки
| Задача | Срок |
|---|---|
| Частичный возврат без фискализации | 1–2 дня |
| Частичный возврат + чек возврата (54-ФЗ) | 2–4 дня |
| Интерфейс для менеджера в админке | 1–2 дня |







