פיתוח טופס החזרה מותאם אישית ל-1C-Bitrix

כאשר טופס ההחזרה הסטנדרטי ב-1C-Bitrix אינו מאפשר ללקוחות לצרף תמונות תקלה או לציין סיבה לכל פריט, הטיפול בפניות הופך לשיחות והודעות אינסופיות. אנו בונים טפסי החזרה מותאמים אישית במפתח מלא, תוך אוטומציה של כל התהליך מהעלאת תמונות ועד אינטגרציה עם 1C. הצוות שלנו מספק את הפרויקט בהתאמה לתהליכי העבודה שלכם ומבטיח פעילות יציבה עם תמיכה מתמשכת.
השירותים שאנו מציעים
מציג 1 מתוך 1כל 1626 השירותים
פיתוח טופס החזרה מותאם אישית ל-1C-Bitrix
בינוני
~1-2 שבועות

הכישורים שלנו:

שאלות נפוצות

לעתים קרובות אנו נתקלים בפרויקטים שבהם הרכיב הסטנדרטי bitrix:sale.order.return.edit אינו יכול להתמודד עם המשימות: חסרה בו העלאת תמונות של ליקויים, ממשק שלבי, והיכולת לציין סיבות שונות עבור כל פריט. עם 50–100 בקשות החזרה ביום, טופס מסורבל מתורגם ישירות לאובדן זמן של מנהלים המושקע בבירורים טלפוניים.

תארו לעצמכם: לקוח מקבל מוצר פגום. הוא נכנס לחשבון האישי שלו, מוצא את ההזמנה, אך הטופס הסטנדרטי להחזרה אינו מאפשר לצרף תמונה של הליקוי. הוא צריך להתקשר למנהל, לברר את הסיבה, לשלוח את התמונה בדוא"ל. זה מגדיל את זמן הטיפול בממוצע ב-15 דקות. עם 100 החזרות ביום—אובדן של 25 שעות עבודה. שני מנהלים מבלים חצי יום על הודעות דוא"ל ושיחות במקום לטפל בפניות אחרות.

טופס ההחזרה המותאם אישית שלנו עבור 1C-Bitrix משלב אשף, העלאת תמונות, ואינטגרציה עם 1C כדי לייעל את תהליך הטיפול בהחזרות. אנו מפתחים טפסי החזרה מותאמים אישית במפתח מלא עבור 1C-Bitrix, ומפחיתים את זמן הטיפול ב-30%. הניסיון שלנו עם Bitrix—10+ שנים, מעל 50 פרויקטי החזרה. עלות הפיתוח מתחילה ב-$1,500 עבור טופס בסיסי, והחיסכון החודשי מהפחתת זמן הטיפול יכול לעלות על $2,000. הטמעת טופס כזה מחזירה את ההשקעה תוך 3–6 חודשים.

למה אתם צריכים טופס החזרה מותאם אישית?

אשף מותאם אישית מעבד החזרה פי 3 מהר יותר מהטופס המובנה—4 דקות במקום 15. הלקוח עובר 4 שלבים, והמנהל מקבל נתונים מלאים ללא צורך להתקשר חזרה.

מאפיין טופס סטנדרטי טופס מותאם אישית
העלאת תמונות לא כן (עד 5 MB)
בחירת סיבה לכל פריט לא כן
מספר שלבים 1 4 (אשף)
זמן מילוי ~15 דקות ~4 דקות
אינטגרציה עם 1C דרך החלפה ישירה דרך REST

מבנה טופס האשף והיתרונות

UX אופטימלי לטופס החזרה—3–4 שלבים:

  1. בחירת הזמנה — הלקוח בוחר מתוך היסטוריית ההזמנות שלו הזמינות להחזרה.
  2. בחירת מוצר וסיבה — תיבות סימון לפריטים, כל אחת עם סיבה וכמות.
  3. מידע נוסף — הערה, העלאת תמונה/מסמך.
  4. אישור — מסך סופי עם נתוני הבקשה והוראות.

שלב 1: הזמנות זמינות להחזרה

