This commit is contained in:
parent
1bbd4c643f
commit
94d5facdc9
BIN
data/XMILES.xlsx (Stored with Git LFS)
BIN
data/XMILES.xlsx (Stored with Git LFS)
Binary file not shown.
BIN
data/欧洲卡派-GEL.xlsx (Stored with Git LFS)
BIN
data/欧洲卡派-GEL.xlsx (Stored with Git LFS)
Binary file not shown.
BIN
data/澳洲三大渠道.xlsx (Stored with Git LFS)
BIN
data/澳洲三大渠道.xlsx (Stored with Git LFS)
Binary file not shown.
BIN
data/美国卡派-AM.xlsx (Stored with Git LFS)
BIN
data/美国卡派-AM.xlsx (Stored with Git LFS)
Binary file not shown.
|
|
@ -0,0 +1,29 @@
|
|||
from logisticsClass.logisticsBaseClass import HeadLogistics, LogisticsType
|
||||
"""
|
||||
port:LAX(default) 加拿大 暂定为美国
|
||||
currency:str = 'CNY'(default)
|
||||
logistics_type:LogisticsType (海运(default),空运)
|
||||
"""
|
||||
|
||||
class OceanMSLogistics_US(HeadLogistics):
|
||||
"""加拿大海运"""
|
||||
logistics_type = LogisticsType.OCEAN # 默认海运
|
||||
company = "海CA"
|
||||
country_code = "CA"
|
||||
country = "Canada"
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.head_ratio = 9
|
||||
|
||||
class AirLAXLogistics_US(HeadLogistics):
|
||||
"""加拿大空运LAX"""
|
||||
logistics_type = LogisticsType.AIR
|
||||
company = "空LAX"
|
||||
country_code = "CA"
|
||||
country = "Canada"
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.head_ratio = 35
|
||||
|
||||
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ class PostLogistics_AU(TailLogistics):
|
|||
def calculate_fee(self, packages, postcode):
|
||||
"""
|
||||
计费重: 常规计费, 4000
|
||||
限制条件: 32kg,最长边100cm
|
||||
限制条件: 32kg,最长边100cm.3KG以内实重计费,3KG以上标准计费,2.5KG按3KG算
|
||||
是否有燃油费:是
|
||||
"""
|
||||
detail_amount = {
|
||||
|
|
@ -83,9 +83,16 @@ class PostLogistics_AU(TailLogistics):
|
|||
|
||||
base_data = list(zip(self.eparcel_price.columns[1:], row.values[0][1:]))
|
||||
for package in packages:
|
||||
# 2500g-3000g按3kg算
|
||||
if 2500<=package.weight<3000:
|
||||
package.weight = 3000
|
||||
if package.weight > 3000:
|
||||
billing_weight = max(package.weight, package.volume/4)
|
||||
else:
|
||||
billing_weight = package.weight
|
||||
|
||||
if package.fst_size > 100 or billing_weight >= 32000:
|
||||
|
||||
if package.fst_size > 100 or billing_weight > 22000:
|
||||
detail_amount['tail_amount'] = 99999
|
||||
return detail_amount
|
||||
if billing_weight > 22000:
|
||||
|
|
@ -170,29 +177,31 @@ class TollLogistics_AU(TailLogistics):
|
|||
volume_weight = package.get_volume_weight(4)
|
||||
billing_weight = max(package.weight,volume_weight)
|
||||
detail_amount['base'] += max(base + per * math.ceil(billing_weight/1000), minimun)
|
||||
# if package.weight >= 35000 or package.fst_size >= 180 or package.volume >=700000:
|
||||
if package.weight >= 35000 or package.fst_size >= 180 or package.volume >=700000:
|
||||
# detail_amount['oversize'] += self.oversize_fee[1]
|
||||
detail_amount['tail_amount'] = 99999 # ERP配置的超过这个尺寸就不派送这个了
|
||||
if package.weight >30000 or package.fst_size > 120 or package.sed_size > 80:
|
||||
detail_amount['oversize'] += self.oversize_fee[0]
|
||||
|
||||
|
||||
# 计算偏远附加费,只跟地区有关,不需要放入循环内部计算
|
||||
postcode_counts = self.toll_zone[self.toll_zone['postcode'] == postcode].shape[0] # 该邮编总共多少个地区
|
||||
remote_count = self.toll_remote[self.toll_remote['postcode'] == postcode].shape[0] # 该邮编有多少个偏远地区
|
||||
postcode_counts = int(postcode_counts)
|
||||
# postcode_counts = self.toll_zone[self.toll_zone['postcode'] == postcode].shape[0] # 该邮编总共多少个地区
|
||||
remote_count = self.toll_remote[self.toll_remote['postcode'] == int(postcode)].shape[0] # 该邮编有多少个偏远地区
|
||||
# postcode_counts = int(postcode_counts)
|
||||
remote_count=int(remote_count)
|
||||
# 将 price 列中的 NaN 替换为 0
|
||||
self.toll_remote['price'] = self.toll_remote['price'].fillna(0)
|
||||
# 该邮编偏远地区的偏远费
|
||||
remote_fee = self.toll_remote[self.toll_remote['postcode'] == postcode]['price'].mean()
|
||||
remote_fee = self.toll_remote[self.toll_remote['postcode'] == int(postcode)]['price'].mean()
|
||||
# 检查 remote_fee 是否为 NaN,若是则设为 0
|
||||
if pd.isna(remote_fee):
|
||||
remote_fee = 0
|
||||
|
||||
# 计算最终的偏远附加费
|
||||
if postcode_counts > 0 and remote_count > 0:
|
||||
remote_fee = remote_fee * remote_count / postcode_counts
|
||||
else:
|
||||
remote_fee = 0 # 处理为其他合适的值
|
||||
# # 计算最终的偏远附加费
|
||||
# if postcode_counts > 0 and remote_count > 0:
|
||||
# remote_fee = remote_fee * remote_count / postcode_counts
|
||||
# else:
|
||||
# remote_fee = 0 # 处理为其他合适的值
|
||||
|
||||
detail_amount['remote'] = remote_fee * len(packages)
|
||||
for key in detail_amount:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
""" 加拿大尾端物流模块实现类"""
|
||||
import math
|
||||
import re
|
||||
import pandas
|
||||
from logisticsClass.logisticsBaseClass import LogisticsType, TailLogistics
|
||||
from pathlib import Path
|
||||
from utils.gtools import DBconnect
|
||||
|
||||
class FedexLogistics(TailLogistics):
|
||||
"""Fedex"""
|
||||
country = "United States"
|
||||
country_code = "US"
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.fuel_rate = 0.18 # 燃油费率
|
||||
|
||||
def calculate_fee(self,packages,postcode):
|
||||
"""计算运费,抛重计费,系数275"""
|
||||
detail_amount = {
|
||||
"base":0.00,
|
||||
"oversize":0.00,
|
||||
"remote":0.00,
|
||||
"big_package":0.00,
|
||||
"big_package_peak":0.00,
|
||||
"residential_delivery":0.00,
|
||||
"residential_peak":0.00,
|
||||
"fuel":0.00,
|
||||
"tail_amount":0.00
|
||||
}
|
||||
# 先看分区
|
||||
zone = self.get_west_zone(postcode)
|
||||
|
||||
|
|
@ -40,9 +40,9 @@ class DPDASLLogistics(TailLogistics):
|
|||
detail_amount['tail_amount'] = 99999
|
||||
return detail_amount
|
||||
for package in packages: # 逐个处理列表中的每个包裹
|
||||
if package.weight > 31500 or package.girth > 350 or package.fst_size > 200:
|
||||
detail_amount['tail_amount'] = 99999
|
||||
return detail_amount
|
||||
# if package.weight > 31500 or package.girth > 350 or package.fst_size > 200:
|
||||
# detail_amount['tail_amount'] = 99999
|
||||
# return detail_amount
|
||||
detail_amount['base'] += self.base_fee
|
||||
detail_amount['remote'] +=self.remote_fee* isremote
|
||||
detail_amount['overweight'] += self.overweight if package.weight >= 20000 else 0
|
||||
|
|
@ -54,7 +54,6 @@ class DPDASLLogistics(TailLogistics):
|
|||
detail_amount['tail_amount'] += detail_amount[key]
|
||||
detail_amount['tail_amount'] +=detail_amount['fuel']
|
||||
return detail_amount
|
||||
|
||||
# DPDASL 德国实现
|
||||
class DPDASLLogistics_DE(DPDASLLogistics):
|
||||
country_code = 'DE'
|
||||
|
|
@ -80,7 +79,6 @@ class DPDASLLogistics_DE(DPDASLLogistics):
|
|||
else:
|
||||
postcodes.append(int(code))
|
||||
return 1 if postcode in postcodes else 0
|
||||
|
||||
# DPDASL 法国实现
|
||||
class DPDASLLogistics_FR(DPDASLLogistics):
|
||||
country_code = 'FR'
|
||||
|
|
@ -116,6 +114,90 @@ class DPDASLLogistics_ES(DPDASLLogistics):
|
|||
return 1
|
||||
else:
|
||||
return 0
|
||||
# DPDASL 荷兰实现
|
||||
class DPDASLLogistics_NL(DPDASLLogistics):
|
||||
country_code = 'NL'
|
||||
country = 'Netherlands'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.base_fee = 6.9
|
||||
self.remote_fee = 7.5
|
||||
def is_remote(self,postcode):
|
||||
"""判断是否偏远,1偏远0非偏远"""
|
||||
# 先判断邮编是否合法
|
||||
postcode_str = postcode[:4]
|
||||
postcode_str = int(postcode_str)
|
||||
remote_postcodes = ["1156","1791-1797","8881-8884","8891-8897","8899","9161-9164","9166"]
|
||||
postcodes = []
|
||||
for code in remote_postcodes:
|
||||
if '-' in code:
|
||||
start,end = code.split('-')
|
||||
postcodes.extend(list(range(int(start),int(end)+1)))
|
||||
else:
|
||||
postcodes.append(int(code))
|
||||
return 1 if postcode_str in postcodes else 0
|
||||
# DPDASL 意大利实现
|
||||
class DPDASLLogistics_IT(DPDASLLogistics):
|
||||
country_code = 'IT'
|
||||
country = 'Italy'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.base_fee = 11.3
|
||||
self.remote_fee=20.65
|
||||
def is_remote(self,postcode):
|
||||
"""判断是否偏远,1偏远0非偏远"""
|
||||
# 先判断邮编是否合法
|
||||
if not re.match(r'^\d{5}$', postcode):
|
||||
return "邮编格式不合法"
|
||||
remote_postcodes = ["04020","04027","07024","07042","07046","09014",
|
||||
"25050","30010","30012","30100","30121-30126","30131-30133","30135", "30141","57030-57039","58010","58012-58013","58018-58019","71040","80070-80071",
|
||||
"80073-80077","80079","90010","91017", "91023","92010","98050", "98052","98055", "90010-90151","91010-91100","92010-92100","93010-93100",
|
||||
"94010-94100","95010-95127","96010-96100", "97010-97100", "98020-98168","08010-08100","09010-09049","09070-09099","09100","09124","09126","09170"
|
||||
]
|
||||
postcodes = []
|
||||
for code in remote_postcodes:
|
||||
if '-' in code:
|
||||
start,end = code.split('-')
|
||||
postcodes.extend(list(range(int(start),int(end)+1)))
|
||||
else:
|
||||
postcodes.append(int(code))
|
||||
return 1 if postcode in postcodes else 0
|
||||
# DPDASL 葡萄牙实现
|
||||
class DPDASLLogistics_PT(DPDASLLogistics):
|
||||
country_code = 'PT'
|
||||
country = 'Portugal'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.base_fee = 13.1
|
||||
self.remote_fee=52
|
||||
def is_remote(self,postcode):
|
||||
"""判断是否偏远,1偏远0非偏远"""
|
||||
# 先判断邮编是否合法
|
||||
postcode_str = postcode[:4]
|
||||
postcode_str = int(postcode_str)
|
||||
remote_postcodes = ["9500-9999","9000-9499"]
|
||||
postcodes = []
|
||||
for code in remote_postcodes:
|
||||
if '-' in code:
|
||||
start,end = code.split('-')
|
||||
postcodes.extend(list(range(int(start),int(end)+1)))
|
||||
else:
|
||||
postcodes.append(int(code))
|
||||
return 1 if postcode_str in postcodes else 0
|
||||
# DPDASL 比利时实现
|
||||
class DPDASLLogistics_BE(DPDASLLogistics):
|
||||
country_code = 'BE'
|
||||
country = 'Belgium'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.base_fee = 8.1
|
||||
self.remote_fee=0
|
||||
def is_remote(self,postcode):
|
||||
"""判断是否偏远,1偏远0非偏远"""
|
||||
# 先判断邮编是否合法
|
||||
if not re.match(r'^\d{4}$', postcode):
|
||||
return "邮编格式不合法"
|
||||
return 0
|
||||
|
||||
|
||||
# DPD-ZG 欧洲国家逻辑基类
|
||||
|
|
@ -146,9 +228,9 @@ class DPDZGLogistics(TailLogistics):
|
|||
detail_amount['tail_amount'] = 99999
|
||||
return detail_amount
|
||||
for package in packages: # 逐个处理列表中的每个包裹
|
||||
if package.weight > 31500 or package.girth > 300 or package.fst_size >175:
|
||||
detail_amount['tail_amount'] = 99999
|
||||
return detail_amount
|
||||
# if package.weight > 31500 or package.girth > 300 or package.fst_size >175:
|
||||
# detail_amount['tail_amount'] = 99999
|
||||
# return detail_amount
|
||||
if package.weight <5000:
|
||||
detail_amount['base'] += self.base_fee[0]
|
||||
elif package.weight < 10000:
|
||||
|
|
@ -156,14 +238,13 @@ class DPDZGLogistics(TailLogistics):
|
|||
else:
|
||||
detail_amount['base'] += self.base_fee[2]
|
||||
detail_amount['remote'] += float(self.remote_fee) * float(isremote)
|
||||
detail_amount['operate'] += package.weight * self.operate_rate
|
||||
detail_amount['operate'] += package.weight/1000 * self.operate_rate
|
||||
for key in detail_amount:
|
||||
if key != 'tail_amount' and key != 'fuel':
|
||||
detail_amount['fuel'] += detail_amount[key] * self.fuel_rate
|
||||
detail_amount['tail_amount'] += detail_amount[key]
|
||||
detail_amount['tail_amount'] +=detail_amount['fuel']
|
||||
return detail_amount
|
||||
|
||||
# DPD-ZG 德国实现
|
||||
class DPDZGLogistics_DE(DPDZGLogistics):
|
||||
country_code = 'DE'
|
||||
|
|
@ -171,8 +252,6 @@ class DPDZGLogistics_DE(DPDZGLogistics):
|
|||
def __init__(self):
|
||||
super().__init__()
|
||||
self.base_fee = [7.72,8.83,11.67]
|
||||
self.operate_rate = 0.18
|
||||
self.fuel_rate = 0.125
|
||||
self.remote_fee=11.5
|
||||
def is_remote(self,postcode):
|
||||
"""判断是否偏远,1偏远0非偏远"""
|
||||
|
|
@ -191,7 +270,6 @@ class DPDZGLogistics_DE(DPDZGLogistics):
|
|||
else:
|
||||
postcodes.append(int(code))
|
||||
return 1 if postcode in postcodes else 0
|
||||
|
||||
# DPD-ZG 法国实现
|
||||
class DPDZGLogistics_FR(DPDZGLogistics):
|
||||
country_code = 'FR'
|
||||
|
|
@ -199,8 +277,6 @@ class DPDZGLogistics_FR(DPDZGLogistics):
|
|||
def __init__(self):
|
||||
super().__init__()
|
||||
self.base_fee = [10.77,11.92,14.03]
|
||||
self.operate_rate = 0.18
|
||||
self.fuel_rate = 0.125
|
||||
self.remote_fee= 18.5
|
||||
def is_remote(self,postcode):
|
||||
"""判断是否偏远,1偏远0非偏远"""
|
||||
|
|
@ -212,7 +288,6 @@ class DPDZGLogistics_FR(DPDZGLogistics):
|
|||
remove_postcodes = ["17111","17123","17190","17310","17370","17410","17480","17550","17580","17590","17630","17650",
|
||||
"17670","17740","17840","17880","17940","56360","56590","56780","56840","85330","85350"]
|
||||
return 1 if postcode in remove_postcodes else 0
|
||||
|
||||
# DPD-ZG 西班牙实现
|
||||
class DPDZGLogistics_SP(DPDZGLogistics):
|
||||
country_code = 'ES'
|
||||
|
|
@ -220,8 +295,6 @@ class DPDZGLogistics_SP(DPDZGLogistics):
|
|||
def __init__(self):
|
||||
super().__init__()
|
||||
self.base_fee = [12.1,13.17,15.46]
|
||||
self.operate_rate = 0.18
|
||||
self.fuel_rate = 0.125
|
||||
self.remote_fee= 32
|
||||
def is_remote(self,postcode):
|
||||
"""判断是否偏远,1偏远0非偏远"""
|
||||
|
|
@ -232,6 +305,90 @@ class DPDZGLogistics_SP(DPDZGLogistics):
|
|||
return 1
|
||||
else:
|
||||
return 0
|
||||
# DPD-ZG 意大利实现
|
||||
class DPDZGLogistics_IT(DPDZGLogistics):
|
||||
country_code = 'IT'
|
||||
country = 'Italy'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.base_fee = [13.69,14.75,17.27]
|
||||
self.remote_fee=19.5
|
||||
def is_remote(self,postcode):
|
||||
"""判断是否偏远,1偏远0非偏远"""
|
||||
# 先判断邮编是否合法
|
||||
if not re.match(r'^\d{5}$', postcode):
|
||||
return "邮编格式不合法"
|
||||
remote_postcodes = ["04020","04027","07024","07042","07046","09014",
|
||||
"25050","30010","30012","30100","30121-30126","30131-30133","30135", "30141","57030-57039","58010","58012-58013","58018-58019","71040","80070-80071",
|
||||
"80073-80077","80079","90010","91017", "91023","92010","98050", "98052","98055", "90010-90151","91010-91100","92010-92100","93010-93100",
|
||||
"94010-94100","95010-95127","96010-96100", "97010-97100", "98020-98168","08010-08100","09010-09049","09070-09099","09100","09124","09126","09170"
|
||||
]
|
||||
postcodes = []
|
||||
for code in remote_postcodes:
|
||||
if '-' in code:
|
||||
start,end = code.split('-')
|
||||
postcodes.extend(list(range(int(start),int(end)+1)))
|
||||
else:
|
||||
postcodes.append(int(code))
|
||||
return 1 if postcode in postcodes else 0
|
||||
# DPD-ZG 荷兰实现
|
||||
class DPDZGLogistics_NL(DPDZGLogistics):
|
||||
country_code = 'NL'
|
||||
country = 'Netherlands'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.base_fee = [8.88,9.83,11.62]
|
||||
self.remote_fee=7.5
|
||||
def is_remote(self,postcode):
|
||||
"""判断是否偏远,1偏远0非偏远"""
|
||||
# 先判断邮编是否合法
|
||||
postcode_str = postcode[:4]
|
||||
postcode_str = int(postcode_str)
|
||||
remote_postcodes = ["1156","1791-1797","8881-8884","8891-8897","8899","9161-9164","9166"]
|
||||
postcodes = []
|
||||
for code in remote_postcodes:
|
||||
if '-' in code:
|
||||
start,end = code.split('-')
|
||||
postcodes.extend(list(range(int(start),int(end)+1)))
|
||||
else:
|
||||
postcodes.append(int(code))
|
||||
return 1 if postcode_str in postcodes else 0
|
||||
# DPD-ZG 葡萄牙实现
|
||||
class DPDZGLogistics_PT(DPDZGLogistics):
|
||||
country_code = 'PT'
|
||||
country = 'Portugal'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.base_fee = [8.11,9.27,10.98]
|
||||
self.remote_fee=49
|
||||
def is_remote(self,postcode):
|
||||
"""判断是否偏远,1偏远0非偏远"""
|
||||
# 先判断邮编是否合法
|
||||
postcode_str = postcode[:4]
|
||||
postcode_str = int(postcode_str)
|
||||
remote_postcodes = ["9500-9999","9000-9499"]
|
||||
postcodes = []
|
||||
for code in remote_postcodes:
|
||||
if '-' in code:
|
||||
start,end = code.split('-')
|
||||
postcodes.extend(list(range(int(start),int(end)+1)))
|
||||
else:
|
||||
postcodes.append(int(code))
|
||||
return 1 if postcode_str in postcodes else 0
|
||||
# DPD-ZG 比利时实现
|
||||
class DPDZGLogistics_BE(DPDZGLogistics):
|
||||
country_code = 'BE'
|
||||
country = 'Belgium'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.base_fee = [8.62,9.72,11.51]
|
||||
self.remote_fee=0
|
||||
def is_remote(self,postcode):
|
||||
"""判断是否偏远,1偏远0非偏远"""
|
||||
# 先判断邮编是否合法
|
||||
if not re.match(r'^\d{4}$', postcode):
|
||||
return "邮编格式不合法"
|
||||
return 0
|
||||
|
||||
|
||||
# 卡派-ASL 欧洲各国基类
|
||||
|
|
@ -353,12 +510,12 @@ class KPGELLogistics(TailLogistics):
|
|||
|
||||
total_weight = 0
|
||||
for package in packages:
|
||||
if (package.fst_size > 320 or package.sed_size>170 or package.trd_size>120) and (self.country_code != "DE"):
|
||||
detail_amount['tail_amount'] = 99999
|
||||
return detail_amount
|
||||
if package.fst_size > 320 or package.sed_size>200 or package.trd_size>120:
|
||||
detail_amount['tail_amount'] = 99999
|
||||
return detail_amount
|
||||
# if (package.fst_size > 320 or package.sed_size>170 or package.trd_size>120) and (self.country_code != "DE"):
|
||||
# detail_amount['tail_amount'] = 99999
|
||||
# return detail_amount
|
||||
# if package.fst_size > 320 or package.sed_size>200 or package.trd_size>120:
|
||||
# detail_amount['tail_amount'] = 99999
|
||||
# return detail_amount
|
||||
billing_weight = max(package.weight/1000,package.get_volume_weight(6000))
|
||||
total_weight += billing_weight
|
||||
# 基础费用
|
||||
|
|
@ -379,7 +536,6 @@ class KPGELLogistics(TailLogistics):
|
|||
if key != 'tail_amount':
|
||||
detail_amount['tail_amount'] += detail_amount[key]
|
||||
return detail_amount
|
||||
|
||||
# GEL卡派德国
|
||||
class KPGELLogistics_DE(KPGELLogistics):
|
||||
country_code = 'DE'
|
||||
|
|
@ -432,3 +588,246 @@ class KPGELLogistics_SP(KPGELLogistics):
|
|||
return 1
|
||||
def calculate_fee(self,packages,postcode):
|
||||
return super().calculate_fee(packages,postcode)
|
||||
# GEL卡派意大利
|
||||
class KPGELLogistics_IT(KPGELLogistics):
|
||||
country_code = 'IT'
|
||||
country = 'Italy'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
def is_remote(self, postcode):
|
||||
postcode = str(postcode)
|
||||
postcode_str = postcode[:2]
|
||||
if 10<=int(postcode_str)<=59:
|
||||
return 1
|
||||
elif 0<=int(postcode_str)<=6 or postcode =="6086":
|
||||
return 2
|
||||
elif 7<=int(postcode_str)<=9 or postcode =="8798":
|
||||
return 3
|
||||
|
||||
def calculate_fee(self,packages,postcode):
|
||||
return super().calculate_fee(packages,postcode)
|
||||
# GEL卡派葡萄牙
|
||||
class KPGELLogistics_PT(KPGELLogistics):
|
||||
country_code = 'PT'
|
||||
country = 'Portugal'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
def is_remote(self, postcode):
|
||||
return 1
|
||||
def calculate_fee(self,packages,postcode):
|
||||
return super().calculate_fee(packages,postcode)
|
||||
# GEL卡派荷兰
|
||||
class KPGELLogistics_NL(KPGELLogistics):
|
||||
country_code = 'NL'
|
||||
country = 'Netherlands'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
def is_remote(self, postcode):
|
||||
return 1
|
||||
def calculate_fee(self,packages,postcode):
|
||||
return super().calculate_fee(packages,postcode)
|
||||
# GEL卡派比利时
|
||||
class KPGELLogistics_BE(KPGELLogistics):
|
||||
country_code = 'BE'
|
||||
country = 'Belgium'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
def is_remote(self, postcode):
|
||||
postcode = int(postcode)
|
||||
if 1000<=postcode<=1299:
|
||||
return 1
|
||||
elif 1300<=postcode<=9999:
|
||||
return 2
|
||||
def calculate_fee(self,packages,postcode):
|
||||
return super().calculate_fee(packages,postcode)
|
||||
|
||||
# 欧洲商务报价-智谷
|
||||
class EURZGLogistics(TailLogistics):
|
||||
"""欧洲商务报价-智谷"""
|
||||
currency = "EUR"
|
||||
company = "EUR-ZG"
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.per_item = None
|
||||
self.per_kg = None
|
||||
self.limit_kg = None
|
||||
self.remote = None
|
||||
self.fuel_rate = 0.13
|
||||
def is_remote(self,postcode):
|
||||
"""判断是否偏远,1偏远0非偏远"""
|
||||
raise NotImplementedError("Subclasses must implement remote calculation.")
|
||||
def calculate_fee(self,packages,postcode):
|
||||
"""计算快递费用"""
|
||||
detail_amount = {
|
||||
"base":0.00,
|
||||
"remote":0.00,
|
||||
"fuel":0.00,
|
||||
"tail_amount":0.00
|
||||
}
|
||||
isremote = self.is_remote(postcode)
|
||||
if isremote == "邮编格式不合法":
|
||||
detail_amount['tail_amount'] = 99999
|
||||
return detail_amount
|
||||
if isremote == 1:
|
||||
detail_amount['remote'] = self.remote
|
||||
|
||||
for package in packages: # 逐个处理列表中的每个包裹
|
||||
# if package.length+package.width+package.height > 150 or package.weight > self.limit_kg*1000:
|
||||
# detail_amount['tail_amount'] = 99999
|
||||
# return detail_amount
|
||||
detail_amount['base'] += self.per_item+self.per_kg*package.weight/1000
|
||||
|
||||
for key in detail_amount:
|
||||
if key != 'tail_amount' and key != 'fuel':
|
||||
detail_amount['fuel'] += detail_amount[key] * self.fuel_rate
|
||||
detail_amount['tail_amount'] += detail_amount[key]
|
||||
detail_amount['tail_amount'] +=detail_amount['fuel']
|
||||
return detail_amount
|
||||
class EURZGLogistics_DE(EURZGLogistics):
|
||||
country_code = 'DE'
|
||||
country = 'Germany'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.per_item = 3.71
|
||||
self.per_kg = 0.87
|
||||
self.limit_kg = 30
|
||||
self.remote = 0
|
||||
def is_remote(self,postcode):
|
||||
return 0
|
||||
|
||||
class EURZGLogistics_FR(EURZGLogistics):
|
||||
country_code = 'FR'
|
||||
country = 'France'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.per_item = [3.8,5.08,5.99,7.66]
|
||||
self.per_kg = 1.07
|
||||
self.limit_kg = 30
|
||||
self.remote = [5.5,14]
|
||||
def calculate_fee(self,packages,postcode):
|
||||
"""计算快递费用"""
|
||||
detail_amount = {
|
||||
"base":0.00,
|
||||
"remote":0.00,
|
||||
"fuel":0.00,
|
||||
"tail_amount":0.00
|
||||
}
|
||||
isremote = self.is_remote(postcode)
|
||||
if isremote == "邮编格式不合法":
|
||||
detail_amount['tail_amount'] = 99999
|
||||
return detail_amount
|
||||
|
||||
for package in packages: # 逐个处理列表中的每个包裹
|
||||
# if package.length+package.width+package.height > 150 or package.weight > self.limit_kg*1000:
|
||||
# detail_amount['tail_amount'] = 99999
|
||||
# return detail_amount
|
||||
if package.weight <=500:
|
||||
per_item = self.per_item[0]
|
||||
elif package.weight <=2000:
|
||||
per_item = self.per_item[1]
|
||||
elif package.weight <=1500:
|
||||
per_item = self.per_item[2]
|
||||
else:
|
||||
per_item = self.per_item[3]
|
||||
detail_amount['base'] += per_item+self.per_kg*package.weight/1000
|
||||
if isremote == 1:
|
||||
detail_amount['remote'] += self.remote[0]*package.weight/1000+9.5
|
||||
elif isremote == 2:
|
||||
detail_amount['remote'] += self.remote[1]*package.weight/1000+9.5
|
||||
|
||||
for key in detail_amount:
|
||||
if key != 'tail_amount' and key != 'fuel':
|
||||
detail_amount['fuel'] += detail_amount[key] * self.fuel_rate
|
||||
detail_amount['tail_amount'] += detail_amount[key]
|
||||
detail_amount['tail_amount'] +=detail_amount['fuel']
|
||||
return detail_amount
|
||||
def is_remote(self,postcode):
|
||||
postcode = str(postcode)
|
||||
postcode_str = int(postcode[:3])
|
||||
if 971<=postcode_str <= 976:
|
||||
return 1
|
||||
elif 984<=postcode_str <= 988:
|
||||
return 2
|
||||
return 0
|
||||
|
||||
class EURZGLogistics_IT(EURZGLogistics):
|
||||
country_code = 'IT'
|
||||
country = 'Italy'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.per_item = 5.74
|
||||
self.per_kg = 1.38
|
||||
self.limit_kg = 30
|
||||
self.remote = 6
|
||||
def is_remote(self,postcode):
|
||||
remote_list = ["51024","67020", "67030", "67013", "67049","39030", "39032", "39040", "39043", "39054", "39058","98050", "98055","85046","89030", "89040", "89012", "89049", "89043",
|
||||
"80051", "80071", "80072", "80073", "80074", "80075", "80076", "80077", "80079", "80081",
|
||||
"38041", "38089", "38095", "38036", "38037", "38077", "38048", "38029", "38010", "38071",
|
||||
"87070", "87051", "87035", "87020", "87066", "87073", "87059", "87035", "87014", "87015", "57034", "57031", "57032", "57037", "57038",
|
||||
"64020","64031", "64033", "64030", "64037", "64042", "64043", "64010", "64010", "64010", "64010","9014","86021", "86027", "86043", "86029", "86016","50034","23031", "23020", "23010", "23023", "23029", "23030", "23041","30142", "30133", "30141", "30124", "30126","16048", "16046", "16032", "16039","63096","91023", "91017",
|
||||
"48013","62024", "62025","65010","33040", "33020", "33090", "33014", "33080","88822", "88823", "88825","17030", "17034", "17046", "17037", "17048","07046", "07024","15060", "15056", "15050","71023", "71051","42035","82024", "82028",
|
||||
"41045","13010", "13019", "13028", "13030","32041", "32010", "32030","58019", "58012", "58044","43025","45010","19025", "19020","30124", "30133", "30141", "30142","90051","13888", "13884","04025", "04027", "04031",
|
||||
"29031","53030", "53024","66040", "24014", "84050", "58019", "58012","62024", "62025","04025", "04027", "04031","87035", "87020", "16048", "16046","98050","51024","67020", "67030"]
|
||||
if postcode in remote_list:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
||||
class EURZGLogistics_PT(EURZGLogistics):
|
||||
country_code = 'PT'
|
||||
country = 'Portugal'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.per_item = 3.71
|
||||
self.per_kg = 1.95
|
||||
self.limit_kg = 30
|
||||
self.remote = 5
|
||||
def is_remote(self,postcode):
|
||||
postcode = str(postcode)
|
||||
if postcode.startswith("9"):
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
def calculate_fee(self,packages,postcode):
|
||||
"""计算快递费用"""
|
||||
detail_amount = {
|
||||
"base":0.00,
|
||||
"remote":0.00,
|
||||
"fuel":0.00,
|
||||
"tail_amount":0.00
|
||||
}
|
||||
isremote = self.is_remote(postcode)
|
||||
if isremote == "邮编格式不合法":
|
||||
detail_amount['tail_amount'] = 99999
|
||||
return detail_amount
|
||||
|
||||
for package in packages: # 逐个处理列表中的每个包裹
|
||||
# if package.length+package.width+package.height > 150 or package.weight > self.limit_kg*1000:
|
||||
# detail_amount['tail_amount'] = 99999
|
||||
# return detail_amount
|
||||
detail_amount['base'] += self.per_item+self.per_kg*package.weight/1000
|
||||
if isremote == 1:
|
||||
detail_amount['remote'] += self.remote*package.weight/1000+15
|
||||
for key in detail_amount:
|
||||
if key != 'tail_amount' and key != 'fuel':
|
||||
detail_amount['fuel'] += detail_amount[key] * self.fuel_rate
|
||||
detail_amount['tail_amount'] += detail_amount[key]
|
||||
detail_amount['tail_amount'] +=detail_amount['fuel']
|
||||
return detail_amount
|
||||
|
||||
class EURZGLogistics_ES(EURZGLogistics):
|
||||
country_code = 'ES'
|
||||
country = 'Spain'
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.per_item = 3.93
|
||||
self.per_kg = 1.85
|
||||
self.limit_kg = 30
|
||||
self.remote = 99999
|
||||
def is_remote(self,postcode):
|
||||
postcode = str(postcode)
|
||||
postcode_str = postcode[:2]
|
||||
if postcode_str in ['07','51','52','35','38']:
|
||||
return 1
|
||||
else:
|
||||
return 0
|
||||
|
|
@ -34,9 +34,9 @@ class DPDLogistics_UK(TailLogistics):
|
|||
if self.is_remote(postcode):
|
||||
detail_amount['remote'] = self.remote_fee
|
||||
for package in packages:
|
||||
if package.weight >= 40000 or package.fst_size >= 175 or package.girth>=339:
|
||||
detail_amount['tail_amount'] =99999
|
||||
return detail_amount
|
||||
# if package.weight >= 40000 or package.fst_size >= 175 or package.girth>=339:
|
||||
# detail_amount['tail_amount'] =99999
|
||||
# return detail_amount
|
||||
if package.weight >= 30000 or package.fst_size >= 100 or package.sed_size >=60:
|
||||
detail_amount['oversize'] += self.oversize
|
||||
detail_amount['base'] += self.base_fee
|
||||
|
|
@ -150,7 +150,7 @@ class KPZGLogistics_UK(TailLogistics):
|
|||
# 实重
|
||||
country_code = 'UK'
|
||||
country = 'United Kingdom'
|
||||
company = '海GB-卡派'
|
||||
company = '卡派-ZG'
|
||||
currency = 'GBP'
|
||||
logistics_type = LogisticsType.LTL
|
||||
def __init__(self):
|
||||
|
|
@ -267,6 +267,7 @@ class KPNVlogistics_UK(TailLogistics):
|
|||
detail_amount['tail_amount'] = detail_amount['base']+detail_amount['fuel']
|
||||
return detail_amount
|
||||
|
||||
|
||||
# class KPDXLogistics_UK(TailLogistics):
|
||||
# country_code = 'UK'
|
||||
# country = 'United Kingdom'
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import pandas
|
|||
from logisticsClass.logisticsBaseClass import LogisticsType, TailLogistics
|
||||
from data.us_zone import zone_west, zone_east
|
||||
from pathlib import Path
|
||||
|
||||
from utils.gtools import DBconnect
|
||||
"""
|
||||
port:west(default),east
|
||||
currency:str = 'USD'
|
||||
|
|
@ -111,7 +111,7 @@ class FedexLogistics(WestLogistics_US):
|
|||
self.bigpackage_7:float
|
||||
self.bigpackage_peak:float # 大包裹旺季附加费
|
||||
self.return_package:float # 超大包裹(不可发)
|
||||
self.fuel_rate = 0.16 # 燃油费率
|
||||
self.fuel_rate = 0.18 # 燃油费率
|
||||
|
||||
def calculate_fee(self,packages,postcode):
|
||||
"""计算运费,抛重计费,系数275"""
|
||||
|
|
@ -163,8 +163,8 @@ class FedexLogistics(WestLogistics_US):
|
|||
remote_fee = 0
|
||||
|
||||
for package in packages:
|
||||
if package.lbs_weight>150 or package.fst_inch>108 or package.girth_inch >165:
|
||||
detail_amount['tail_amount'] = self.return_package
|
||||
if package.lbs_weight>150 or package.fst_inch>108 or package.girth_inch >157: # 400cm
|
||||
detail_amount['tail_amount'] = 999999
|
||||
return detail_amount
|
||||
cal_weight = max(package.lbs_weight,package.volume_inch / self.volume_weight_ratio)
|
||||
ahs_fee = 0 # AHS费系列,多种存在只取最高
|
||||
|
|
@ -176,7 +176,7 @@ class FedexLogistics(WestLogistics_US):
|
|||
if package.girth_inch >130 or package.fst_inch >96:
|
||||
cal_weight = max(cal_weight,90)
|
||||
if cal_weight > 150:
|
||||
detail_amount['tail_amount'] = self.return_package
|
||||
detail_amount['tail_amount'] = 999999
|
||||
return detail_amount
|
||||
detail_amount['oversize'] += 0 if package.girth_inch >130 or package.fst_inch >96 else ahs_fee
|
||||
detail_amount['remote'] += remote_fee
|
||||
|
|
@ -184,8 +184,8 @@ class FedexLogistics(WestLogistics_US):
|
|||
detail_amount['big_package_peak'] += self.bigpackage_peak if package.girth_inch >130 or package.fst_inch >96 else 0
|
||||
detail_amount['residential_delivery'] += self.residential
|
||||
detail_amount['residential_peak'] += self.residential_peak
|
||||
|
||||
detail_amount['base'] +=self.base_price[self.base_price['lbs.']==math.ceil(cal_weight)][zone].values[0]
|
||||
self.base_price.columns = self.base_price.columns.map(str)
|
||||
detail_amount['base'] +=self.base_price[self.base_price['lbs.']==math.ceil(cal_weight)][str(zone)].values[0]
|
||||
|
||||
for key in detail_amount:
|
||||
if key!= 'tail_amount' and key!= 'fuel':
|
||||
|
|
@ -279,14 +279,15 @@ class FedexHOMELogistics_US(FedexLogistics):
|
|||
"""FEDEX-HOME (1-35%-30%)"""
|
||||
company = "Fedex-HOME"
|
||||
|
||||
parent_current_directory = Path(__file__).parent.parent
|
||||
price_path = parent_current_directory.joinpath("data")
|
||||
_price_files = price_path.joinpath("美国快递.xlsx")
|
||||
base_price = None
|
||||
_instance = None
|
||||
def __new__(cls):
|
||||
if cls.base_price is None:
|
||||
cls.base_price = pandas.read_excel(cls._price_files,sheet_name='FEDEX')
|
||||
return super().__new__(cls)
|
||||
cls._instance = super().__new__(cls)
|
||||
with DBconnect() as db:
|
||||
cls.base_price = pandas.read_sql("SELECT * FROM us_fedex_home", db.engine())
|
||||
return cls._instance
|
||||
return cls._instance
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.volume_weight_ratio = 250 # lbs抛重系数
|
||||
|
|
@ -411,6 +412,7 @@ class CEVALogistics_US(TailLogistics):
|
|||
company = "大健-CEVA"
|
||||
logistics_type = LogisticsType.LTL
|
||||
|
||||
_instance = None
|
||||
parent_current_directory = Path(__file__).parent.parent
|
||||
data_path = parent_current_directory.joinpath("data")
|
||||
_price_files = data_path.joinpath("CEVA.xlsx")
|
||||
|
|
@ -421,6 +423,7 @@ class CEVALogistics_US(TailLogistics):
|
|||
def __new__(cls):
|
||||
"""实现单例模式,只加载一次文件"""
|
||||
if cls.price_df is None or cls.zone_df is None:
|
||||
cls._instance = super().__new__(cls)
|
||||
cls.price_df = pandas.read_excel(cls._price_files,sheet_name="ceva_base_rate")
|
||||
cls.zone_df = pandas.read_excel(cls._price_files,sheet_name="remote_zone")
|
||||
cls.grade_df = pandas.read_excel(cls._price_files,sheet_name="ceva_zone")
|
||||
|
|
@ -693,7 +696,7 @@ class XmilesLogistics_US(TailLogistics):
|
|||
detail_amount['tail_amount'] += detail_amount[key]
|
||||
return detail_amount
|
||||
|
||||
class AMWestLogistics_US(TailLogistics):
|
||||
class AMTWestLogistics_US(TailLogistics):
|
||||
"""卡派:AM,
|
||||
美西派送,
|
||||
"""
|
||||
|
|
@ -771,7 +774,7 @@ class AMWestLogistics_US(TailLogistics):
|
|||
detail_amount['tail_amount'] += detail_amount[key]
|
||||
return detail_amount
|
||||
|
||||
class AMEastLogistics_US(TailLogistics):
|
||||
class AMTEastLogistics_US(TailLogistics):
|
||||
"""卡派:AM,
|
||||
美东派送,
|
||||
美东在费用上额外+0.5*抛重6000的转运费
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@ def spu_head_type(base_df: pd.DataFrame):
|
|||
|
||||
|
||||
class SellPriceBase:
|
||||
parent_current_directory = Path(__file__).parent.parent
|
||||
sell_usps = None
|
||||
sell_uandf = None
|
||||
sell_fedex = None
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@ from logisticsClass.logisticsBaseClass import HeadLogistics, PortType, TailLogis
|
|||
# logistics_config.py
|
||||
|
||||
ACTIVE_LOGISTICS = {
|
||||
"FedexPPLogistics_US": False,
|
||||
"FedexKHLogistics_US": False,
|
||||
"FedexPPLogistics_US": True,
|
||||
"FedexKHLogistics_US": True,
|
||||
"FedexHOMELogistics_US": True,
|
||||
"FedexGROUDLogistics_US": True,
|
||||
"MetroLogistics_US": True,
|
||||
"GIGALogistics_US": False,
|
||||
"CEVALogistics_US": False,
|
||||
"GIGALogistics_US": True,
|
||||
"CEVALogistics_US": True,
|
||||
"XmilesLogistics_US":True,
|
||||
"AMWestLogistics_US":True,
|
||||
"AMEastLogistics_US":True
|
||||
"AMTWestLogistics_US":True,
|
||||
"AMTEastLogistics_US":True
|
||||
}
|
||||
def apply_active_config():
|
||||
stack = list(BaseLogistics.__subclasses__())
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class Billing:
|
|||
"""从Operator获取费用并添加账单项"""
|
||||
if self.packages is not None or self.postcode is not None:
|
||||
self.operator.set_packages_and_postcode(self.packages, self.postcode) # 设置包裹信息
|
||||
company_name = self.company_name if self.company_name is not None else self.operator.get_min_company()
|
||||
company_name = self.company_name if self.company_name is not None else self.operator.get_min_company() # 取快递类型的最小公司
|
||||
logistic_type = self.logistic_type if self.logistic_type is not None else self.operator.get_logistic_type(company_name)
|
||||
self.company_name = company_name
|
||||
self.logistic_type = logistic_type
|
||||
|
|
@ -67,6 +67,10 @@ class Billing:
|
|||
continue
|
||||
self.add_item(BillItem(amount = round(amount,2),amount_usd = self.operator.convert_to_usd(round(amount,2), tail_currency), item_type = "尾程",item_detail=item_detail, currency=tail_currency))
|
||||
|
||||
def get_logistic_type(self):
|
||||
"""获取渠道类型:快递/卡派"""
|
||||
return self.logistic_type
|
||||
|
||||
def get_items(self):
|
||||
return self.items
|
||||
@property
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
|
||||
logistics_name = {
|
||||
# US
|
||||
"空LAX-FEDEX-SAIR-H": "Fedex-HOME",
|
||||
"空LAX-FEDEX-SAIR-G": "Fedex-GROUD",
|
||||
"海MS-FEDEX-SAIR-H": "Fedex-HOME",
|
||||
|
|
@ -12,7 +13,19 @@ logistics_name = {
|
|||
"海MS-AMT-SAIR": "AM-美西",
|
||||
|
||||
"海MS-FEDEX02":"Fedex-彩虹小马",
|
||||
"空LAX-FEDEX02":"Fedex-彩虹小马"
|
||||
"空LAX-FEDEX02":"Fedex-彩虹小马",
|
||||
|
||||
# AU
|
||||
"海SY-POST3":"POST",
|
||||
"海POST- TMS改重":"POST",
|
||||
"海SY-POST1":"POST",
|
||||
"空SYD-POST3":"POST",
|
||||
"空SYD-POST1":"POST",
|
||||
"空SYD-TMS改重":"POST",
|
||||
"海SY-TOLL1":"TOLL",
|
||||
"空SYD-TOLL1":"TOLL",
|
||||
"海SY-ALL": "ALL",
|
||||
"空SYD-ALL": "ALL",
|
||||
}
|
||||
|
||||
#海NY-WWEX-SAIR,海MS-WWEX-SAIR没报价表,也停用了
|
||||
97201
物流渠道测算.ipynb
97201
物流渠道测算.ipynb
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue