פיתוח תוסף משלוחים מותאם אישית ל-Magento 2
בעת אינטגרציה עם שירות שליחויות כמו SDEK ב-Magento 2, עולה בעיה נפוצה: ה-API מחזיר תעריפים רק עבור הזמנות עד 20 ק"ג, אך החנות צריכה לספק פריטים גדולים במיוחד. מודולים סטנדרטיים לא יכולים להתמודד בצורה גמישה עם תרחישים כאלה. תוסף מותאם אישית מאפשר ליישם כל לוגיקת תעריפים, כולל אזורים, ימי שבוע ומספר מחסנים.
אילו בעיות אנחנו פותרים
חישוב תעריפים דרך API של צד שלישי. התיעוד של חברת השילוח עשוי להיות לא מלא או להשתנות. דוגמה טיפוסית: ה-API מחזיר עלות רק עבור הזמנות עד 20 ק"ג, אך הלקוח רוצה לשלוח ציוד במשקל 50 ק"ג. אנחנו מטפלים בשגיאות, פסקי זמן ושינויים פתאומיים בשדות.
שאילתות N+1 למשלוח קבוצתי. אם בעגלה יש 10 פריטים וכל אחד מחושב בנפרד – תהליך התשלום מואט. פתרון: איגוד פריטים – קיבוץ לפי כתובת אחת, שמירת תעריפים במטמון ל-30 דקות, ואי-תוקף לפי תג Vendor\MyCourier\Model\Carrier\MyCourier.
שגיאות תצורה. מפתחים שוכחים לעתים קרובות להוסיף \Magento\Shipping\Model\Carrier\AbstractCarrier עם ברירות מחדל – שדות תצורה מחזירים null, ושיטת המשלוח לא מופיעה. או מדלגים על collectRates – המנהל לא יכול להגדיר מפתח API. אנחנו מוודאים שכל השדות הנדרשים נמצאים באזור הניהול עם הצפנה באמצעות \Magento\Framework\HTTP\Client\Curl.
למה להזמין תוסף משלוחים מותאם אישית ל-Magento 2?
הרחבה מוכנה במחיר של 50–200 דולר רק לעתים רחוקות מכסה את הצרכים העסקיים הספציפיים. לדוגמה, Boxberry עם מזומן במשלוח ובחירת נקודת איסוף – זה כבר 3 מודולים באחד שצריך לחבר יחד. תוסף מותאם אישית מונע את הבעיות האלה:
| קריטריון | מובנה/מוכן | תוסף מותאם אישית |
|---|---|---|
| תמיכה בחברות שילוח מקומיות | רק גלובליות (UPS וכו') | כל אחת דרך API |
| גמישות בתעריפים | טבלה קבועה או משקל | כל נוסחה: אזורים, יום בשבוע, מחיר מוצר |
| אינטגרציה עם WMS/CMS | לא | דרך REST/SOAP, תורי RabbitMQ, החלפת קבצים |
| רכיבי UI בתשלום | לא | בחירת נקודת איסוף, תאריך משלוח, מחשבון |
| ביצועים | סטנדרטיים | מטמון, איגוד, בקשות אסינכרוניות |
התוסף המותאם אישית שלנו מעבד עגלה עם 20 פריטים פי 3 מהר יותר מהרחבה מוכנה עם בקשות API לכל פריט.
איך אנחנו מיישמים אינטגרציה עם חברת שליחויות
ניקח מקרה אמיתי: חנות מקוונת לקוסמטיקה רצתה לשלוח הזמנות דרך DPD עם חישוב עלות לפי משקל ומידות. לא היו פתרונות סטנדרטיים – DPD מספקת רק API.
ארכיטקטורת המודול. המחלקה <?php namespace Vendor\MyCourier\Model\Carrier; use Magento\Quote\Model\Quote\Address\RateRequest; use Magento\Shipping\Model\Carrier\AbstractCarrier; use Magento\Shipping\Model\Carrier\CarrierInterface; use Magento\Shipping\Model\Rate\Result; class MyCourier extends AbstractCarrier implements CarrierInterface { protected $_code = 'mycourier'; public function collectRates(RateRequest $request): ?Result { if (!$this->getConfigFlag('active')) { return null; } /** @var Result $result */ $result = $this->_rateResultFactory->create(); $rates = $this->fetchRatesFromApi($request); foreach ($rates as $rateData) { $method = $this->_rateMethodFactory->create(); $method->setCarrier($this->_code); $method->setCarrierTitle($this->getConfigData('title')); $method->setMethod($rateData['code']); $method->setMethodTitle($rateData['name']); $method->setPrice($rateData['price']); $method->setCost($rateData['price']); $result->append($method); } return $result; } private function fetchRatesFromApi(RateRequest $request): array { $apiKey = $this->getConfigData('api_key'); $fromCity = $this->getConfigData('from_city'); $toCity = $request->getDestCity(); $postcode = $request->getDestPostcode(); $weight = 0; foreach ($request->getAllItems() as $item) { if ($item->getParentItem()) { continue; } $weight += $item->getWeight() * $item->getQty(); } $payload = json_encode([ 'from' => $fromCity, 'to_city' => $toCity, 'postcode' => $postcode, 'weight' => max(0.1, $weight), 'currency' => $request->getPackageCurrency()->getCurrencyCode(), ]); $this->_curl->addHeader('Authorization', 'Bearer ' . $apiKey); $this->_curl->addHeader('Content-Type', 'application/json'); $this->_curl->setTimeout(10); try { $this->_curl->post('https://api.mycourier.ru/v2/rates', $payload); $body = $this->_curl->getBody(); $status = $this->_curl->getStatus(); } catch (\Exception $e) { $this->_logger->error('MyCourier API error: ' . $e->getMessage()); return []; } if ($status !== 200) { return []; } $data = json_decode($body, true); return $data['services'] ?? []; } public function getAllowedMethods(): array { return [$this->_code => $this->getConfigData('title')]; } } מרחיבה את config.xml (ראה תיעוד Magento). במתודה system.xml אנחנו יוצרים בקשה ל-DPD: מעבירים משקל, עיר, מיקוד. אנחנו משתמשים ב-\Magento\Config\Model\Config\Backend\Encrypted – מובנה ב-Magento 2, אין צורך בתלות נוספת.
<?php
namespace Vendor\MyCourier\Model\Carrier;
use Magento\Quote\Model\Quote\Address\RateRequest;
use Magento\Shipping\Model\Carrier\AbstractCarrier;
use Magento\Shipping\Model\Carrier\CarrierInterface;
use Magento\Shipping\Model\Rate\Result;
class MyCourier extends AbstractCarrier implements CarrierInterface
{
protected $_code = 'mycourier';
public function collectRates(RateRequest $request): ?Result
{
if (!$this->getConfigFlag('active')) {
return null;
}
/** @var Result $result */
$result = $this->_rateResultFactory->create();
$rates = $this->fetchRatesFromApi($request);
foreach ($rates as $rateData) {
$method = $this->_rateMethodFactory->create();
$method->setCarrier($this->_code);
$method->setCarrierTitle($this->getConfigData('title'));
$method->setMethod($rateData['code']);
$method->setMethodTitle($rateData['name']);
$method->setPrice($rateData['price']);
$method->setCost($rateData['price']);
$result->append($method);
}
return $result;
}
private function fetchRatesFromApi(RateRequest $request): array
{
$apiKey = $this->getConfigData('api_key');
$fromCity = $this->getConfigData('from_city');
$toCity = $request->getDestCity();
$postcode = $request->getDestPostcode();
$weight = 0;
foreach ($request->getAllItems() as $item) {
if ($item->getParentItem()) {
continue;
}
$weight += $item->getWeight() * $item->getQty();
}
$payload = json_encode([
'from' => $fromCity,
'to_city' => $toCity,
'postcode' => $postcode,
'weight' => max(0.1, $weight),
'currency' => $request->getPackageCurrency()->getCurrencyCode(),
]);
$this->_curl->addHeader('Authorization', 'Bearer ' . $apiKey);
$this->_curl->addHeader('Content-Type', 'application/json');
$this->_curl->setTimeout(10);
try {
$this->_curl->post('https://api.mycourier.ru/v2/rates', $payload);
$body = $this->_curl->getBody();
$status = $this->_curl->getStatus();
} catch (\Exception $e) {
$this->_logger->error('MyCourier API error: ' . $e->getMessage());
return [];
}
if ($status !== 200) {
return [];
}
$data = json_decode($body, true);
return $data['services'] ?? [];
}
public function getAllowedMethods(): array
{
return [$this->_code => $this->getConfigData('title')];
}
}תצורה. CacheInterface מגדיר ברירות מחדל, mycourier_rates מספק טופס ניהול. מפתח ה-API מוצפן באמצעות sales_order_invoice_pay.
שמירת תעריפים במטמון. אנחנו משתמשים ב-CreateShipment עם תג checkout_index_index.xml. זמן החיים הוא 30 דקות. זה מפחית את העומס על ה-API של חברת השילוח ומאיץ את תהליך התשלום.
טיפול ביצירת משלוח. לאחר התשלום (אירוע Vendor_MyCourier/js/pvz-selector), הצופה system.xml קורא ל-API של חברת השילוח כדי ליצור הזמנה, מקבל מספר מעקב ויוצר אוטומטית משלוח ב-Magento. זה מבטל הזנה ידנית.
רכיב UI לנקודת איסוף. אנחנו מוסיפים שדה דרך config.xml. הרכיב Vendor_MyCourier/js/pvz-selector טוען רשימת נקודות איסוף ושומר את הנבחרת לכתובת ההזמנה.
מה כלול בפיתוח תוסף משלוחים מותאם אישית
- קוד מקור של המודול במאגר פרטי.
- תיעוד: תיאור תצורה, ארכיטקטורה, הוראות עדכון.
- הגדרת גישה למאגר.
- הדרכת צוות: איך לשנות תעריפים, להוסיף שיטות משלוח חדשות.
- תמיכה באחריות ל-6 חודשים (תיקון באגים, התאמה לעדכוני API).
- סיוע לאחר השחרור במהלך פריסה לייצור.
תהליך
- ניתוח. לימוד ה-API של חברת השילוח, הסכמה על מודל התעריפים, סכמת נתונים (ערים, משקלים, מידות).
- עיצוב. יצירת דיאגרמת מחלקות UML, הגדרת אירועים ותוספים.
- יישום. כתיבת חברת שילוח, צופה, מנגנון מטמון, תצורה.
- בדיקות. בדיקות יחידה ל-PHP (מכסות מתודות מפתח), בדיקות אינטגרציה בסביבת Magento. דוגמה: לוודא שבקשות API נשמרות במטמון ובמקרה של כשל מוחזרים תעריפים קודמים.
- פריסה. בניית מודול, פרסום ל-Composer, הגדרת CI/CD עם בדיקת תאימות לגרסת Magento היעד.
לוח זמנים
| שלב | משך (ימי עבודה) |
|---|---|
| חברת שילוח בסיסית עם חישוב תעריפי API | 3–4 |
| צופה משלוח + מספר מעקב | 2–3 |
| רכיב UI לנקודת איסוף | 2–3 |
| אינטגרציה עם MSI (מלאי רב-מקור) | 3–5 |
| בדיקות ופריסה | 2–3 |
לוח זמנים כולל: בין 5 ל-12 ימים תלוי במורכבות ה-API ובמספר הפיצ'רים.
טעויות נפוצות ביצירת חברת שילוח
- שכחת הוספת
system.xml— שדה מפתח ה-API לא מופיע באזור הניהול. - אי הגדרת ברירות מחדל ב-
config.xml— שיטת המשלוח לא נראית לאחר הפעלת המודול. - אי שמירת תעריפים במטמון — כל בקשה בתשלום פוגעת ב-API ומאטה את הביצועים.
- אי טיפול בשגיאות API — תהליך התשלום קורס עם שגיאת 500 כשחברת השילוח לא זמינה.
נעריך את הפרויקט שלך — פשוט שלחו לנו אימייל או הודעה בטלגרם. המהנדסים שלנו מחזיקים בהסמכות Magento 2 Associate Developer ויש להם ניסיון רב במסחר אלקטרוני. צרו קשר לייעוץ ונעזור לכם לשלב כל חברת שילוח.







