166 lines
5.9 KiB
Python
166 lines
5.9 KiB
Python
|
|
"""物流费用计算统一入口服务"""
|
|||
|
|
import re
|
|||
|
|
from typing import Dict, List, Any, Optional
|
|||
|
|
|
|||
|
|
from utils.Package import Package, Package_group
|
|||
|
|
from utils.countryOperator import OperateCountry
|
|||
|
|
from logisticsClass.logisticsBaseClass import PortType
|
|||
|
|
|
|||
|
|
|
|||
|
|
class LogisticsService:
|
|||
|
|
"""物流费用计算统一服务"""
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def _detect_country(postcode: str) -> str:
|
|||
|
|
"""根据邮编格式自动识别国家"""
|
|||
|
|
postcode = postcode.strip().upper()
|
|||
|
|
|
|||
|
|
# 英国邮编格式:字母+数字(+字母)+空格+数字+字母
|
|||
|
|
# 支持格式: SW1A 1AA, M1 1AA, BT1 1AA, AA11 1AA 等
|
|||
|
|
if re.match(r'^[A-Z]{1,2}[0-9][A-Z0-9]?\s?[0-9][A-Z]{2}$', postcode):
|
|||
|
|
return "UK"
|
|||
|
|
|
|||
|
|
# 美国邮编格式:5位数字或5位-4位
|
|||
|
|
if re.match(r'^\d{5}(-\d{4})?$', postcode):
|
|||
|
|
return "US"
|
|||
|
|
|
|||
|
|
# 澳洲邮编格式:4位数字
|
|||
|
|
if re.match(r'^\d{4}$', postcode):
|
|||
|
|
return "AU"
|
|||
|
|
|
|||
|
|
# 欧洲格式(德国、法国等)
|
|||
|
|
if re.match(r'^\d{5}$', postcode):
|
|||
|
|
return "DE" # 默认德国
|
|||
|
|
|
|||
|
|
raise ValueError(f"无法识别的邮编格式: {postcode}")
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def _parse_packages(packages_data: List[Dict]) -> Package_group:
|
|||
|
|
"""解析包裹数据"""
|
|||
|
|
packages = []
|
|||
|
|
for i, pkg in enumerate(packages_data):
|
|||
|
|
name = pkg.get("name", f"包裹{i+1}")
|
|||
|
|
length = pkg.get("length", 0)
|
|||
|
|
width = pkg.get("width", 0)
|
|||
|
|
height = pkg.get("height", 0)
|
|||
|
|
weight = pkg.get("weight", 0)
|
|||
|
|
|
|||
|
|
package = Package(name, length, width, height, weight)
|
|||
|
|
packages.append(package)
|
|||
|
|
|
|||
|
|
return Package_group(packages)
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def calculate(postcode: str, packages_data: List[Dict],
|
|||
|
|
port: PortType = PortType.DEFAULT) -> Dict[str, Any]:
|
|||
|
|
"""
|
|||
|
|
计算物流费用并返回最优渠道
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
postcode: 收件人邮编
|
|||
|
|
packages_data: 包裹数据列表,格式为:
|
|||
|
|
[
|
|||
|
|
{"length": 63, "width": 59, "height": 48, "weight": 8000}, # 单位:cm, g
|
|||
|
|
...
|
|||
|
|
]
|
|||
|
|
port: 港口类型,默认DEFAULT
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
包含最优渠道和所有渠道费用的字典
|
|||
|
|
"""
|
|||
|
|
# 1. 识别国家
|
|||
|
|
country = LogisticsService._detect_country(postcode)
|
|||
|
|
|
|||
|
|
# 2. 解析包裹
|
|||
|
|
packages = LogisticsService._parse_packages(packages_data)
|
|||
|
|
|
|||
|
|
# 3. 创建国家操作对象
|
|||
|
|
op_country = OperateCountry(country, port, packages, postcode)
|
|||
|
|
|
|||
|
|
# 4. 获取所有渠道费用
|
|||
|
|
all_fees = op_country.get_all_tail_info()
|
|||
|
|
|
|||
|
|
# 5. 找出最优渠道
|
|||
|
|
valid_fees = {k: v for k, v in all_fees.items() if v < 99999}
|
|||
|
|
if not valid_fees:
|
|||
|
|
return {
|
|||
|
|
"country": country,
|
|||
|
|
"postcode": postcode,
|
|||
|
|
"optimal_channel": None,
|
|||
|
|
"optimal_fee": None,
|
|||
|
|
"currency": None,
|
|||
|
|
"all_channels": all_fees,
|
|||
|
|
"error": "所有渠道均不可用"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
optimal_channel = min(valid_fees, key=valid_fees.get)
|
|||
|
|
optimal_fee = valid_fees[optimal_channel]
|
|||
|
|
currency = op_country.get_tail_currency(optimal_channel)
|
|||
|
|
|
|||
|
|
# 6. 构建结果
|
|||
|
|
result = {
|
|||
|
|
"country": country,
|
|||
|
|
"postcode": postcode,
|
|||
|
|
"optimal_channel": optimal_channel,
|
|||
|
|
"optimal_fee": optimal_fee,
|
|||
|
|
"currency": currency,
|
|||
|
|
"all_channels": {},
|
|||
|
|
"package_count": len(packages_data),
|
|||
|
|
"total_weight": sum(p.weight for p in packages) / 1000, # kg
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 7. 添加所有渠道详情
|
|||
|
|
for company, fee in all_fees.items():
|
|||
|
|
company_type = op_country.get_logistic_type(company)
|
|||
|
|
company_currency = op_country.get_tail_currency(company)
|
|||
|
|
result["all_channels"][company] = {
|
|||
|
|
"fee": fee if fee < 99999 else None,
|
|||
|
|
"currency": company_currency,
|
|||
|
|
"type": company_type,
|
|||
|
|
"available": fee < 99999
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def calculate_us(postcode: str, packages_data: List[Dict],
|
|||
|
|
port: PortType = PortType.DEFAULT) -> Dict[str, Any]:
|
|||
|
|
"""计算美国物流费用"""
|
|||
|
|
return LogisticsService.calculate(postcode, packages_data, port)
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def calculate_uk(postcode: str, packages_data: List[Dict],
|
|||
|
|
port: PortType = PortType.DEFAULT) -> Dict[str, Any]:
|
|||
|
|
"""计算英国物流费用"""
|
|||
|
|
return LogisticsService.calculate(postcode, packages_data, port)
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def calculate_au(postcode: str, packages_data: List[Dict],
|
|||
|
|
port: PortType = PortType.DEFAULT) -> Dict[str, Any]:
|
|||
|
|
"""计算澳洲物流费用"""
|
|||
|
|
return LogisticsService.calculate(postcode, packages_data, port)
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def calculate_eur(postcode: str, packages_data: List[Dict],
|
|||
|
|
port: PortType = PortType.DEFAULT) -> Dict[str, Any]:
|
|||
|
|
"""计算欧洲物流费用"""
|
|||
|
|
return LogisticsService.calculate(postcode, packages_data, port)
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def get_company_detail(postcode: str, packages_data: List[Dict],
|
|||
|
|
company_name: str) -> Dict[str, Any]:
|
|||
|
|
"""获取指定物流公司的费用明细"""
|
|||
|
|
country = LogisticsService._detect_country(postcode)
|
|||
|
|
packages = LogisticsService._parse_packages(packages_data)
|
|||
|
|
op_country = OperateCountry(country, PortType.DEFAULT, packages, postcode)
|
|||
|
|
|
|||
|
|
detail = op_country.get_detail_amount(company_name, packages, postcode)
|
|||
|
|
currency = op_country.get_tail_currency(company_name)
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
"company": company_name,
|
|||
|
|
"currency": currency,
|
|||
|
|
"detail": detail,
|
|||
|
|
"total": detail.get("tail_amount", 0)
|
|||
|
|
}
|