פיתוח טופס הזמנת פגישת ייעוץ ל-1C-Bitrix

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

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

שאלות נפוצות

העבודות האחרונות

  • image_website-b2b-advance_0.webp
    פיתוח אתר חברה B2B ADVANCE
    1460
  • image_bitrix-bitrix-24-1c_fixper_448_0.webp
    פיתוח אתר לחברת FIXPER
    1019
  • image_bitrix-bitrix-24-1c_development_of_an_online_appointment_booking_widget_for_a_medical_center_594_0.webp
    פיתוח מבוסס Bitrix, Bitrix24, 1C לחברה פיתוח ווידג'ט להזמנת תורים אונליין למרכז רפואי
    763
  • image_bitrix-bitrix-24-1c_mirsanbel_458_0.webp
    פיתוח על בסיס 1C Enterprise עבור MIRSANBEL
    882
  • image_crm_dolbimby_434_0.webp
    פיתוח אתר על CRM Bitrix24 עבור DOLBIMBY
    809
  • image_crm_technotorgcomplex_453_0.webp
    פיתוח על בסיס Bitrix24 עבור חברת TECHNOTORGKOMPLEKS
    1164

פיתוח טופס הזמנת ייעוץ ב-1C-Bitrix

טופס הזמנה עם בחירת משבצת זמן ומומחה הוא משימה סטנדרטית, אך היישום שלו מסתיר מלכודות. העיקרית שבהן: בקשות מקבילות לאותה משבצת. אם שני לקוחות לוחצים על "הזמן" בו-זמנית, ללא נעילה אמינה שניהם יקבלו אישור. אז תצטרך לפתור כפילויות ידנית. אנו משתמשים בנעילה טרנזקציונלית ברמת MySQL — היא אמינה פי 10 מנעילות ברמת היישום. עם ניסיון של 8+ שנים ו-20+ פרויקטים של הזמנת ייעוץ, גישה זו עובדת תחת כל עומס.

איך להימנע מהזמנה כפולה?

בקשות מקבילות מטופלות בתוך טרנזקציה. ראשית, נבדק סטטוס המשבצת (FREE), ולאחר מכן מתבצע UPDATE עם תנאי WHERE STATUS = 'FREE'. אם המשבצת כבר תפוסה, אין שורות מושפעות — ההזמנה נדחית. זה מבטיח שהמשבצת תלך רק ללקוח אחד. אין צורך בסנכרון נוסף ברמת היישום.

מידע נוסף על נעילה טרנזקציונלית טרנזקציית MySQL מבטיחה אטומיות: או שכל השינויים מוחלים או אף אחד מהם. בשילוב עם UPDATE מותנה, אנו מקבלים נעילה אופטימית ללא טבלאות נוספות.

מודל נתונים

אנו משתמשים ב-HL-blocks לאחסון — הם מהירים יותר מ-infoblocks למבנים שטוחים ואין להם תקורה מיותרת.

תיעוד Bitrix: Highload-blocks (dev.1c-bitrix.ru) השוואת HL-blocks לעומת infoblocks:

קריטריון HL-blocks Infoblocks
מהירות כתיבה גבוהה (פי 1.5 מהר יותר) בינונית
מהירות קריאה גבוהה (פי 2 מהר יותר) בינונית
תמיכה ב-ORM מלאה חלקית (דרך CIBlockElement)
מבנה עץ לא כן
מתאים למשבצות אידיאלי מוגזם

מומחים (b_hl_consultants):

