备货相关

This commit is contained in:
Wenxixi 2025-11-28 17:52:27 +08:00
parent c89ad5f159
commit 6e14684f5d
1 changed files with 310 additions and 0 deletions

310
备货.ipynb Normal file
View File

@ -0,0 +1,310 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"一stock_date表示备货日期"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 取备货时间date符合方案的SKU\n",
"\"\"\"\n",
"1.订单上线时间三个月以上\n",
"2.前一个月订单数>=4或前两个月订单数>=5\n",
"数据提取方案:\n",
"1.设置变量stock_date为备货时间\n",
"2.计算出stock_date的两个月前的order_date2和一个月前的order_date1\n",
"3.查询order_date1至stock_date的订单数和order_date2至stock_date的订单数\n",
"4.筛选出order_date1至stock_date的订单数>=4或order_date2至stock_date的订单数>=5的SKU\n",
"5.计算上线时间和date的差值,筛选>3个月天的产品\n",
"\"\"\"\n",
"import pandas as pd\n",
"import numpy as np\n",
"from datetime import datetime\n",
"from dateutil.relativedelta import relativedelta\n",
"\n",
"stock_date = '2025-11-18'\n",
"stock_datetime = datetime.strptime(stock_date, '%Y-%m-%d')\n",
"\n",
"# 计算一个月前和两个月前\n",
"order_date1 = (stock_datetime - relativedelta(months=1)).strftime('%Y-%m-%d') # 一个月前订单时间\n",
"order_date2 = (stock_datetime - relativedelta(months=2)).strftime('%Y-%m-%d') # 两个月前订单时间\n",
"online_date = (stock_datetime - relativedelta(months=3)).strftime('%Y-%m-%d') # 上线时间\n",
"\n",
"after_date1 = (stock_datetime + relativedelta(months=1)).strftime('%Y-%m-%d') # 一个月后订单时间\n",
"after_date2 = (stock_datetime + relativedelta(months=2)).strftime('%Y-%m-%d') # 两个月后订单时间\n",
"after_date3 = (stock_datetime + relativedelta(months=3)).strftime('%Y-%m-%d') # 三个月后订单时间\n",
"after_date4 = (stock_datetime + relativedelta(months=4)).strftime('%Y-%m-%d') # 四个月后订单时间\n",
"\n",
"print(after_date1, after_date2, after_date3, after_date4, order_date1,order_date2,online_date)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"当前板块直接跑是计算美国区的备货情况如果需要看全球的请搜索delivery_country并把这行注释掉在sql里"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 读取订单数据\n",
"from utils.gtools import MySQLconnect\n",
"with MySQLconnect('ods') as db:\n",
" enginal = db.engine()\n",
" sql = f\"\"\"\n",
" # 取采购价\n",
" with \n",
" pur_cost AS (\n",
" SELECT\n",
" SUBSTRING_INDEX(opl.order_product_id, '_', 2) AS order_product_id,\n",
" SUM(actual_price) AS 采购成本,\n",
" SKU,\n",
" ROW_NUMBER() OVER (PARTITION BY SKU ORDER BY order_date DESC) as rn\n",
" FROM\n",
" dws.order_product_list opl\n",
" LEFT JOIN ods.warehouse_purchasing wp ON opl.order_product_id = wp.order_product_id\n",
" WHERE\n",
" NOT EXISTS (\n",
" SELECT 1 \n",
" FROM dws.log_order_reissue_detail AS r \n",
" WHERE left(r.order_product_id,15) = opl.order_id)\n",
" AND order_date >= '{order_date1}'\n",
" AND order_date < '{stock_datetime}'\n",
" AND opl.fun_audit NOT REGEXP \"等待\"\n",
" AND opl.site_name REGEXP \"Litfad\"\n",
" AND opl.product_audit REGEXP \"采购完成\"\n",
" AND opl.SKU IS NOT NULL and opl.SKU <>0\n",
" GROUP BY \n",
" SUBSTRING_INDEX(opl.order_product_id, '_', 2) \n",
"\n",
" ),\n",
" t1 AS (\n",
" SELECT\n",
" spu.`产品品类`,\n",
" spu.`产品分类`,\n",
" pc.采购成本,\n",
" opl.SKU,\n",
" COUNT(DISTINCT CASE WHEN DATE_FORMAT(opl.order_date, '%%Y-%%m-%%d') >= '{order_date2}' and DATE_FORMAT(opl.order_date, '%%Y-%%m-%%d') < '{order_date1}' THEN opl.order_id END) AS 前第二月订单数,\n",
" COUNT(DISTINCT CASE WHEN DATE_FORMAT(opl.order_date, '%%Y-%%m-%%d') >= '{order_date1}' and DATE_FORMAT(opl.order_date, '%%Y-%%m-%%d') < '{stock_datetime}' THEN opl.order_id END) AS 前一月订单数,\n",
" SUM(CASE WHEN (DATE_FORMAT(opl.order_date, '%%Y-%%m-%%d') >= '{stock_datetime}' AND DATE_FORMAT(opl.order_date, '%%Y-%%m') < '{after_date1}') \n",
" THEN opl.product_num ELSE 0 END) AS 后第一月产品数,\n",
" SUM(CASE WHEN (DATE_FORMAT(opl.order_date, '%%Y-%%m') >= '{after_date1}' AND DATE_FORMAT(opl.order_date, '%%Y-%%m-%%d') <'{after_date2}') \n",
" THEN opl.product_num ELSE 0 END) AS 后第两月产品数,\n",
" SUM(CASE WHEN (DATE_FORMAT(opl.order_date, '%%Y-%%m') >= '{after_date2}' AND DATE_FORMAT(opl.order_date, '%%Y-%%m') < '{after_date3}') \n",
" THEN opl.product_num ELSE 0 END) AS 后第三月产品数,\n",
" SUM(CASE WHEN DATE_FORMAT(opl.order_date, '%%Y-%%m') >= '{after_date3}' \n",
" THEN opl.product_num ELSE 0 END) AS 后第四月产品数,\n",
" DATE_FORMAT(sku.添加时间,'%%Y-%%m-%%d') AS 上线时间,\n",
" DATE_FORMAT(sku.更新时间,'%%Y-%%m-%%d') AS 更新时间\n",
" \n",
" FROM\n",
" dws.order_product_list opl\n",
" LEFT JOIN pur_cost pc ON opl.SKU = pc.SKU \n",
" LEFT JOIN ods.order_list ol ON opl.order_id =ol.order_id\n",
" LEFT JOIN ods.stg_bayshop_litfad_sku sku ON opl.SKU = sku.SKU\n",
" LEFT JOIN ods.stg_bayshop_litfad_spu spu ON sku.`产品PID` = spu.`产品PID` \n",
" WHERE\n",
" opl.order_date >= '{order_date2}'\n",
" AND DATE_FORMAT(opl.order_date, '%%Y-%%m') < '{after_date4}'\n",
" AND DATE_FORMAT(sku.添加时间,'%%Y-%%m-%%d') < '{online_date}'\n",
" AND opl.SKU IS NOT NULL and opl.SKU <>0\n",
" AND opl.order_product_id NOT REGEXP '^[^_]*_[^_]*_[^_]*$'\n",
" AND site_type REGEXP \"独立站\"\n",
" AND ol.fund_status NOT REGEXP \"等待\"\n",
" and sku.状态 REGEXP \"启用\"\n",
" AND spu.状态 REGEXP \"正常\"\n",
" AND 采购成本>0\n",
" AND rn = 1\n",
" and 产品品类 <> \"126 - Outdoor\"\n",
" and 产品品类 <>\"57 - Rugs\"\n",
" and 产品分类 <> \"151 - Peel & Stick Backsplash Tile\"\n",
" and 产品分类 <> \"138 - Bathroom Sinks\"\n",
" and 产品分类 <> \"184 - Toddler & Kids Chairs\"\n",
" and opl.delivery_country regexp \"United States\"\n",
" GROUP BY opl.SKU\n",
" )\n",
" \n",
" \n",
" SELECT \n",
" 产品品类,\n",
" 产品分类,\n",
" SKU,\n",
" 采购成本,\n",
" 前第二月订单数+前一月订单数 AS 前两月订单数,\n",
" 前一月订单数 AS 备货数,\n",
" 后第一月产品数,\n",
" 后第两月产品数,\n",
" 后第三月产品数,\n",
" 后第四月产品数,\n",
" (后第一月产品数+后第两月产品数+后第三月产品数+后第四月产品数) AS 后四月总产品数\n",
" FROM \n",
" t1\n",
" WHERE\n",
" 前一月订单数 >=4 OR (前一月订单数>=2 AND (前第二月订单数+前一月订单数)>=5)\n",
" ORDER BY 前一月订单数 DESC\n",
" \"\"\"\n",
" df = pd.read_sql(sql, enginal)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 取上诉SKU的体积\n",
"import pandas as pd\n",
"from utils.gtools import MySQLconnect\n",
"\n",
"sku_list = (\n",
" df['SKU']\n",
" .apply(pd.to_numeric, errors='coerce')\n",
" .dropna()\n",
" .astype(int)\n",
" .astype(str)\n",
" .drop_duplicates() # 加这一行\n",
" .tolist()\n",
")\n",
"\n",
"# 读取需要计算的包裹信息\n",
"with MySQLconnect('ods') as db:\n",
" enginal = db.engine()\n",
" quoted_spus = ','.join([f\"'{sku}'\" for sku in sku_list])\n",
" sql = f\"\"\" \n",
" WITH\n",
" t1 AS (\n",
" SELECT\n",
" opl.order_id,\n",
" SKU,\n",
" ol.order_price_dollar AS 订单售价,\n",
" sum(CASE WHEN opl.order_product_id REGEXP \"[0-9]{{15}}_[0-9]*$\"\n",
" THEN product_num END) AS product_num,\n",
" count(DISTINCT opl.SKU) AS 产品种类\n",
" FROM\n",
" dws.order_product_list opl\n",
" left join ods.order_list ol ON opl.order_id = ol.order_id\n",
" WHERE\n",
" NOT EXISTS (\n",
" SELECT 1 \n",
" FROM dws.log_order_reissue_detail AS r \n",
" WHERE left(r.order_product_id,15) = opl.order_id\n",
" \n",
" )\n",
" and opl.delivery_country regexp \"United States\"\n",
" AND SKU in ({quoted_spus})\n",
" AND SKU <> \"\" AND SKU IS NOT NULL AND SKU <> 0\n",
" GROUP BY order_id\n",
" ),\n",
" t2 AS (\n",
" SELECT \n",
" t1.SKU,\n",
" 订单售价,\n",
" round(SUM(b.weight/1000 ),0)AS 重量,\n",
" ROUND(SUM(b.length*b.width*b.hight/1000000),2) AS 体积,\n",
" COUNT(package) AS 包裹数\n",
" FROM\n",
" t1\n",
" LEFT JOIN order_express a ON t1.order_id = a.单号\n",
" JOIN package_vol_info b ON a.`包裹号` = b.package\n",
" WHERE\n",
" a.`包裹状态` = '客户签收'\n",
" AND b.hight > 0 \n",
" AND b.length > 0 \n",
" AND b.width > 0 \n",
" AND b.hight > 0 \n",
" AND b.weight > 0\n",
" AND t1.product_num = 1\n",
" AND t1.产品种类=1\n",
" GROUP BY order_id\n",
" )\n",
" SELECT\n",
" SKU,\n",
" AVG(订单售价) AS 订单平均售价,\n",
" AVG(重量) AS 平均重量,\n",
" AVG(体积) AS 平均体积\n",
" FROM t2\n",
" GROUP BY SKU\n",
" \n",
"\n",
" \"\"\"\n",
" package_df = pd.read_sql(sql, enginal)\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"all_df = pd.merge(df, package_df, on='SKU', how='left')\n",
"all_df"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 处理每个条目的不同备货要求\n",
"# 66 - Furniture\n",
"fir_df = all_df[\n",
" ((all_df['产品品类'] == '66 - Furniture') & (all_df['前两月订单数'] >5))|\n",
" ((all_df['产品品类'] == '1 - Lighting' )& (all_df['前两月订单数'] >5))]\n",
"\n",
"fir_df"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"len(fir_df)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fir_df.to_clipboard(index = False)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "base",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.5"
}
},
"nbformat": 4,
"nbformat_minor": 2
}