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

174 lines
6.8 KiB
Python
Raw Permalink 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中有但供应商为空的补充
规则:
1. 内料(-NL/【内料】): 去掉 -NL 后缀,找到主产品,继承主产品的供应商
2. CSV中有记录但供应商为空的包材: 去掉后缀找主产品继承
3. CSV中有记录且有供应商的:不再处理(v2已完成)
"""
import csv
import pymysql
from config import DB_CONFIG
CSV_FILE = "/home/gxd/.openclaw/workspace-dingtalk-assistant/media/inbound/采购订单-20260531-1780213945661.csv"
def strip_suffix(code):
"""去掉已知后缀返回base_code"""
SUFFIXES = [
'-FM/GZ', '-TMGJ-NL', '-ALJK-BT', '-ALJK-FM/GZ',
'-TM-BT', '-TM-PZ', '-TM-CH', '-TM-BQ', '-TM-SSM',
'-TM-HMT', '-TM-RG', '-TM-GZ', '-TM-FM/GZ',
'-PDD-BT', '-PDD-PZ', '-PDD-CH', '-PDD-HMT',
'-NL', '-BT', '-PZ', '-CH', '-BQ', '-SSM', '-HMT',
'-RG', '-GZ', '-JD', '-PDD', '-ALJK', '-TM',
'-WPH', '-DW',
]
for s in SUFFIXES:
if code.endswith(s):
base = code[:-len(s)]
if base:
return base
return code
def main():
conn = pymysql.connect(**DB_CONFIG)
cur = conn.cursor()
# 1. 读取CSV——构建精确匹配索引
csv_best = {}
with open(CSV_FILE, encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
for row in reader:
code = row["物料编码"].strip()
supplier = row["供应商"].strip()
price_str = row["含税单价"].strip()
try:
price = float(price_str) if price_str else None
except ValueError:
price = None
if code not in csv_best:
csv_best[code] = (supplier, price)
else:
old_sup, old_price = csv_best[code]
if supplier and not old_sup:
csv_best[code] = (supplier, old_price if old_price is not None else price)
if old_price is None and price is not None:
csv_best[code] = (old_sup if old_sup else supplier, price)
print(f"CSV唯一物料编码: {len(csv_best)}")
# 2. 找出所有包材类且supplier_name_match为空的产品
keywords = ['瓶子','泵头','彩盒','海绵头','瓶贴','标签','收缩膜','瓶体','瓶标','软管','盖子','膜袋','标贴','唇膏管','内料','海绵','瓶子+内塞','泵头','瓶标','海绵头']
clauses = " OR ".join(["product_name LIKE '%%{}%%'".format(k) for k in keywords])
cur.execute("""
SELECT id, product_code, product_name, cost_price
FROM products
WHERE ({}) AND (supplier_name_match IS NULL OR supplier_name_match = '')
""".format(clauses))
need_fix = cur.fetchall()
print(f"需要修复的包材(当前supplier为空): {len(need_fix)}")
# 3. 加载所有产品的supplier_name_match(包括已有值的),用于继承
cur.execute("SELECT product_code, supplier_name_match, cost_price FROM products")
all_prod = {}
for code, sup, price in cur.fetchall():
all_prod[code.strip()] = {
'supplier': sup or '',
'cost_price': float(price) if price else 0
}
# 4. 逐个处理
update_1 = [] # 内料继承主产品供应商
update_2 = [] # CSV中供应商为空但可继承主产品的
update_3 = [] # 通过找主产品获得供应商(其他后缀)
for pid, product_code, product_name, old_price in need_fix:
code = product_code.strip()
is_nl = code.endswith('-NL') or '【内料】' in product_name
new_supplier = None
# 4a. 检查CSV是否有该编码且供应商不为空
if code in csv_best:
csv_sup, csv_price = csv_best[code]
if csv_sup:
# CSV有供应商——v2应该已经覆盖了,但如果还没覆盖到
new_supplier = csv_sup
new_price = csv_price if csv_price is not None else (float(old_price) if old_price else None)
update_2.append((new_supplier, new_price, pid))
continue
# 4b. 去掉后缀找主产品
base_code = strip_suffix(code)
if base_code and base_code != code and base_code in all_prod:
base = all_prod[base_code]
if base['supplier']:
new_supplier = base['supplier']
# 4c. 对于内料,特别处理:多剥一层后缀
if not new_supplier and is_nl:
# 去-NL后缀后再去一次
stripped = code
if stripped.endswith('-NL'):
stripped = stripped[:-3]
# 再去其他后缀
base_code2 = strip_suffix(stripped)
if base_code2 and base_code2 in all_prod:
base = all_prod[base_code2]
if base['supplier']:
new_supplier = base['supplier']
if new_supplier:
new_price = float(old_price) if old_price else None
if is_nl:
update_1.append((new_supplier, new_price, pid))
else:
update_2.append((new_supplier, new_price, pid))
print(f"\n内料继承主产品供应商: {len(update_1)}")
print(f"其他后缀继承主产品供应商: {len(update_2)}")
print(f"仍然无法匹配: {len(need_fix) - len(update_1) - len(update_2)}")
# 5. 批量更新
def run_updates(label, updates_data):
if not updates_data:
return
sql = "UPDATE products SET supplier_name_match=%s, cost_price=%s WHERE id=%s"
n = 0
for i in range(0, len(updates_data), 500):
batch = updates_data[i:i+500]
cur.executemany(sql, batch)
conn.commit()
n += len(batch)
print(f" {label}: {n} 条已更新")
run_updates("内料继承", update_1)
run_updates("其他继承", update_2)
# 6. 最终统计
cur.execute("SELECT COUNT(*) FROM products WHERE ({}) AND (supplier_name_match IS NULL OR supplier_name_match = '')".format(clauses))
still_empty = cur.fetchone()[0]
print(f"\n修复后,包材仍然为空: {still_empty}")
# 按后缀分类查看剩余为空的情况
if still_empty > 0:
cur.execute("""
SELECT product_code, product_name FROM products
WHERE ({}) AND (supplier_name_match IS NULL OR supplier_name_match = '')
""".format(clauses))
remain = cur.fetchall()
nl_left = sum(1 for c, _ in remain if c.endswith('-NL'))
print(f" 其中-NL内料: {nl_left}")
print(f" 其他: {still_empty - nl_left}")
cur.execute("SELECT COUNT(*) FROM products WHERE supplier_name_match != ''")
total_sup = cur.fetchone()[0]
print(f"\n全部产品有供应商: {total_sup}")
conn.close()
print("\n✅ 完成!")
if __name__ == "__main__":
main()