Разработка кастомного плагина Saleor
Saleor построен на Django и предоставляет явную точку расширения через систему плагинов — BasePlugin. Каждый плагин регистрируется в PLUGINS настроек Django и перехватывает события через хуки. Это не WordPress-плагины: здесь нет магии, есть Python-классы с предсказуемым жизненным циклом.
Архитектура плагина
Плагин в Saleor — это класс, наследующий BasePlugin из saleor.plugins.base_plugin. Доступные хуки покрывают весь жизненный цикл заказа, платёжный pipeline, отображение товаров и webhook-события.
from saleor.plugins.base_plugin import BasePlugin, ConfigurationTypeField
class TaxProviderPlugin(BasePlugin):
PLUGIN_ID = "custom.tax_provider"
PLUGIN_NAME = "Custom Tax Provider"
DEFAULT_ACTIVE = False
CONFIG_STRUCTURE = {
"api_key": {
"type": ConfigurationTypeField.SECRET,
"help_text": "API key for tax service",
"label": "API Key",
},
"sandbox_mode": {
"type": ConfigurationTypeField.BOOLEAN,
"help_text": "Use sandbox endpoint",
"label": "Sandbox",
},
}
def calculate_checkout_line_tax(
self, checkout_line_info, checkout_info, address, discounts, previous_value
):
config = self._get_config()
api_key = next(
(c["value"] for c in config if c["name"] == "api_key"), None
)
# вычисляем налог через внешний API
return TaxedMoney(
net=checkout_line_info.line.unit_price_net,
gross=self._fetch_tax(checkout_line_info, api_key),
)
Метод _get_config() возвращает конфигурацию, сохранённую через Dashboard. Значения типа SECRET хранятся зашифрованными.
Хуки для платёжного pipeline
Наиболее востребованные хуки — платёжные. Saleor разделяет процессинг на authorize, capture, refund, void:
def authorize_payment(
self, payment_information: "PaymentData", previous_value
) -> "GatewayResponse":
token = payment_information.token
amount = payment_information.amount
currency = payment_information.currency
response = self._call_payment_gateway(
action="authorize",
token=token,
amount=amount,
currency=currency,
)
return GatewayResponse(
is_success=response.get("status") == "authorized",
action_required=False,
kind=TransactionKind.AUTH,
amount=amount,
currency=currency,
transaction_id=response.get("transaction_id"),
error=response.get("error_message"),
)
Webhook-события
С версии 3.x Saleor поддерживает async webhooks. Плагин может объявить подписки через GraphQL subscriptions вместо polling:
WEBHOOK_EVENTS_SUBSCRIPTIONS = """
subscription {
event {
... on OrderCreated {
order {
id
number
total { gross { amount currency } }
user { email }
}
}
}
}
"""
Saleor отправит POST с payload на указанный endpoint при каждом событии ORDER_CREATED. Тело подписки определяет, какие поля попадут в payload — это GraphQL fragment, не просто конфиг.
Регистрация и конфигурация
# settings.py
PLUGINS = [
"myapp.plugins.tax_provider.TaxProviderPlugin",
"myapp.plugins.custom_payment.CustomPaymentPlugin",
]
После перезапуска сервера плагин появится в разделе Plugins Dashboard. Конфигурационные поля из CONFIG_STRUCTURE рендерятся автоматически.
Тестирование
Saleor предоставляет PluginsManager — через него тестируют плагины без поднятия полного Django окружения:
from unittest.mock import patch, MagicMock
from saleor.plugins.manager import PluginsManager
def test_tax_calculation():
plugin = TaxProviderPlugin(
configuration=[{"name": "api_key", "value": "test-key"}],
active=True,
)
with patch.object(plugin, "_fetch_tax", return_value=Decimal("12.50")):
result = plugin.calculate_checkout_line_tax(
checkout_line_info=mock_line,
checkout_info=mock_checkout,
address=mock_address,
discounts=[],
previous_value=TaxedMoney(net=Decimal("100"), gross=Decimal("100")),
)
assert result.gross.amount == Decimal("12.50")
Типичные задачи и сроки
| Задача | Сложность | Срок |
|---|---|---|
| Плагин налогообложения с внешним API | Средняя | 3–5 дней |
| Платёжный gateway (authorize + capture + refund) | Высокая | 5–8 дней |
| Webhook-интеграция с CRM/ERP | Средняя | 2–4 дня |
| Кастомная логика скидок | Средняя | 3–4 дня |
| Плагин уведомлений (email/SMS) | Низкая | 1–2 дня |
Что нужно передать перед стартом
- Версия Saleor (3.x меняет сигнатуры хуков относительно 2.x)
- Описание бизнес-логики: какие события перехватываем, какой внешний API вызываем
- Credentials тестового окружения
- Требования к конфигурации через Dashboard (нужны ли секретные поля)
Разработка ведётся в отдельном Python-пакете, подключаемом через pip install -e. Это позволяет версионировать плагин независимо от ядра Saleor и обновлять его без форка.