החזרה אפשרית רק עבור הזמנות ששולמו בתוך תקופה מסוימת (בדרך כלל 14 יום לפי חוק). אנו טוענים את הרשימה:

<?php

namespace Local\Returns;

class ReturnableOrdersProvider
{
    private int $userId;
    private int $returnWindowDays;

    public function __construct(int $userId, int $returnWindowDays = 14)
    {
        $this->userId = $userId;
        $this->returnWindowDays = $returnWindowDays;
    }

    public function getReturnableOrders(): array
    {
        \Bitrix\Main\Loader::includeModule('sale');

        $dateFrom = new \Bitrix\Main\Type\Date();
        $dateFrom->add('-' . $this->returnWindowDays . ' days');

        $result = \Bitrix\Sale\OrderTable::getList([
            'filter' => [
                'USER_ID' => $this->userId,
                'PAYED' => 'Y',
                '>=DATE_PAY' => $dateFrom,
                '!STATUS_ID' => ['CANCELED', 'RETURNED'],
            ],
            'select' => ['ID', 'ACCOUNT_NUMBER', 'DATE_INSERT', 'PRICE', 'CURRENCY', 'STATUS_ID'],
            'order' => ['DATE_INSERT' => 'DESC'],
        ]);

        $orders = [];
        while ($row = $result->fetch()) {
            // Проверяем: нет ли уже полного возврата по этому заказу
            if (!$this->hasFullReturn($row['ID'])) {
                $orders[] = $row;
            }
        }

        return $orders;
    }

    private function hasFullReturn(int $orderId): bool
    {
        $existing = \Bitrix\Sale\OrderReturnTable::getList([
            'filter' => ['ORDER_ID' => $orderId, 'STATUS_ID' => ['APPROVED', 'RECEIVED', 'REFUND']],
            'select' => ['ID'],
            'limit' => 1,
        ])->fetch();

        return (bool)$existing;
    }
}

שלב 2: פריטי הזמנה עם בחירת סיבה

<?php
class OrderItemsProvider {
    public function getReturnableItems(int $orderId, int $userId): array {
        $order = \Bitrix\Sale\Order::load($orderId);
        if (!$order || $order->getUserId() !== $userId) {
            throw new \RuntimeException('Order not found or access denied');
        }
        $items = [];
        foreach ($order->getBasket() as $item) {
            // Считаем уже возвращённое количество
            $returnedQty = $this->getReturnedQuantity($orderId, $item->getId());
            $availableQty = $item->getQuantity() - $returnedQty;
            if ($availableQty <= 0) continue;
            $items[] = [
                'basket_id' => $item->getId(),
                'product_id' => $item->getProductId(),
                'name' => $item->getField('NAME'),
                'quantity' => $item->getQuantity(),
                'available_qty' => $availableQty,
                'price' => $item->getFinalPrice(),
                'image' => $this->getProductImage($item->getProductId()),
                'article' => $item->getField('ARTICLE'),
            ];
        }
        return $items;
    }
    private function getReturnedQuantity(int $orderId, int $basketItemId): float {
        $result = \Bitrix\Sale\OrderReturnBasketTable::getList([
            'filter' => [
                'ORDER_RETURN.ORDER_ID' => $orderId,
                'BASKET_ID' => $basketItemId,
                'ORDER_RETURN.STATUS_ID' => ['WAIT', 'REVIEW', 'APPROVED', 'RECEIVED', 'REFUND'],
            ],
            'runtime' => [
                new \Bitrix\Main\ORM\Fields\ExpressionField('TOTAL_QTY', 'SUM(%s)', 'QUANTITY'),
            ],
            'select' => ['TOTAL_QTY'],
        ])->fetch();
        return (float)($result['TOTAL_QTY'] ?? 0);
    }
}

איך ליישם את האשף בצד הלקוח?

רכיב React לאשף (או Vue—בחירתכם):

import React, { useState } from 'react';

