dy-dashboard/sync_inventory_0531.py
2026-10-28 11:14:17 +08:00

156 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""
批量下载并导入钉盘库存CSV(20260531版本)
流程:
1. dws doc list 获取所有文件列表(已完成)
2. 按文件名匹配仓库编码,下载每个文件
3. 解析CSV(GBK→UTF-8),合并写入 inventory_detail
4. 清空旧数据,插入新数据
"""
import json, subprocess, csv, io, os, re
from config import DB_CONFIG
import pymysql
from datetime import datetime
FOLDER_ID = "NkDwLng8ZLGrXmrnFxYq3vRqVKMEvZBY"
DATA_DATE = "2026-05-31"
def dws(args):
result = subprocess.run(["dws"] + args.split(), capture_output=True, text=True, timeout=60)
return json.loads(result.stdout)
def main():
# 1. 列出文件夹中所有文件
print("📋 获取文件列表...")
result = dws(f"doc list --folder {FOLDER_ID}")
files = []
for n in result['nodes']:
name = n['name']
ext = n.get('extension', '')
if ext != 'csv':
continue
# 提取仓库编码(文件名不包含扩展名)
m = re.search(r'-(\d+)$', name)
if not m:
continue
wh_code = m.group(1)
if len(wh_code) == 1:
wh_code = '0' + wh_code
files.append({
'name': name,
'node_id': n['nodeId'],
'wh_code': wh_code,
'date_part': name[:8] if len(name) >= 8 else ''
})
# 只处理最新日期的文件
new_files = [f for f in files if f['date_part'] == '20260531']
print(f"找到 {len(new_files)} 个新文件(20260531)")
conn = pymysql.connect(**DB_CONFIG)
cur = conn.cursor()
total_rows = 0
all_rows = []
for f in new_files:
print(f" ⬇️ 下载 {f['name']} (仓库{f['wh_code']})...")
dl = dws(f"doc download --node {f['node_id']}")
url = dl.get('resourceUrl', dl.get('cdnUrl', ''))
if not url:
print(f" ❌ 无下载链接")
continue
resp = subprocess.run(["curl", "-s", url], capture_output=True, timeout=120)
raw = resp.stdout
# 尝试GBK解码
try:
text = raw.decode('gbk')
except:
try:
text = raw.decode('utf-8-sig')
except:
text = raw.decode('utf-8', errors='ignore')
# 跳过BOM
if text.startswith('\ufeff'):
text = text[1:]
# 解析CSV
reader = csv.DictReader(io.StringIO(text))
count = 0
for row in reader:
# 字段可能有BOM前缀,清洗
cleaned = {}
for k, v in row.items():
k2 = k.strip().replace('\ufeff', '').replace('"', '')
cleaned[k2] = (v or '').strip()
product_code = cleaned.get('货品编号', cleaned.get('商品编码', '')).strip()
product_name = cleaned.get('货品名称', '')
brand = cleaned.get('品牌', '')
cost_price = cleaned.get('成本价', cleaned.get('单价', '0'))
available_qty = cleaned.get('可用库存', '0')
prod_transit = cleaned.get('生产在途', '0')
purch_transit = cleaned.get('采购在途量', cleaned.get('采购在途', '0'))
category1 = cleaned.get('一级类目', '')
category2 = cleaned.get('二级类目', '')
category3 = cleaned.get('三级类目', '')
created_time = cleaned.get('单品创建时间', cleaned.get('创建时间', ''))
if not product_code:
continue
all_rows.append((
DATA_DATE, '旺店通', f['wh_code'],
product_code, product_code, product_name, brand,
float(cost_price) if cost_price else 0,
int(float(available_qty)) if available_qty else 0,
int(float(prod_transit)) if prod_transit else 0,
int(float(purch_transit)) if purch_transit else 0,
category1, category2, category3,
created_time
))
count += 1
total_rows += count
print(f" ✅ {count} 条")
print(f"\n📊 共读取 {total_rows} 条数据")
# 2. 清空旧数据(该日期的)
cur.execute("DELETE FROM inventory_detail WHERE data_date=%s", (DATA_DATE,))
deleted = cur.rowcount
print(f"🗑️ 已清空 {DATA_DATE} 旧数据: {deleted} 条")
# 3. 批量插入
if total_rows > 0:
insert_sql = """INSERT INTO inventory_detail
(data_date, source, warehouse_code, goods_code, product_code,
product_name, brand, cost_price, available_qty,
production_in_transit, purchase_in_transit,
category1, category2, category3, created_time)
VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"""
batch_size = 500
inserted = 0
for i in range(0, len(all_rows), batch_size):
batch = all_rows[i:i+batch_size]
cur.executemany(insert_sql, batch)
conn.commit()
inserted += len(batch)
if inserted % 2000 == 0:
print(f" 💾 已写入 {inserted}/{total_rows}")
print(f"✅ 写入完成: {inserted} 条")
# 4. 统计
cur.execute("SELECT COUNT(*) FROM inventory_detail WHERE data_date=%s", (DATA_DATE,))
final_count = cur.fetchone()[0]
print(f"\n📈 {DATA_DATE} 库存数据共 {final_count} 条")
conn.close()
if __name__ == "__main__":
main()