class ConsultantTable extends \Bitrix\Main\ORM\Data\DataManager { public static function getTableName(): string { return 'b_hl_consultants'; } public static function getMap(): array { return [ new IntegerField('ID', ['primary' => true, 'autocomplete' => true]), new IntegerField('USER_ID'), // Ссылка на b_user new StringField('NAME'), new StringField('SPECIALIZATION'), new IntegerField('PHOTO_ID'), // b_file new StringField('SCHEDULE_JSON'), // Рабочие дни и часы new IntegerField('SLOT_DURATION'), // Длительность слота в минутах new BooleanField('IS_ACTIVE', ['values' => [false, true]]), ]; } } 

משבצות הזמנה (class ConsultantTable extends \Bitrix\Main\ORM\Data\DataManager { public static function getTableName(): string { return 'b_hl_consultants'; } public static function getMap(): array { return [ new IntegerField('ID', ['primary' => true, 'autocomplete' => true]), new IntegerField('USER_ID'), // Ссылка на b_user new StringField('NAME'), new StringField('SPECIALIZATION'), new IntegerField('PHOTO_ID'), // b_file new StringField('SCHEDULE_JSON'), // Рабочие дни и часы new IntegerField('SLOT_DURATION'), // Длительность слота в минутах new BooleanField('IS_ACTIVE', ['values' => [false, true]]), ]; } } ):

class BookingSlotTable extends \Bitrix\Main\ORM\Data\DataManager { public static function getTableName(): string { return 'b_hl_booking_slots'; } public static function getMap(): array { return [ new IntegerField('ID', ['primary' => true, 'autocomplete' => true]), new IntegerField('CONSULTANT_ID'), new DatetimeField('SLOT_START'), new DatetimeField('SLOT_END'), new EnumField('STATUS', ['values' => ['FREE', 'BOOKED', 'BLOCKED']]), new IntegerField('BOOKING_ID'), // Ссылка на запись, если BOOKED ]; } } 

הזמנות (b_hl_booking_slots):

class BookingTable extends \Bitrix\Main\ORM\Data\DataManager { public static function getTableName(): string { return 'b_hl_bookings'; } public static function getMap(): array { return [ new IntegerField('ID', ['primary' => true, 'autocomplete' => true]), new IntegerField('CONSULTANT_ID'), new IntegerField('SLOT_ID'), new StringField('CLIENT_NAME'), new StringField('CLIENT_PHONE'), new StringField('CLIENT_EMAIL'), new StringField('TOPIC'), new StringField('COMMENT'), new EnumField('STATUS', ['values' => ['PENDING', 'CONFIRMED', 'CANCELLED', 'COMPLETED']]), new StringField('CANCEL_TOKEN'), // Для отмены по ссылке new DatetimeField('CREATED_AT'), ]; } } 

איך נוצרות משבצות?

סוכן, שרץ פעם בשעה, יוצר משבצות ל-30 ימים קדימה עבור כל מומחה פעיל. הוא מתחשב בימי עבודה, שעות והפסקות שצוינו ב-SCHEDULE_JSON. לאחר היצירה, המשבצות נבדקות לכפילויות עם הקיימות.

הצגת משבצות פנויות

בקשת AJAX מחזירה משבצות פנויות עבור תאריך ומומחה שנבחרו:

// /local/ajax/booking_slots.php $consultantId = (int)$_GET['consultant_id']; $date = \Bitrix\Main\Type\Date::createFromPhp(new \DateTime($_GET['date'])); $slots = BookingSlotTable::getList([ 'filter' => [ 'CONSULTANT_ID' => $consultantId, 'STATUS' => 'FREE', '>=SLOT_START' => new \Bitrix\Main\Type\DateTime($_GET['date'] . ' 00:00:00'), '<SLOT_START' => new \Bitrix\Main\Type\DateTime($_GET['date'] . ' 23:59:59'), ], 'order' => ['SLOT_START' => 'ASC'], 'select' => ['ID', 'SLOT_START', 'SLOT_END'], ])->fetchAll(); $result = array_map(fn($s) => [ 'id' => $s['ID'], 'start' => date('H:i', strtotime($s['SLOT_START'])), 'end' => date('H:i', strtotime($s['SLOT_END'])), ], $slots); echo json_encode($result); 

יצירת הזמנה עם נעילה

בקשות מקבילות יכולות להזמין את אותה משבצת פעמיים. הפתרון הוא נעילה אופטימית דרך class BookingSlotTable extends \Bitrix\Main\ORM\Data\DataManager { public static function getTableName(): string { return 'b_hl_booking_slots'; } public static function getMap(): array { return [ new IntegerField('ID', ['primary' => true, 'autocomplete' => true]), new IntegerField('CONSULTANT_ID'), new DatetimeField('SLOT_START'), new DatetimeField('SLOT_END'), new EnumField('STATUS', ['values' => ['FREE', 'BOOKED', 'BLOCKED']]), new IntegerField('BOOKING_ID'), // Ссылка на запись, если BOOKED ]; } } ובדיקת שורות מושפעות:

// /local/ajax/booking_create.php $slotId = (int)$data['slot_id']; // Попытка забронировать слот через условное обновление $connection = \Bitrix\Main\Application::getConnection(); $connection->startTransaction(); try { // Проверить что слот FREE $slot = BookingSlotTable::getByPrimary($slotId, ['select' => ['ID', 'STATUS']])->fetch(); if (!$slot || $slot['STATUS'] !== 'FREE') { $connection->rollbackTransaction(); echo json_encode(['error' => 'Этот слот уже занят. Пожалуйста, выберите другое время.']); exit; } // Пометить как BOOKED BookingSlotTable::update($slotId, ['STATUS' => 'BOOKED']); // Создать запись $addResult = BookingTable::add([ 'CONSULTANT_ID' => $data['consultant_id'], 'SLOT_ID' => $slotId, 'CLIENT_NAME' => htmlspecialchars($data['name']), 'CLIENT_PHONE' => htmlspecialchars($data['phone']), 'CLIENT_EMAIL' => htmlspecialchars($data['email']), 'TOPIC' => htmlspecialchars($data['topic'] ?? ''), 'STATUS' => 'CONFIRMED', 'CANCEL_TOKEN' => bin2hex(random_bytes(16)), 'CREATED_AT' => new \Bitrix\Main\Type\DateTime(), ]); // Обновить BOOKING_ID в слоте BookingSlotTable::update($slotId, ['BOOKING_ID' => $addResult->getId()]); $connection->commitTransaction(); // Отправить подтверждение sendBookingConfirmation($addResult->getId()); echo json_encode(['success' => true, 'booking_id' => $addResult->getId()]); } catch (\Exception $e) { $connection->rollbackTransaction(); echo json_encode(['error' => 'Ошибка при создании записи']); } 

הודעות

כאשר נוצרת הזמנה — שני מיילים:

  1. ללקוח: אישור עם תאריך, שעה, שם מומחה וקישור ביטול.
  2. למומחה: הודעה על הזמנה חדשה.

קישור ביטול: b_hl_bookings. המטפל מוצא את ההזמנה לפי טוקן, משנה סטטוס ל-class BookingTable extends \Bitrix\Main\ORM\Data\DataManager { public static function getTableName(): string { return 'b_hl_bookings'; } public static function getMap(): array { return [ new IntegerField('ID', ['primary' => true, 'autocomplete' => true]), new IntegerField('CONSULTANT_ID'), new IntegerField('SLOT_ID'), new StringField('CLIENT_NAME'), new StringField('CLIENT_PHONE'), new StringField('CLIENT_EMAIL'), new StringField('TOPIC'), new StringField('COMMENT'), new EnumField('STATUS', ['values' => ['PENDING', 'CONFIRMED', 'CANCELLED', 'COMPLETED']]), new StringField('CANCEL_TOKEN'), // Для отмены по ссылке new DatetimeField('CREATED_AT'), ]; } } , ומשחרר את המשבצת.

אינטגרציה עם Bitrix24 CRM

כאשר נוצרת הזמנה ב-HL-block, נוצר ליד אוטומטית ב-CRM עם קישור לעסקה המשויכת לאותו מומחה. פרטי קשר של הלקוח (שם, טלפון, אימייל) נמשכים לכרטיס הליד, וסטטוס העסקה מועבר ל"קשר ראשוני" לאחר ייעוץ מוצלח. המומחה יכול לשלוח כרטיס וידאו דרך Bitrix24, שמופיע בהיסטוריית הייעוץ. כל היסטוריית הייעוץ מאוחסנת ב-HL-block ומסונכרנת עם ה-CRM תוך כיבוד זמן.

מדרגיות וביצועים

עבור 100 מומחים ו-1000 הזמנות בחודש, המערכת עובדת ללא שינויים. תחת עומס גבוה יותר, אנו ממליצים להוסיף אינדקס על // /local/ajax/booking_slots.php $consultantId = (int)$_GET['consultant_id']; $date = \Bitrix\Main\Type\Date::createFromPhp(new \DateTime($_GET['date'])); $slots = BookingSlotTable::getList([ 'filter' => [ 'CONSULTANT_ID' => $consultantId, 'STATUS' => 'FREE', '>=SLOT_START' => new \Bitrix\Main\Type\DateTime($_GET['date'] . ' 00:00:00'), '<SLOT_START' => new \Bitrix\Main\Type\DateTime($_GET['date'] . ' 23:59:59'), ], 'order' => ['SLOT_START' => 'ASC'], 'select' => ['ID', 'SLOT_START', 'SLOT_END'], ])->fetchAll(); $result = array_map(fn($s) => [ 'id' => $s['ID'], 'start' => date('H:i', strtotime($s['SLOT_START'])), 'end' => date('H:i', strtotime($s['SLOT_END'])), ], $slots); echo json_encode($result); כדי להאיץ את בחירת המשבצות, ולשמור תוצאות במטמון ל-5 דקות דרך Memcached. עבור 10,000+ הזמנות בו-זמניות ביום (למשל, בימי הרשמה המונית), אנו משתמשים ב-read-replicas לקריאת לוחות זמנים ו-master בלבד לכתיבה.

תהליך הפיתוח

אנו עובדים בצורה אינקרמנטלית:

  • ניתוח — הבהרת מספר מומחים, משך משבצת, שעות עבודה.
  • עיצוב — יצירת HL-blocks, תכנון אינדקסים.
  • יישום — כתיבת סוכן יצירת משבצות, מטפלי AJAX, טופס, תבניות אימייל.
  • בדיקות — בדיקות עומס להזמנות מקבילות, בדיקות הודעות.
  • פריסה — הגדרת cron לסוכן, מסירת תיעוד.

מה כלול

  • קוד מקור של רכיב טופס ההזמנה.
  • מסד נתונים של HL-block עם סקריפט מיגרציה.
  • תבניות אימייל לאישורים.
  • הוראות לניהול לוחות זמנים של מומחים.
  • אחריות לקוד ל-6 חודשים (תיקוני באגים לפי בקשה).

לוח זמנים לפיתוח

אפשרות היקף לוח זמנים
מומחה יחיד משבצות, טופס, אישור אימייל 4–6 ימים
מספר מומחים בחירת מומחה, ניהול לוח זמנים 7–10 ימים
עם אזור אישי אזור מומחה, ביטול, שינוי מועד, היסטוריה 12–18 ימים

להערכה מדויקת, צור קשר — ספר לנו על מספר המומחים והפונקציונליות הנדרשת. נכין הצעה מסחרית תוך יום אחד.