Удалить shipping_calculator(1).py
This commit is contained in:
parent
ac88935ebe
commit
467113cfef
|
|
@ -1,119 +0,0 @@
|
||||||
import math
|
|
||||||
import re
|
|
||||||
from typing import Dict, Optional
|
|
||||||
|
|
||||||
def calculate_shipping_cost(shipment: Dict) -> Optional[Dict]:
|
|
||||||
"""
|
|
||||||
Расчёт стоимости авиаперевозки на основе параметров груза.
|
|
||||||
Возвращает словарь с ключами:
|
|
||||||
total_usd, total_rub, chargeable_weight, actual_weight, volume_weight
|
|
||||||
или None, если не хватает данных.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# Проверяем наличие обязательных данных
|
|
||||||
if not all(k in shipment for k in ['total_weight_kg', 'dimensions', 'cargo_value']):
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Параметры груза
|
|
||||||
actual_weight = shipment.get('total_weight_kg', 0)
|
|
||||||
if not actual_weight or actual_weight <= 0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
# Расчёт объёмного веса
|
|
||||||
dimensions = shipment.get('dimensions', [])
|
|
||||||
if not dimensions:
|
|
||||||
return None
|
|
||||||
|
|
||||||
total_volume_weight = 0
|
|
||||||
for dim in dimensions:
|
|
||||||
if dim.get('length_cm') and dim.get('width_cm') and dim.get('height_cm'):
|
|
||||||
# Объёмный вес = (Д×Ш×В в метрах) × 167
|
|
||||||
length_m = dim['length_cm'] / 100
|
|
||||||
width_m = dim['width_cm'] / 100
|
|
||||||
height_m = dim['height_cm'] / 100
|
|
||||||
volume = length_m * width_m * height_m
|
|
||||||
volume_weight = volume * 167
|
|
||||||
total_volume_weight += volume_weight
|
|
||||||
|
|
||||||
# Платный вес (оплачивается по большему)
|
|
||||||
chargeable_weight = max(actual_weight, total_volume_weight)
|
|
||||||
chargeable_weight = math.ceil(chargeable_weight) # округляем вверх
|
|
||||||
|
|
||||||
# Базовый тариф в зависимости от веса (USD/кг)
|
|
||||||
if chargeable_weight < 45:
|
|
||||||
base_rate = 6.5
|
|
||||||
elif chargeable_weight < 100:
|
|
||||||
base_rate = 5.5
|
|
||||||
elif chargeable_weight < 300:
|
|
||||||
base_rate = 4.5
|
|
||||||
elif chargeable_weight < 500:
|
|
||||||
base_rate = 3.8
|
|
||||||
elif chargeable_weight < 1000:
|
|
||||||
base_rate = 3.2
|
|
||||||
else:
|
|
||||||
base_rate = 2.8
|
|
||||||
|
|
||||||
# Топливный сбор и сбор за безопасность
|
|
||||||
fuel_surcharge_rate = 0.9 # USD/кг
|
|
||||||
min_fuel_surcharge = 90 # USD минимум
|
|
||||||
|
|
||||||
# Терминальные сборы
|
|
||||||
terminal_export_rate = 0.22 # USD/кг (~20 руб/кг)
|
|
||||||
terminal_export_fixed = 25 # USD фиксированных сборов (~2300 руб)
|
|
||||||
terminal_import_rate = 0.35 # EUR/кг ≈ 0.38 USD/кг по курсу 1.1
|
|
||||||
|
|
||||||
# Таможенное оформление
|
|
||||||
customs_export = 170 # USD (~15500 руб)
|
|
||||||
customs_import = 220 # EUR ≈ 242 USD
|
|
||||||
|
|
||||||
# Надбавки за особые условия
|
|
||||||
special_rate_multiplier = 1.0
|
|
||||||
|
|
||||||
# Терморежим (+15…+25 °C)
|
|
||||||
if shipment.get('special_transport_requirements') and 'термо' in str(shipment.get('special_transport_requirements', '')).lower():
|
|
||||||
special_rate_multiplier *= 1.3 # +30%
|
|
||||||
|
|
||||||
# Страхование
|
|
||||||
cargo_value_usd = 0
|
|
||||||
cargo_value_str = shipment.get('cargo_value', '0')
|
|
||||||
# Извлекаем числовое значение из строки (например, "18 500 EUR" -> 18500)
|
|
||||||
value_match = re.search(r'[\d\s]+', cargo_value_str.replace(' ', ''))
|
|
||||||
if value_match:
|
|
||||||
cargo_value_usd = float(value_match.group().replace(' ', ''))
|
|
||||||
# Если указано в EUR, конвертируем
|
|
||||||
if 'EUR' in cargo_value_str or '€' in cargo_value_str:
|
|
||||||
cargo_value_usd *= 1.1 # приблизительный курс EUR/USD
|
|
||||||
|
|
||||||
insurance_cost = cargo_value_usd * 0.01 # 1% от стоимости груза
|
|
||||||
|
|
||||||
# Расчёт компонентов
|
|
||||||
base_freight = chargeable_weight * base_rate * special_rate_multiplier
|
|
||||||
fuel_surcharge = max(chargeable_weight * fuel_surcharge_rate, min_fuel_surcharge)
|
|
||||||
terminal_export = chargeable_weight * terminal_export_rate + terminal_export_fixed
|
|
||||||
terminal_import = chargeable_weight * 0.38 # конвертация EUR->USD
|
|
||||||
customs_total = customs_export + customs_import
|
|
||||||
|
|
||||||
# Дополнительные услуги
|
|
||||||
additional_services = shipment.get('additional_services', [])
|
|
||||||
additional_cost = 0
|
|
||||||
if isinstance(additional_services, list):
|
|
||||||
if 'уведомление о прибытии' in str(additional_services).lower():
|
|
||||||
additional_cost += 25 # USD
|
|
||||||
|
|
||||||
# Итог
|
|
||||||
total_usd = (base_freight + fuel_surcharge + terminal_export +
|
|
||||||
terminal_import + customs_total + additional_cost + insurance_cost)
|
|
||||||
|
|
||||||
# Конвертация в рубли для удобства (курс USD/RUB ~90)
|
|
||||||
total_rub = total_usd * 90
|
|
||||||
|
|
||||||
return {
|
|
||||||
"total_usd": round(total_usd, 2),
|
|
||||||
"total_rub": round(total_rub, 2),
|
|
||||||
"chargeable_weight": chargeable_weight,
|
|
||||||
"actual_weight": actual_weight,
|
|
||||||
"volume_weight": round(total_volume_weight, 2)
|
|
||||||
}
|
|
||||||
except Exception as e:
|
|
||||||
# Логирование ошибки, если нужно
|
|
||||||
return None
|
|
||||||
Loading…
Reference in New Issue