עיבוד ידני של החזרות הוא צוואר בקבוק עבור חנות מסחר אלקטרוני על 1C-Bitrix עם למעלה מ-100 הזמנות ביום. מנהלים מתבלבלים בין סטטוסים, עושים שגיאות בסכומים, ובקשות הולכות לאיבוד. מהניסיון שלנו: לקוח אחד עם 500 הזמנות ביום בילה עד 10 ימים על החזרות, עם שיעור שגיאות של 30%. לאחר הטמעת המערכת שלנו, זמן העיבוד ירד ליום אחד וההוצאות התפעוליות ירדו ב-$14k–20k בשנה. אוטומציה מלאה פותרת את הבעיות האלה: הלקוח מקבל החזר כספי תוך 1-2 ימים, מנהלים מבזבזים לא יותר מ-5 דקות על כל החזרה. המערכת מעבדת החזרות פי 10 מהר יותר מעיבוד ידני. כדי לקבל תוכנית מדויקת לחנות שלך, בקש ייעוץ.
בעיות שאנחנו פותרים
כאוס סטטוסים הוא נקודת הכאב המרכזית. סטטוסי מכירה רגילים לא מתאימים להחזרות; יש צורך בשרשרת נפרדת עם שלבים ברורים. החזרים ידניים דרך החשבון האישי של שער התשלום מובילים לשגיאות סכום ועיכובים. חוסר אינטגרציה עם המחסן לאחר החזרה: המלאי לא מתעדכן, או שהנתונים משוכפלים במהלך החלפה עם 1C. כל אחת מהבעיות האלה בנפרד פוגעת בנאמנות הלקוחות ומכבידה על המנהלים בשגרה. בניסיון שלנו, תיקון החזרה בודדת נהג לקחת כמה שעות עד שאוטמטנו את כל המחזור.
איך אנחנו עושים את זה: מחסן טכנולוגי ומקרה אמיתי
אנחנו משתמשים במודול הסטנדרטי sale וב-infoblocks v2.0. הישות המרכזית היא \Bitrix\Sale\OrderReturn. היא מקשרת את ההחזרה להזמנה, שומרת את הסוג (כסף/החלפה/זיכוי) ורשימת פריטים. אנחנו בונים את התהליך סביבה. להלן דוגמה ליצירת החזרה דרך API.
namespace Local\Returns;
use Bitrix\Sale;
class ReturnManager
{
/**
* Создаём возврат по заказу
*
* @param int $orderId ID заказа
* @param array $items [['basket_id' => int, 'quantity' => float, 'reason' => string], ...]
* @param string $returnType 'MONEY' | 'EXCHANGE' | 'CREDIT'
*/
public function createReturn(int $orderId, array $items, string $returnType = 'MONEY'): int
{
\Bitrix\Main\Loader::includeModule('sale');
$order = Sale\Order::load($orderId);
if (!$order) {
throw new \RuntimeException("Order #{$orderId} not found");
}
// Проверяем, что заказ оплачен
if (!$order->isPaid()) {
throw new \RuntimeException("Order #{$orderId} is not paid");
}
$returnCollection = $order->getPaymentCollection();
// Создаём объект возврата
$orderReturn = Sale\OrderReturn::create($order);
$orderReturn->setField('TYPE', $returnType);
$orderReturn->setField('REASON', 'Заявка покупателя');
// Добавляем позиции возврата
$basketCollection = $order->getBasket();
foreach ($items as $item) {
$basketItem = $basketCollection->getItemById($item['basket_id']);
if (!$basketItem) continue;
$maxQty = $basketItem->getQuantity();
$qty = min((float)$item['quantity'], $maxQty);
$returnItem = $orderReturn->getReturn()->createItem($basketItem);
$returnItem->setField('QUANTITY', $qty);
$returnItem->setField('REASON', $item['reason'] ?? '');
}
$result = $orderReturn->save();
if (!$result->isSuccess()) {
throw new \RuntimeException('Return creation failed: ' . implode('; ', $result->getErrorMessages()));
}
return $orderReturn->getId();
}
}פיתוח רכיב חשבון אישי מותאם לוקח פי 2-3 פחות זמן מאשר כתיבה מאפס, הודות לשימוש ברכיב הסטנדרטי namespace Local\Returns; use Bitrix\Sale; class ReturnManager { /** * Создаём возврат по заказу * * @param int $orderId ID заказа * @param array $items [['basket_id' => int, 'quantity' => float, 'reason' => string], ...] * @param string $returnType 'MONEY' | 'EXCHANGE' | 'CREDIT' */ public function createReturn(int $orderId, array $items, string $returnType = 'MONEY'): int { \Bitrix\Main\Loader::includeModule('sale'); $order = Sale\Order::load($orderId); if (!$order) { throw new \RuntimeException("Order #{$orderId} not found"); } // Проверяем, что заказ оплачен if (!$order->isPaid()) { throw new \RuntimeException("Order #{$orderId} is not paid"); } $returnCollection = $order->getPaymentCollection(); // Создаём объект возврата $orderReturn = Sale\OrderReturn::create($order); $orderReturn->setField('TYPE', $returnType); $orderReturn->setField('REASON', 'Заявка покупателя'); // Добавляем позиции возврата $basketCollection = $order->getBasket(); foreach ($items as $item) { $basketItem = $basketCollection->getItemById($item['basket_id']); if (!$basketItem) continue; $maxQty = $basketItem->getQuantity(); $qty = min((float)$item['quantity'], $maxQty); $returnItem = $orderReturn->getReturn()->createItem($basketItem); $returnItem->setField('QUANTITY', $qty); $returnItem->setField('REASON', $item['reason'] ?? ''); } $result = $orderReturn->save(); if (!$result->isSuccess()) { throw new \RuntimeException('Return creation failed: ' . implode('; ', $result->getErrorMessages())); } return $orderReturn->getId(); } } . מהניסיון שלנו: הטמעת מערכת החזרות עבור מרקטפלייס גדול צמצמה את זמן המחזור המלא מ-14 ל-2 ימים.
הגדרת מחזור החיים של ההחזרה
סטטוסי החזרה: סט סטנדרטי
בפאנל הניהול, אנחנו יוצרים סטטוסים המכסים כל שלב בתהליך העסקי. סט מינימלי: WAIT, REVIEW, APPROVED, RECEIVED, REFUND, REJECTED, EXCHANGE. כל סטטוס מכסה באופן לוגי שלב.
| קוד | שם | תיאור |
|---|---|---|
| WAIT | ממתין לבדיקה | בקשה חדשה, לא טופלה |
| REVIEW | בבדיקה | המנהל בודק את הבקשה |
| APPROVED | אושר | ההחזרה אושרה, ממתין לסחורה |
| RECEIVED | הסחורה התקבלה | המחסן קיבל את הסחורה המוחזרת |
| REFUND | הכסף הוחזר | התשלום הושלם |
| REJECTED | נדחה | ההחזרה נדחתה עם סיבה |
| EXCHANGE | החלפה | החלפה במוצר אחר |
האירוע bitrix:sale.order.return.edit הוא המנגנון הסטנדרטי לסנכרון סטטוסי החזרה עם מערכות חיצוניות, כמתואר בתיעוד 1C-Bitrix.
למה הגדרת סטטוסים נכונה חשובה?
שגיאות בסטטוסים מובילות לחוסר סנכרון עם 1C ולחישוב מלאי שגוי. לדוגמה, אם המחסן מקבל סחורה אבל הסטטוס לא משתנה ל-RECEIVED, 1C לא תשחרר את הרזרבה. התוצאה היא יתרות מלאי שליליות ב-1C. אנחנו מצמידים handlers לשינויי סטטוס כדי למנוע מצבים כאלה.
איך לשלב החזרות עם 1C?
כשהסחורה מוחזרת למחסן, אנחנו צריכים לעדכן את המלאי. אם המחסן מנוהל ב-1C, אנחנו שולחים הודעה ל-1C דרך תור כשסטטוס ההחזרה משתנה ל'הסחורה התקבלה'.
\Bitrix\Main\EventManager::getInstance()->addEventHandler(
'sale',
'OnSaleOrderReturnStatusChange',
function (\Bitrix\Main\Event $event) {
$returnId = $event->getParameter('RETURN_ID');
$newStatus = $event->getParameter('NEW_STATUS_ID');
if ($newStatus === 'RECEIVED') {
\Local\OneC\StockSync::scheduleReturnSync($returnId);
}
if ($newStatus === 'REFUND') {
\Local\Returns\RefundProcessor::processPaymentReturn($returnId);
}
}
); איך עובד החזר כספי אוטומטי?
רוב מערכות התשלום של Bitrix (YooKassa, Tinkoff, Sber) תומכות בהחזרים דרך API. ב-Bitrix, זה מיושם דרך handler של מערכת תשלום:
namespace Local\Returns;
class RefundProcessor
{
public static function processPaymentReturn(int $returnId): bool
{
\Bitrix\Main\Loader::includeModule('sale');
$return = \Bitrix\Sale\OrderReturn::loadById($returnId);
if (!$return) return false;
$order = \Bitrix\Sale\Order::load($return->getField('ORDER_ID'));
$payments = $order->getPaymentCollection();
$amount = $return->getField('REFUND_AMOUNT'); // сумма к возврату
foreach ($payments as $payment) {
if (!$payment->isPaid()) continue;
// Метод возврата зависит от платёжной системы
$paySystem = $payment->getPaySystem();
if (!$paySystem) continue;
$result = $paySystem->refund($payment, $amount);
if ($result->isSuccess()) {
$return->setField('STATUS_ID', 'REFUND');
$return->setField('REFUND_DATE', new \Bitrix\Main\Type\DateTime());
$return->save();
return true;
}
}
return false;
}
}החזר אוטומטי דרך API מאיץ את התהליך פי 5-10 בהשוואה לידני — הלקוח מקבל את הכסף באותו היום.
חשבון אישי והרשאות גישה
הרכיב הסטנדרטי OnSaleOrderReturnStatusChange מאפשר ללקוחות ליצור בקשת החזרה מהיסטוריית ההזמנות שלהם. חיבורו בתבנית החשבון האישי:
$APPLICATION->IncludeComponent(
'bitrix:sale.order.return.edit',
'default',
[
'ORDER_ID' => (int)$_GET['ORDER_ID'],
'RETURN_ID' => (int)$_GET['RETURN_ID'],
'SITE_ID' => SITE_ID,
'PATH_TO_RETURN_LIST' => '/personal/returns/',
]
);הרשאות גישה להחזרות מנוהלות דרך תפקידים במודול \Bitrix\Main\EventManager::getInstance()->addEventHandler( 'sale', 'OnSaleOrderReturnStatusChange', function (\Bitrix\Main\Event $event) { $returnId = $event->getParameter('RETURN_ID'); $newStatus = $event->getParameter('NEW_STATUS_ID'); if ($newStatus === 'RECEIVED') { \Local\OneC\StockSync::scheduleReturnSync($returnId); } if ($newStatus === 'REFUND') { \Local\Returns\RefundProcessor::processPaymentReturn($returnId); } } ); : מנהל החזרות (צפייה, שינוי עד 'אושר'), מנהל בכיר (הרשאות מלאות), לקוח (יצירת בקשה). הגדרת הרשאות אורכת לא יותר משעה. עבור החזרות חלקיות, אנחנו יוצרים החזרה עם פריטים ספציפיים ב-namespace Local\Returns; class RefundProcessor { public static function processPaymentReturn(int $returnId): bool { \Bitrix\Main\Loader::includeModule('sale'); $return = \Bitrix\Sale\OrderReturn::loadById($returnId); if (!$return) return false; $order = \Bitrix\Sale\Order::load($return->getField('ORDER_ID')); $payments = $order->getPaymentCollection(); $amount = $return->getField('REFUND_AMOUNT'); // сумма к возврату foreach ($payments as $payment) { if (!$payment->isPaid()) continue; // Метод возврата зависит от платёжной системы $paySystem = $payment->getPaySystem(); if (!$paySystem) continue; $result = $paySystem->refund($payment, $amount); if ($result->isSuccess()) { $return->setField('STATUS_ID', 'REFUND'); $return->setField('REFUND_DATE', new \Bitrix\Main\Type\DateTime()); $return->save(); return true; } } return false; } } — ה-handler מתאים את סכום ההחזר באופן יחסי.
מה כלול בהגדרת ניהול החזרות
- ביקורת תהליכי החזרה קיימים ואיסוף דרישות.
- פיתוח מפרט טכני ותכנית סטטוסים.
- יצירת שרשרת סטטוסי החזרה נפרדת עם קודים נדרשים.
- הגדרת אירועים ו-handlers לשינויי סטטוס.
- אינטגרציה עם 1C (סנכרון מלאי ומסמכים).
- חיבור החזר אוטומטי דרך APIs של שערי תשלום.
- פיתוח או התאמה של רכיב החשבון האישי של הלקוח.
- בדיקת כל התרחישים (כולל החזרה חלקית והחזר כספי).
- הדרכת מנהלים על המערכת.
- מסירת תיעוד ניהול.
- תמיכה למשך 6 חודשים לאחר ההשקה.
תהליך עבודה ולוחות זמנים
| שלב | מה אנחנו עושים | תוצאה |
|---|---|---|
| אנליטיקה | ביקורת תהליכי החזרה קיימים, איסוף דרישות, תיאור תהליך עסקי | מפרט טכני |
| עיצוב | פיתוח תכנית סטטוסים, קישור עם 1C, בחירת מערכות תשלום | תיעוד פרויקט |
| הטמעה | הגדרת סטטוסים, יצירת רכיב חשבון אישי, event handlers, אינטגרציה עם תשלומים ו-1C | אב טיפוס עובד בסביבת בדיקה |
| בדיקות | בדיקת כל התרחישים: יצירת החזרה, שינוי סטטוסים, החזר כספי, סנכרון | דוח בדיקות |
| השקה | פריסה לסביבת ייצור, הדרכת מנהלים, מסירת תיעוד | תעודת קבלה |
הגדרה בסיסית עם חשבון אישי וסטטוסים — בין שבוע לשבועיים. מערכת מלאה עם החזר אוטומטי ואינטגרציה עם 1C — בין 3 ל-5 שבועות. נעריך את הפרויקט שלך לאחר ניתוח המפרט הטכני.
אנחנו מבטיחים 6 חודשי תמיכה לאחר ההטמעה. כל הפתרונות עוברים בדיקת קוד ובדיקות עומס.
צור קשר לייעוץ — נספר לך כמה זמן ומשאבים האוטומציה תחסוך. בקש ביקורת על תהליך ההחזרה הנוכחי שלך כדי לקבל תכנית עבודה מדויקת.