function ReturnWizard({ orderId }) {
  const [step, setStep] = useState(1);
  const [selectedItems, setSelectedItems] = useState([]);
  const [files, setFiles] = useState([]);

  const returnReasons = [
    { id: 'defect', label: 'Производственный брак' },
    { id: 'wrong_item', label: 'Прислали не тот товар' },
    { id: 'damaged', label: 'Повреждён при доставке' },
    { id: 'not_fit', label: 'Не подошёл' },
    { id: 'other', label: 'Другая причина' },
  ];

  const canProceed = selectedItems.some(item => item.selected && item.reason);

  async function submitReturn() {
    const formData = new FormData();
    formData.append('order_id', orderId);
    formData.append('sessid', BX.bitrix_sessid());
    formData.append('items', JSON.stringify(selectedItems.filter(i => i.selected)));
    files.forEach((file, i) => formData.append(`files[${i}]`, file));
    const res = await fetch('/local/api/return-submit.php', {
      method: 'POST',
      body: formData,
    });
    const data = await res.json();
    if (data.success) {
      setStep(4); // Success screen
    }
  }

  // ... рендер шагов
}

מטפל בצד השרת להגשה סופית

<?php // /local/api/return-submit.php
require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php');
header('Content-Type: application/json');

if (!\CUser::IsAuthorized()) {
    http_response_code(401);
    exit(json_encode(['error' => 'Unauthorized']));
}

if (!\bitrix_sessid_check($_POST['sessid'] ?? '')) {
    http_response_code(403);
    exit(json_encode(['error' => 'Invalid session']));
}

$orderId = (int)($_POST['order_id'] ?? 0);
$items = json_decode($_POST['items'] ?? '[]', true);
$userId = (int)\CUser::GetID();

// Валидируем, что заказ принадлежит пользователю
$validator = new \Local\Returns\ReturnValidator($userId);
if (!$validator->canReturnOrder($orderId)) {
    exit(json_encode(['success' => false, 'error' => 'Заказ недоступен для возврата']));
}

// Загружаем прикреплённые файлы
$fileIds = [];
$uploader = new \Local\Upload\FileUploader();
foreach ($_FILES as $key => $file) {
    if (strpos($key, 'files') === 0 && $file['error'] === UPLOAD_ERR_OK) {
        try {
            $result = $uploader->handle($file);
            $fileIds[] = $result['id'];
        } catch (\Exception $e) {
            // Логируем, но не прерываем
        }
    }
}

// Создаём заявку на возврат
$manager = new \Local\Returns\ReturnManager();
$returnId = $manager->createReturn($orderId, $items, 'MONEY');

// Прикрепляем файлы к заявке
if ($fileIds) {
    \Local\Returns\ReturnAttachments::attach($returnId, $fileIds);
}

// Отправляем уведомления
\Local\Returns\Notifications::sendToCustomer($returnId);
\Local\Returns\Notifications::sendToManager($returnId);

exit(json_encode([
    'success' => true,
    'return_id' => $returnId,
    'message' => 'Заявка #' . $returnId . ' создана. Рассмотрим в течение 2 рабочих дней.',
]));

קבצים מצורפים לבקשה: הרחבת הטבלה

מערכת ההחזרות הסטנדרטית של Bitrix אינה מאחסנת קבצים מצורפים. אנו מרחיבים באמצעות Highload-block:

<?php
class ReturnAttachmentTable extends \Bitrix\Main\ORM\Data\DataManager
{
    public static function getTableName(): string
    {
        return 'local_return_attachments';
    }

    public static function getMap(): array
    {
        return [
            new \Bitrix\Main\ORM\Fields\IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
            new \Bitrix\Main\ORM\Fields\IntegerField('RETURN_ID'),
            new \Bitrix\Main\ORM\Fields\IntegerField('FILE_ID'), // b_file.ID
            new \Bitrix\Main\ORM\Fields\DatetimeField('CREATED_AT'),
        ];
    }
}

אבטחת עיבוד בקשות

