cdek 0.3.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +123 -0
- data/LICENSE +21 -0
- data/README.md +138 -0
- data/app/assets/javascripts/cdek/widget.umd.js +2 -0
- data/app/controllers/cdek/widget_service_controller.rb +78 -0
- data/app/helpers/cdek/widget_helper.rb +133 -0
- data/cdek.gemspec +38 -0
- data/config/routes.rb +11 -0
- data/lib/cdek/client.rb +41 -0
- data/lib/cdek/configuration.rb +56 -0
- data/lib/cdek/connection.rb +228 -0
- data/lib/cdek/engine.rb +46 -0
- data/lib/cdek/error.rb +31 -0
- data/lib/cdek/railtie.rb +11 -0
- data/lib/cdek/resources/base.rb +17 -0
- data/lib/cdek/resources/deliverypoints.rb +50 -0
- data/lib/cdek/resources/locations.rb +47 -0
- data/lib/cdek/version.rb +5 -0
- data/lib/cdek.rb +69 -0
- data/lib/generators/cdek/install/install_generator.rb +56 -0
- data/lib/generators/cdek/install/templates/cdek.rb +32 -0
- data/lib/generators/cdek/install/templates/cdek_widget_controller.js +184 -0
- metadata +78 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cdek
|
|
4
|
+
module Resources
|
|
5
|
+
# Базовый класс для high-level ресурсов CDEK API.
|
|
6
|
+
#
|
|
7
|
+
# Хранит ссылку на клиент. Конкретные ресурсы (Locations, Deliverypoints
|
|
8
|
+
# и т.п.) наследуются и проксируют вызовы в client.get/post/...
|
|
9
|
+
class Base
|
|
10
|
+
attr_reader :client
|
|
11
|
+
|
|
12
|
+
def initialize(client = Cdek.client)
|
|
13
|
+
@client = client
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cdek
|
|
4
|
+
module Resources
|
|
5
|
+
# Список пунктов выдачи заказов (ПВЗ/Постамат) CDEK API v2.
|
|
6
|
+
# Эндпоинт: GET /deliverypoints
|
|
7
|
+
#
|
|
8
|
+
# Параметры (наиболее часто используемые):
|
|
9
|
+
# * city_code — код города CDEK (получается через Locations#cities)
|
|
10
|
+
# * postal_code — почтовый индекс
|
|
11
|
+
# * type — "PVZ" | "POSTAMAT" | "ALL"
|
|
12
|
+
# * country_code — двухбуквенный код страны (RU и т.п.)
|
|
13
|
+
# * region_code — код региона
|
|
14
|
+
# * code — код конкретного пункта (например MSK2181)
|
|
15
|
+
# * have_cashless / have_cash / allowed_cod / is_dressing_room —
|
|
16
|
+
# булевы фильтры
|
|
17
|
+
# * weight_min / weight_max — допустимый вес посылки
|
|
18
|
+
# * is_handout — выдаёт ли посылки
|
|
19
|
+
# * is_reception — принимает ли посылки
|
|
20
|
+
# * size / page — пагинация
|
|
21
|
+
#
|
|
22
|
+
# Возвращает массив пунктов в формате CDEK API (массив Hash).
|
|
23
|
+
#
|
|
24
|
+
# Примеры:
|
|
25
|
+
# Cdek.deliverypoints.list(city_code: 44, type: "PVZ", size: 100)
|
|
26
|
+
# Cdek.deliverypoints.pvz_for_city(44)
|
|
27
|
+
# Cdek.deliverypoints.find("MSK2181")
|
|
28
|
+
class Deliverypoints < Base
|
|
29
|
+
LIST_PATH = "/deliverypoints"
|
|
30
|
+
DEFAULT_TYPE = "PVZ"
|
|
31
|
+
|
|
32
|
+
def list(params = {})
|
|
33
|
+
client.get(LIST_PATH, params: params.compact)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Шорткат: ПВЗ по коду города. extra — дополнительные фильтры (например,
|
|
37
|
+
# have_cashless: true), которые мерджатся к city_code и type.
|
|
38
|
+
def pvz_for_city(city_code, extra = {})
|
|
39
|
+
list({ city_code: city_code, type: DEFAULT_TYPE }.merge(extra))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Найти конкретный пункт по его коду (CDEK ID, например MSK2181).
|
|
43
|
+
# Возвращает Hash пункта или nil.
|
|
44
|
+
def find(code)
|
|
45
|
+
result = list(code: code, size: 1)
|
|
46
|
+
result.is_a?(Array) ? result.first : nil
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cdek
|
|
4
|
+
module Resources
|
|
5
|
+
# Справочники локаций CDEK API v2.
|
|
6
|
+
#
|
|
7
|
+
# Тонкая обёртка над эндпоинтами:
|
|
8
|
+
# * GET /location/cities — список городов
|
|
9
|
+
# * GET /location/regions — список регионов
|
|
10
|
+
# * GET /location/suggest/cities — подсказка городов по подстроке
|
|
11
|
+
#
|
|
12
|
+
# Параметры передаются как есть в query-string; обязательной нормализации
|
|
13
|
+
# или валидации не делаем — структура и набор параметров полностью
|
|
14
|
+
# соответствуют официальной документации CDEK. Значения nil автоматически
|
|
15
|
+
# отбрасываются, чтобы не попадать в URL пустыми ключами.
|
|
16
|
+
#
|
|
17
|
+
# Примеры:
|
|
18
|
+
# Cdek.locations.cities(country_codes: "RU", city: "Москва", size: 5)
|
|
19
|
+
# Cdek.locations.regions(country_codes: "RU", size: 10)
|
|
20
|
+
# Cdek.locations.suggest_cities(name: "Моск", country_code: "RU")
|
|
21
|
+
# Cdek.locations.find_city("Москва")
|
|
22
|
+
class Locations < Base
|
|
23
|
+
CITIES_PATH = "/location/cities"
|
|
24
|
+
REGIONS_PATH = "/location/regions"
|
|
25
|
+
SUGGEST_CITIES_PATH = "/location/suggest/cities"
|
|
26
|
+
|
|
27
|
+
def cities(params = {})
|
|
28
|
+
client.get(CITIES_PATH, params: params.compact)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def regions(params = {})
|
|
32
|
+
client.get(REGIONS_PATH, params: params.compact)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def suggest_cities(params = {})
|
|
36
|
+
client.get(SUGGEST_CITIES_PATH, params: params.compact)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Удобный шорткат: найти первый город по точному названию (и стране).
|
|
40
|
+
# Возвращает Hash города или nil, если ничего не нашлось.
|
|
41
|
+
def find_city(name, country_codes: "RU", **extra)
|
|
42
|
+
list = cities({ city: name, country_codes: country_codes, size: 1 }.merge(extra))
|
|
43
|
+
list.is_a?(Array) ? list.first : nil
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
data/lib/cdek/version.rb
ADDED
data/lib/cdek.rb
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cdek/version"
|
|
4
|
+
require "cdek/error"
|
|
5
|
+
require "cdek/configuration"
|
|
6
|
+
require "cdek/connection"
|
|
7
|
+
require "cdek/client"
|
|
8
|
+
require "cdek/resources/base"
|
|
9
|
+
require "cdek/resources/locations"
|
|
10
|
+
require "cdek/resources/deliverypoints"
|
|
11
|
+
|
|
12
|
+
module Cdek
|
|
13
|
+
CLIENT_MUTEX = Mutex.new
|
|
14
|
+
private_constant :CLIENT_MUTEX
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
# Возвращает текущий объект конфигурации (создавая его при первом обращении).
|
|
18
|
+
def configuration
|
|
19
|
+
@configuration ||= Configuration.new
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Блочный синтаксис настройки.
|
|
23
|
+
#
|
|
24
|
+
# Cdek.configure do |config|
|
|
25
|
+
# config.account = ENV["CDEK_ACCOUNT"]
|
|
26
|
+
# config.secure_password = ENV["CDEK_SECURE_PASSWORD"]
|
|
27
|
+
# config.production_mode!
|
|
28
|
+
# end
|
|
29
|
+
def configure
|
|
30
|
+
yield configuration
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Шареный клиент. Потокобезопасная мемоизация.
|
|
34
|
+
def client
|
|
35
|
+
CLIENT_MUTEX.synchronize { @client ||= Client.new(configuration) }
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Сбрасывает мемоизированный клиент (полезно после изменения конфигурации
|
|
39
|
+
# или в тестах).
|
|
40
|
+
def reset_client!
|
|
41
|
+
CLIENT_MUTEX.synchronize { @client = nil }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Полный сброс — и конфигурации, и клиента.
|
|
45
|
+
def reset!
|
|
46
|
+
CLIENT_MUTEX.synchronize do
|
|
47
|
+
@configuration = nil
|
|
48
|
+
@client = nil
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# High-level ресурс «Локации» — справочники городов/регионов и suggest.
|
|
53
|
+
# По умолчанию использует шареный Cdek.client; можно передать кастомный
|
|
54
|
+
# клиент (например, в тестах с подменённым transport).
|
|
55
|
+
def locations(custom_client = client)
|
|
56
|
+
Resources::Locations.new(custom_client)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# High-level ресурс «Пункты выдачи» — список ПВЗ/постаматов по фильтрам.
|
|
60
|
+
def deliverypoints(custom_client = client)
|
|
61
|
+
Resources::Deliverypoints.new(custom_client)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Rails Engine — подключает прокси-эндпоинт, виджет, helper. Подгружаем только
|
|
67
|
+
# если хост — Rails-приложение. Версия гема без Rails (standalone скрипты,
|
|
68
|
+
# CLI-утилиты) продолжит работать как тонкий клиент API.
|
|
69
|
+
require "cdek/engine" if defined?(::Rails::Engine)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/base"
|
|
4
|
+
|
|
5
|
+
module Cdek
|
|
6
|
+
module Generators
|
|
7
|
+
# bin/rails generate cdek:install
|
|
8
|
+
#
|
|
9
|
+
# Кладёт в хост-приложение:
|
|
10
|
+
# * config/initializers/cdek.rb — настройка гема
|
|
11
|
+
# * app/javascript/controllers/cdek_widget_controller.js — Stimulus-контроллер виджета ПВЗ
|
|
12
|
+
#
|
|
13
|
+
# Сам Engine монтируется отдельной строкой в config/routes.rb пользователя:
|
|
14
|
+
# mount Cdek::Engine, at: "/cdek"
|
|
15
|
+
class InstallGenerator < Rails::Generators::Base
|
|
16
|
+
source_root File.expand_path("templates", __dir__)
|
|
17
|
+
|
|
18
|
+
desc "Создаёт config/initializers/cdek.rb и Stimulus-контроллер виджета ПВЗ."
|
|
19
|
+
|
|
20
|
+
def copy_initializer
|
|
21
|
+
template "cdek.rb", "config/initializers/cdek.rb"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def copy_stimulus_controller
|
|
25
|
+
copy_file "cdek_widget_controller.js",
|
|
26
|
+
"app/javascript/controllers/cdek_widget_controller.js"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def print_post_install
|
|
30
|
+
say "\n========================================================================", :green
|
|
31
|
+
say " Гем Cdek установлен.", :green
|
|
32
|
+
say "========================================================================", :green
|
|
33
|
+
say " 1) Добавьте маршрут в config/routes.rb:"
|
|
34
|
+
say " mount Cdek::Engine, at: \"/cdek\""
|
|
35
|
+
say ""
|
|
36
|
+
say " 2) Заполните .env (или ENV) переменными:"
|
|
37
|
+
say " CDEK_ACCOUNT=..."
|
|
38
|
+
say " CDEK_SECURE_PASSWORD=..."
|
|
39
|
+
say " YANDEX_MAPS_API_KEY=... # ключ Yandex Maps JS API для карты виджета"
|
|
40
|
+
say ""
|
|
41
|
+
say " 3) Вставьте виджет в любую view, например в модалку оформления заказа:"
|
|
42
|
+
say " = cdek_widget_tag api_key: ENV[\"YANDEX_MAPS_API_KEY\"],"
|
|
43
|
+
say " default_city: \"Москва\","
|
|
44
|
+
say " modal_id: \"cdek-points-modal\""
|
|
45
|
+
say ""
|
|
46
|
+
say " 4) Скрытые поля для приёма выбранного пункта (внутри order_form):"
|
|
47
|
+
say " order_cdek_point_code"
|
|
48
|
+
say " order_cdek_point_name"
|
|
49
|
+
say " order_cdek_point_address"
|
|
50
|
+
say " order_cdek_city_code"
|
|
51
|
+
say " (DOM-id можно переопределить аргументами field_* у cdek_widget_tag.)"
|
|
52
|
+
say "========================================================================", :green
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Настройка гема Cdek.
|
|
4
|
+
#
|
|
5
|
+
# Учётные данные удобно хранить в Rails encrypted credentials или ENV.
|
|
6
|
+
# В примере ниже используются ENV-переменные.
|
|
7
|
+
Cdek.configure do |config|
|
|
8
|
+
config.account = ENV["CDEK_ACCOUNT"]
|
|
9
|
+
config.secure_password = ENV["CDEK_SECURE_PASSWORD"]
|
|
10
|
+
|
|
11
|
+
# Контур CDEK API. По умолчанию — боевой (api.cdek.ru/v2). С боевыми
|
|
12
|
+
# учётными данными это правильный выбор и в development. Чтобы временно
|
|
13
|
+
# переключиться на песочницу (api.edu.cdek.ru/v2) — добавь в .env:
|
|
14
|
+
#
|
|
15
|
+
# CDEK_SANDBOX=1
|
|
16
|
+
#
|
|
17
|
+
# либо явно поменяй вызов на config.test_mode!.
|
|
18
|
+
if ENV["CDEK_SANDBOX"].to_s.match?(/\A(1|true|yes|on)\z/i)
|
|
19
|
+
config.test_mode!
|
|
20
|
+
else
|
|
21
|
+
config.production_mode!
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Опциональная тонкая настройка:
|
|
25
|
+
# config.timeout = 15
|
|
26
|
+
# config.open_timeout = 5
|
|
27
|
+
# config.user_agent = "MyApp/1.0 (+https://example.com)"
|
|
28
|
+
config.logger = Rails.logger
|
|
29
|
+
|
|
30
|
+
# Быстрый старт с публичными тестовыми кредами CDEK (только для песочницы):
|
|
31
|
+
# config.use_sandbox_credentials!
|
|
32
|
+
end
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
|
2
|
+
|
|
3
|
+
// Stimulus-контроллер виджета ПВЗ СДЭК.
|
|
4
|
+
//
|
|
5
|
+
// КРИТИЧНО: @cdek-it/widget@3 (UMD) ожидает параметр `root` как СТРОКОВЫЙ
|
|
6
|
+
// ID DOM-элемента, не как сам DOM-объект. Внутри виджет вызывает
|
|
7
|
+
// `document.getElementById(params.root)`. Если передать туда HTMLElement —
|
|
8
|
+
// getElementById вернёт null, и виджет создаст «висячий» div в памяти,
|
|
9
|
+
// продолжит делать запросы офисов (мы это видим в server-логах), но в
|
|
10
|
+
// видимом DOM нашего root-таргета ничего не отрисует. Поэтому здесь мы
|
|
11
|
+
// гарантируем, что у root-элемента есть уникальный id, и передаём
|
|
12
|
+
// виджету именно строку.
|
|
13
|
+
//
|
|
14
|
+
// Про from / sender_city_code:
|
|
15
|
+
// Если в `from` передавать только { address: "Москва" }, CDEK API не
|
|
16
|
+
// возвращает склад-склад тарифы (только дверь-*), и виджет показывает
|
|
17
|
+
// «Выберите тариф». Чтобы получить полный набор тарифов, нужно передать
|
|
18
|
+
// CDEK-код города отправителя (см. справочник /location/cities). Если код
|
|
19
|
+
// задан через data-cdek-widget-sender-city-code-value — используем его,
|
|
20
|
+
// иначе fallback на address.
|
|
21
|
+
//
|
|
22
|
+
// Про goods:
|
|
23
|
+
// CDEK считает тарифы по габаритам и весу отправления. Значение `goods`
|
|
24
|
+
// должно приходить от хост-приложения через data-cdek-widget-goods-value.
|
|
25
|
+
// Если массив не передан или невалиден, не подставляем статичные габариты:
|
|
26
|
+
// виджет будет открыт без расчётных packages, чтобы не считать доставку
|
|
27
|
+
// по выдуманным размерам.
|
|
28
|
+
|
|
29
|
+
let _scriptPromise = null
|
|
30
|
+
|
|
31
|
+
function ensureWidgetScript(url) {
|
|
32
|
+
if (typeof window.CDEKWidget !== "undefined") {
|
|
33
|
+
return Promise.resolve()
|
|
34
|
+
}
|
|
35
|
+
if (_scriptPromise) return _scriptPromise
|
|
36
|
+
_scriptPromise = new Promise((resolve, reject) => {
|
|
37
|
+
const s = document.createElement("script")
|
|
38
|
+
s.src = url
|
|
39
|
+
s.async = true
|
|
40
|
+
s.onload = () => resolve()
|
|
41
|
+
s.onerror = () => { _scriptPromise = null; reject(new Error("Не удалось загрузить скрипт виджета СДЭК")) }
|
|
42
|
+
document.head.appendChild(s)
|
|
43
|
+
})
|
|
44
|
+
return _scriptPromise
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function setFieldValue(id, value) {
|
|
48
|
+
if (!id) return
|
|
49
|
+
const el = document.getElementById(id)
|
|
50
|
+
if (el) {
|
|
51
|
+
el.value = value == null ? "" : String(value)
|
|
52
|
+
el.dispatchEvent(new Event("change", { bubbles: true }))
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function setText(selector, value) {
|
|
57
|
+
if (!selector) return
|
|
58
|
+
document.querySelectorAll(selector).forEach((el) => { el.textContent = value })
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function parseGoods(rawJson) {
|
|
62
|
+
const trimmed = (rawJson || "").trim()
|
|
63
|
+
if (trimmed === "") return []
|
|
64
|
+
try {
|
|
65
|
+
const parsed = JSON.parse(trimmed)
|
|
66
|
+
if (Array.isArray(parsed)) return parsed
|
|
67
|
+
return []
|
|
68
|
+
} catch (_) {
|
|
69
|
+
return []
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default class extends Controller {
|
|
74
|
+
static targets = ["root", "error"]
|
|
75
|
+
static values = {
|
|
76
|
+
servicePath: String,
|
|
77
|
+
scriptUrl: String,
|
|
78
|
+
apiKey: String,
|
|
79
|
+
defaultLocation: { type: String, default: "Москва" },
|
|
80
|
+
senderCity: { type: String, default: "Москва" },
|
|
81
|
+
senderCityCode: { type: String, default: "" },
|
|
82
|
+
goods: { type: String, default: "" },
|
|
83
|
+
modalId: { type: String, default: "" },
|
|
84
|
+
fieldCode: { type: String, default: "order_cdek_point_code" },
|
|
85
|
+
fieldName: { type: String, default: "order_cdek_point_name" },
|
|
86
|
+
fieldAddress: { type: String, default: "order_cdek_point_address" },
|
|
87
|
+
fieldCityCode: { type: String, default: "order_cdek_city_code" },
|
|
88
|
+
labelSelector: { type: String, default: "[data-cdek-widget-label]" },
|
|
89
|
+
addressSelector: { type: String, default: "#order_cdek_point_address_view" }
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
connect() {
|
|
93
|
+
ensureWidgetScript(this.scriptUrlValue)
|
|
94
|
+
.then(() => this._mountWidget())
|
|
95
|
+
.catch((err) => this._showError(err && err.message ? err.message : "ошибка"))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
disconnect() {
|
|
99
|
+
if (this._widget) {
|
|
100
|
+
try {
|
|
101
|
+
if (typeof this._widget.destroy === "function") this._widget.destroy()
|
|
102
|
+
else if (typeof this._widget.close === "function") this._widget.close()
|
|
103
|
+
} catch (_) { /* no-op */ }
|
|
104
|
+
this._widget = null
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
_mountWidget() {
|
|
109
|
+
if (!this.hasRootTarget) return
|
|
110
|
+
if (typeof window.CDEKWidget !== "function") {
|
|
111
|
+
this._showError("CDEKWidget недоступен после загрузки скрипта")
|
|
112
|
+
return
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Гарантируем уникальный DOM-id у root'а и передаём его виджету строкой.
|
|
116
|
+
if (!this.rootTarget.id) {
|
|
117
|
+
this.rootTarget.id = "cdek-widget-root-" + Math.random().toString(36).slice(2, 10)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Если задан CDEK-код города отправителя — передаём его, иначе fallback
|
|
121
|
+
// на address. С code CDEK вернёт склад-склад тарифы; с одним address —
|
|
122
|
+
// только дверь-* (тогда виджет покажет "Выберите тариф" для офиса).
|
|
123
|
+
const senderCodeRaw = this.senderCityCodeValue.trim()
|
|
124
|
+
const senderCodeNum = senderCodeRaw === "" ? null : Number(senderCodeRaw)
|
|
125
|
+
const from = (senderCodeNum !== null && Number.isFinite(senderCodeNum))
|
|
126
|
+
? { code: senderCodeNum }
|
|
127
|
+
: { address: this.senderCityValue }
|
|
128
|
+
|
|
129
|
+
const goods = parseGoods(this.goodsValue)
|
|
130
|
+
const widgetOptions = {
|
|
131
|
+
root: this.rootTarget.id,
|
|
132
|
+
servicePath: this.servicePathValue,
|
|
133
|
+
apiKey: this.apiKeyValue,
|
|
134
|
+
defaultLocation: this.defaultLocationValue,
|
|
135
|
+
from: from,
|
|
136
|
+
hideDeliveryOptions: { door: true, office: false },
|
|
137
|
+
lang: "rus",
|
|
138
|
+
currency: "RUB",
|
|
139
|
+
onChoose: (mode, tariff, office) => this._handleChoose(office)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (goods.length > 0) {
|
|
143
|
+
widgetOptions.goods = goods
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
this._widget = new window.CDEKWidget(widgetOptions)
|
|
148
|
+
} catch (err) {
|
|
149
|
+
this._showError(err && err.message ? err.message : "ошибка инициализации виджета")
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
_handleChoose(office) {
|
|
154
|
+
if (!office) return
|
|
155
|
+
const code = office.code || ""
|
|
156
|
+
const name = office.name || ""
|
|
157
|
+
const address = office.address || office.address_full || ""
|
|
158
|
+
const cityCode = office.city_code || ""
|
|
159
|
+
|
|
160
|
+
setFieldValue(this.fieldCodeValue, code)
|
|
161
|
+
setFieldValue(this.fieldNameValue, name)
|
|
162
|
+
setFieldValue(this.fieldAddressValue, address)
|
|
163
|
+
setFieldValue(this.fieldCityCodeValue, cityCode)
|
|
164
|
+
|
|
165
|
+
const label = name ? (code ? `${name} (${code})` : name) : "не выбран"
|
|
166
|
+
setText(this.labelSelectorValue, label)
|
|
167
|
+
setText(this.addressSelectorValue, address)
|
|
168
|
+
|
|
169
|
+
this.dispatch("chosen", { detail: { office } })
|
|
170
|
+
if (this.modalIdValue) {
|
|
171
|
+
document.dispatchEvent(new CustomEvent("modal:close", { detail: { id: this.modalIdValue } }))
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
_showError(message) {
|
|
176
|
+
if (this.hasErrorTarget) {
|
|
177
|
+
this.errorTarget.textContent = `Не удалось открыть виджет СДЭК: ${message}.`
|
|
178
|
+
this.errorTarget.style.display = ""
|
|
179
|
+
}
|
|
180
|
+
if (this.hasRootTarget) {
|
|
181
|
+
this.rootTarget.style.display = "none"
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
metadata
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: cdek
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.3.9
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Your Name
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rake
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - "~>"
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '13.0'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - "~>"
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '13.0'
|
|
26
|
+
description: 'Тонкий клиент для CDEK API v2 без внешних рантайм-зависимостей: конфигурация,
|
|
27
|
+
иерархия ошибок, автоматическое управление OAuth2-токеном. Поверх клиента — монтируемый
|
|
28
|
+
Rails Engine с прокси-эндпоинтом, вендорным JS-виджетом ПВЗ и Stimulus-контроллером.'
|
|
29
|
+
email:
|
|
30
|
+
- you@example.com
|
|
31
|
+
executables: []
|
|
32
|
+
extensions: []
|
|
33
|
+
extra_rdoc_files: []
|
|
34
|
+
files:
|
|
35
|
+
- CHANGELOG.md
|
|
36
|
+
- LICENSE
|
|
37
|
+
- README.md
|
|
38
|
+
- app/assets/javascripts/cdek/widget.umd.js
|
|
39
|
+
- app/controllers/cdek/widget_service_controller.rb
|
|
40
|
+
- app/helpers/cdek/widget_helper.rb
|
|
41
|
+
- cdek.gemspec
|
|
42
|
+
- config/routes.rb
|
|
43
|
+
- lib/cdek.rb
|
|
44
|
+
- lib/cdek/client.rb
|
|
45
|
+
- lib/cdek/configuration.rb
|
|
46
|
+
- lib/cdek/connection.rb
|
|
47
|
+
- lib/cdek/engine.rb
|
|
48
|
+
- lib/cdek/error.rb
|
|
49
|
+
- lib/cdek/railtie.rb
|
|
50
|
+
- lib/cdek/resources/base.rb
|
|
51
|
+
- lib/cdek/resources/deliverypoints.rb
|
|
52
|
+
- lib/cdek/resources/locations.rb
|
|
53
|
+
- lib/cdek/version.rb
|
|
54
|
+
- lib/generators/cdek/install/install_generator.rb
|
|
55
|
+
- lib/generators/cdek/install/templates/cdek.rb
|
|
56
|
+
- lib/generators/cdek/install/templates/cdek_widget_controller.js
|
|
57
|
+
licenses:
|
|
58
|
+
- MIT
|
|
59
|
+
metadata:
|
|
60
|
+
rubygems_mfa_required: 'true'
|
|
61
|
+
rdoc_options: []
|
|
62
|
+
require_paths:
|
|
63
|
+
- lib
|
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '3.0'
|
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
70
|
+
requirements:
|
|
71
|
+
- - ">="
|
|
72
|
+
- !ruby/object:Gem::Version
|
|
73
|
+
version: '0'
|
|
74
|
+
requirements: []
|
|
75
|
+
rubygems_version: 4.0.6
|
|
76
|
+
specification_version: 4
|
|
77
|
+
summary: Ruby/Rails клиент и Engine для CDEK API v2 с виджетом ПВЗ
|
|
78
|
+
test_files: []
|