Загрузить файлы в «/»
This commit is contained in:
parent
14841c0835
commit
4fedd08e8f
|
|
@ -1,88 +1,88 @@
|
|||
{
|
||||
"meta": {
|
||||
"source": "Таблица основных типов ISO-контейнеров (внешние/внутренние размеры, дверной проём, масса, объём)",
|
||||
"usage": "Сверка п.21 FCL (проходимость груза в дверной проём 20DV, 40DV, 40HC) и оценка payload/объёма."
|
||||
},
|
||||
"types": {
|
||||
"20DV": {
|
||||
"label": "20' Standard (Dry Cube) — соответствует 20DV в критериях",
|
||||
"external_mm": { "length": 6058, "width": 2438, "height": 2591 },
|
||||
"internal_mm": { "length": 5905, "width": 2350, "height": 2381 },
|
||||
"door_opening_mm": { "width": 2336, "height": 2291 },
|
||||
"max_gross_kg": 30480,
|
||||
"tare_kg": 2370,
|
||||
"payload_kg": 28110,
|
||||
"volume_m3": 33.2
|
||||
},
|
||||
"20HC": {
|
||||
"label": "20' High Cube",
|
||||
"external_mm": { "length": 6058, "width": 2438, "height": 2896 },
|
||||
"internal_mm": { "length": 5905, "width": 2350, "height": 2693 },
|
||||
"door_opening_mm": { "width": 2340, "height": 2597 },
|
||||
"max_gross_kg": 30480,
|
||||
"tare_kg": 2340,
|
||||
"payload_kg": 28140,
|
||||
"volume_m3": 37.5
|
||||
},
|
||||
"20HC_PW": {
|
||||
"label": "20' High Cube Pallet Wide",
|
||||
"external_mm": { "length": 6058, "width": 2484, "height": 2896 },
|
||||
"internal_mm": { "length": 5898, "width": 2426, "height": 2698 },
|
||||
"door_opening_mm": { "width": 2374, "height": 2585 },
|
||||
"max_gross_kg": 30480,
|
||||
"tare_kg": 2580,
|
||||
"payload_kg": 27900,
|
||||
"volume_m3": 38.6
|
||||
},
|
||||
"40DV": {
|
||||
"label": "40' Standard (Dry Van) — соответствует 40DV в критериях",
|
||||
"external_mm": { "length": 12192, "width": 2438, "height": 2591 },
|
||||
"internal_mm": { "length": 12039, "width": 2350, "height": 2372 },
|
||||
"door_opening_mm": { "width": 2336, "height": 2291 },
|
||||
"max_gross_kg": 30480,
|
||||
"tare_kg": 4000,
|
||||
"payload_kg": 26480,
|
||||
"volume_m3": 67.8
|
||||
},
|
||||
"40HC": {
|
||||
"label": "40' High Cube — соответствует 40HC в критериях",
|
||||
"external_mm": { "length": 12192, "width": 2438, "height": 2896 },
|
||||
"internal_mm": { "length": 12039, "width": 2350, "height": 2693 },
|
||||
"door_opening_mm": { "width": 2340, "height": 2597 },
|
||||
"max_gross_kg": 32500,
|
||||
"tare_kg": 4200,
|
||||
"payload_kg": 28300,
|
||||
"volume_m3": 76.5
|
||||
},
|
||||
"40HC_PW": {
|
||||
"label": "40' High Cube Pallet Wide",
|
||||
"external_mm": { "length": 12192, "width": 2500, "height": 2896 },
|
||||
"internal_mm": { "length": 12039, "width": 2432, "height": 2693 },
|
||||
"door_opening_mm": { "width": 2432, "height": 2597 },
|
||||
"max_gross_kg": 35000,
|
||||
"tare_kg": 4400,
|
||||
"payload_kg": 30600,
|
||||
"volume_m3": 79.3
|
||||
},
|
||||
"45HC_PW_A": {
|
||||
"label": "45' High Cube Pallet Wide (Type A)",
|
||||
"external_mm": { "length": 13716, "width": 2500, "height": 2750 },
|
||||
"internal_mm": { "length": 13513, "width": 2444, "height": 2549 },
|
||||
"door_opening_mm": { "width": 2416, "height": 2439 },
|
||||
"max_gross_kg": 34000,
|
||||
"tare_kg": 4180,
|
||||
"payload_kg": 29820,
|
||||
"volume_m3": 85.1
|
||||
},
|
||||
"45HC_PW_B": {
|
||||
"label": "45' High Cube Pallet Wide (Type B)",
|
||||
"external_mm": { "length": 13716, "width": 2500, "height": 2896 },
|
||||
"internal_mm": { "length": 13513, "width": 2444, "height": 2670 },
|
||||
"door_opening_mm": { "width": 2416, "height": 2580 },
|
||||
"max_gross_kg": 34000,
|
||||
"tare_kg": 5080,
|
||||
"payload_kg": 28920,
|
||||
"volume_m3": 89.5
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
"meta": {
|
||||
"source": "Таблица основных типов ISO-контейнеров (внешние/внутренние размеры, дверной проём, масса, объём)",
|
||||
"usage": "Сверка п.21 FCL (проходимость груза в дверной проём 20DV, 40DV, 40HC) и оценка payload/объёма."
|
||||
},
|
||||
"types": {
|
||||
"20DV": {
|
||||
"label": "20' Standard (Dry Cube) — соответствует 20DV в критериях",
|
||||
"external_mm": { "length": 6058, "width": 2438, "height": 2591 },
|
||||
"internal_mm": { "length": 5905, "width": 2350, "height": 2381 },
|
||||
"door_opening_mm": { "width": 2336, "height": 2291 },
|
||||
"max_gross_kg": 30480,
|
||||
"tare_kg": 2370,
|
||||
"payload_kg": 28110,
|
||||
"volume_m3": 33.2
|
||||
},
|
||||
"20HC": {
|
||||
"label": "20' High Cube",
|
||||
"external_mm": { "length": 6058, "width": 2438, "height": 2896 },
|
||||
"internal_mm": { "length": 5905, "width": 2350, "height": 2693 },
|
||||
"door_opening_mm": { "width": 2340, "height": 2597 },
|
||||
"max_gross_kg": 30480,
|
||||
"tare_kg": 2340,
|
||||
"payload_kg": 28140,
|
||||
"volume_m3": 37.5
|
||||
},
|
||||
"20HC_PW": {
|
||||
"label": "20' High Cube Pallet Wide",
|
||||
"external_mm": { "length": 6058, "width": 2484, "height": 2896 },
|
||||
"internal_mm": { "length": 5898, "width": 2426, "height": 2698 },
|
||||
"door_opening_mm": { "width": 2374, "height": 2585 },
|
||||
"max_gross_kg": 30480,
|
||||
"tare_kg": 2580,
|
||||
"payload_kg": 27900,
|
||||
"volume_m3": 38.6
|
||||
},
|
||||
"40DV": {
|
||||
"label": "40' Standard (Dry Van) — соответствует 40DV в критериях",
|
||||
"external_mm": { "length": 12192, "width": 2438, "height": 2591 },
|
||||
"internal_mm": { "length": 12039, "width": 2350, "height": 2372 },
|
||||
"door_opening_mm": { "width": 2336, "height": 2291 },
|
||||
"max_gross_kg": 30480,
|
||||
"tare_kg": 4000,
|
||||
"payload_kg": 26480,
|
||||
"volume_m3": 67.8
|
||||
},
|
||||
"40HC": {
|
||||
"label": "40' High Cube — соответствует 40HC в критериях",
|
||||
"external_mm": { "length": 12192, "width": 2438, "height": 2896 },
|
||||
"internal_mm": { "length": 12039, "width": 2350, "height": 2693 },
|
||||
"door_opening_mm": { "width": 2340, "height": 2597 },
|
||||
"max_gross_kg": 32500,
|
||||
"tare_kg": 4200,
|
||||
"payload_kg": 28300,
|
||||
"volume_m3": 76.5
|
||||
},
|
||||
"40HC_PW": {
|
||||
"label": "40' High Cube Pallet Wide",
|
||||
"external_mm": { "length": 12192, "width": 2500, "height": 2896 },
|
||||
"internal_mm": { "length": 12039, "width": 2432, "height": 2693 },
|
||||
"door_opening_mm": { "width": 2432, "height": 2597 },
|
||||
"max_gross_kg": 35000,
|
||||
"tare_kg": 4400,
|
||||
"payload_kg": 30600,
|
||||
"volume_m3": 79.3
|
||||
},
|
||||
"45HC_PW_A": {
|
||||
"label": "45' High Cube Pallet Wide (Type A)",
|
||||
"external_mm": { "length": 13716, "width": 2500, "height": 2750 },
|
||||
"internal_mm": { "length": 13513, "width": 2444, "height": 2549 },
|
||||
"door_opening_mm": { "width": 2416, "height": 2439 },
|
||||
"max_gross_kg": 34000,
|
||||
"tare_kg": 4180,
|
||||
"payload_kg": 29820,
|
||||
"volume_m3": 85.1
|
||||
},
|
||||
"45HC_PW_B": {
|
||||
"label": "45' High Cube Pallet Wide (Type B)",
|
||||
"external_mm": { "length": 13716, "width": 2500, "height": 2896 },
|
||||
"internal_mm": { "length": 13513, "width": 2444, "height": 2670 },
|
||||
"door_opening_mm": { "width": 2416, "height": 2580 },
|
||||
"max_gross_kg": 34000,
|
||||
"tare_kg": 5080,
|
||||
"payload_kg": 28920,
|
||||
"volume_m3": 89.5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,178 +1,178 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""Справочник ISO-контейнеров: промпт RAG и сверка п.21 FCL (дверной проём vs габариты груза)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
_JSON_PATH = os.path.join(_DIR, "container_iso_reference.json")
|
||||
|
||||
_iso_cache: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
def load_iso_reference() -> Dict[str, Any]:
|
||||
global _iso_cache
|
||||
if _iso_cache is not None:
|
||||
return _iso_cache
|
||||
try:
|
||||
with open(_JSON_PATH, "r", encoding="utf-8") as f:
|
||||
_iso_cache = json.load(f)
|
||||
except Exception:
|
||||
_iso_cache = {"types": {}}
|
||||
return _iso_cache
|
||||
|
||||
|
||||
def iso_reference_prompt_block() -> str:
|
||||
"""Компактный блок для system prompt LLM (сверка п.21 и выбора контейнера)."""
|
||||
data = load_iso_reference()
|
||||
types = data.get("types") or {}
|
||||
if not types:
|
||||
return ""
|
||||
lines: List[str] = [
|
||||
"СПРАВОЧНИК ISO-КОНТЕЙНЕРОВ (мм, кг, м³) — для сверки с п.21 FCL (дверной проём) и оценки объёма/полезной нагрузки. "
|
||||
"Не выдумывай числа; при расчётах используй только эти значения.",
|
||||
"Ключи 20DV / 40DV / 40HC соответствуют формулировкам в критериях (проём 20DV, 40DV, 40HC).",
|
||||
]
|
||||
for key in ("20DV", "20HC", "20HC_PW", "40DV", "40HC", "40HC_PW", "45HC_PW_A", "45HC_PW_B"):
|
||||
t = types.get(key)
|
||||
if not isinstance(t, dict):
|
||||
continue
|
||||
door = t.get("door_opening_mm") or {}
|
||||
inn = t.get("internal_mm") or {}
|
||||
dw = door.get("width")
|
||||
dh = door.get("height")
|
||||
il = inn.get("length")
|
||||
iw = inn.get("width")
|
||||
ih = inn.get("height")
|
||||
vol = t.get("volume_m3")
|
||||
pay = t.get("payload_kg")
|
||||
lines.append(
|
||||
f"- {key} ({t.get('label', '')}): дверь {dw}×{dh} мм; "
|
||||
f"внутри {il}×{iw}×{ih} мм; объём ~{vol} м³; payload ~{pay} кг"
|
||||
)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _edges_mm_from_dim(d: Dict[str, Any]) -> Optional[Tuple[float, float, float]]:
|
||||
"""Длина/ширина/высота груза в мм (из см в shipment)."""
|
||||
if not isinstance(d, dict):
|
||||
return None
|
||||
|
||||
def _num(v: Any) -> Optional[float]:
|
||||
if v is None:
|
||||
return None
|
||||
if isinstance(v, (int, float)):
|
||||
return float(v)
|
||||
s = str(v).strip().replace(" ", "").replace(",", ".")
|
||||
try:
|
||||
return float(s)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
l = _num(d.get("length_cm"))
|
||||
w = _num(d.get("width_cm"))
|
||||
h = _num(d.get("height_cm"))
|
||||
if l is None or w is None or h is None:
|
||||
return None
|
||||
return l * 10.0, w * 10.0, h * 10.0
|
||||
|
||||
|
||||
def _box_fits_door(
|
||||
edges_mm: Tuple[float, float, float],
|
||||
door_w_mm: float,
|
||||
door_h_mm: float,
|
||||
) -> bool:
|
||||
"""Два наименьших ребра груза должны укладываться в ширину/высоту проёма (сортировка)."""
|
||||
s0, s1, s2 = sorted(edges_mm)
|
||||
dw, dh = sorted((door_w_mm, door_h_mm))
|
||||
return s0 <= dw + 0.5 and s1 <= dh + 0.5
|
||||
|
||||
|
||||
def _codes_from_container_type(ct: str) -> List[str]:
|
||||
"""Из строки вида «2×40HC, 1×20DC» извлекает коды из справочника."""
|
||||
if not isinstance(ct, str) or not ct.strip():
|
||||
return ["20DV", "40DV", "40HC"]
|
||||
t = ct.upper()
|
||||
found: List[str] = []
|
||||
|
||||
def _add(size: str, kind: Optional[str]) -> None:
|
||||
k = (kind or "DV").upper()
|
||||
if size == "20":
|
||||
code = "20" + ("HC" if k in ("HC", "HQ") else "DV")
|
||||
elif size == "40":
|
||||
code = "40" + ("HC" if k in ("HC", "HQ") else "DV")
|
||||
elif size == "45":
|
||||
code = "45HC_PW_B"
|
||||
else:
|
||||
return
|
||||
if code not in found:
|
||||
found.append(code)
|
||||
|
||||
for m in re.finditer(
|
||||
r"(\d{1,3})\s*[x×х**]\s*(20|40|45)\s*(DC|DV|GP|HC|HQ|OT|FR|RF|RH)?",
|
||||
t,
|
||||
re.IGNORECASE,
|
||||
):
|
||||
_add(m.group(2), m.group(3))
|
||||
for m in re.finditer(
|
||||
r"\b(20|40|45)\s*(DC|DV|GP|HC|HQ|OT|FR|RF|RH)\b",
|
||||
t,
|
||||
re.IGNORECASE,
|
||||
):
|
||||
_add(m.group(1), m.group(2))
|
||||
if not found:
|
||||
return ["20DV", "40DV", "40HC"]
|
||||
return found
|
||||
|
||||
|
||||
def door_clearance_summary(shipment: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Текст для п.21: сверка габаритов мест с дверным проёмом 20DV/40DV/40HC из справочника.
|
||||
"""
|
||||
data = load_iso_reference()
|
||||
types = data.get("types") or {}
|
||||
dims = shipment.get("dimensions")
|
||||
if not isinstance(dims, list) or not dims:
|
||||
return (
|
||||
"Нет габаритов грузовых мест — проверка проходимости по справочнику дверных проёмов "
|
||||
"(20DV 2336×2291 мм, 40DV 2336×2291 мм, 40HC 2340×2597 мм) невозможна."
|
||||
)
|
||||
|
||||
ct_raw = (shipment.get("container_type") or "").strip()
|
||||
codes = _codes_from_container_type(ct_raw)
|
||||
parts: List[str] = []
|
||||
for i, d in enumerate(dims, start=1):
|
||||
edges = _edges_mm_from_dim(d)
|
||||
if not edges:
|
||||
parts.append(f"Место {i}: нет полных Д×Ш×В в см.")
|
||||
continue
|
||||
place_bits: List[str] = []
|
||||
for code in codes:
|
||||
spec = types.get(code)
|
||||
if not isinstance(spec, dict):
|
||||
continue
|
||||
door = spec.get("door_opening_mm") or {}
|
||||
dw = float(door.get("width") or 0)
|
||||
dh = float(door.get("height") or 0)
|
||||
if dw <= 0 or dh <= 0:
|
||||
continue
|
||||
ok = _box_fits_door(edges, dw, dh)
|
||||
label = spec.get("label", code)
|
||||
status = "проходит" if ok else "не проходит"
|
||||
place_bits.append(f"{code} ({int(dw)}×{int(dh)} мм): {status}")
|
||||
if place_bits:
|
||||
parts.append(f"Место {i} (рёбра {int(min(edges))}×{int(sorted(edges)[1])}×{int(max(edges))} мм): " + "; ".join(place_bits))
|
||||
else:
|
||||
parts.append(f"Место {i}: нет данных дверного проёма в справочнике для кодов {', '.join(codes)}.")
|
||||
|
||||
note = (
|
||||
" Оценка: два наименьших габарита сравниваются с шириной и высотой дверного проёма (ориентация коробки)."
|
||||
)
|
||||
prefix = (
|
||||
f"Справочник дверных проёмов (п.21). Контейнеры в заявке: {ct_raw or 'не указаны — проверка по 20DV/40DV/40HC'}. "
|
||||
)
|
||||
return prefix + " ".join(parts) + note
|
||||
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Справочник ISO-контейнеров: промпт RAG и сверка п.21 FCL (дверной проём vs габариты груза)."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
from typing import Any, Dict, List, Optional, Tuple
|
||||
|
||||
_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
_JSON_PATH = os.path.join(_DIR, "container_iso_reference.json")
|
||||
|
||||
_iso_cache: Optional[Dict[str, Any]] = None
|
||||
|
||||
|
||||
def load_iso_reference() -> Dict[str, Any]:
|
||||
global _iso_cache
|
||||
if _iso_cache is not None:
|
||||
return _iso_cache
|
||||
try:
|
||||
with open(_JSON_PATH, "r", encoding="utf-8") as f:
|
||||
_iso_cache = json.load(f)
|
||||
except Exception:
|
||||
_iso_cache = {"types": {}}
|
||||
return _iso_cache
|
||||
|
||||
|
||||
def iso_reference_prompt_block() -> str:
|
||||
"""Компактный блок для system prompt LLM (сверка п.21 и выбора контейнера)."""
|
||||
data = load_iso_reference()
|
||||
types = data.get("types") or {}
|
||||
if not types:
|
||||
return ""
|
||||
lines: List[str] = [
|
||||
"СПРАВОЧНИК ISO-КОНТЕЙНЕРОВ (мм, кг, м³) — для сверки с п.21 FCL (дверной проём) и оценки объёма/полезной нагрузки. "
|
||||
"Не выдумывай числа; при расчётах используй только эти значения.",
|
||||
"Ключи 20DV / 40DV / 40HC соответствуют формулировкам в критериях (проём 20DV, 40DV, 40HC).",
|
||||
]
|
||||
for key in ("20DV", "20HC", "20HC_PW", "40DV", "40HC", "40HC_PW", "45HC_PW_A", "45HC_PW_B"):
|
||||
t = types.get(key)
|
||||
if not isinstance(t, dict):
|
||||
continue
|
||||
door = t.get("door_opening_mm") or {}
|
||||
inn = t.get("internal_mm") or {}
|
||||
dw = door.get("width")
|
||||
dh = door.get("height")
|
||||
il = inn.get("length")
|
||||
iw = inn.get("width")
|
||||
ih = inn.get("height")
|
||||
vol = t.get("volume_m3")
|
||||
pay = t.get("payload_kg")
|
||||
lines.append(
|
||||
f"- {key} ({t.get('label', '')}): дверь {dw}×{dh} мм; "
|
||||
f"внутри {il}×{iw}×{ih} мм; объём ~{vol} м³; payload ~{pay} кг"
|
||||
)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _edges_mm_from_dim(d: Dict[str, Any]) -> Optional[Tuple[float, float, float]]:
|
||||
"""Длина/ширина/высота груза в мм (из см в shipment)."""
|
||||
if not isinstance(d, dict):
|
||||
return None
|
||||
|
||||
def _num(v: Any) -> Optional[float]:
|
||||
if v is None:
|
||||
return None
|
||||
if isinstance(v, (int, float)):
|
||||
return float(v)
|
||||
s = str(v).strip().replace(" ", "").replace(",", ".")
|
||||
try:
|
||||
return float(s)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
l = _num(d.get("length_cm"))
|
||||
w = _num(d.get("width_cm"))
|
||||
h = _num(d.get("height_cm"))
|
||||
if l is None or w is None or h is None:
|
||||
return None
|
||||
return l * 10.0, w * 10.0, h * 10.0
|
||||
|
||||
|
||||
def _box_fits_door(
|
||||
edges_mm: Tuple[float, float, float],
|
||||
door_w_mm: float,
|
||||
door_h_mm: float,
|
||||
) -> bool:
|
||||
"""Два наименьших ребра груза должны укладываться в ширину/высоту проёма (сортировка)."""
|
||||
s0, s1, s2 = sorted(edges_mm)
|
||||
dw, dh = sorted((door_w_mm, door_h_mm))
|
||||
return s0 <= dw + 0.5 and s1 <= dh + 0.5
|
||||
|
||||
|
||||
def _codes_from_container_type(ct: str) -> List[str]:
|
||||
"""Из строки вида «2×40HC, 1×20DC» извлекает коды из справочника."""
|
||||
if not isinstance(ct, str) or not ct.strip():
|
||||
return ["20DV", "40DV", "40HC"]
|
||||
t = ct.upper()
|
||||
found: List[str] = []
|
||||
|
||||
def _add(size: str, kind: Optional[str]) -> None:
|
||||
k = (kind or "DV").upper()
|
||||
if size == "20":
|
||||
code = "20" + ("HC" if k in ("HC", "HQ") else "DV")
|
||||
elif size == "40":
|
||||
code = "40" + ("HC" if k in ("HC", "HQ") else "DV")
|
||||
elif size == "45":
|
||||
code = "45HC_PW_B"
|
||||
else:
|
||||
return
|
||||
if code not in found:
|
||||
found.append(code)
|
||||
|
||||
for m in re.finditer(
|
||||
r"(\d{1,3})\s*[x×х**]\s*(20|40|45)\s*(DC|DV|GP|HC|HQ|OT|FR|RF|RH)?",
|
||||
t,
|
||||
re.IGNORECASE,
|
||||
):
|
||||
_add(m.group(2), m.group(3))
|
||||
for m in re.finditer(
|
||||
r"\b(20|40|45)\s*(DC|DV|GP|HC|HQ|OT|FR|RF|RH)\b",
|
||||
t,
|
||||
re.IGNORECASE,
|
||||
):
|
||||
_add(m.group(1), m.group(2))
|
||||
if not found:
|
||||
return ["20DV", "40DV", "40HC"]
|
||||
return found
|
||||
|
||||
|
||||
def door_clearance_summary(shipment: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Текст для п.21: сверка габаритов мест с дверным проёмом 20DV/40DV/40HC из справочника.
|
||||
"""
|
||||
data = load_iso_reference()
|
||||
types = data.get("types") or {}
|
||||
dims = shipment.get("dimensions")
|
||||
if not isinstance(dims, list) or not dims:
|
||||
return (
|
||||
"Нет габаритов грузовых мест — проверка проходимости по справочнику дверных проёмов "
|
||||
"(20DV 2336×2291 мм, 40DV 2336×2291 мм, 40HC 2340×2597 мм) невозможна."
|
||||
)
|
||||
|
||||
ct_raw = (shipment.get("container_type") or "").strip()
|
||||
codes = _codes_from_container_type(ct_raw)
|
||||
parts: List[str] = []
|
||||
for i, d in enumerate(dims, start=1):
|
||||
edges = _edges_mm_from_dim(d)
|
||||
if not edges:
|
||||
parts.append(f"Место {i}: нет полных Д×Ш×В в см.")
|
||||
continue
|
||||
place_bits: List[str] = []
|
||||
for code in codes:
|
||||
spec = types.get(code)
|
||||
if not isinstance(spec, dict):
|
||||
continue
|
||||
door = spec.get("door_opening_mm") or {}
|
||||
dw = float(door.get("width") or 0)
|
||||
dh = float(door.get("height") or 0)
|
||||
if dw <= 0 or dh <= 0:
|
||||
continue
|
||||
ok = _box_fits_door(edges, dw, dh)
|
||||
label = spec.get("label", code)
|
||||
status = "проходит" if ok else "не проходит"
|
||||
place_bits.append(f"{code} ({int(dw)}×{int(dh)} мм): {status}")
|
||||
if place_bits:
|
||||
parts.append(f"Место {i} (рёбра {int(min(edges))}×{int(sorted(edges)[1])}×{int(max(edges))} мм): " + "; ".join(place_bits))
|
||||
else:
|
||||
parts.append(f"Место {i}: нет данных дверного проёма в справочнике для кодов {', '.join(codes)}.")
|
||||
|
||||
note = (
|
||||
" Оценка: два наименьших габарита сравниваются с шириной и высотой дверного проёма (ориентация коробки)."
|
||||
)
|
||||
prefix = (
|
||||
f"Справочник дверных проёмов (п.21). Контейнеры в заявке: {ct_raw or 'не указаны — проверка по 20DV/40DV/40HC'}. "
|
||||
)
|
||||
return prefix + " ".join(parts) + note
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
83
proxy.py
83
proxy.py
|
|
@ -1,92 +1,41 @@
|
|||
import logging
|
||||
import os
|
||||
from fastapi import FastAPI, Request
|
||||
from fastapi.responses import JSONResponse, Response
|
||||
import httpx
|
||||
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
UPSTREAM_URL = os.getenv(
|
||||
"LLM_UPSTREAM_URL",
|
||||
"https://llm.corp.septem.pro/v1/chat/completions",
|
||||
).strip()
|
||||
OPENROUTER_KEY = os.getenv("OPENROUTER_API_KEY", "").strip()
|
||||
|
||||
|
||||
def _client_timeout() -> httpx.Timeout:
|
||||
total = float(os.getenv("LLM_PROXY_TIMEOUT_SECONDS", "120"))
|
||||
connect = float(os.getenv("LLM_PROXY_CONNECT_TIMEOUT", "15"))
|
||||
return httpx.Timeout(total, connect=connect)
|
||||
|
||||
OPENROUTER_KEY = "sk-9cfed30eb6894df5b9a3ffb4b1fb956d"
|
||||
|
||||
@app.post("/v1/chat/completions")
|
||||
async def proxy(req: Request):
|
||||
if not OPENROUTER_KEY:
|
||||
logger.error("OPENROUTER_API_KEY is not set (env or .env)")
|
||||
return JSONResponse(
|
||||
status_code=503,
|
||||
content={
|
||||
"error": "Service unavailable",
|
||||
"details": "Set OPENROUTER_API_KEY for the LLM proxy (or add it to .env).",
|
||||
},
|
||||
)
|
||||
body = await req.json()
|
||||
|
||||
try:
|
||||
body = await req.json()
|
||||
except Exception as e:
|
||||
return JSONResponse(
|
||||
status_code=400,
|
||||
content={"error": "Invalid JSON", "details": str(e)},
|
||||
)
|
||||
|
||||
verify = os.getenv("HTTPX_VERIFY", "true").lower() not in ("0", "false", "no")
|
||||
|
||||
async with httpx.AsyncClient(verify=verify) as client:
|
||||
async with httpx.AsyncClient() as client:
|
||||
try:
|
||||
r = await client.post(
|
||||
UPSTREAM_URL,
|
||||
"https://api.deepseek.com/chat/completions",
|
||||
headers={
|
||||
"Authorization": f"Bearer {OPENROUTER_KEY}",
|
||||
"HTTP-Referer": os.getenv("LLM_HTTP_REFERER", "http://localhost"),
|
||||
"X-Title": os.getenv("LLM_PROXY_X_TITLE", "rag-engine"),
|
||||
"HTTP-Referer": "http://localhost",
|
||||
"model": "deepseek-v4-flash",
|
||||
"X-Title": "rag-engine"
|
||||
},
|
||||
json=body,
|
||||
timeout=_client_timeout(),
|
||||
)
|
||||
except httpx.RequestError as e:
|
||||
logger.error(
|
||||
"LLM upstream unreachable (%s): %s",
|
||||
UPSTREAM_URL,
|
||||
e,
|
||||
exc_info=True,
|
||||
timeout=300,
|
||||
)
|
||||
except httpx.HTTPError as e:
|
||||
# Ошибка сети / таймаут
|
||||
return JSONResponse(
|
||||
status_code=502,
|
||||
content={
|
||||
"error": "Bad gateway",
|
||||
"details": str(e),
|
||||
"upstream": UPSTREAM_URL,
|
||||
"hint": "Проверьте VPN, DNS, доступность хоста и переменную LLM_UPSTREAM_URL.",
|
||||
},
|
||||
content={"error": "Bad gateway", "details": str(e)},
|
||||
)
|
||||
|
||||
if r.status_code >= 500:
|
||||
logger.warning(
|
||||
"LLM upstream HTTP %s, body (prefix): %s",
|
||||
r.status_code,
|
||||
(r.text or "")[:800],
|
||||
)
|
||||
print(r.text)
|
||||
|
||||
# Если бэкенд всегда отвечает JSON:
|
||||
# return JSONResponse(status_code=r.status_code, content=r.json())
|
||||
|
||||
# Универсальный вариант — пробрасываем «как есть»
|
||||
return Response(
|
||||
content=r.content,
|
||||
status_code=r.status_code,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,216 @@
|
|||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Автомобильная перевозка (LTL)",
|
||||
"employee_email": "denis.fomin@timnet.ch, Yana.Schkabrova@timnet.ch",
|
||||
"extra_required_fields": [
|
||||
"hs_code",
|
||||
"customs_clearance_place_export_rf"
|
||||
],
|
||||
"mandatory_counterparty_criteria": "По макету интерфейса обязательно отражать в письме контрагенту и запрашивать у клиента при отсутствии: название клиента; Incoterms; характер/наименование груза и код ТН ВЭД; страна, город, адрес забора; страна, город, точный адрес доставки; место таможенного оформления в РФ; количество грузовых мест и вес; габариты грузовых мест (Д×Ш×В).",
|
||||
"criteria": "1\tНазвание клиента\n2\tУсловия поставки Incoterms\n3\tДата готовности груза\n4\tСтрана, город, адрес забора\n5\tСтоимость груза\n6\tКоличество грузовых мест и вес\n7\tГабариты каждого грузового места в см или мм (длина × ширина × высота) и их вес и объём\n8\tХарактер груза или наименование груза, код ТН ВЭД\n9\tСодержатся ли в грузе батарейки, газы под давлением, жидкости\n10\tМожно ли штабелировать груз с другими отправками\n11\tЕсли груз нельзя штабелировать с другими грузами — можно ли штабелировать грузовые места между собой\n12\tЕсли груз — химия, литиевые батареи, жидкости, аэрозоли, газы или порошки — предоставить MSDS\n13\tЕсли есть батарейки — в составе груза или отдельно упакованы\n14\tЕсли груз из п.13 отгружается из материкового Китая авто транспортом — дополнительно DGM\n15\tНазвание бренда\n16\tЕсли бренд зарегистрирован в таможенной системе Китая — есть ли у отправителя авторизационное письмо/разрешение на вывоз бренда\n17\tДополнительные сервисы (фитоконтроль и т.п.)\n18\tТребуется ли замена документов\n19\tСтрана, город, точный адрес доставки\n20\tМесто таможенного оформления в РФ",
|
||||
"keywords": [
|
||||
"ltl",
|
||||
"сборный трак",
|
||||
"догруз",
|
||||
"группаж авто",
|
||||
"less than truckload",
|
||||
"неполная фура",
|
||||
"авто ltl",
|
||||
"мелкий груз авто",
|
||||
"road ltl",
|
||||
"partial truckload"
|
||||
],
|
||||
"confirmation_template": "Dear Partner!\n\nThank you for contacting SEPTEM. We are pleased to confirm the possibility of road freight (LTL) for your cargo under the following terms:\n\n- Route: (Pickup address) -> (Delivery address)\n- Cargo weight: (Cargo weight) kg\n- Number of packages: (Number of packages)\n- Volume: (Volume) m3\n- Dimensions: (Dimensions)\n- Cargo description: (Cargo description)\n- HS code: (HS code)\n- Dangerous properties: (Dangerous properties)\n- MSDS required: (MSDS required)\n- Freight cost: (Estimated cost)\n- Estimated transit time: (Transit time)\n\nTo confirm the order and issue the invoice, please reply to this email or contact your manager.\n\nBest regards,\nSEPTEM Cargo Team",
|
||||
"info_request_template": "Уважаемый (Клиент)!\n\nБлагодарим вас за обращение в компанию SEPTEM. Для расчёта автомобильной перевозки (LTL) нам необходима следующая информация:\n\n(Необходимая информация)\n\nПожалуйста, дополните данные по вашему грузу. Вы можете ответить на это письмо или загрузить недостающие документы через личный кабинет.\n\nС уважением,\nКоманда SEPTEM Cargo"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Автомобильная перевозка (FTL)",
|
||||
"employee_email": "denis.fomin@timnet.ch, Yana.Schkabrova@timnet.ch",
|
||||
"extra_required_fields": [
|
||||
"hs_code",
|
||||
"vehicle_type",
|
||||
"customs_clearance_place_export_rf"
|
||||
],
|
||||
"mandatory_counterparty_criteria": "Обязательно в письме и при запросе клиенту: клиент; Incoterms; характер/наименование груза и ТН ВЭД; адрес забора; адрес доставки; место таможенного оформления в РФ; количество и типоразмер машин; вес груза в машине.",
|
||||
"criteria": "1\tНазвание клиента\n2\tУсловия поставки Incoterms\n3\tДата готовности груза\n4\tСтрана, город, адрес забора\n5\tСтоимость груза\n6\tКоличество и типоразмер машин\n7\tВес груза в машине и объём\n8\tЕсли нет данных о количестве машин — габариты каждого грузового места (Д×Ш×В в см или мм) и их вес и объём\n9\tХарактер груза или наименование груза, код ТН ВЭД\n10\tСодержатся ли в грузе батарейки, газы под давлением, жидкости\n11\tХимия, литиевые батареи, жидкости, аэрозоли, газы или порошки — MSDS\n12\tБатарейки — в составе груза или отдельно упакованы\n13\tОтгрузка из материкового Китая авто транспортом — DGM\n14\tНазвание бренда\n15\tЕсли бренд зарегистрирован в таможенной системе Китая — есть ли у отправителя авторизационное письмо/разрешение на вывоз бренда\n16\tДополнительные сервисы (фитоконтроль и т.п.)\n17\tТребуется ли замена документов\n18\tСтрана, город, точный адрес доставки\n19\tМесто таможенного оформления в РФ",
|
||||
"keywords": [
|
||||
"ftl",
|
||||
"полная фура",
|
||||
"целая машина",
|
||||
"full truckload",
|
||||
"отдельный автомобиль",
|
||||
"авто ftl",
|
||||
"тент фура целиком",
|
||||
"road ftl",
|
||||
"exclusive truck"
|
||||
],
|
||||
"confirmation_template": "Dear Partner!\n\nThank you for contacting SEPTEM. We are pleased to confirm the possibility of road freight (FTL) for your cargo under the following terms:\n\n- Route: (Pickup address) -> (Delivery address)\n- Vehicle type: (Vehicle type)\n- Cargo weight: (Cargo weight) kg\n- Number of packages: (Number of packages)\n- Volume: (Volume) m3\n- Dimensions: (Dimensions)\n- Cargo description: (Cargo description)\n- HS code: (HS code)\n- Dangerous properties: (Dangerous properties)\n- MSDS required: (MSDS required)\n- Freight cost: (Estimated cost)\n- Transit time: (Transit time)\n\nBest regards,\nSEPTEM Cargo Team",
|
||||
"info_request_template": "Уважаемый (Клиент)!\n\nБлагодарим за обращение в SEPTEM. Для расчёта автомобильной перевозки (FTL) нам необходима следующая информация:\n\n(Необходимая информация)\n\nПожалуйста, дополните данные по грузу.\n\nС уважением,\nКоманда SEPTEM Cargo"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"name": "Морская перевозка (LCL)",
|
||||
"employee_email": "marina.eremina@timnet.ch, ekaterina.kochenkova@timnet.ch, Yana.Schkabrova@timnet.ch",
|
||||
"extra_required_fields": [
|
||||
"hs_code",
|
||||
"stackable_with_others"
|
||||
],
|
||||
"mandatory_counterparty_criteria": "Обязательно: клиент; Incoterms; характер груза и ТН ВЭД; адрес забора; адрес доставки; количество мест и вес; габариты Д×Ш×В; возможность штабелирования с другими отправками.",
|
||||
"criteria": "1\tНазвание клиента\n2\tУсловия поставки Incoterms\n3\tДата готовности груза\n4\tСтрана, город, адрес забора\n5\tСтоимость груза\n6\tКоличество грузовых мест и вес с объёмом\n7\tГабариты каждого грузового места (Д×Ш×В в см или мм) и их вес и объём\n8\tХарактер груза или наименование, код ТН ВЭД\n9\tБатарейки, газы, газы под давлением, жидкости в грузе\n10\tМожно ли штабелировать груз с другими отправками\n11\tЕсли нельзя с другими — можно ли штабелировать места между собой\n12\tХимия, литиевые батареи, жидкости, аэрозоли, газы, порошки — MSDS\n13\tБатарейки — в составе или отдельно\n14\tОтгрузка из материкового Китая по ж/д — Technical Description of Goods in Railway Transport\n15\tНазвание бренда\n16\tЕсли бренд зарегистрирован в таможенной системе Китая — есть ли у отправителя авторизационное письмо/разрешение на вывоз бренда\n17\tДополнительные сервисы (фитоконтроль и т.п.)\n18\tСтрана, город, точный адрес доставки\n\nПрименимо к морской сборной перевозке (LCL): порт погрузки/выгрузки и морской этап явно указаны в переписке; без доминирования ж/д как основного этапа.",
|
||||
"keywords": [
|
||||
"море lcl",
|
||||
"морская сборная",
|
||||
"морской lcl",
|
||||
"sea lcl",
|
||||
"сборный морской",
|
||||
"консолидация море",
|
||||
"groupage sea",
|
||||
"lcl порт",
|
||||
"морской группаж",
|
||||
"неполный контейнер море"
|
||||
],
|
||||
"confirmation_template": "Dear Partner!\n\nThank you for contacting SEPTEM. We confirm the possibility of sea freight (LCL) under the following terms:\n\n- Route: (Port of loading) -> (Port of discharge)\n- Shipment type: LCL\n- Cargo weight: (Cargo weight) kg\n- Packages: (Number of packages)\n- Volume: (Volume) m3\n- Dimensions: (Dimensions)\n- Cargo: (Cargo description)\n- HS code: (HS code)\n- Dangerous properties: (Dangerous properties)\n- MSDS: (MSDS required)\n- Freight: (Estimated cost)\n- Transit: (Transit time)\n\nBest regards,\nSEPTEM Cargo Team",
|
||||
"info_request_template": "Уважаемый (Клиент)!\n\nДля расчёта морской сборной перевозки (LCL) нам необходима следующая информация:\n\n(Необходимая информация)\n\nПожалуйста, дополните данные.\n\nС уважением,\nКоманда SEPTEM Cargo"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"name": "Железнодорожная перевозка (LCL)",
|
||||
"employee_email": "marina.eremina@timnet.ch, ekaterina.kochenkova@timnet.ch, Yana.Schkabrova@timnet.ch",
|
||||
"extra_required_fields": [
|
||||
"hs_code",
|
||||
"stackable_with_others"
|
||||
],
|
||||
"mandatory_counterparty_criteria": "Обязательно: клиент; Incoterms; характер груза и ТН ВЭД; адрес забора; адрес доставки; количество мест и вес; габариты; штабелирование с другими отправками.",
|
||||
"criteria": "1\tНазвание клиента\n2\tУсловия поставки Incoterms\n3\tДата готовности груза\n4\tСтрана, город, адрес забора\n5\tСтоимость груза\n6\tКоличество грузовых мест и вес с объёмом\n7\tГабариты каждого грузового места (Д×Ш×В в см или мм) и их вес и объём\n8\tХарактер груза или наименование, код ТН ВЭД\n9\tБатарейки, газы, газы под давлением, жидкости в грузе\n10\tМожно ли штабелировать груз с другими отправками\n11\tЕсли нельзя с другими — можно ли штабелировать места между собой\n12\tХимия, литиевые батареи, жидкости, аэрозоли, газы, порошки — MSDS\n13\tБатарейки — в составе или отдельно\n14\tОтгрузка из материкового Китая по ж/д — Technical Description of Goods in Railway Transport\n15\tНазвание бренда\n16\tЕсли бренд зарегистрирован в таможенной системе Китая — есть ли у отправителя авторизационное письмо/разрешение на вывоз бренда\n17\tДополнительные сервисы (фитоконтроль и т.п.)\n18\tСтрана, город, точный адрес доставки\n\nПрименимо к ж/д сборной перевозке (LCL): станции/терминалы ж/д, контейнер сборный по ж/д; морской этап в запросе не основной.",
|
||||
"keywords": [
|
||||
"жд lcl",
|
||||
"ж/д lcl",
|
||||
"rail lcl",
|
||||
"сборный контейнер жд",
|
||||
"сборная жд",
|
||||
"lcl поезд",
|
||||
"группаж жд",
|
||||
"железная дорога сборный"
|
||||
],
|
||||
"confirmation_template": "Dear Partner!\n\nThank you for contacting SEPTEM. We confirm rail freight (LCL) under the following terms:\n\n- Route: (Pickup address) -> (Delivery address)\n- Shipment type: LCL\n- Weight: (Cargo weight) kg\n- Packages: (Number of packages)\n- Volume: (Volume) m3\n- Dimensions: (Dimensions)\n- Cargo: (Cargo description)\n- HS: (HS code)\n- MSDS: (MSDS required)\n- Cost: (Estimated cost)\n- Transit: (Transit time)\n\nBest regards,\nSEPTEM Cargo Team",
|
||||
"info_request_template": "Уважаемый (Клиент)!\n\nДля расчёта железнодорожной сборной перевозки (LCL) нам необходима следующая информация:\n\n(Необходимая информация)\n\nС уважением,\nКоманда SEPTEM Cargo"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"name": "Мультимодальная перевозка море + ж/д (LCL)",
|
||||
"employee_email": "marina.eremina@timnet.ch, ekaterina.kochenkova@timnet.ch, Yana.Schkabrova@timnet.ch",
|
||||
"extra_required_fields": [
|
||||
"hs_code",
|
||||
"stackable_with_others"
|
||||
],
|
||||
"mandatory_counterparty_criteria": "Обязательно: клиент; Incoterms; характер груза и ТН ВЭД; адрес забора; адрес доставки; количество мест и вес; габариты; штабелирование с другими отправками.",
|
||||
"criteria": "1\tНазвание клиента\n2\tУсловия поставки Incoterms\n3\tДата готовности груза\n4\tСтрана, город, адрес забора\n5\tСтоимость груза\n6\tКоличество грузовых мест и вес с объёмом\n7\tГабариты каждого грузового места (Д×Ш×В в см или мм) и их вес и объём\n8\tХарактер груза или наименование, код ТН ВЭД\n9\tБатарейки, газы, газы под давлением, жидкости в грузе\n10\tМожно ли штабелировать груз с другими отправками\n11\tЕсли нельзя с другими — можно ли штабелировать места между собой\n12\tХимия, литиевые батареи, жидкости, аэрозоли, газы, порошки — MSDS\n13\tБатарейки — в составе или отдельно\n14\tОтгрузка из материкового Китая по ж/д — Technical Description of Goods in Railway Transport\n15\tНазвание бренда\n16\tЕсли бренд зарегистрирован в таможенной системе Китая — есть ли у отправителя авторизационное письмо/разрешение на вывоз бренда\n17\tДополнительные сервисы (фитоконтроль и т.п.)\n18\tСтрана, город, точный адрес доставки\n\nКритерии как для сборного груза при цепочке море и ж/д (интермодаль): в переписке явно присутствуют и морской, и железнодорожный этапы.",
|
||||
"keywords": [
|
||||
"море жд",
|
||||
"море+жд",
|
||||
"море и жд",
|
||||
"sea rail",
|
||||
"интермодальн",
|
||||
"multimodal lcl",
|
||||
"морской и жд этап",
|
||||
"порт и станция сборный"
|
||||
],
|
||||
"confirmation_template": "Dear Partner!\n\nThank you for contacting SEPTEM. We confirm multimodal sea+rail (LCL) under the following terms:\n\n- Route: (Pickup address) -> (Delivery address)\n- Modes: sea + rail (LCL)\n- Weight: (Cargo weight) kg\n- Packages: (Number of packages)\n- Volume: (Volume) m3\n- Dimensions: (Dimensions)\n- Cargo: (Cargo description)\n- HS: (HS code)\n- MSDS: (MSDS required)\n- Cost: (Estimated cost)\n- Transit: (Transit time)\n\nBest regards,\nSEPTEM Cargo Team",
|
||||
"info_request_template": "Уважаемый (Клиент)!\n\nДля расчёта мультимодальной перевозки (море + ж/д, LCL) нам необходима следующая информация:\n\n(Необходимая информация)\n\nС уважением,\nКоманда SEPTEM Cargo"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"name": "Морская перевозка (FCL)",
|
||||
"employee_email": "marina.eremina@timnet.ch, ekaterina.kochenkova@timnet.ch, Yana.Schkabrova@timnet.ch",
|
||||
"extra_required_fields": [
|
||||
"hs_code",
|
||||
"container_type"
|
||||
],
|
||||
"mandatory_counterparty_criteria": "Обязательно: клиент; Incoterms; характер груза и ТН ВЭД; адрес забора; адрес доставки; количество и типоразмер контейнеров; вес груза в контейнере.",
|
||||
"criteria": "1\tНазвание клиента\n2\tУсловия поставки Incoterms\n3\tДата готовности груза\n4\tСтрана, город, адрес забора\n5\tСтоимость груза\n6\tКоличество и типоразмер контейнеров\n7\tВес груза в контейнере и объём\n8\tЕсли нет данных о контейнерах — габариты каждого грузового места (Д×Ш×В) и их вес и объём\n9\tХарактер груза или наименование, код ТН ВЭД\n10\tБатарейки, газы, жидкости\n11\tMSDS при необходимости\n12\tБатарейки в составе или отдельно\n13\tИз материкового Китая по ж/д — Technical Description of Goods in Railway Transport\n14\tНазвание бренда\n15\tЕсли бренд зарегистрирован в таможенной системе Китая — есть ли у отправителя авторизационное письмо/разрешение на вывоз бренда\n16\tДополнительные сервисы (крепление в контейнере, фитосанитарный контроль и т.п.)\n17\tТребуется ли замена документов\n18\tСтрана, город, точный адрес доставки\n19\tМесто таможенного оформления при экспорте из РФ\n20\tФумигация деревянной тары при экспорте из РФ\n21\tПроверка габаритов грузовых мест на проходимость в дверной проём контейнеров 20DV, 40DV, 40HC\n\nМорской FCL: ISO-контейнеры под морской фрахт и погрузку на судно.",
|
||||
"keywords": [
|
||||
"морской fcl",
|
||||
"море fcl",
|
||||
"sea fcl",
|
||||
"полный контейнер море",
|
||||
"морской контейнер",
|
||||
"fcl порт",
|
||||
"цельный контейнер море",
|
||||
"ocean fcl"
|
||||
],
|
||||
"confirmation_template": "Dear Partner!\n\nThank you for contacting SEPTEM. We confirm sea freight (FCL):\n\n- Port: (Port of loading) -> (Port of discharge)\n- Container: (Container type)\n- Weight: (Cargo weight) kg\n- Cargo: (Cargo description)\n- HS: (HS code)\n- MSDS/IMDG: (MSDS required)\n- Cost: (Estimated cost)\n- Transit: (Transit time)\n\nBest regards,\nSEPTEM Cargo Team",
|
||||
"info_request_template": "Уважаемый (Клиент)!\n\nДля расчёта морской перевозки (FCL) нам необходима следующая информация:\n\n(Необходимая информация)\n\nС уважением,\nКоманда SEPTEM Cargo"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"name": "Железнодорожная перевозка (FCL)",
|
||||
"employee_email": "marina.eremina@timnet.ch, ekaterina.kochenkova@timnet.ch, Yana.Schkabrova@timnet.ch",
|
||||
"extra_required_fields": [
|
||||
"hs_code",
|
||||
"container_type"
|
||||
],
|
||||
"mandatory_counterparty_criteria": "Обязательно: клиент; Incoterms; характер груза и ТН ВЭД; адрес забора; адрес доставки; количество и типоразмер контейнеров; вес груза в контейнере.",
|
||||
"criteria": "1\tНазвание клиента\n2\tУсловия поставки Incoterms\n3\tДата готовности груза\n4\tСтрана, город, адрес забора\n5\tСтоимость груза\n6\tКоличество и типоразмер контейнеров\n7\tВес груза в контейнере и объём\n8\tЕсли нет данных о контейнерах — габариты каждого грузового места (Д×Ш×В) и их вес и объём\n9\tХарактер груза или наименование, код ТН ВЭД\n10\tБатарейки, газы, жидкости\n11\tMSDS при необходимости\n12\tБатарейки в составе или отдельно\n13\tИз материкового Китая по ж/д — Technical Description of Goods in Railway Transport\n14\tНазвание бренда\n15\tЕсли бренд зарегистрирован в таможенной системе Китая — есть ли у отправителя авторизационное письмо/разрешение на вывоз бренда\n16\tДополнительные сервисы (крепление в контейнере, фитосанитарный контроль и т.п.)\n17\tТребуется ли замена документов\n18\tСтрана, город, точный адрес доставки\n19\tМесто таможенного оформления при экспорте из РФ\n20\tФумигация деревянной тары при экспорте из РФ\n21\tПроверка габаритов грузовых мест на проходимость в дверной проём контейнеров 20DV, 40DV, 40HC\n\nЖ/д FCL: ISO 20'/40' на платформах/вагонных комплектах (1520 мм); без обязательного морского этапа.",
|
||||
"keywords": [
|
||||
"жд fcl",
|
||||
"ж/д fcl",
|
||||
"rail fcl",
|
||||
"контейнер по жд целый",
|
||||
"полный контейнер жд",
|
||||
"fcl поезд",
|
||||
"вагон контейнер"
|
||||
],
|
||||
"confirmation_template": "Dear Partner!\n\nThank you for contacting SEPTEM. We confirm rail freight (FCL):\n\n- Route: (Pickup address) -> (Delivery address)\n- Container: (Container type)\n- Weight: (Cargo weight) kg\n- Cargo: (Cargo description)\n- HS: (HS code)\n- MSDS: (MSDS required)\n- Cost: (Estimated cost)\n- Transit: (Transit time)\n\nBest regards,\nSEPTEM Cargo Team",
|
||||
"info_request_template": "Уважаемый (Клиент)!\n\nДля расчёта железнодорожной перевозки (FCL) нам необходима следующая информация:\n\n(Необходимая информация)\n\nС уважением,\nКоманда SEPTEM Cargo"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"name": "Мультимодальная перевозка море + ж/д (FCL)",
|
||||
"employee_email": "marina.eremina@timnet.ch, ekaterina.kochenkova@timnet.ch, Yana.Schkabrova@timnet.ch",
|
||||
"extra_required_fields": [
|
||||
"hs_code",
|
||||
"container_type"
|
||||
],
|
||||
"mandatory_counterparty_criteria": "Обязательно: клиент; Incoterms; характер груза и ТН ВЭД; адрес забора; адрес доставки; количество и типоразмер контейнеров; вес груза в контейнере.",
|
||||
"criteria": "1\tНазвание клиента\n2\tУсловия поставки Incoterms\n3\tДата готовности груза\n4\tСтрана, город, адрес забора\n5\tСтоимость груза\n6\tКоличество и типоразмер контейнеров\n7\tВес груза в контейнере и объём\n8\tЕсли нет данных о контейнерах — габариты каждого грузового места (Д×Ш×В) и их вес и объём\n9\tХарактер груза или наименование, код ТН ВЭД\n10\tБатарейки, газы, жидкости\n11\tMSDS при необходимости\n12\tБатарейки в составе или отдельно\n13\tИз материкового Китая по ж/д — Technical Description of Goods in Railway Transport\n14\tНазвание бренда\n15\tЕсли бренд зарегистрирован в таможенной системе Китая — есть ли у отправителя авторизационное письмо/разрешение на вывоз бренда\n16\tДополнительные сервисы (крепление в контейнере, фитосанитарный контроль и т.п.)\n17\tТребуется ли замена документов\n18\tСтрана, город, точный адрес доставки\n19\tМесто таможенного оформления при экспорте из РФ\n20\tФумигация деревянной тары при экспорте из РФ\n21\tПроверка габаритов грузовых мест на проходимость в дверной проём контейнеров 20DV, 40DV, 40HC\n\nМультимодальная перевозка море + ж/д (FCL): в запросе явно сочетаются морской и ж/д этапы с полным контейнером (интермодаль).",
|
||||
"keywords": [
|
||||
"море жд fcl",
|
||||
"море+жд fcl",
|
||||
"sea rail fcl",
|
||||
"интермодальн fcl",
|
||||
"контейнер море и жд",
|
||||
"порт станция fcl"
|
||||
],
|
||||
"confirmation_template": "Dear Partner!\n\nThank you for contacting SEPTEM. We confirm multimodal sea+rail (FCL):\n\n- Route: (Port of loading) / rail -> (Delivery address)\n- Container: (Container type)\n- Weight: (Cargo weight) kg\n- Cargo: (Cargo description)\n- HS: (HS code)\n- MSDS: (MSDS required)\n- Cost: (Estimated cost)\n- Transit: (Transit time)\n\nBest regards,\nSEPTEM Cargo Team",
|
||||
"info_request_template": "Уважаемый (Клиент)!\n\nДля расчёта мультимодальной перевозки (море + ж/д, FCL) нам необходима следующая информация:\n\n(Необходимая информация)\n\nС уважением,\nКоманда SEPTEM Cargo"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"name": "Авиаперевозка",
|
||||
"employee_email": "evgeniy.domashnev@timnet.ch, olga.ermakova@timnet.ch, andrey.reshetnyak@timnet.ch, anastasia.fatkina@timnet.ch",
|
||||
"extra_required_fields": [
|
||||
"hs_code",
|
||||
"stackable_with_others",
|
||||
"total_volume_cbm",
|
||||
"dangerous_goods_clarification",
|
||||
"customs_clearance_place_export_rf"
|
||||
],
|
||||
"mandatory_counterparty_criteria": "Обязательно: клиент; Incoterms; характер груза и ТН ВЭД; адрес забора; адрес доставки; количество мест, вес и объём; габариты Д×Ш×В; штабелирование с другими отправками; сведения о батарейках, газах, жидкостях, аэрозолях; место таможенного оформления при экспорте из РФ (и прочие пункты чек-листа авиа по полному criteria).",
|
||||
"criteria": "1\tНазвание клиента\n2\tУсловия поставки Incoterms\n3\tДата готовности груза\n4\tСтрана, город, адрес забора\n5\tСтоимость груза\n6\tКоличество грузовых мест, вес, объём\n7\tГабариты каждого грузового места (Д×Ш×В в см или мм)\n8\tХарактер груза или наименование, код ТН ВЭД\n9\tБатарейки, газы, жидкости, хладоагенты, сухой лёд\n10\tШтабелирование с другими отправками\n11\tШтабелирование мест между собой\n12\tMSDS при химии, батареях, жидкостях, аэрозолях, порошках\n13\tБатарейки — в составе или отдельно\n14\tБатарейки и вылет из материкового Китая — DGM (Dangerous Goods Management) report\n15\tНазвание бренда\n16\tЕсли бренд зарегистрирован в таможенной системе Китая — есть ли у отправителя авторизационное письмо/разрешение на вывоз бренда\n17\tПерелёт через третью страну со сменой авианакладных\n18\tЭкспортная лицензия у отправителя\n19\t Дополнительные сервисы (фитоконтроль и т.п.)\n20\tКто осуществляет экспедирование в аэропорту прибытия (терминал, сборы авиакомпании)\n21\tСтрана, город, точный адрес доставки\n22\tВывоз из аэропорта — особые требования к автотранспорту, время подачи\n23\tНужно ли таможенное оформление\n24\tМесто таможенного оформления при экспорте из РФ\n25\tФумигация деревянной тары при экспорте из РФ",
|
||||
"keywords": [
|
||||
"авиа",
|
||||
"авиаперевозка",
|
||||
"самолёт",
|
||||
"air freight",
|
||||
"air cargo",
|
||||
"аэропорт",
|
||||
"flight",
|
||||
"авианакладная",
|
||||
"awb"
|
||||
],
|
||||
"confirmation_template": "Dear Partner!\n\nThank you for contacting SEPTEM. We confirm air freight:\n\n- Route: (Pickup address) -> (Delivery address)\n- Weight: (Cargo weight) kg\n- Packages: (Number of packages)\n- Volume: (Volume) m3\n- Dimensions: (Dimensions)\n- Cargo: (Cargo description)\n- HS: (HS code)\n- Dangerous goods: (Dangerous properties)\n- MSDS: (MSDS required)\n- DGM (при опасном грузе / вылет из материкового Китая — по правилам перевозчика)\n- Cost: (Estimated cost)\n- Transit: (Transit time)\n\nBest regards,\nSEPTEM Cargo Team",
|
||||
"info_request_template": "Уважаемый (Клиент)!\n\nДля расчёта авиаперевозки нам необходима следующая информация:\n\n(Необходимая информация)\n\nС уважением,\nКоманда SEPTEM Cargo"
|
||||
}
|
||||
]
|
||||
Loading…
Reference in New Issue