🤖 每日自动备份 - 2026-06-15 08:00:01

This commit is contained in:
小溪 2026-06-15 08:00:01 +08:00
parent f4fac513f0
commit 4135e93b17
7 changed files with 1149 additions and 11 deletions

View File

@ -1,6 +1,6 @@
{
"version": 1,
"updatedAt": "2026-06-09T07:36:53.566Z",
"updatedAt": "2026-06-14T07:14:40.970Z",
"entries": {
"memory:memory/2026-05-06.md:1:20": {
"key": "memory:memory/2026-05-06.md:1:20",
@ -462,22 +462,25 @@
"endLine": 30,
"source": "memory",
"snippet": "# 2026-06-02 工作日志 ## 微伴线索更新 - [陈逸鸫] 提供微伴导出数据更新6/1-6/2线索 - 映射确认:益达老师 = 小龙 - 写入结果:小龙表+50条6/1 25+6/2 25吴迪表+15条6/1 - ⚠️ 首次写入时重复了小龙24行+吴迪2行已清理 - 每日线索汇总已修正6/1 小龙25 吴迪15 / 6/2 小龙25 ## Tom/Bob 6月不接小红书线索 - [陈逸鸫] 告知 Tom 和 Bob 6月开始不接小红书线索了 - 微伴数据确认6/1-6/2 Tom/Bob 新增为0 ## 订单汇总 2smjwA 全量覆盖进展 - Cursor 确认方案:数据库 bi_vala_order 为唯一源,全量覆盖 2smjwA - 数据库匹配到 390 单销转团队线索关联按月3月88/4月158/5月138/6月6 - 看板去重后 406 单,差异 40 单已分类: - 有uid无订单 8单 - 金额对不上 6单 - 未注册用户 10单 - 昵称为空 2单 - 2025年订单 6单不纳入 - 重复录入 1单孙婧 - 已有但key比对误差 7单 - 26 单待杨羽确认,清单已发群 - 闸门:杨羽确认 → v2 数据 → 备份→清空→覆盖→挂定时 ## 看板全量审计 - 13 张 sheet 全部扫完,公式引用正确,无硬值 - Cursor 补修:关键投放数据 Row131 裸IF包IFERROR、销售结算 M1/M2 废弃清空、每日线索月合计行金色",
"recallCount": 4,
"recallCount": 6,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 4,
"totalScore": 6,
"maxScore": 1,
"firstRecalledAt": "2026-06-03T00:01:27.128Z",
"lastRecalledAt": "2026-06-05T14:06:12.562Z",
"lastRecalledAt": "2026-06-14T07:14:40.970Z",
"queryHashes": [
"5f57ba3c20a6",
"b76e8457b2ee",
"4354c1e39886",
"70f4bbaea7b1"
"70f4bbaea7b1",
"d26345ebc273",
"cd28f28f1a7c"
],
"recallDays": [
"2026-06-03",
"2026-06-05"
"2026-06-05",
"2026-06-14"
],
"conceptTags": [
"备份",
@ -601,18 +604,20 @@
"endLine": 33,
"source": "memory",
"snippet": "- 抖音+联报退费率最高49.2%也是最大组合124单 - **分析脚本:** `scripts/channel_lead_refund_analysis.py` ## 王虹茗 - V2修正纳入多角色因素 - **反馈:** 指出 Sheet2 一个用户可能创建多个角色,要求重新分析 - **关键修正:** - 按用户聚合时保留角色数量、创建节奏、行课覆盖等信息 - 行课行为以\"任一角色完成即算\"聚合 - **新增发现:** - 1个角色退费率46.7% > 2个角色34.8% > ≥4个角色28.6%(角色越多退费越低) - 同日多角色45.7% vs 1周以上多角色28.6%(跨时间创建=持续使用信号) - 全角色无行课退费率75.9%(最高危) - 1角色+无行课=76.0%最危险组合≥4角色+有行课=16.7%(最安全) - **输出文件:** `output/渠道4-5月线索_退款相关性分析_v2_20260519_202711.xlsx`20个维度+明细) - **分析脚本:** `scripts/channel_lead_refund_analysis_v2.py`",
"recallCount": 1,
"recallCount": 2,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"totalScore": 2,
"maxScore": 1,
"firstRecalledAt": "2026-06-05T00:46:22.699Z",
"lastRecalledAt": "2026-06-05T00:46:22.699Z",
"lastRecalledAt": "2026-06-14T06:58:06.164Z",
"queryHashes": [
"34106cf619c4"
"34106cf619c4",
"6769ba9ebb36"
],
"recallDays": [
"2026-06-05"
"2026-06-05",
"2026-06-14"
],
"conceptTags": [
"联报退费率最高49.2",
@ -624,6 +629,68 @@
"全角色无行课退费率75.9",
"76.0"
]
},
"memory:memory/2026-06-12.md:18:38": {
"key": "memory:memory/2026-06-12.md:18:38",
"path": "memory/2026-06-12.md",
"startLine": 18,
"endLine": 38,
"source": "memory",
"snippet": "| 6 | 小乖大人 | 16158 | 13944890221 | 3/1 | 无订单 | - | 0 | 0 | DB无任何订单 | | 7 | 潘潘 | 16150 | 18610935696 | 3/1 | 无订单 | - | 0 | 0 | DB无任何订单 | | 8 | 张滢ya | 17894 | 13799768340 | 3/7 | 无订单 | - | 0 | 0 | DB无任何订单 | | 9 | sallywu | 17816 | 15998103065 | 3/7 | 无订单 | - | 0 | 0 | DB无任何订单 | | 10 | 🦁萨摩 | 21858 | 13685553716 | 3/8 | 4/8 | ✓ | 1999 | 1999 | 达人-学霸三人行 | ### Group B (有手机4笔) - phone_encrypt查UID | # | 昵称 | 手机 | 加密结果 | DB匹配 | |---|------|------|---------|--------| | 11 | 潘提提 | 13427741613 | IiShdIaiY1oy7B_Xn4EH3g.. | 无匹配 | | 12 | 狸小路 | 18622850293 | YPAQ-740vKwxroqZGkeGyQ.. | 无匹配 | | 13 | 希小希 | 18086665321 | c8zfpqBrN1nikMkwAj64aQ.. | 无匹配 | | 14 | 曼 | 13520255515 | NBVtGuxEge7f7hdkyK3y7Q.. | 无匹配",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-06-14T06:58:06.164Z",
"lastRecalledAt": "2026-06-14T06:58:06.164Z",
"queryHashes": [
"6769ba9ebb36"
],
"recallDays": [
"2026-06-14"
],
"conceptTags": [
"3/1",
"3/7",
"3/8",
"4/8",
"达人-学霸三人行",
"phone-encrypt查uid",
"iishdiaiy1oy7b-xn4eh3g",
"ypaq-740vkwxroqzgkegyq"
]
},
"memory:memory/2026-06-12.md:35:56": {
"key": "memory:memory/2026-06-12.md:35:56",
"path": "memory/2026-06-12.md",
"startLine": 35,
"endLine": 56,
"source": "memory",
"snippet": "| 15 | Rachel | 3/5 | 10994 | 13510564547 | 3/7 | ✓ | sales-adp-bj-jxl-0, GMV=1999 | | 16 | soul | 3/2 | 17387 | 15640464255 | 3/12 | ✓ | sales-adp-bj-jxl-0, GMV=1999 | | 17 | 红 | 3/7 | 17025 | 13533955004 | 3/14 | ✓ | sales-adp-bj-jxl-0, GMV=1999 | | 18 | 一笑轩渠 | 3/8 | 17425 | 15017528458 | 3/11 | ✓ | sales-adp-bj-jxl-0, GMV=1999 | | 19 | 蜗牛 | 3/2 | ❓ | ❓ | ❓ | - | 晚柠5/15订单数百笔无手机/UID无法定位 | | 20 | c_瑶 | 3/6 | ❓ | ❓ | ❓ | - | \"直购\"渠道DB不存在3/14无3998/1999匹配 | ### 关键发现 1. Group A 中 7/10 用户 DB 中无任何订单pre汇总有GMV但DB不存在 2. Group B 4个手机号全部未注册H=未注册 确认正确) 3. Group C #15-#18 4笔 jxl-0 均 L≥Cpre怀疑#18 L<C不成立 4. #19 蜗牛和 #20 c_瑶 无法定位 ## 陈逸鸫 - full_refresh (S2+S3) 联调 ### 执行记录 - 时间2026-06-12 18:00 左右 - S2",
"recallCount": 1,
"dailyCount": 0,
"groundedCount": 0,
"totalScore": 1,
"maxScore": 1,
"firstRecalledAt": "2026-06-14T06:58:06.164Z",
"lastRecalledAt": "2026-06-14T06:58:06.164Z",
"queryHashes": [
"6769ba9ebb36"
],
"recallDays": [
"2026-06-14"
],
"conceptTags": [
"3/5",
"3/7",
"sales-adp-bj-jxl-0",
"3/2",
"3/12",
"3/14",
"3/8",
"3/11"
]
}
}
}

189
scripts/check_gap_57.py Normal file
View File

@ -0,0 +1,189 @@
#!/usr/bin/env python3
"""Check 57 gap orders against DB"""
import subprocess, json, re
# Gap data from chat: (month, source_sheet, sales, nickname, date_str, amount, channel, phone, has_clue, keyfrom, is_direct)
gaps = [
# === 3月 (20) ===
("3月","qX7oJ6","小龙","雪珂💗","3月6日",1999,"微信小店","","线索","sales-adp-bj-jxl-0",False),
("3月","qX7oJ6","小龙","Mars","3月7日",3598,"小红书-晚柠","","线索","",False),
("3月","qX7oJ6","小龙","薇薇","3月",1999,"小红书直购","13520306626","无线索","",True),
("3月","qX7oJ6","小龙","Yeah^_^","3月20日",3598,"小红书-晚柠","","线索","",False),
("3月","qX7oJ6","小龙","TutuTu","3月",1999,"小红书直购","18107332677","线索","",True),
("3月","qX7oJ6","小龙","EFFIE","3月25日",3598,"微信小店","","线索","newmedia-dianpu-xhs-0-0",False),
("3月","sSCT22","Tom","JeanneLᴇᴇ🦄","3月4日",3598,"微信小店","","线索","newmedia-dianpu-wxxd-0-0",False),
("3月","sSCT22","Tom","薇妮姐","3月8日",599,"端内","","线索","",False),
("3月","sSCT22","Tom","","3月7日",599,"端内","","线索","app-active-h5-0-0",False),
("3月","sSCT22","Bob","Mogu","3月6日",599,"端内","","线索","",False),
("3月","sSCT22","Bob","L. 一颗夹星糖🌟","3月12日",3598,"小红书-晚柠","","线索","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
("3月","sSCT22","Tom","阿雅呀","3月15日",3598,"小红书-晚柠","","线索","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
("3月","sSCT22","Tom","Anna","3月4日",1999,"抖音","","线索","newmedia-dianpu-douyin-0-0",True),
("3月","sSCT22","Bob","Echo Liang","3月15日",1999,"微信小店","","线索","sales-adp-cd-zjf-0",False),
("3月","sSCT22","Tom","幼兒園高材生🍼","3月23日",3598,"微信小店","13055770067","线索","sales-adp-cd-yy-0",False),
("3月","sSCT22","Tom","Nancy","3月26日",599,"端内","","线索","",False),
("3月","sSCT22","Tom","依米","3月30日",3598,"微信小店","","线索","sales-adp-cd-zjf-0",False),
("3月","sSCT22","Bob","zhouyun","3月6日",1999,"小红书-学霸老王","13588706769","线索","",False),
("3月","sSCT22","Tom","💗小超人棒棒哒🍭","3月29日",3598,"小红书-晚柠","18630368296","线索","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
("3月","sSCT22","Bob","鹿","3月14日",3598,"小红书-晚柠","","线索","",False),
# === 4月 (15) ===
("4月","qX7oJ6","小龙","琳溪","4月19日",3598,"微信小店","","线索","",False),
("4月","qX7oJ6","小龙","小丽","4月26日",599,"端内","","线索","",False),
("4月","qX7oJ6","小龙","子曦","4月16日",3598,"晚柠-小红书","","线索","",False),
("4月","qX7oJ6","小龙","Gaᴗao","4月24日",3598,"微信小店","","线索","",False),
("4月","XqxgjP","吴迪","ཚེ་རིང་མཚོ彩让措","2026/4/26",599,"端内","","无线索","",False),
("4月","XqxgjP","吴迪","莉筱雅","2026/4/27",1999,"晚柠-小红书","","线索","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
("4月","XqxgjP","吴迪","爱吃巧克力","2026/4/24",1999,"微信小店","","无线索","",False),
("4月","XqxgjP","吴迪","Aa~Jessie💝","2026/4/27",1999,"抖音","","线索","newmedia-dianpu-douyin-0-0",True),
("4月","XqxgjP","吴迪","🐷","2026/4/26",3598,"宣儿妈妈-小红书","","线索","sales-adp-cd-yy-0",False),
("4月","XqxgjP","吴迪","🐷","2026/4/26",3598,"宣儿妈妈-小红书","","线索","sales-adp-cd-yy-0",False), # dup
("4月","sSCT22","Tom","静静是我🍃","4月8日",1999,"小红书-学霸老王","15975769851","线索","partner-actives-0-0-0",False),
("4月","sSCT22","Bob","胆大鬼","4月8日",3598,"小红书-学霸老王","15262255267","线索","newmedia-daren-xhs-学霸老王讲真话-0",False),
("4月","sSCT22","Tom","希Cissy-427","4月27日",3598,"微信小店","","线索","",False),
("4月","sSCT22","Tom","Kerry","4月9日",3598,"微信小店","18328334683","线索","sales-adp-cd-yy-0",False),
("4月","sSCT22","Tom","SHAN_Q_Q","4月1日",3598,"小红书-官店","","无线索","",True),
# === 5月 (22) ===
("5月","qX7oJ6","小龙","Sia","5月9日",599,"微信小店","","线索","",False),
("5月","XqxgjP","吴迪","","2026/5/9",1999,"微信小店","","线索","sales-adp-bj-wd-0",False),
("5月","XqxgjP","吴迪","^_^","2026/5/16",3598,"晚柠-小红书","","线索","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
("5月","XqxgjP","吴迪","🌸白色铃兰🌸","2026/5/17",3598,"抖音","","无线索","",True),
("5月","XqxgjP","吴迪","咔咔","2026/5/7",3598,"微信小店","","线索","sales-adp-bj-wd-0",False),
("5月","XqxgjP","吴迪","梦马","2026/5/21",3598,"小红书","","线索","newmedia-dianpu-xhs-0-0",False),
("5月","XqxgjP","吴迪","梦马","2026/5/21",3598,"小红书","","线索","newmedia-dianpu-xhs-0-0",False), # dup
("5月","XqxgjP","吴迪","小西瓜","2026/5/30",1999,"微信小店","","无线索","",False),
("5月","XqxgjP","吴迪","","2026/5/9",1999,"微信小店","","线索","sales-adp-bj-wd-0",False), # dup
("5月","sSCT22","Bob","Yuki-515","5月15日",3598,"小红书-晚柠","","线索","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
("5月","sSCT22","Tom","冬-515","5月15日",1999,"小红书-晚柠","","线索","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
("5月","sSCT22","Bob","微笑向暖","5月4日",1999,"微信小店","","无线索","",False),
("5月","sSCT22","Bob","cici-511","5月11日",1999,"微信小店","","线索","sales-adp-cd-xsy-0",False),
("5月","sSCT22","Tom","🐷-519","5月19日",1999,"小红书-宣儿妈妈","","线索","",False),
("5月","sSCT22","Bob","妃-516","5月16日",1999,"微信小店","","线索","",False),
("5月","sSCT22","Tom","黄晔-516","5月16日",3598,"微信小店","","无线索","",False),
("5月","sSCT22","Tom","朵朵呀!","5月25日",1999,"微信小店","","线索","",False),
("5月","sSCT22","Tom","雷鸣-414","5月14日",599,"微信小店","","无线索","",False),
("5月","sSCT22","Tom","毛阿毛🐱-520","5月20日",1999,"小红书-官店","","无线索","",True),
("5月","sSCT22","Tom","____Miss_y-519","5月19日",599,"微信小店","","线索","",False),
("5月","sSCT22","Tom","Mandy-526","5月26日",1999,"微信小店","","无线索","",False),
("5月","sSCT22","Bob","Yoki-529","5月29日",1999,"微信小店","","线索","",False),
]
# Map channel names to key_from patterns
def channel_to_pattern(channel):
if "微信小店" in channel:
return "newmedia-dianpu-wxxd-0-0"
if "晚柠" in channel or "小红书-晚柠" in channel:
return "newmedia-daren-xhs-晚柠也是个妈妈了-0"
if "学霸老王" in channel and "小红书" in channel:
return "newmedia-daren-xhs-学霸老王讲真话-0"
if "学霸三人行" in channel:
return "newmedia-daren-xhs-学霸三人行-0"
if "学霸老王" in channel and "抖音" in channel:
return "newmedia-daren-douyin-学霸老王%"
if "宣儿妈妈" in channel:
return "newmedia-daren-xhs-宣儿妈妈%"
if "念妈" in channel:
return "newmedia-daren%念妈%"
if "端内" in channel:
return "app-active-h5-0-0"
if "抖音" in channel and "直购" not in channel:
return "newmedia-dianpu-douyin-0-0"
if "小红书-官店" in channel:
return "newmedia-dianpu-xhs-0-0"
if "小红书直购" in channel:
return "newmedia-dianpu-xhs-0-0"
if "小红书" in channel:
return "newmedia-dianpu-xhs-0-0"
return None
# For each gap, try to find matching order in DB
import os
PGPASS = "LdfjdjL83h3h3^$&**YGG*"
def parse_date(d):
d = d.replace("","").replace("","/").replace(" ","").strip()
if "/" in d:
parts = d.split("/")
if len(parts) < 2 or not parts[1]:
return None
m = int(parts[0])
day = int(parts[1])
return f"2026-{m:02d}-{day:02d}"
else:
return None
# Build a set of unique dates to query
dates = set()
for g in gaps:
d = parse_date(g[4])
if d:
dates.add(d)
# Query all matching orders in one go
date_conditions = " OR ".join([f"o.pay_success_date::date = '{d}'" for d in sorted(dates)])
sql = f"""
SELECT o.id, o.trade_no, o.pay_amount_int, to_char(o.pay_success_date,'YYYY-MM-DD') as pay_date,
o.key_from, o.order_status, o.account_id, a.tel, a.created_at::date as reg_date
FROM bi_vala_order o
JOIN bi_vala_app_account a ON o.account_id = a.id
WHERE a.status = 1
AND o.pay_success_date >= '2026-03-01' AND o.pay_success_date < '2026-06-01'
AND o.order_status IN (3, 4)
AND o.pay_amount_int IN (59900, 199900, 359800)
AND ({date_conditions})
ORDER BY o.pay_success_date, o.pay_amount_int, o.key_from;
"""
result = subprocess.run([
"psql", "-h", "bj-postgres-16pob4sg.sql.tencentcdb.com",
"-p", "28591", "-U", "ai_member", "-d", "vala_bi",
"-c", sql
], env={**os.environ, "PGPASSWORD": PGPASS}, capture_output=True, text=True, timeout=30)
# Parse results
orders = []
for line in result.stdout.strip().split("\n")[2:-1]: # skip header and footer
parts = line.split("|")
if len(parts) >= 9:
orders.append({
"id": parts[0].strip(),
"trade_no": parts[1].strip(),
"amount": int(parts[2].strip()) if parts[2].strip() else 0,
"pay_date": parts[3].strip(),
"key_from": parts[4].strip(),
"order_status": parts[5].strip(),
"account_id": parts[6].strip(),
"tel": parts[7].strip(),
"reg_date": parts[8].strip() if len(parts) > 8 else "",
})
print(f"Total orders found: {len(orders)}")
# Now match each gap
for i, g in enumerate(gaps):
month, src, sales, nick, date_str, amount, channel, phone, clue, keyfrom, is_direct = g
idx = i + 1
d = parse_date(date_str)
amount_int = amount * 100
# If phone provided, match by phone
if phone:
matched = [o for o in orders if o["tel"].replace("*","")[-4:] == phone[-4:] and o["pay_date"] == d and o["amount"] == amount_int] if d else []
if not matched and d:
matched = [o for o in orders if o["tel"].replace("*","")[-4:] == phone[-4:]]
else:
# Match by date + amount + channel pattern
pat = keyfrom if keyfrom else channel_to_pattern(channel)
if d and pat:
if "%" in pat:
matched = [o for o in orders if o["pay_date"] == d and o["amount"] == amount_int and pat.replace("%","") in o["key_from"]]
else:
matched = [o for o in orders if o["pay_date"] == d and o["amount"] == amount_int and o["key_from"] == pat]
elif d:
matched = [o for o in orders if o["pay_date"] == d and o["amount"] == amount_int]
else:
matched = []
status = "" if matched else ""
print(f"{idx}. [{month}] {sales} {nick} | {date_str} ¥{amount} {channel} | {status} | {len(matched)} matches")
if matched:
for m in matched:
print(f" -> order_id={m['id']} {m['pay_date']} ¥{m['amount']/100} {m['key_from'][:60]} status={m['order_status']} tel={m['tel']} reg={m['reg_date']}")

173
scripts/check_gap_57_v2.py Normal file
View File

@ -0,0 +1,173 @@
#!/usr/bin/env python3
"""Check 57 gap orders - efficient approach"""
import subprocess, os, re
PGPASS = "LdfjdjL83h3h3^$&**YGG*"
# Gap data extracted from chat history
gaps = [
# 3月 (20)
(1,"3月","qX7oJ6","小龙","雪珂💗","3月6日",1999,"微信小店","","sales-adp-bj-jxl-0"),
(2,"3月","qX7oJ6","小龙","Mars","3月7日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0"),
(3,"3月","qX7oJ6","小龙","薇薇","3月",1999,"小红书直购","13520306626","newmedia-dianpu-xhs-0-0"),
(4,"3月","qX7oJ6","小龙","Yeah^_^","3月20日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0"),
(5,"3月","qX7oJ6","小龙","TutuTu","3月",1999,"小红书直购","18107332677","newmedia-dianpu-xhs-0-0"),
(6,"3月","qX7oJ6","小龙","EFFIE","3月25日",3598,"微信小店","","newmedia-dianpu-xhs-0-0"),
(7,"3月","sSCT22","Tom","JeanneLᴇᴇ🦄","3月4日",3598,"微信小店","","newmedia-dianpu-wxxd-0-0"),
(8,"3月","sSCT22","Tom","薇妮姐","3月8日",599,"端内","","app-active-h5-0-0"),
(9,"3月","sSCT22","Tom","","3月7日",599,"端内","","app-active-h5-0-0"),
(10,"3月","sSCT22","Bob","Mogu","3月6日",599,"端内","","app-active-h5-0-0"),
(11,"3月","sSCT22","Bob","L. 一颗夹星糖🌟","3月12日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0"),
(12,"3月","sSCT22","Tom","阿雅呀","3月15日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0"),
(13,"3月","sSCT22","Tom","Anna","3月4日",1999,"抖音","","newmedia-dianpu-douyin-0-0"),
(14,"3月","sSCT22","Bob","Echo Liang","3月15日",1999,"微信小店","","sales-adp-cd-zjf-0"),
(15,"3月","sSCT22","Tom","幼兒園高材生🍼","3月23日",3598,"微信小店","13055770067","sales-adp-cd-yy-0"),
(16,"3月","sSCT22","Tom","Nancy","3月26日",599,"端内","","app-active-h5-0-0"),
(17,"3月","sSCT22","Tom","依米","3月30日",3598,"微信小店","","sales-adp-cd-zjf-0"),
(18,"3月","sSCT22","Bob","zhouyun","3月6日",1999,"小红书-学霸老王","13588706769","newmedia-daren-xhs-学霸老王讲真话-0"),
(19,"3月","sSCT22","Tom","💗小超人棒棒哒🍭","3月29日",3598,"小红书-晚柠","18630368296","newmedia-daren-xhs-晚柠也是个妈妈了-0"),
(20,"3月","sSCT22","Bob","鹿","3月14日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0"),
# 4月 (15)
(21,"4月","qX7oJ6","小龙","琳溪","4月19日",3598,"微信小店","","sales-adp-bj-jxl-0"),
(22,"4月","qX7oJ6","小龙","小丽","4月26日",599,"端内","","app-active-h5-0-0"),
(23,"4月","qX7oJ6","小龙","子曦","4月16日",3598,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0"),
(24,"4月","qX7oJ6","小龙","Gaᴗao","4月24日",3598,"微信小店","","sales-adp-bj-jxl-0"),
(25,"4月","XqxgjP","吴迪","ཚེ་རིང་མཚོ彩让措","2026/4/26",599,"端内","","app-active-h5-0-0"),
(26,"4月","XqxgjP","吴迪","莉筱雅","2026/4/27",1999,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0"),
(27,"4月","XqxgjP","吴迪","爱吃巧克力","2026/4/24",1999,"微信小店","","sales-adp-bj-wd-0"),
(28,"4月","XqxgjP","吴迪","Aa~Jessie💝","2026/4/27",1999,"抖音","","newmedia-dianpu-douyin-0-0"),
(29,"4月","XqxgjP","吴迪","🐷","2026/4/26",3598,"宣儿妈妈-小红书","","sales-adp-cd-yy-0"),
(30,"4月","XqxgjP","吴迪","🐷","2026/4/26",3598,"宣儿妈妈-小红书","","sales-adp-cd-yy-0"),
(31,"4月","sSCT22","Tom","静静是我🍃","4月8日",1999,"小红书-学霸老王","15975769851","partner-actives-0-0-0"),
(32,"4月","sSCT22","Bob","胆大鬼","4月8日",3598,"小红书-学霸老王","15262255267","newmedia-daren-xhs-学霸老王讲真话-0"),
(33,"4月","sSCT22","Tom","希Cissy-427","4月27日",3598,"微信小店","","sales-adp-cd-zjf-0"),
(34,"4月","sSCT22","Tom","Kerry","4月9日",3598,"微信小店","18328334683","sales-adp-cd-yy-0"),
(35,"4月","sSCT22","Tom","SHAN_Q_Q","4月1日",3598,"小红书-官店","","newmedia-dianpu-xhs-0-0"),
# 5月 (22)
(36,"5月","qX7oJ6","小龙","Sia","5月9日",599,"微信小店","","sales-adp-bj-jxl-0"),
(37,"5月","XqxgjP","吴迪","","2026/5/9",1999,"微信小店","","sales-adp-bj-wd-0"),
(38,"5月","XqxgjP","吴迪","^_^","2026/5/16",3598,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0"),
(39,"5月","XqxgjP","吴迪","🌸白色铃兰🌸","2026/5/17",3598,"抖音","","newmedia-dianpu-douyin-0-0"),
(40,"5月","XqxgjP","吴迪","咔咔","2026/5/7",3598,"微信小店","","sales-adp-bj-wd-0"),
(41,"5月","XqxgjP","吴迪","梦马","2026/5/21",3598,"小红书","","newmedia-dianpu-xhs-0-0"),
(42,"5月","XqxgjP","吴迪","梦马","2026/5/21",3598,"小红书","","newmedia-dianpu-xhs-0-0"),
(43,"5月","XqxgjP","吴迪","小西瓜","2026/5/30",1999,"微信小店","","sales-adp-bj-wd-0"),
(44,"5月","XqxgjP","吴迪","","2026/5/9",1999,"微信小店","","sales-adp-bj-wd-0"),
(45,"5月","sSCT22","Bob","Yuki-515","5月15日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0"),
(46,"5月","sSCT22","Tom","冬-515","5月15日",1999,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0"),
(47,"5月","sSCT22","Bob","微笑向暖","5月4日",1999,"微信小店","","sales-adp-bj-wd-0"),
(48,"5月","sSCT22","Bob","cici-511","5月11日",1999,"微信小店","","sales-adp-cd-xsy-0"),
(49,"5月","sSCT22","Tom","🐷-519","5月19日",1999,"小红书-宣儿妈妈","","newmedia-daren-xhs-宣儿妈妈%"),
(50,"5月","sSCT22","Bob","妃-516","5月16日",1999,"微信小店","","sales-adp-cd-zjf-0"),
(51,"5月","sSCT22","Tom","黄晔-516","5月16日",3598,"微信小店","","sales-adp-bj-wd-0"),
(52,"5月","sSCT22","Tom","朵朵呀!","5月25日",1999,"微信小店","","sales-adp-cd-zjf-0"),
(53,"5月","sSCT22","Tom","雷鸣-414","5月14日",599,"微信小店","","sales-adp-bj-wd-0"),
(54,"5月","sSCT22","Tom","毛阿毛🐱-520","5月20日",1999,"小红书-官店","","newmedia-dianpu-xhs-0-0"),
(55,"5月","sSCT22","Tom","____Miss_y-519","5月19日",599,"微信小店","","sales-adp-bj-wd-0"),
(56,"5月","sSCT22","Tom","Mandy-526","5月26日",1999,"微信小店","","sales-adp-bj-wd-0"),
(57,"5月","sSCT22","Bob","Yoki-529","5月29日",1999,"微信小店","","sales-adp-cd-zjf-0"),
]
# Parse date
def parse_date(d):
d = d.replace("","").replace("","/").replace(" ","").strip()
if "/" in d:
parts = d.split("/")
if len(parts) >= 2 and parts[1]:
m = int(parts[0])
day = int(parts[1])
return f"2026-{m:02d}-{day:02d}"
return None
# Encrypt phones
from scripts.phone_encrypt import encrypt_phone
phone_map = {}
for g in gaps:
phone = g[7]
if phone:
phone_map[phone] = encrypt_phone(phone)
# Look up accounts by encrypted phone
if phone_map:
phone_conds = " OR ".join([f"a.tel_encrypt LIKE '{v}%'" for v in phone_map.values()])
sql = f"SELECT a.id, a.tel, a.tel_encrypt FROM bi_vala_app_account a WHERE a.status=1 AND ({phone_conds})"
r = subprocess.run(["psql","-h","bj-postgres-16pob4sg.sql.tencentcdb.com","-p","28591","-U","ai_member","-d","vala_bi","-c",sql],
env={**os.environ,"PGPASSWORD":PGPASS}, capture_output=True, text=True, timeout=15)
# Build account_id -> tel mapping
acct_tel = {}
for line in r.stdout.strip().split("\n")[2:-1]:
parts = [p.strip() for p in line.split("|")]
if len(parts) >= 3:
acct_tel[parts[0]] = parts[1]
else:
acct_tel = {}
# Now query orders by key_from + date for each gap
results = []
for g in gaps:
idx, month, src, sales, nick, date_str, amount, channel, phone, keyfrom = g
d = parse_date(date_str)
amt = amount * 100
found = None
# If we have phone match
if phone and phone in phone_map:
enc = phone_map[phone]
# Find account_id
sql2 = f"SELECT a.id FROM bi_vala_app_account a WHERE a.status=1 AND a.tel_encrypt LIKE '{enc}%'"
r2 = subprocess.run(["psql","-h","bj-postgres-16pob4sg.sql.tencentcdb.com","-p","28591","-U","ai_member","-d","vala_bi","-c",sql2],
env={**os.environ,"PGPASSWORD":PGPASS}, capture_output=True, text=True, timeout=10)
acct_ids = []
for line in r2.stdout.strip().split("\n")[2:-1]:
p = line.split("|")[0].strip()
if p.isdigit():
acct_ids.append(p)
if acct_ids:
acct_list = ",".join(acct_ids)
sql3 = f"SELECT o.id, o.trade_no, o.pay_amount_int, to_char(o.pay_success_date,'YYYY-MM-DD'), o.key_from, o.order_status, o.account_id FROM bi_vala_order o WHERE o.account_id IN ({acct_list}) AND o.pay_amount_int={amt} AND o.order_status IN (3,4) AND o.pay_success_date IS NOT NULL ORDER BY o.pay_success_date"
r3 = subprocess.run(["psql","-h","bj-postgres-16pob4sg.sql.tencentcdb.com","-p","28591","-U","ai_member","-d","vala_bi","-c",sql3],
env={**os.environ,"PGPASSWORD":PGPASS}, capture_output=True, text=True, timeout=10)
for line in r3.stdout.strip().split("\n")[2:-1]:
parts = [p.strip() for p in line.split("|")]
if len(parts) >= 7:
found = {"order_id":parts[0],"trade_no":parts[1],"amount":int(parts[2]),"pay_date":parts[3],"key_from":parts[4],"status":parts[5],"account_id":parts[6]}
break
# If no phone match, try keyfrom + date + amount
if not found and d and keyfrom:
if "%" in keyfrom:
like = keyfrom.replace("%","")
sql4 = f"SELECT o.id, o.trade_no, o.pay_amount_int, to_char(o.pay_success_date,'YYYY-MM-DD'), o.key_from, o.order_status, o.account_id, a.tel FROM bi_vala_order o JOIN bi_vala_app_account a ON o.account_id=a.id WHERE a.status=1 AND o.pay_success_date::date='{d}' AND o.pay_amount_int={amt} AND o.key_from LIKE '%{like}%' AND o.order_status IN (3,4) LIMIT 3"
else:
sql4 = f"SELECT o.id, o.trade_no, o.pay_amount_int, to_char(o.pay_success_date,'YYYY-MM-DD'), o.key_from, o.order_status, o.account_id, a.tel FROM bi_vala_order o JOIN bi_vala_app_account a ON o.account_id=a.id WHERE a.status=1 AND o.pay_success_date::date='{d}' AND o.pay_amount_int={amt} AND o.key_from='{keyfrom}' AND o.order_status IN (3,4) LIMIT 3"
r4 = subprocess.run(["psql","-h","bj-postgres-16pob4sg.sql.tencentcdb.com","-p","28591","-U","ai_member","-d","vala_bi","-c",sql4],
env={**os.environ,"PGPASSWORD":PGPASS}, capture_output=True, text=True, timeout=10)
matches = []
for line in r4.stdout.strip().split("\n")[2:-1]:
parts = [p.strip() for p in line.split("|")]
if len(parts) >= 8:
matches.append({"order_id":parts[0],"trade_no":parts[1],"amount":int(parts[2]),"pay_date":parts[3],"key_from":parts[4],"status":parts[5],"account_id":parts[6],"tel":parts[7]})
if matches:
found = matches[0]
# Check refunds
gsv = 0
if found:
aid = found.get("account_id","")
sql5 = f"SELECT SUM(r.refund_amount_int) FROM bi_refund_order r JOIN bi_vala_order o ON r.trade_no=o.trade_no WHERE o.account_id={aid} AND r.status=3"
r5 = subprocess.run(["psql","-h","bj-postgres-16pob4sg.sql.tencentcdb.com","-p","28591","-U","ai_member","-d","vala_bi","-c",sql5],
env={**os.environ,"PGPASSWORD":PGPASS}, capture_output=True, text=True, timeout=10)
refund = 0
for line in r5.stdout.strip().split("\n")[2:-1]:
val = line.strip()
if val and val.isdigit():
refund = int(val)
gsv = found["amount"] - refund
status = "" if found else ""
is_direct = keyfrom in ("newmedia-dianpu-xhs-0-0","newmedia-dianpu-douyin-0-0","newmedia-dianpu-wxxd-0-0","app-active-h5-0-0")
should_enter = "" if (found and gsv > 0 and not is_direct) else ""
print(f"{idx}. [{month}] {sales} {nick} | {date_str} ¥{amount} {channel} | {status} | GSV={gsv/100:.0f} | 应进Bot={should_enter}")
if found:
print(f" order_id={found['order_id']} {found.get('pay_date','')} ¥{found['amount']/100:.0f} {found.get('key_from','')[:50]} status={found.get('status','')}")

197
scripts/check_gap_57_v3.py Normal file
View File

@ -0,0 +1,197 @@
#!/usr/bin/env python3
"""Check 57 gap orders - bulk approach"""
import subprocess, os, json, sys
sys.path.insert(0, '/root/.openclaw/workspace')
PGPASS = "LdfjdjL83h3h3^$&**YGG*"
DB = ["psql","-h","bj-postgres-16pob4sg.sql.tencentcdb.com","-p","28591","-U","ai_member","-d","vala_bi"]
ENV = {**os.environ, "PGPASSWORD": PGPASS}
def q(sql):
r = subprocess.run(DB + ["-c", sql], env=ENV, capture_output=True, text=True, timeout=15)
rows = []
for line in r.stdout.strip().split("\n")[2:-1]:
parts = [p.strip() for p in line.split("|")]
rows.append(parts)
return rows
# Gap data
gaps = [
(1,"3月","小龙","雪珂💗","3月6日",1999,"微信小店","","sales-adp-bj-jxl-0",False),
(2,"3月","小龙","Mars","3月7日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(3,"3月","小龙","薇薇","3月",1999,"小红书直购","13520306626","newmedia-dianpu-xhs-0-0",True),
(4,"3月","小龙","Yeah^_^","3月20日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(5,"3月","小龙","TutuTu","3月",1999,"小红书直购","18107332677","newmedia-dianpu-xhs-0-0",True),
(6,"3月","小龙","EFFIE","3月25日",3598,"微信小店","","newmedia-dianpu-xhs-0-0",False),
(7,"3月","Tom","JeanneLᴇᴇ🦄","3月4日",3598,"微信小店","","newmedia-dianpu-wxxd-0-0",False),
(8,"3月","Tom","薇妮姐","3月8日",599,"端内","","app-active-h5-0-0",False),
(9,"3月","Tom","","3月7日",599,"端内","","app-active-h5-0-0",False),
(10,"3月","Bob","Mogu","3月6日",599,"端内","","app-active-h5-0-0",False),
(11,"3月","Bob","L. 一颗夹星糖🌟","3月12日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(12,"3月","Tom","阿雅呀","3月15日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(13,"3月","Tom","Anna","3月4日",1999,"抖音","","newmedia-dianpu-douyin-0-0",True),
(14,"3月","Bob","Echo Liang","3月15日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
(15,"3月","Tom","幼兒園高材生🍼","3月23日",3598,"微信小店","13055770067","sales-adp-cd-yy-0",False),
(16,"3月","Tom","Nancy","3月26日",599,"端内","","app-active-h5-0-0",False),
(17,"3月","Tom","依米","3月30日",3598,"微信小店","","sales-adp-cd-zjf-0",False),
(18,"3月","Bob","zhouyun","3月6日",1999,"小红书-学霸老王","13588706769","newmedia-daren-xhs-学霸老王讲真话-0",False),
(19,"3月","Tom","💗小超人棒棒哒🍭","3月29日",3598,"小红书-晚柠","18630368296","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(20,"3月","Bob","鹿","3月14日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(21,"4月","小龙","琳溪","4月19日",3598,"微信小店","","sales-adp-bj-jxl-0",False),
(22,"4月","小龙","小丽","4月26日",599,"端内","","app-active-h5-0-0",False),
(23,"4月","小龙","子曦","4月16日",3598,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(24,"4月","小龙","Gaᴗao","4月24日",3598,"微信小店","","sales-adp-bj-jxl-0",False),
(25,"4月","吴迪","ཚེ་རིང་མཚོ彩让措","2026/4/26",599,"端内","","app-active-h5-0-0",False),
(26,"4月","吴迪","莉筱雅","2026/4/27",1999,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(27,"4月","吴迪","爱吃巧克力","2026/4/24",1999,"微信小店","","sales-adp-bj-wd-0",False),
(28,"4月","吴迪","Aa~Jessie💝","2026/4/27",1999,"抖音","","newmedia-dianpu-douyin-0-0",True),
(29,"4月","吴迪","🐷","2026/4/26",3598,"宣儿妈妈-小红书","","sales-adp-cd-yy-0",False),
(30,"4月","吴迪","🐷","2026/4/26",3598,"宣儿妈妈-小红书","","sales-adp-cd-yy-0",False),
(31,"4月","Tom","静静是我🍃","4月8日",1999,"小红书-学霸老王","15975769851","partner-actives-0-0-0",False),
(32,"4月","Bob","胆大鬼","4月8日",3598,"小红书-学霸老王","15262255267","newmedia-daren-xhs-学霸老王讲真话-0",False),
(33,"4月","Tom","希Cissy-427","4月27日",3598,"微信小店","","sales-adp-cd-zjf-0",False),
(34,"4月","Tom","Kerry","4月9日",3598,"微信小店","18328334683","sales-adp-cd-yy-0",False),
(35,"4月","Tom","SHAN_Q_Q","4月1日",3598,"小红书-官店","","newmedia-dianpu-xhs-0-0",True),
(36,"5月","小龙","Sia","5月9日",599,"微信小店","","sales-adp-bj-jxl-0",False),
(37,"5月","吴迪","","2026/5/9",1999,"微信小店","","sales-adp-bj-wd-0",False),
(38,"5月","吴迪","^_^","2026/5/16",3598,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(39,"5月","吴迪","🌸白色铃兰🌸","2026/5/17",3598,"抖音","","newmedia-dianpu-douyin-0-0",True),
(40,"5月","吴迪","咔咔","2026/5/7",3598,"微信小店","","sales-adp-bj-wd-0",False),
(41,"5月","吴迪","梦马","2026/5/21",3598,"小红书","","newmedia-dianpu-xhs-0-0",False),
(42,"5月","吴迪","梦马","2026/5/21",3598,"小红书","","newmedia-dianpu-xhs-0-0",False),
(43,"5月","吴迪","小西瓜","2026/5/30",1999,"微信小店","","sales-adp-bj-wd-0",False),
(44,"5月","吴迪","","2026/5/9",1999,"微信小店","","sales-adp-bj-wd-0",False),
(45,"5月","Bob","Yuki-515","5月15日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(46,"5月","Tom","冬-515","5月15日",1999,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(47,"5月","Bob","微笑向暖","5月4日",1999,"微信小店","","sales-adp-bj-wd-0",False),
(48,"5月","Bob","cici-511","5月11日",1999,"微信小店","","sales-adp-cd-xsy-0",False),
(49,"5月","Tom","🐷-519","5月19日",1999,"小红书-宣儿妈妈","","newmedia-daren-xhs-宣儿妈妈%",False),
(50,"5月","Bob","妃-516","5月16日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
(51,"5月","Tom","黄晔-516","5月16日",3598,"微信小店","","sales-adp-bj-wd-0",False),
(52,"5月","Tom","朵朵呀!","5月25日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
(53,"5月","Tom","雷鸣-414","5月14日",599,"微信小店","","sales-adp-bj-wd-0",False),
(54,"5月","Tom","毛阿毛🐱-520","5月20日",1999,"小红书-官店","","newmedia-dianpu-xhs-0-0",True),
(55,"5月","Tom","____Miss_y-519","5月19日",599,"微信小店","","sales-adp-bj-wd-0",False),
(56,"5月","Tom","Mandy-526","5月26日",1999,"微信小店","","sales-adp-bj-wd-0",False),
(57,"5月","Bob","Yoki-529","5月29日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
]
def parse_date(d):
d = d.replace("","").replace("","/").replace(" ","").strip()
if "/" in d:
parts = d.split("/")
if len(parts) >= 2 and parts[1]:
return f"2026-{int(parts[0]):02d}-{int(parts[1]):02d}"
return None
# Step 1: Encrypt all phones
from scripts.phone_encrypt import encrypt_phone
phone_to_enc = {}
for g in gaps:
if g[7]:
phone_to_enc[g[7]] = encrypt_phone(g[7])
# Step 2: Look up all accounts by encrypted phone
enc_to_acct = {}
if phone_to_enc:
conds = " OR ".join([f"tel_encrypt LIKE '{v}%'" for v in phone_to_enc.values()])
rows = q(f"SELECT id, tel, tel_encrypt FROM bi_vala_app_account WHERE status=1 AND ({conds})")
for r in rows:
if len(r) >= 3:
enc_to_acct[r[2]] = r[0]
# Step 3: Get all orders for matched accounts
phone_acct_ids = set(enc_to_acct.values())
phone_orders = {}
if phone_acct_ids:
ids = ",".join(phone_acct_ids)
rows = q(f"SELECT id, trade_no, pay_amount_int, to_char(pay_success_date,'YYYY-MM-DD'), key_from, order_status, account_id FROM bi_vala_order WHERE account_id IN ({ids}) AND pay_amount_int IN (59900,199900,359800) AND order_status IN (3,4) AND pay_success_date IS NOT NULL ORDER BY pay_success_date")
for r in rows:
if len(r) >= 7:
aid = r[6]
if aid not in phone_orders:
phone_orders[aid] = []
phone_orders[aid].append({"id":r[0],"trade_no":r[1],"amount":int(r[2]),"pay_date":r[3],"key_from":r[4],"status":r[5]})
# Step 4: Bulk query by keyfrom+date combos
# Collect unique (date, amount, keyfrom) combos
combos = set()
for g in gaps:
d = parse_date(g[4])
if d and g[8]:
combos.add((d, g[5]*100, g[8]))
# Build OR conditions
kf_conds = []
for d, amt, kf in combos:
if "%" in kf:
kf_conds.append(f"(pay_success_date::date='{d}' AND pay_amount_int={amt} AND key_from LIKE '%{kf.replace('%','')}%')")
else:
kf_conds.append(f"(pay_success_date::date='{d}' AND pay_amount_int={amt} AND key_from='{kf}')")
kf_orders = {}
if kf_conds:
# Split into batches of 50
for i in range(0, len(kf_conds), 50):
batch = kf_conds[i:i+50]
sql = f"SELECT o.id, o.trade_no, o.pay_amount_int, to_char(o.pay_success_date,'YYYY-MM-DD'), o.key_from, o.order_status, o.account_id, a.tel FROM bi_vala_order o JOIN bi_vala_app_account a ON o.account_id=a.id WHERE a.status=1 AND o.order_status IN (3,4) AND o.pay_success_date >= '2026-03-01' AND o.pay_success_date < '2026-06-01' AND ({' OR '.join(batch)})"
rows = q(sql)
for r in rows:
if len(r) >= 8:
kf_orders[(r[3], int(r[2]), r[4])] = {"id":r[0],"trade_no":r[1],"amount":int(r[2]),"pay_date":r[3],"key_from":r[4],"status":r[5],"account_id":r[6],"tel":r[7]}
# Step 5: Get all refunds for matched accounts
all_acct_ids = set()
for aid in phone_acct_ids:
all_acct_ids.add(aid)
for v in kf_orders.values():
all_acct_ids.add(v["account_id"])
refunds = {}
if all_acct_ids:
ids = ",".join(all_acct_ids)
rows = q(f"SELECT o.account_id, SUM(r.refund_amount_int) FROM bi_refund_order r JOIN bi_vala_order o ON r.trade_no=o.trade_no WHERE o.account_id IN ({ids}) AND r.status=3 GROUP BY o.account_id")
for r in rows:
if len(r) >= 2 and r[1]:
refunds[r[0]] = int(r[1])
# Step 6: Match
for g in gaps:
idx, month, sales, nick, date_str, amount, channel, phone, keyfrom, is_direct = g
d = parse_date(date_str)
amt = amount * 100
found = None
# Try phone match first
if phone and phone in phone_to_enc:
enc = phone_to_enc[phone]
aid = enc_to_acct.get(enc)
if aid and aid in phone_orders:
for o in phone_orders[aid]:
if o["amount"] == amt:
found = o
break
# Try keyfrom+date+amount match
if not found and d and keyfrom:
if "%" in keyfrom:
like = keyfrom.replace("%","")
for k, v in kf_orders.items():
if v["pay_date"] == d and v["amount"] == amt and like in v["key_from"]:
found = v
break
else:
found = kf_orders.get((d, amt, keyfrom))
gsv = 0
if found:
aid = found.get("account_id","")
refund = refunds.get(aid, 0)
gsv = found["amount"] - refund
status = "" if found else ""
should = "" if (found and gsv > 0 and not is_direct) else ""
print(f"{idx}. [{month}] {sales} {nick} | {date_str} ¥{amount} {channel} | {status} | GSV={gsv/100:.0f} | 应进Bot={should}")
if found:
print(f" order_id={found['id']} {found.get('pay_date','')} ¥{found['amount']/100:.0f} {found.get('key_from','')[:50]} status={found.get('status','')}")

193
scripts/check_gap_57_v4.py Normal file
View File

@ -0,0 +1,193 @@
#!/usr/bin/env python3
"""Check 57 gap orders v4 - broader matching"""
import subprocess, os, sys
sys.path.insert(0, '/root/.openclaw/workspace')
PGPASS = "LdfjdjL83h3h3^$&**YGG*"
DB = ["psql","-h","bj-postgres-16pob4sg.sql.tencentcdb.com","-p","28591","-U","ai_member","-d","vala_bi"]
ENV = {**os.environ, "PGPASSWORD": PGPASS}
def q(sql):
r = subprocess.run(DB + ["-c", sql], env=ENV, capture_output=True, text=True, timeout=30)
rows = []
for line in r.stdout.strip().split("\n")[2:-1]:
parts = [p.strip() for p in line.split("|")]
rows.append(parts)
return rows
# Gap data from chat - exact keyfrom from gap messages
gaps = [
(1,"3月","小龙","雪珂💗","3月6日",1999,"微信小店","","sales-adp-bj-jxl-0",False),
(2,"3月","小龙","Mars","3月7日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(3,"3月","小龙","薇薇","3月",1999,"小红书直购","13520306626","newmedia-dianpu-xhs-0-0",True),
(4,"3月","小龙","Yeah^_^","3月20日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(5,"3月","小龙","TutuTu","3月",1999,"小红书直购","18107332677","newmedia-dianpu-xhs-0-0",True),
(6,"3月","小龙","EFFIE","3月25日",3598,"微信小店","","newmedia-dianpu-xhs-0-0",False),
(7,"3月","Tom","JeanneLᴇᴇ🦄","3月4日",3598,"微信小店","","newmedia-dianpu-wxxd-0-0",False),
(8,"3月","Tom","薇妮姐","3月8日",599,"端内","","app-active-h5-0-0",False),
(9,"3月","Tom","","3月7日",599,"端内","","app-active-h5-0-0",False),
(10,"3月","Bob","Mogu","3月6日",599,"端内","","app-active-h5-0-0",False),
(11,"3月","Bob","L. 一颗夹星糖🌟","3月12日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(12,"3月","Tom","阿雅呀","3月15日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(13,"3月","Tom","Anna","3月4日",1999,"抖音","","newmedia-dianpu-douyin-0-0",True),
(14,"3月","Bob","Echo Liang","3月15日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
(15,"3月","Tom","幼兒園高材生🍼","3月23日",3598,"微信小店","13055770067","sales-adp-cd-yy-0",False),
(16,"3月","Tom","Nancy","3月26日",599,"端内","","app-active-h5-0-0",False),
(17,"3月","Tom","依米","3月30日",3598,"微信小店","","sales-adp-cd-zjf-0",False),
(18,"3月","Bob","zhouyun","3月6日",1999,"小红书-学霸老王","13588706769","newmedia-daren-xhs-学霸老王讲真话-0",False),
(19,"3月","Tom","💗小超人棒棒哒🍭","3月29日",3598,"小红书-晚柠","18630368296","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(20,"3月","Bob","鹿","3月14日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(21,"4月","小龙","琳溪","4月19日",3598,"微信小店","","sales-adp-bj-jxl-0",False),
(22,"4月","小龙","小丽","4月26日",599,"端内","","app-active-h5-0-0",False),
(23,"4月","小龙","子曦","4月16日",3598,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(24,"4月","小龙","Gaᴗao","4月24日",3598,"微信小店","","sales-adp-bj-jxl-0",False),
(25,"4月","吴迪","ཚེ་རིང་མཚོ彩让措","2026/4/26",599,"端内","","app-active-h5-0-0",False),
(26,"4月","吴迪","莉筱雅","2026/4/27",1999,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(27,"4月","吴迪","爱吃巧克力","2026/4/24",1999,"微信小店","","sales-adp-bj-wd-0",False),
(28,"4月","吴迪","Aa~Jessie💝","2026/4/27",1999,"抖音","","newmedia-dianpu-douyin-0-0",True),
(29,"4月","吴迪","🐷","2026/4/26",3598,"宣儿妈妈-小红书","","sales-adp-cd-yy-0",False),
(30,"4月","吴迪","🐷","2026/4/26",3598,"宣儿妈妈-小红书","","sales-adp-cd-yy-0",False),
(31,"4月","Tom","静静是我🍃","4月8日",1999,"小红书-学霸老王","15975769851","partner-actives-0-0-0",False),
(32,"4月","Bob","胆大鬼","4月8日",3598,"小红书-学霸老王","15262255267","newmedia-daren-xhs-学霸老王讲真话-0",False),
(33,"4月","Tom","希Cissy-427","4月27日",3598,"微信小店","","sales-adp-cd-zjf-0",False),
(34,"4月","Tom","Kerry","4月9日",3598,"微信小店","18328334683","sales-adp-cd-yy-0",False),
(35,"4月","Tom","SHAN_Q_Q","4月1日",3598,"小红书-官店","","newmedia-dianpu-xhs-0-0",True),
(36,"5月","小龙","Sia","5月9日",599,"微信小店","","sales-adp-bj-jxl-0",False),
(37,"5月","吴迪","","2026/5/9",1999,"微信小店","","sales-adp-bj-wd-0",False),
(38,"5月","吴迪","^_^","2026/5/16",3598,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(39,"5月","吴迪","🌸白色铃兰🌸","2026/5/17",3598,"抖音","","newmedia-dianpu-douyin-0-0",True),
(40,"5月","吴迪","咔咔","2026/5/7",3598,"微信小店","","sales-adp-bj-wd-0",False),
(41,"5月","吴迪","梦马","2026/5/21",3598,"小红书","","newmedia-dianpu-xhs-0-0",False),
(42,"5月","吴迪","梦马","2026/5/21",3598,"小红书","","newmedia-dianpu-xhs-0-0",False),
(43,"5月","吴迪","小西瓜","2026/5/30",1999,"微信小店","","sales-adp-bj-wd-0",False),
(44,"5月","吴迪","","2026/5/9",1999,"微信小店","","sales-adp-bj-wd-0",False),
(45,"5月","Bob","Yuki-515","5月15日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(46,"5月","Tom","冬-515","5月15日",1999,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(47,"5月","Bob","微笑向暖","5月4日",1999,"微信小店","","sales-adp-bj-wd-0",False),
(48,"5月","Bob","cici-511","5月11日",1999,"微信小店","","sales-adp-cd-xsy-0",False),
(49,"5月","Tom","🐷-519","5月19日",1999,"小红书-宣儿妈妈","","newmedia-daren-xhs-宣儿妈妈%",False),
(50,"5月","Bob","妃-516","5月16日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
(51,"5月","Tom","黄晔-516","5月16日",3598,"微信小店","","sales-adp-bj-wd-0",False),
(52,"5月","Tom","朵朵呀!","5月25日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
(53,"5月","Tom","雷鸣-414","5月14日",599,"微信小店","","sales-adp-bj-wd-0",False),
(54,"5月","Tom","毛阿毛🐱-520","5月20日",1999,"小红书-官店","","newmedia-dianpu-xhs-0-0",True),
(55,"5月","Tom","____Miss_y-519","5月19日",599,"微信小店","","sales-adp-bj-wd-0",False),
(56,"5月","Tom","Mandy-526","5月26日",1999,"微信小店","","sales-adp-bj-wd-0",False),
(57,"5月","Bob","Yoki-529","5月29日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
]
def parse_date(d):
d = d.replace("","").replace("","/").replace(" ","").strip()
if "/" in d:
parts = d.split("/")
if len(parts) >= 2 and parts[1]:
return f"2026-{int(parts[0]):02d}-{int(parts[1]):02d}"
return None
from scripts.phone_encrypt import encrypt_phone
# Step 1: Encrypt phones
phone_enc = {}
for g in gaps:
if g[7]:
phone_enc[g[7]] = encrypt_phone(g[7])
# Step 2: Get account IDs for phones
phone_to_aid = {}
if phone_enc:
conds = " OR ".join([f"tel_encrypt LIKE '{v}%'" for v in phone_enc.values()])
for r in q(f"SELECT id, tel_encrypt FROM bi_vala_app_account WHERE status=1 AND ({conds})"):
if len(r) >= 2:
phone_to_aid[r[1]] = r[0]
# Step 3: Get all orders for phone-matched accounts
phone_orders = {}
if phone_to_aid:
ids = ",".join(phone_to_aid.values())
for r in q(f"SELECT id, trade_no, pay_amount_int, to_char(pay_success_date,'YYYY-MM-DD'), key_from, order_status, account_id FROM bi_vala_order WHERE account_id IN ({ids}) AND pay_amount_int IN (59900,199900,359800) AND order_status IN (3,4) AND pay_success_date IS NOT NULL"):
if len(r) >= 7:
aid = r[6]
phone_orders.setdefault(aid, []).append({"id":r[0],"trade_no":r[1],"amount":int(r[2]),"pay_date":r[3],"key_from":r[4],"status":r[5]})
# Step 4: Get ALL orders for all gap dates (broader query, no keyfrom filter)
all_dates = set()
for g in gaps:
d = parse_date(g[4])
if d:
all_dates.add(d)
date_orders = {} # (date, amount) -> list of orders
if all_dates:
date_list = ",".join([f"'{d}'" for d in sorted(all_dates)])
sql = f"SELECT o.id, o.trade_no, o.pay_amount_int, to_char(o.pay_success_date,'YYYY-MM-DD'), o.key_from, o.order_status, o.account_id, a.tel FROM bi_vala_order o JOIN bi_vala_app_account a ON o.account_id=a.id WHERE a.status=1 AND o.order_status IN (3,4) AND o.pay_success_date::date IN ({date_list}) AND o.pay_amount_int IN (59900,199900,359800)"
for r in q(sql):
if len(r) >= 8:
key = (r[3], int(r[2]))
date_orders.setdefault(key, []).append({"id":r[0],"trade_no":r[1],"amount":int(r[2]),"pay_date":r[3],"key_from":r[4],"status":r[5],"account_id":r[6],"tel":r[7]})
# Step 5: Get refunds for all matched accounts
all_aids = set()
for aid, orders in phone_orders.items():
all_aids.add(aid)
for orders in date_orders.values():
for o in orders:
all_aids.add(o["account_id"])
refunds = {}
if all_aids:
ids = ",".join(all_aids)
for r in q(f"SELECT o.account_id, SUM(rf.refund_amount_int) FROM bi_refund_order rf JOIN bi_vala_order o ON rf.trade_no=o.trade_no WHERE o.account_id IN ({ids}) AND rf.status=3 GROUP BY o.account_id"):
if len(r) >= 2 and r[1]:
refunds[r[0]] = int(r[1])
# Step 6: Match each gap
for g in gaps:
idx, month, sales, nick, date_str, amount, channel, phone, keyfrom, is_direct = g
d = parse_date(date_str)
amt = amount * 100
found = None
# Try phone match
if phone and phone in phone_enc:
enc = phone_enc[phone]
aid = phone_to_aid.get(enc)
if aid and aid in phone_orders:
for o in phone_orders[aid]:
if o["amount"] == amt:
found = o
break
# Try keyfrom+date+amount
if not found and d and keyfrom:
candidates = date_orders.get((d, amt), [])
if "%" in keyfrom:
like = keyfrom.replace("%","")
for o in candidates:
if like in o["key_from"]:
found = o
break
else:
for o in candidates:
if o["key_from"] == keyfrom:
found = o
break
# If still not found, try date+amount only (any keyfrom)
if not found and d:
candidates = date_orders.get((d, amt), [])
if candidates:
found = candidates[0] # Take first match
gsv = 0
if found:
aid = found.get("account_id","")
refund = refunds.get(aid, 0)
gsv = found["amount"] - refund
status = "" if found else ""
should = "" if (found and gsv > 0 and not is_direct) else ""
print(f"{idx}. [{month}] {sales} {nick} | {date_str} ¥{amount} {channel} | {status} | GSV={gsv/100:.0f} | 应进Bot={should}")
if found:
print(f" order_id={found['id']} {found.get('pay_date','')} ¥{found['amount']/100:.0f} {found.get('key_from','')[:60]} status={found.get('status','')}")

147
scripts/check_gap_57_v5.py Normal file
View File

@ -0,0 +1,147 @@
#!/usr/bin/env python3
"""Check 57 gaps - one query per gap to avoid truncation"""
import subprocess, os, sys
sys.path.insert(0, '/root/.openclaw/workspace')
PGPASS = "LdfjdjL83h3h3^$&**YGG*"
DB = ["psql","-h","bj-postgres-16pob4sg.sql.tencentcdb.com","-p","28591","-U","ai_member","-d","vala_bi"]
ENV = {**os.environ, "PGPASSWORD": PGPASS}
def q(sql):
r = subprocess.run(DB + ["-c", sql], env=ENV, capture_output=True, text=True, timeout=15)
rows = []
for line in r.stdout.strip().split("\n")[2:-1]:
parts = [p.strip() for p in line.split("|")]
rows.append(parts)
return rows
gaps = [
(1,"3月","小龙","雪珂💗","3月6日",1999,"微信小店","","sales-adp-bj-jxl-0",False),
(2,"3月","小龙","Mars","3月7日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(3,"3月","小龙","薇薇","3月",1999,"小红书直购","13520306626","newmedia-dianpu-xhs-0-0",True),
(4,"3月","小龙","Yeah^_^","3月20日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(5,"3月","小龙","TutuTu","3月",1999,"小红书直购","18107332677","newmedia-dianpu-xhs-0-0",True),
(6,"3月","小龙","EFFIE","3月25日",3598,"微信小店","","newmedia-dianpu-xhs-0-0",False),
(7,"3月","Tom","JeanneLᴇᴇ🦄","3月4日",3598,"微信小店","","newmedia-dianpu-wxxd-0-0",False),
(8,"3月","Tom","薇妮姐","3月8日",599,"端内","","app-active-h5-0-0",False),
(9,"3月","Tom","","3月7日",599,"端内","","app-active-h5-0-0",False),
(10,"3月","Bob","Mogu","3月6日",599,"端内","","app-active-h5-0-0",False),
(11,"3月","Bob","L. 一颗夹星糖🌟","3月12日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(12,"3月","Tom","阿雅呀","3月15日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(13,"3月","Tom","Anna","3月4日",1999,"抖音","","newmedia-dianpu-douyin-0-0",True),
(14,"3月","Bob","Echo Liang","3月15日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
(15,"3月","Tom","幼兒園高材生🍼","3月23日",3598,"微信小店","13055770067","sales-adp-cd-yy-0",False),
(16,"3月","Tom","Nancy","3月26日",599,"端内","","app-active-h5-0-0",False),
(17,"3月","Tom","依米","3月30日",3598,"微信小店","","sales-adp-cd-zjf-0",False),
(18,"3月","Bob","zhouyun","3月6日",1999,"小红书-学霸老王","13588706769","newmedia-daren-xhs-学霸老王讲真话-0",False),
(19,"3月","Tom","💗小超人棒棒哒🍭","3月29日",3598,"小红书-晚柠","18630368296","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(20,"3月","Bob","鹿","3月14日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(21,"4月","小龙","琳溪","4月19日",3598,"微信小店","","sales-adp-bj-jxl-0",False),
(22,"4月","小龙","小丽","4月26日",599,"端内","","app-active-h5-0-0",False),
(23,"4月","小龙","子曦","4月16日",3598,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(24,"4月","小龙","Gaᴗao","4月24日",3598,"微信小店","","sales-adp-bj-jxl-0",False),
(25,"4月","吴迪","彩让措","2026/4/26",599,"端内","","app-active-h5-0-0",False),
(26,"4月","吴迪","莉筱雅","2026/4/27",1999,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(27,"4月","吴迪","爱吃巧克力","2026/4/24",1999,"微信小店","","sales-adp-bj-wd-0",False),
(28,"4月","吴迪","Aa~Jessie💝","2026/4/27",1999,"抖音","","newmedia-dianpu-douyin-0-0",True),
(29,"4月","吴迪","🐷","2026/4/26",3598,"宣儿妈妈-小红书","","sales-adp-cd-yy-0",False),
(30,"4月","吴迪","🐷","2026/4/26",3598,"宣儿妈妈-小红书","","sales-adp-cd-yy-0",False),
(31,"4月","Tom","静静是我🍃","4月8日",1999,"小红书-学霸老王","15975769851","partner-actives-0-0-0",False),
(32,"4月","Bob","胆大鬼","4月8日",3598,"小红书-学霸老王","15262255267","newmedia-daren-xhs-学霸老王讲真话-0",False),
(33,"4月","Tom","希Cissy-427","4月27日",3598,"微信小店","","sales-adp-cd-zjf-0",False),
(34,"4月","Tom","Kerry","4月9日",3598,"微信小店","18328334683","sales-adp-cd-yy-0",False),
(35,"4月","Tom","SHAN_Q_Q","4月1日",3598,"小红书-官店","","newmedia-dianpu-xhs-0-0",True),
(36,"5月","小龙","Sia","5月9日",599,"微信小店","","sales-adp-bj-jxl-0",False),
(37,"5月","吴迪","","2026/5/9",1999,"微信小店","","sales-adp-bj-wd-0",False),
(38,"5月","吴迪","^_^","2026/5/16",3598,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(39,"5月","吴迪","🌸白色铃兰🌸","2026/5/17",3598,"抖音","","newmedia-dianpu-douyin-0-0",True),
(40,"5月","吴迪","咔咔","2026/5/7",3598,"微信小店","","sales-adp-bj-wd-0",False),
(41,"5月","吴迪","梦马","2026/5/21",3598,"小红书","","newmedia-dianpu-xhs-0-0",False),
(42,"5月","吴迪","梦马","2026/5/21",3598,"小红书","","newmedia-dianpu-xhs-0-0",False),
(43,"5月","吴迪","小西瓜","2026/5/30",1999,"微信小店","","sales-adp-bj-wd-0",False),
(44,"5月","吴迪","","2026/5/9",1999,"微信小店","","sales-adp-bj-wd-0",False),
(45,"5月","Bob","Yuki-515","5月15日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(46,"5月","Tom","冬-515","5月15日",1999,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(47,"5月","Bob","微笑向暖","5月4日",1999,"微信小店","","sales-adp-bj-wd-0",False),
(48,"5月","Bob","cici-511","5月11日",1999,"微信小店","","sales-adp-cd-xsy-0",False),
(49,"5月","Tom","🐷-519","5月19日",1999,"小红书-宣儿妈妈","","newmedia-daren-xhs-宣儿妈妈%",False),
(50,"5月","Bob","妃-516","5月16日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
(51,"5月","Tom","黄晔-516","5月16日",3598,"微信小店","","sales-adp-bj-wd-0",False),
(52,"5月","Tom","朵朵呀!","5月25日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
(53,"5月","Tom","雷鸣-414","5月14日",599,"微信小店","","sales-adp-bj-wd-0",False),
(54,"5月","Tom","毛阿毛🐱-520","5月20日",1999,"小红书-官店","","newmedia-dianpu-xhs-0-0",True),
(55,"5月","Tom","____Miss_y-519","5月19日",599,"微信小店","","sales-adp-bj-wd-0",False),
(56,"5月","Tom","Mandy-526","5月26日",1999,"微信小店","","sales-adp-bj-wd-0",False),
(57,"5月","Bob","Yoki-529","5月29日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
]
def parse_date(d):
d = d.replace("","").replace("","/").replace(" ","").strip()
if "/" in d:
parts = d.split("/")
if len(parts) >= 2 and parts[1]:
return f"2026-{int(parts[0]):02d}-{int(parts[1]):02d}"
return None
from scripts.phone_encrypt import encrypt_phone
# Pre-encrypt phones
phone_enc = {}
for g in gaps:
if g[7]:
phone_enc[g[7]] = encrypt_phone(g[7])
# Get account IDs for phones
phone_to_aid = {}
if phone_enc:
conds = " OR ".join([f"tel_encrypt LIKE '{v}%'" for v in phone_enc.values()])
for r in q(f"SELECT id, tel_encrypt FROM bi_vala_app_account WHERE status=1 AND ({conds})"):
if len(r) >= 2:
phone_to_aid[r[1]] = r[0]
# For each gap, query individually
for g in gaps:
idx, month, sales, nick, date_str, amount, channel, phone, keyfrom, is_direct = g
d = parse_date(date_str)
amt = amount * 100
found = None
# Phone match
if phone and phone in phone_enc:
enc = phone_enc[phone]
aid = phone_to_aid.get(enc)
if aid:
rows = q(f"SELECT o.id, o.trade_no, o.pay_amount_int, to_char(o.pay_success_date,'YYYY-MM-DD'), o.key_from, o.order_status FROM bi_vala_order o WHERE o.account_id={aid} AND o.pay_amount_int={amt} AND o.order_status IN (3,4) AND o.pay_success_date IS NOT NULL ORDER BY o.pay_success_date LIMIT 5")
for r in rows:
if len(r) >= 6:
found = {"id":r[0],"trade_no":r[1],"amount":int(r[2]),"pay_date":r[3],"key_from":r[4],"status":r[5],"account_id":aid}
break
# Keyfrom + date match (±1 day)
if not found and d and keyfrom:
if "%" in keyfrom:
like = keyfrom.replace("%","")
rows = q(f"SELECT o.id, o.trade_no, o.pay_amount_int, to_char(o.pay_success_date,'YYYY-MM-DD'), o.key_from, o.order_status, o.account_id FROM bi_vala_order o JOIN bi_vala_app_account a ON o.account_id=a.id WHERE a.status=1 AND o.order_status IN (3,4) AND o.pay_success_date::date BETWEEN '{d}'::date-1 AND '{d}'::date+1 AND o.pay_amount_int={amt} AND o.key_from LIKE '%{like}%' LIMIT 3")
else:
rows = q(f"SELECT o.id, o.trade_no, o.pay_amount_int, to_char(o.pay_success_date,'YYYY-MM-DD'), o.key_from, o.order_status, o.account_id FROM bi_vala_order o JOIN bi_vala_app_account a ON o.account_id=a.id WHERE a.status=1 AND o.order_status IN (3,4) AND o.pay_success_date::date BETWEEN '{d}'::date-1 AND '{d}'::date+1 AND o.pay_amount_int={amt} AND o.key_from='{keyfrom}' LIMIT 3")
if rows and len(rows[0]) >= 7:
r = rows[0]
found = {"id":r[0],"trade_no":r[1],"amount":int(r[2]),"pay_date":r[3],"key_from":r[4],"status":r[5],"account_id":r[6]}
# Get refund
gsv = 0
if found:
aid = found.get("account_id","")
rows = q(f"SELECT SUM(rf.refund_amount_int) FROM bi_refund_order rf JOIN bi_vala_order o ON rf.trade_no=o.trade_no WHERE o.account_id={aid} AND rf.status=3")
refund = 0
if rows and rows[0] and rows[0][0] and rows[0][0].isdigit():
refund = int(rows[0][0])
gsv = found["amount"] - refund
status = "" if found else ""
should = "" if (found and gsv > 0 and not is_direct) else ""
print(f"{idx}. [{month}] {sales} {nick} | {date_str} ¥{amount} {channel} | {status} | GSV={gsv/100:.0f} | 应进Bot={should}")
if found:
print(f" order_id={found['id']} {found.get('pay_date','')} ¥{found['amount']/100:.0f} {found.get('key_from','')[:60]} status={found.get('status','')}")

172
scripts/check_gap_57_v6.py Normal file
View File

@ -0,0 +1,172 @@
#!/usr/bin/env python3
"""Check 57 gaps v6 - correct refund per-order, proper matching"""
import subprocess, os, sys
sys.path.insert(0, '/root/.openclaw/workspace')
PGPASS = "LdfjdjL83h3h3^$&**YGG*"
DB = ["psql","-h","bj-postgres-16pob4sg.sql.tencentcdb.com","-p","28591","-U","ai_member","-d","vala_bi"]
ENV = {**os.environ, "PGPASSWORD": PGPASS}
def q(sql):
r = subprocess.run(DB + ["-c", sql], env=ENV, capture_output=True, text=True, timeout=15)
rows = []
for line in r.stdout.strip().split("\n")[2:-1]:
parts = [p.strip() for p in line.split("|")]
rows.append(parts)
return rows
gaps = [
(1,"3月","小龙","雪珂💗","3月6日",1999,"微信小店","","sales-adp-bj-jxl-0",False),
(2,"3月","小龙","Mars","3月7日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(3,"3月","小龙","薇薇","3月",1999,"小红书直购","13520306626","newmedia-dianpu-xhs-0-0",True),
(4,"3月","小龙","Yeah^_^","3月20日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(5,"3月","小龙","TutuTu","3月",1999,"小红书直购","18107332677","newmedia-dianpu-xhs-0-0",True),
(6,"3月","小龙","EFFIE","3月25日",3598,"微信小店","","newmedia-dianpu-xhs-0-0",False),
(7,"3月","Tom","JeanneLᴇᴇ🦄","3月4日",3598,"微信小店","","newmedia-dianpu-wxxd-0-0",False),
(8,"3月","Tom","薇妮姐","3月8日",599,"端内","","app-active-h5-0-0",False),
(9,"3月","Tom","","3月7日",599,"端内","","app-active-h5-0-0",False),
(10,"3月","Bob","Mogu","3月6日",599,"端内","","app-active-h5-0-0",False),
(11,"3月","Bob","L. 一颗夹星糖🌟","3月12日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(12,"3月","Tom","阿雅呀","3月15日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(13,"3月","Tom","Anna","3月4日",1999,"抖音","","newmedia-dianpu-douyin-0-0",True),
(14,"3月","Bob","Echo Liang","3月15日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
(15,"3月","Tom","幼兒園高材生🍼","3月23日",3598,"微信小店","13055770067","sales-adp-cd-yy-0",False),
(16,"3月","Tom","Nancy","3月26日",599,"端内","","app-active-h5-0-0",False),
(17,"3月","Tom","依米","3月30日",3598,"微信小店","","sales-adp-cd-zjf-0",False),
(18,"3月","Bob","zhouyun","3月6日",1999,"小红书-学霸老王","13588706769","newmedia-daren-xhs-学霸老王讲真话-0",False),
(19,"3月","Tom","💗小超人棒棒哒🍭","3月29日",3598,"小红书-晚柠","18630368296","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(20,"3月","Bob","鹿","3月14日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(21,"4月","小龙","琳溪","4月19日",3598,"微信小店","","sales-adp-bj-jxl-0",False),
(22,"4月","小龙","小丽","4月26日",599,"端内","","app-active-h5-0-0",False),
(23,"4月","小龙","子曦","4月16日",3598,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(24,"4月","小龙","Gaᴗao","4月24日",3598,"微信小店","","sales-adp-bj-jxl-0",False),
(25,"4月","吴迪","彩让措","2026/4/26",599,"端内","","app-active-h5-0-0",False),
(26,"4月","吴迪","莉筱雅","2026/4/27",1999,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(27,"4月","吴迪","爱吃巧克力","2026/4/24",1999,"微信小店","","sales-adp-bj-wd-0",False),
(28,"4月","吴迪","Aa~Jessie💝","2026/4/27",1999,"抖音","","newmedia-dianpu-douyin-0-0",True),
(29,"4月","吴迪","🐷","2026/4/26",3598,"宣儿妈妈-小红书","","sales-adp-cd-yy-0",False),
(30,"4月","吴迪","🐷","2026/4/26",3598,"宣儿妈妈-小红书","","sales-adp-cd-yy-0",False),
(31,"4月","Tom","静静是我🍃","4月8日",1999,"小红书-学霸老王","15975769851","partner-actives-0-0-0",False),
(32,"4月","Bob","胆大鬼","4月8日",3598,"小红书-学霸老王","15262255267","newmedia-daren-xhs-学霸老王讲真话-0",False),
(33,"4月","Tom","希Cissy-427","4月27日",3598,"微信小店","","sales-adp-cd-zjf-0",False),
(34,"4月","Tom","Kerry","4月9日",3598,"微信小店","18328334683","sales-adp-cd-yy-0",False),
(35,"4月","Tom","SHAN_Q_Q","4月1日",3598,"小红书-官店","","newmedia-dianpu-xhs-0-0",True),
(36,"5月","小龙","Sia","5月9日",599,"微信小店","","sales-adp-bj-jxl-0",False),
(37,"5月","吴迪","","2026/5/9",1999,"微信小店","","sales-adp-bj-wd-0",False),
(38,"5月","吴迪","^_^","2026/5/16",3598,"晚柠-小红书","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(39,"5月","吴迪","🌸白色铃兰🌸","2026/5/17",3598,"抖音","","newmedia-dianpu-douyin-0-0",True),
(40,"5月","吴迪","咔咔","2026/5/7",3598,"微信小店","","sales-adp-bj-wd-0",False),
(41,"5月","吴迪","梦马","2026/5/21",3598,"小红书","","newmedia-dianpu-xhs-0-0",False),
(42,"5月","吴迪","梦马","2026/5/21",3598,"小红书","","newmedia-dianpu-xhs-0-0",False),
(43,"5月","吴迪","小西瓜","2026/5/30",1999,"微信小店","","sales-adp-bj-wd-0",False),
(44,"5月","吴迪","","2026/5/9",1999,"微信小店","","sales-adp-bj-wd-0",False),
(45,"5月","Bob","Yuki-515","5月15日",3598,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(46,"5月","Tom","冬-515","5月15日",1999,"小红书-晚柠","","newmedia-daren-xhs-晚柠也是个妈妈了-0",False),
(47,"5月","Bob","微笑向暖","5月4日",1999,"微信小店","","sales-adp-bj-wd-0",False),
(48,"5月","Bob","cici-511","5月11日",1999,"微信小店","","sales-adp-cd-xsy-0",False),
(49,"5月","Tom","🐷-519","5月19日",1999,"小红书-宣儿妈妈","","newmedia-daren-xhs-宣儿妈妈%",False),
(50,"5月","Bob","妃-516","5月16日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
(51,"5月","Tom","黄晔-516","5月16日",3598,"微信小店","","sales-adp-bj-wd-0",False),
(52,"5月","Tom","朵朵呀!","5月25日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
(53,"5月","Tom","雷鸣-414","5月14日",599,"微信小店","","sales-adp-bj-wd-0",False),
(54,"5月","Tom","毛阿毛🐱-520","5月20日",1999,"小红书-官店","","newmedia-dianpu-xhs-0-0",True),
(55,"5月","Tom","____Miss_y-519","5月19日",599,"微信小店","","sales-adp-bj-wd-0",False),
(56,"5月","Tom","Mandy-526","5月26日",1999,"微信小店","","sales-adp-bj-wd-0",False),
(57,"5月","Bob","Yoki-529","5月29日",1999,"微信小店","","sales-adp-cd-zjf-0",False),
]
def parse_date(d):
d = d.replace("","").replace("","/").replace(" ","").strip()
if "/" in d:
parts = d.split("/")
if len(parts) >= 2 and parts[1]:
return f"2026-{int(parts[0]):02d}-{int(parts[1]):02d}"
return None
from scripts.phone_encrypt import encrypt_phone
# Pre-encrypt phones
phone_enc = {}
for g in gaps:
if g[7]:
phone_enc[g[7]] = encrypt_phone(g[7])
# Get account IDs for phones
phone_to_aid = {}
if phone_enc:
conds = " OR ".join([f"tel_encrypt LIKE '{v}%'" for v in phone_enc.values()])
for r in q(f"SELECT id, tel_encrypt FROM bi_vala_app_account WHERE status=1 AND ({conds})"):
if len(r) >= 2:
phone_to_aid[r[1]] = r[0]
# For each phone-matched account, get ALL orders + refunds
phone_all = {} # aid -> {orders: [...], refunds_by_trade: {...}}
for aid in phone_to_aid.values():
orders = []
for r in q(f"SELECT id, trade_no, pay_amount_int, to_char(pay_success_date,'YYYY-MM-DD'), key_from, order_status FROM bi_vala_order WHERE account_id={aid} AND pay_amount_int IN (59900,199900,359800) AND order_status IN (3,4) AND pay_success_date IS NOT NULL ORDER BY pay_success_date"):
if len(r) >= 6:
orders.append({"id":r[0],"trade_no":r[1],"amount":int(r[2]),"pay_date":r[3],"key_from":r[4],"status":r[5]})
refunds = {}
if orders:
trades = ",".join([f"'{o['trade_no']}'" for o in orders])
for r in q(f"SELECT trade_no, SUM(refund_amount_int) FROM bi_refund_order WHERE trade_no IN ({trades}) AND status=3 GROUP BY trade_no"):
if len(r) >= 2 and r[1]:
refunds[r[0]] = int(r[1])
phone_all[aid] = {"orders": orders, "refunds": refunds}
# For each gap, query
for g in gaps:
idx, month, sales, nick, date_str, amount, channel, phone, keyfrom, is_direct = g
d = parse_date(date_str)
amt = amount * 100
found = None
gsv = 0
# Phone match - get all matching orders
if phone and phone in phone_enc:
enc = phone_enc[phone]
aid = phone_to_aid.get(enc)
if aid and aid in phone_all:
matching = [o for o in phone_all[aid]["orders"] if o["amount"] == amt]
if matching:
# Calculate total GSV: sum all order amounts minus refunds
total_amt = sum(o["amount"] for o in phone_all[aid]["orders"])
total_refund = sum(phone_all[aid]["refunds"].values())
gsv = total_amt - total_refund
found = matching[0] # Use first match for display
# Show all orders
found["all_orders"] = phone_all[aid]["orders"]
found["all_refunds"] = phone_all[aid]["refunds"]
# Keyfrom + date match
if not found and d and keyfrom:
if "%" in keyfrom:
like = keyfrom.replace("%","")
rows = q(f"SELECT o.id, o.trade_no, o.pay_amount_int, to_char(o.pay_success_date,'YYYY-MM-DD'), o.key_from, o.order_status, o.account_id FROM bi_vala_order o JOIN bi_vala_app_account a ON o.account_id=a.id WHERE a.status=1 AND o.order_status IN (3,4) AND o.pay_success_date::date BETWEEN '{d}'::date-1 AND '{d}'::date+1 AND o.pay_amount_int={amt} AND o.key_from LIKE '%{like}%' LIMIT 3")
else:
rows = q(f"SELECT o.id, o.trade_no, o.pay_amount_int, to_char(o.pay_success_date,'YYYY-MM-DD'), o.key_from, o.order_status, o.account_id FROM bi_vala_order o JOIN bi_vala_app_account a ON o.account_id=a.id WHERE a.status=1 AND o.order_status IN (3,4) AND o.pay_success_date::date BETWEEN '{d}'::date-1 AND '{d}'::date+1 AND o.pay_amount_int={amt} AND o.key_from='{keyfrom}' LIMIT 3")
if rows and len(rows[0]) >= 7:
r = rows[0]
aid = r[6]
trade = r[1]
# Get refund for this specific trade
ref_rows = q(f"SELECT SUM(refund_amount_int) FROM bi_refund_order WHERE trade_no='{trade}' AND status=3")
refund = 0
if ref_rows and ref_rows[0] and ref_rows[0][0] and ref_rows[0][0].isdigit():
refund = int(ref_rows[0][0])
gsv = int(r[2]) - refund
found = {"id":r[0],"trade_no":r[1],"amount":int(r[2]),"pay_date":r[3],"key_from":r[4],"status":r[5],"account_id":aid}
status = "" if found else ""
should = "" if (found and gsv > 0 and not is_direct) else ""
print(f"{idx}. [{month}] {sales} {nick} | {date_str} ¥{amount} {channel} | {status} | GSV={gsv/100:.0f} | 应进Bot={should}")
if found:
if "all_orders" in found:
for o in found["all_orders"]:
ref = found["all_refunds"].get(o["trade_no"], 0)
net = o["amount"] - ref
print(f" order_id={o['id']} {o['pay_date']} ¥{o['amount']/100:.0f} {o['key_from'][:50]} status={o['status']} 退={ref/100:.0f} 净={net/100:.0f}")
else:
print(f" order_id={found['id']} {found.get('pay_date','')} ¥{found['amount']/100:.0f} {found.get('key_from','')[:60]} status={found.get('status','')}")