חשוב להגן על מטפל ה-AJAX מפני התקפות XSS ו-CSRF. ראשית, אנו בודקים את הסשן באמצעות <?php namespace Local\Returns; class ReturnableOrdersProvider { private int $userId; private int $returnWindowDays; public function __construct(int $userId, int $returnWindowDays = 14) { $this->userId = $userId; $this->returnWindowDays = $returnWindowDays; } public function getReturnableOrders(): array { \Bitrix\Main\Loader::includeModule('sale'); $dateFrom = new \Bitrix\Main\Type\Date(); $dateFrom->add('-' . $this->returnWindowDays . ' days'); $result = \Bitrix\Sale\OrderTable::getList([ 'filter' => [ 'USER_ID' => $this->userId, 'PAYED' => 'Y', '>=DATE_PAY' => $dateFrom, '!STATUS_ID' => ['CANCELED', 'RETURNED'], ], 'select' => ['ID', 'ACCOUNT_NUMBER', 'DATE_INSERT', 'PRICE', 'CURRENCY', 'STATUS_ID'], 'order' => ['DATE_INSERT' => 'DESC'], ]); $orders = []; while ($row = $result->fetch()) { // Проверяем: нет ли уже полного возврата по этому заказу if (!$this->hasFullReturn($row['ID'])) { $orders[] = $row; } } return $orders; } private function hasFullReturn(int $orderId): bool { $existing = \Bitrix\Sale\OrderReturnTable::getList([ 'filter' => ['ORDER_ID' => $orderId, 'STATUS_ID' => ['APPROVED', 'RECEIVED', 'REFUND']], 'select' => ['ID'], 'limit' => 1, ])->fetch(); return (bool)$existing; } } . שנית, אנו מוודאים שההזמנה שייכת למשתמש הנוכחי. שלישית, אנו מסננים קבצים שהועלו לפי סוג וגודל—רק תמונות עד 5 MB, האחרות נדחות.

אינטגרציה עם 1C

האינטגרציה עם 1C מתבצעת דרך CommerceML או REST API. אנו מגדירים יצירה אוטומטית של מסמכי החזרה ב-1C עם אישור הבקשה. זה מבטל הזנת נתונים כפולה ומאיץ את תהליך ההחזרה.

היקף הפרויקט ותוצרים

שלב פעילות אחראי לוח זמנים
ניתוח ביקורת תהליכי החזרה הנוכחיים אנליסט 1-3 ימים
עיצוב הסכמה על לוגיקת האשף ומסכים אנליסט + לקוח 2-5 ימים
פיתוח API בצד השרת, אשף ב-React/Vue, אינטגרציות מפתח 1-3 שבועות
בדיקות בדיקות יחידה, בדיקות עומס, UAT בודק 3-5 ימים
השקה פריסה לשרת הייצור DevOps יום אחד
הדרכה תיעוד, הדרכת מנהלים אנליסט עד שעתיים

מה כלול

  • ביקורת תהליך ההחזרה הנוכחי והסכמה על הלוגיקה
  • פיתוח טופס אשף עם 4 שלבים (React/Vue)
  • צד שרת: API ליצירה וסטטוסים של החזרות
  • אינטגרציה עם הודעות דוא"ל (לקוח + מנהל)
  • עמוד "ההחזרות שלי" בחשבון האישי
  • תיעוד לכל רכיב
  • הדרכת עובדים (עד שעתיים)
  • תמיכה טכנית למשך חודש לאחר ההשקה
טעויות אינטגרציה נפוצות - שכחת בדיקת סשן במטפל ה-AJAX—מובילה ל-XSS. - אי התחשבות בהחזרות חלקיות: יש לחשב כמות שכבר הוחזרה. - אי בדיקת גודל קובץ במהלך העלאת תמונות—קבצים יכולים לחרוג מ-5 MB.

לוחות זמנים משוערים

טופס מלא עם אשף והעלאת קבצים—מ-2 עד 4 שבועות. אינטגרציות מורכבות יותר (1C, תהליכים עסקיים מותאמים)—עד 6 שבועות. העלות מחושבת באופן אישי. אנו נעריך את הפרויקט שלכם—צרו קשר.

הזמינו פיתוח טופס החזרה היום—קבלו ביקורת של התהליכים הנוכחיים. אנו מבטיחים פעולה תקינה תחת עומסים גבוהים (1000+ החזרות ביום) ועמידה ב-54-FZ לפיסקליזציה. צרו קשר לייעוץ—נציג טופס הדגמה.

תיעוד רשמי: Bitrix REST API לאינטגרציות.