מפעילי תיירות עומדים בפני בעיה: המחירים משתנים מדי יום, תאריכי היציאה משתנים, ומערכות ההזמנה החיצוניות מגיבות במהירויות שונות. אחת מחזירה JSON תוך 200 אלפיות השנייה, אחרת מחזירה XML תוך 8 שניות. אם הקטלוג מעוצב כבלוק מידע סטטי עם עדכונים ידניים, תוך חודש מנהלים מפסיקים לעדכן מחירים, ולקוחות מזמינים טיולים עם נתונים מיושנים. אנחנו צוות פיתוח עם 10 שנות ניסיון ב-1C-Bitrix, המתמחה בפיתוח Bitrix מוסמך ובארכיטקטורה מוכחת שפותר את הבעיות הללו. הגישה שלנו מבטיחה שהאתר עובד עם נתונים אמיתיים בזמן אמת. במשך 10 שנים, יישמנו יותר מ-50 פרויקטים למפעילי תיירות—מחלונות ראווה קטנים ועד פלטפורמות מורכבות עם פורטלי סוכנים B2B. עלויות פרויקט בסיסיות מתחילות מ-$5,000 לחלון ראווה פשוט, וחוסכות ללקוחות עד 40% בעלויות תפעול באמצעות אוטומציה. עבור קטלוג טיפוסי עם אינטגרציית API אחת, לקוחות חוסכים בממוצע $15,000 בשנה על עדכונים ידניים.
כיצד לבנות קטלוג טיולים על בלוקי מידע
הקטלוג בנוי על שני בלוקי מידע ובלוק Highload אחד. ארכיטקטורה זו מספקת גמישות וביצועים גם עם אלפי טיולים.
בלוק מידע "יעדים" — סעיפים של בלוק מידע הטיולים. היררכיה: "אירופה" → "איטליה" → "טוסקנה". מאפייני סעיף דרך שדות UF_*: UF_COUNTRY_CODE (ISO 3166-1), UF_CLIMATE_INFO, UF_VISA_REQUIRED, UF_GALLERY. הסעיפים משמשים גם לסינון וגם לאופטימיזציית SEO עם סימון Schema.org לנתונים מובנים.
בלוק מידע "טיולים" (סוג tours) — אלמנטים בתוך סעיפי היעדים. המאפיינים כוללים משך, תאריכי יציאה, סוג טיול, רמת קושי, גודל קבוצה, שירותים כלולים, מחיר בסיס, כוכבי מלון, מזהה מערכת הזמנות חיצונית, גלריה ווידאו. קישור לקטלוג המסחרי (CCatalog::Add()) נדרש רק אם ההזמנה עוברת דרך מודול המכירות. אם התשלום עובר למערכת חיצונית (Samo.Tourvisor), קטלוג Bitrix אינו מחובר—בלוק המידע עובד כחלון ראווה.
בלוק Highload "מקדמי מחיר" (PriceCoefficients) מאחסן כללי תמחור דינמיים: שדות TOUR_ID, DATE_FROM, DATE_TO, COEFFICIENT, RULE_TYPE (הזמנה מוקדמת, דיל חם, עונתי, הנחה קבוצתית), PRIORITY. Highload נבחר כי יהיו אלפי רשומות—כל טיול × כל עונה × כל סוג כלל. שאילתה דרך \Bitrix\Highloadblock\HighloadBlockTable::getList() עם פילטר לפי TOUR_ID ותאריך נוכחי.
הצורך ברכיב פילטר פנים מותאם אישית
ה-catalog.smart.filter הסטנדרטי אינו מתאים לטיולים: תאריכי יציאה הם מאפיין מרובה, המחיר מחושב דינמית, והיעד הוא היררכיית סעיפים. אנו מפתחים רכיב מותאם אישית project:tour.filter שמעבד בקשות פי 3 מהר יותר מהסטנדרטי על קטלוג של 2000 טיולים.
סינון לפי יעד. בחירה היררכית: מדינה → אזור → אתר נופש. כאשר נבחרת מדינה, הפילטר טוען אזורים דרך בקשת AJAX ל-/api/tours/regions/?country=IT. ב-component.php — CIBlockSection::GetList() עם שמירה במטמון דרך CPHPCache עם תגית iblock_id_N.
סינון לפי תאריכי יציאה. הלקוח בוחר טווח—לדוגמה, "מ-1 ביוני עד 30 ביוני". במסד הנתונים, התאריכים מאוחסנים כערכי מאפיין מרובים. בעיה: CIBlockElement::GetList() הסטנדרטי עם פילטר כזה עובד לאט על כמויות גדולות. פתרון—טבלת ביניים b_tour_departure_index, המאוכלסת על ידי סוכן כאשר הטיול מתעדכן. הסינון משתמש ב-JOIN על טבלה זו, והתוצאה היא מערך של TOUR_ID.
סינון לפי מחיר. המחיר מחושב בזמן הבקשה: BASE_PRICE × מקדם עונתי × מקדם הזמנה מוקדמת. סינון ישיר אינו אפשרי. קיימות שתי אפשרויות:
- מחיר ממומש — סוכן מחשב מחדש את המחיר הנוכחי של כל טיול פעם בשעה וכותב אותו למאפיין CURRENT_PRICE. הסינון לפיו הוא סטנדרטי. חסרון: עד שעה עיכוב.
- סינון דו-שלבי — תחילה בחירת טיולים לפי כל הפילטרים האחרים, ולאחר מכן חישוב מחיר לכל אחד וחתך של אלה שאינם בטווח. עובד במדויק, אך עם קטלוג של 5000 טיולים, השלב השני יכול לקחת 200–500 אלפיות השנייה. זה נפתר על ידי שמירת מחירים מחושבים במטמון ב-Redis עם TTL של 15 דקות.
בפועל, אנו בוחרים באפשרות הראשונה—הלקוח רואה מחיר עם מרווח שגיאה של עד שעה, אך הסינון עובד מיידית. המחיר המדויק מוצג בעמוד פרטי הטיול ובמהלך התשלום.
סינון AJAX. כל הפילטרים נשלחים כבקשת GET אחת: /api/tours/search/?destination=IT&date_from=01.06&date_to=30.06&duration_min=7&duration_max=10&price_max=2000&type=excursion. הבקר ב-local/modules/project.tours/lib/controller/search.php יורש \Bitrix\Main\Engine\Controller, מאמת פרמטרים, בונה את הפילטר עבור CIBlockElement::GetList(), ומחזיר JSON עם מערך טיולים ומטא-נתוני פנים (כמה טיולים לכל סוג תחת הפילטרים הנוכחיים). פנים—מוני ליד כל ערך פילטר—מחושבים עם שאילתות COUNT(*) נפרדות, ונשמרים במטמון למשך 5 דקות.
כיצד אנו מתמודדים עם תמחור דינמי?
שלוש רמות תמחור:
- מקדמים עונתיים — עונה גבוהה ×1.3, עונה נמוכה ×0.8. מאוחסנים ב-Highload-block PriceCoefficients עם טווחי תאריכים.
- הזמנה מוקדמת — הנחה של 10–20% בהזמנה 60+ ימים לפני היציאה. כלל: אם DEPARTURE_DATE - TODAY > 60, החל מקדם 0.85.
- דילים חמים — הנחה של 15–40% למשך 3–7 ימים לפני היציאה כאשר הקבוצה אינה מלאה. המקדם תלוי באחוז המילוי: GROUP_FILLED < 50% → 0.6.
חישוב מחיר ב-\Project\Tours\PriceCalculator::calculate($tourId, $departureDate):
לחצו לראות את אלגוריתם חישוב המחיר
$basePrice = $tour['BASE_PRICE']; $coefficients = HighloadBlockTable::getList([ 'filter' => [ 'TOUR_ID' => $tourId, '<=DATE_FROM' => $departureDate, '>=DATE_TO' => $departureDate, ], 'order' => ['PRIORITY' => 'ASC'], ])->fetchAll();
$finalPrice = $basePrice; foreach ($coefficients as $c) { $finalPrice *= $c['COEFFICIENT']; }
העדיפות קובעת את סדר היישום. מקדם עונתי (עדיפות 1) מוחל ראשון, לאחר מכן הזמנה מוקדמת (עדיפות 2), ולאחר מכן דיל חם (עדיפות 3). הכללים אינם מתנגשים: הזמנה מוקדמת ודיל חם הם בלעדיים הדדית לפי עיצוב.
אינטגרציה עם Samo.Tourvisor ו-Sletat
מפעיל תיירות ממכיר רק לעתים רחוקות רק את הטיולים שלו. האתר מצרף הצעות ממספר מקורות: טיולים עצמיים (בבלוק מידע), טיולי חבילות מ-Samo.Tourvisor, והצעות מ-Sletat.ru.
Samo.Tourvisor API — RESTful JSON. נקודות קצה עיקריות:
- GET /api/search — חיפוש טיולים לפי פרמטרים (מדינה, אתר נופש, תאריך, לילות, מבוגרים/ילדים). תגובה: מערך הצעות עם מחיר, מלון, תאריך יציאה, מפעיל.
- GET /api/hotel/{id} — פרטי מלון: תמונות, תיאור, קואורדינטות.
- POST /api/order — יצירת בקשת הזמנה.
האינטגרציה מיושמת דרך מודול local/modules/project.tourvisor/. המחלקה \Project\Tourvisor\Client עוטפת בקשות HTTP דרך \Bitrix\Main\Web\HttpClient. נקודה קריטית—זמן תגובה. Samo.Tourvisor מגיב תוך 2–8 שניות. המשתמש לא צריך לחכות: הטעינה הראשונה מציגה תוצאות מבלוק המידע המקומי (טיולים עצמיים) מיידית; במקביל, הפרונטאנד שולח בקשת AJAX ל-/api/tourvisor/search/, והבקאנד שומר את התוצאה במטמון ב-Redis עם TTL של 30 דקות.
Sletat.ru API — XML/SOAP. פרוטוקול ישן, אך מסד נתונים עצום של טיולים. שיטה עיקרית—GetTours(). זמן תגובה—5–15 שניות. תכונה—RequestId: הבקשה הראשונה מחזירה RequestId, שיש לבדוק דרך GetSearchResult() כל 2–3 שניות עד שהסטטוס הופך ל-Completed. מנגנון בדיקה זה מיושם בפרונטאנד.
מיזוג תוצאות ממקורות שונים. בפרונטאנד—רשימה אחת עם סימון מקור. כל תוצאה מכילה מקור (local / tourvisor / sletat), external_id, מחיר, מטבע. מיון לפי מחיר דורש המרת מטבע לפי שער הבנק המרכזי, המאוחסן ב-Highload-block CurrencyRates ומתעדכן על ידי סוכן פעם ביום.
שלבים להגדרת סינון פנים
הנה מדריך שלב-אחר-שלב ליישום סינון פנים:
- הגדירו היררכיית יעדים בסעיפי בלוק המידע.
- צרו את הטבלה הבינונית
UF_*ואכלסו אותה דרך סוכן. - בנו את הרכיב המותאם אישית
UF_COUNTRY_CODEעם נקודות קצה AJAX. - יישמו עדכוני מחיר ממומשים באמצעות סוכן.
- שמרו ספירות פנים במטמון עם TTL קצר (5 דקות).
- בדקו עם קטלוג של 2000 טיולים כדי להבטיח ביצועים.
מה כלול בעבודה (תוצרים)
- תיעוד ארכיטקטוני (סכמת מסד נתונים, מבנה מודול, תיאורי אינטגרציית API)
- הגדרת גישה מרחוק והעברת קוד מקור
- הכשרת מנהלים לעבודה עם פאנל הניהול והפילטרים
- תמיכה לאחר השקה למשך 3 חודשים (תיקוני באגים, ייעוץ)
טעויות נפוצות במהלך היישום:
- חוסר באינדקסים על מאפיינים מרובים מוביל לסינון איטי.
- התעלמות מזמני פסק זמן של API חיצוני—המשתמש רואה טעינה אינסופית.
- קריאה סינכרונית לכל מקורות ההזמנה—העמוד נטען 10+ שניות.
| היקף הפרויקט | לוח זמנים משוער |
|---|---|
| חלון ראווה של טיולים עצמיים ללא הזמנה מקוונת | 3–5 שבועות |
| קטלוג עם סינון, הזמנה, אינטגרציה אחת (Tourvisor) | 6–10 שבועות |
| פלטפורמה מלאה: מספר APIs, פורטל B2B, תמחור דינמי | 10–14 שבועות |
| מקור | סוג API | זמן תגובה טיפוסי | מורכבות אינטגרציה |
|---|---|---|---|
| בלוק מידע מקומי | — | < 50 אלפיות השנייה | נמוכה |
| Samo.Tourvisor | REST JSON | 2–8 שניות | בינונית |
| Sletat.ru | XML/SOAP | 5–15 שניות | גבוהה (בדיקה חוזרת) |
אנו מתמחים בפיתוח אתרי מפעילי תיירות, כולל אופטימיזציית SEO ומערכות הזמנת טיולים. צרו קשר כדי לדון בארכיטקטורת הקטלוג שלכם. קבלו ייעוץ על לוחות זמנים ועלויות—נחשב תוכנית אישית. המהנדסים שלנו עם מומחיות 1C-Bitrix מוסמכת ו-10 שנות ניסיון מבטיחים פתרון בעל ביצועים גבוהים שנמנע ממלכודות נפוצות.

