43 KiB
43 KiB
In [ ]:
from utils.gtools import MySQLconnect import pandas as pd ads = MySQLconnect('ads') engine = ads.engine() conn = ads.connect() # sql = """ SELECT # sku.SKU, # 包裹数据, # 成本价 # FROM # ods.`stg_bayshop_litfad_sku` sku # LEFT JOIN ads.new_erp_sku_size size ON sku.SKU=size.SKU # WHERE sku.状态 = "启用" # AND EXISTS (SELECT 1 FROM ods.stg_bayshop_litfad_spu s1 where s1.`产品PID` = sku.`产品PID` AND s1.状态 = "正常销售" and s1.`产品分类` regexp "light") AND sku.添加时间 >="2024-01-01" # """ # df = pd.read_sql(sql, conn)
In [ ]:
# 计算售价 from sell.sell_price import call_sell_and_order_price import json import pandas as pd DATE_LIST = ["2024-01-01","2024-02-01","2024-03-01","2024-04-01","2024-05-01","2024-06-01","2024-07-01","2024-08-01","2024-09-01","2024-10-01","2024-11-01","2024-12-01","2025-01-01","2025-02-01","2025-03-01"] def cal_sell_price(df): """ 计算所有SKU的售价,物流分摊费 """ for index, row in df.iterrows(): try: package_dict = json.loads(row['包裹数据']) sell_price,order_price,order_type = call_sell_and_order_price(row['成本价'], package_dict) except Exception as e: print(f" {row['SKU']} 报错: {e}") continue df.loc[index, '售价'] = sell_price df.loc[index, '物流分摊费'] = order_price df.loc[index, '物流类型'] = order_type # print(f"sku:{row['SKU']},售价:{sell_price},物流分摊费:{order_price},物流类型:{order_type}") return df for date in DATE_LIST: sql = f""" SELECT sku.SKU, 包裹数据, 成本价, 产品售价, `产品品类`, `产品分类` FROM ods.`stg_bayshop_litfad_sku` sku LEFT JOIN ads.new_erp_sku_size size ON sku.SKU = size.SKU LEFT JOIN ods.stg_bayshop_litfad_spu spu ON sku.`产品PID` =spu.`产品PID` WHERE sku.状态 = "启用" AND spu.`产品品类` REGEXP "66" AND spu.`状态` ="正常销售" AND DATE_FORMAT( sku.添加时间, "%Y-%m-01" )= "{date}" """ df = pd.read_sql(sql, conn) df1 = cal_sell_price(df) df1.to_excel(f'售价_{date}.xlsx', index=False) print(f"日期:{date}, 售价计算完成")
美国2024版订单物流费
In [1]:
import math import pandas as pd from utils.gtools import MySQLconnect mat = MySQLconnect('mat') engine = mat.engine() df1 = pd.read_sql('select * from fedex2_0814', engine) import math # 美国海运订单费用,返回单个sku的订单费用和订单类型 def us_ocean_order_price(packages): # 处理包裹 if packages is None or len(packages) == 0: return 0, '包裹数为0' order_fee = 0 base_fee = 0 other_fee = 0 order_type1 = '' # 快递订单类型 # 快递费用 for package in packages: lbs_weight = package.get_volume_weight(8.5) if package.weight > 67000 or package.fst_size > 264 or lbs_weight > 67950 or package.girth > 391: base_fee = 999999 break base_fee += df1[df1['g'] >= lbs_weight]['费用'].iloc[0] if package.fst_size >= 116 or package.sed_size >= 71 or package.girth >= 251: other_fee += 16.3 order_type1 += '超长' # 超长费 if package.weight >= 21000 and package.fst_size < 238 and package.girth < 315: other_fee += 25.5 order_type1 += '超重' # 超重费: if package.fst_size >= 238 or package.girth >= 315: other_fee += 118.7 order_type1 += '大包裹费' # 大包裹费 express_fee = base_fee + other_fee # 卡派(步长为3) ltl_base = 0 ltl_fee = 0 count1 = 0 count2 = 0 count3 = 0 count4 = 0 order_type2 = '卡派' order_other_type1 = '' order_other_type2 = '' order_other_type3 = '' order_other_type4 = '' order_ltl_oversize = 0 order_ltl_overweight1 = 0 order_ltl_overweight2 = 0 order_ltl_overpackage = 0 sku_total_cubic_feet = 0 for package in packages: cubic_feet= package.length * package.width * package.height / 1000000 * 35.3 sku_total_cubic_feet += cubic_feet # 卡派额外费用 if package.fst_size>= 250: count1 += 1 order_ltl_oversize = 118 order_other_type1 = '超长' if package.weight >= 111000: count2 += 1 order_ltl_overweight1 = 78 order_other_type2 = '超重' if package.weight >= 130000: count3 += 1 order_ltl_overweight2 = 30 order_other_type3 = '超重' if package.fst_size >= 310: count4 += 1 order_ltl_overpackage = 30 order_other_type4 = '大包裹' order_type2 += order_other_type3 + order_other_type1 + order_other_type2 + order_other_type4 # 卡派基础费用 体积/1000000 *35.3 if sku_total_cubic_feet < 25: ltl_base = round(163 / 0.45 / 2, 2) # 181.11 elif sku_total_cubic_feet < 35: ltl_base = round(180 / 0.45 / 2, 2) # 200 else: # 大于一个立方的(35立方英尺) 按照每立方英尺*5美金 # 最低为190美金 ltl_base = round(max(190, 5 * sku_total_cubic_feet) / 0.45 / 2) ltl_fee = math.ceil(count1 / 3) * order_ltl_oversize + math.ceil(count2 / 3) * order_ltl_overweight1 + math.ceil( count3 / 3) * order_ltl_overweight2 + math.ceil(count4 / 3) * order_ltl_overpackage + ltl_base if ltl_fee < express_fee: order_fee = ltl_fee order_type = order_type2 else: order_fee = express_fee order_type = order_type1 return order_fee, order_type
美国2024版订单物流费
In [2]:
# 英国海运订单费用,返回单个sku的订单费用和订单类型 def uk_ocean_order_price(packages): # 计算uk经济直达费用 order_fee = 0 express_fee = 0 order_type1 = '' # 订单类型 ltl_fee = 0 if packages is None or len(packages) == 0: return 0, '包裹数为0' num = len(packages) if num > 30: return 0, '包裹数超过30' for package in packages: base_fee = 0 other_fee1 = 0 other_fee2 = 0 girth = package.girth if package.fst_size <= 90 and package.sed_size <= 50 and package.trd_size <= 50 and package.weight <= 29000: base_fee = 2.5 elif package.fst_size <= 165 and package.weight <= 39000: base_fee = 4.5 if package.weight >= 29000: other_fee1 = 17.8 # 超重费 order_type1 += '超重' if package.fst_size > 95 or package.sed_size > 55 or package.trd_size > 55: other_fee2 = 12.7 # 超长费 order_type1 += '超长' elif package.fst_size <= 290 and package.weight <= 69000 and girth <= 410: if package.weight <= 29000: base_fee = (7 * 9 / 7) / 0.45 elif 29000 < package.weight <= 49000: base_fee = (17.5 * 9 / 7) / 0.45 elif 49000 < package.weight <= 69000: base_fee = (28 * 9 / 7) / 0.45 order_type1 += '大包裹' else: base_fee = 999999 express_fee += (base_fee + other_fee1 + other_fee2) express_fee = round(express_fee, 2) # 卡派 主计费实重,辅计费抛重 order_type2 = '卡派' sku_total_cubic_feet = 0 for package in packages: cubic_feet= package.length * package.width * package.height / 6000 sku_total_cubic_feet += cubic_feet if package.length >310: return 999999,'包裹超尺寸' ltl_fee = max(151/0.45 - 2.4 /7 * sku_total_cubic_feet,2.5) if express_fee <= ltl_fee: order_fee = express_fee order_type = order_type1 else: order_fee = ltl_fee order_type = order_type2 return round(order_fee,2), order_type
计算2024版本售价
In [3]:
from utils.Package import Package, Package_group from sell.base_sell_price import SellPriceBase import re import json def call_sell_price(price, packages): if packages is None: return 0 litfad = SellPriceBase.litfad(packages, price,1) # 修改版本,网站售价 sell_price = litfad.cal_sell_price() return sell_price
In [6]:
from utils.gtools import MySQLconnect from tqdm import tqdm import pandas as pd from concurrent.futures import ThreadPoolExecutor def to_package(package_data): packages = Package_group() def extract_number(value): # 提取字符串中的第一个数字 match = re.search(r"[-+]?\d*\.\d+|\d+", str(value)) return float(match.group()) if match else 0.0 package_dict = json.loads(package_data) for key, package in package_dict.items(): package['长'] = extract_number(package['长']) package['宽'] = extract_number(package['宽']) package['高'] = extract_number(package['高']) package['重量'] = extract_number(package['重量']) if package['长'] == 0 or package['宽'] == 0 or package['高'] == 0 or package['重量'] == 0: return None packages.add_package(Package(key,package['长'], package['宽'], package['高'], package['重量'])) return packages if __name__ == '__main__': sql = """SELECT * , sku.`成本价` FROM dwd.dim_erp_sku_package_vol_info t1 LEFT JOIN ods.stg_bayshop_litfad_sku sku ON t1.erp_sku = sku.SKU WHERE NOT EXISTS ( SELECT 1 FROM ads.sku_order_compare t2 WHERE t1.erp_sku = t2.SKU ) AND id >= %s AND id <= %s AND `状态` = '启用'""" with MySQLconnect('ads') as db: for i in tqdm(range(110,150)): print(i,"开始") dfsql = sql % (i*100000, (i+1)*100000-1) df = pd.read_sql(dfsql, db.engine()) if len(df) == 0: continue # 包裹数据格式化 df['erp_package_vol'] = df.apply(lambda x: to_package(x['erp_package_vol']), axis=1) # df['售价'] = df.apply(lambda x: call_sell_and_order_price(x['成本价'], x['erp_package_vol'], "海运")[0], axis=1) # df[['美国海运','美国海运类型']] = df.apply(lambda x: us_ocean_order_price(x['erp_package_vol']), axis=1, result_type='expand') # df[['英国海运','英国海运类型']] = df.apply(lambda x: uk_ocean_order_price(x['erp_package_vol']), axis=1, result_type='expand') def process_row(x): # 单行处理逻辑 try: sell_price = call_sell_price(x['成本价'], x['erp_package_vol']) # print("售价计算完成") us_price, us_type = us_ocean_order_price(x['erp_package_vol']) # print("美国海运计算完成") uk_price, uk_type = uk_ocean_order_price(x['erp_package_vol']) # print("英国海运计算完成") return [round(sell_price, 2), us_price, us_type, uk_price, uk_type] except Exception as e: return [None, None, None, None, None] # 用 dict 更稳妥 rows = df.to_dict(orient='records') # 转为 list of dict print("到这儿了") with ThreadPoolExecutor(max_workers=50) as executor: results = list(executor.map(process_row, rows)) # 组装结果 print("到这儿了") result_df = pd.DataFrame(results, columns=['售价', '美国海运', '美国海运类型', '英国海运', '英国海运类型']) df = pd.concat([df.reset_index(drop=True), result_df], axis=1) # 清空临时表 db.cur.execute("TRUNCATE TABLE ads.temp_sku_order_compare;") print("临时表清空完成") # 组装需要输出的字段 df = df.rename(columns={ 'erp_package_vol':'包裹数据' }) columns_needed = ['SKU', '售价','包裹数据', '美国海运', '美国海运类型', '英国海运', '英国海运类型'] df_out = df[columns_needed] # 写入当前批次数据 df_out.to_sql( "temp_sku_order_compare", db.eng, if_exists='append', index=False, method='multi', chunksize=500 # 分批写入 ) print("当前批次数据写入完成") # 更新主表 update_sql = """ REPLACE INTO ads.sku_order_compare SELECT * FROM ads.temp_sku_order_compare """ db.cur.execute(update_sql) print("主表更新完成") db.con.commit() print(i,"结束")
0%| | 0/40 [00:00<?, ?it/s]
110 开始
2%|▎ | 1/40 [00:00<00:19, 2.03it/s]
111 开始
5%|▌ | 2/40 [00:00<00:18, 2.09it/s]
112 开始
8%|▊ | 3/40 [00:01<00:17, 2.08it/s]
113 开始
10%|█ | 4/40 [00:01<00:17, 2.02it/s]
114 开始
12%|█▎ | 5/40 [00:02<00:17, 1.98it/s]
115 开始
15%|█▌ | 6/40 [00:02<00:16, 2.05it/s]
116 开始
18%|█▊ | 7/40 [00:03<00:15, 2.11it/s]
117 开始
20%|██ | 8/40 [00:03<00:14, 2.14it/s]
118 开始
22%|██▎ | 9/40 [00:04<00:14, 2.10it/s]
119 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
25%|██▌ | 10/40 [00:34<04:47, 9.58s/it]
主表更新完成 119 结束 120 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成
28%|██▊ | 11/40 [00:38<03:53, 8.07s/it]
当前批次数据写入完成 主表更新完成 120 结束 121 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成
30%|███ | 12/40 [00:41<03:01, 6.47s/it]
当前批次数据写入完成 主表更新完成 121 结束 122 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成
32%|███▎ | 13/40 [00:44<02:22, 5.28s/it]
当前批次数据写入完成 主表更新完成 122 结束 123 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成
35%|███▌ | 14/40 [00:47<02:00, 4.65s/it]
当前批次数据写入完成 主表更新完成 123 结束 124 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成
38%|███▊ | 15/40 [00:50<01:46, 4.27s/it]
当前批次数据写入完成 主表更新完成 124 结束 125 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成
40%|████ | 16/40 [00:56<01:53, 4.71s/it]
当前批次数据写入完成 主表更新完成 125 结束 126 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
42%|████▎ | 17/40 [01:44<06:46, 17.66s/it]
主表更新完成 126 结束 127 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
45%|████▌ | 18/40 [02:37<10:24, 28.39s/it]
主表更新完成 127 结束 128 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
48%|████▊ | 19/40 [03:17<11:05, 31.67s/it]
主表更新完成 128 结束 129 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
50%|█████ | 20/40 [03:51<10:51, 32.59s/it]
主表更新完成 129 结束 130 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
52%|█████▎ | 21/40 [04:34<11:16, 35.63s/it]
主表更新完成 130 结束 131 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
55%|█████▌ | 22/40 [05:31<12:35, 41.97s/it]
主表更新完成 131 结束 132 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
57%|█████▊ | 23/40 [06:13<11:56, 42.13s/it]
主表更新完成 132 结束 133 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
60%|██████ | 24/40 [07:04<11:53, 44.57s/it]
主表更新完成 133 结束 134 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
62%|██████▎ | 25/40 [07:50<11:18, 45.22s/it]
主表更新完成 134 结束 135 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
65%|██████▌ | 26/40 [08:35<10:31, 45.09s/it]
主表更新完成 135 结束 136 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
68%|██████▊ | 27/40 [09:22<09:52, 45.54s/it]
主表更新完成 136 结束 137 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成
70%|███████ | 28/40 [09:26<06:37, 33.15s/it]
当前批次数据写入完成 主表更新完成 137 结束 138 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
72%|███████▎ | 29/40 [10:31<07:49, 42.68s/it]
主表更新完成 138 结束 139 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成 主表更新完成
75%|███████▌ | 30/40 [11:49<08:53, 53.38s/it]
139 结束 140 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
78%|███████▊ | 31/40 [13:07<09:06, 60.74s/it]
主表更新完成 140 结束 141 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
80%|████████ | 32/40 [13:17<06:04, 45.61s/it]
主表更新完成 141 结束 142 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
82%|████████▎ | 33/40 [13:58<05:09, 44.25s/it]
主表更新完成 142 结束 143 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成 主表更新完成
85%|████████▌ | 34/40 [15:06<05:07, 51.32s/it]
143 结束 144 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
88%|████████▊ | 35/40 [15:46<03:59, 47.85s/it]
主表更新完成 144 结束 145 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
90%|█████████ | 36/40 [16:53<03:34, 53.61s/it]
主表更新完成 145 结束 146 开始
C:\Users\Admin\AppData\Local\Temp\ipykernel_34964\4122513777.py:65: UserWarning: DataFrame columns are not unique, some columns will be omitted. rows = df.to_dict(orient='records') # 转为 list of dict
到这儿了 到这儿了 临时表清空完成 当前批次数据写入完成
100%|██████████| 40/40 [17:10<00:00, 25.76s/it]
主表更新完成 146 结束 147 开始 148 开始 149 开始