🤖 每日自动备份 - 2026-06-15 08:00:01
This commit is contained in:
parent
f4fac513f0
commit
4135e93b17
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"updatedAt": "2026-06-09T07:36:53.566Z",
|
"updatedAt": "2026-06-14T07:14:40.970Z",
|
||||||
"entries": {
|
"entries": {
|
||||||
"memory:memory/2026-05-06.md:1:20": {
|
"memory:memory/2026-05-06.md:1:20": {
|
||||||
"key": "memory:memory/2026-05-06.md:1:20",
|
"key": "memory:memory/2026-05-06.md:1:20",
|
||||||
@ -462,22 +462,25 @@
|
|||||||
"endLine": 30,
|
"endLine": 30,
|
||||||
"source": "memory",
|
"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 废弃清空、每日线索月合计行金色",
|
"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,
|
"dailyCount": 0,
|
||||||
"groundedCount": 0,
|
"groundedCount": 0,
|
||||||
"totalScore": 4,
|
"totalScore": 6,
|
||||||
"maxScore": 1,
|
"maxScore": 1,
|
||||||
"firstRecalledAt": "2026-06-03T00:01:27.128Z",
|
"firstRecalledAt": "2026-06-03T00:01:27.128Z",
|
||||||
"lastRecalledAt": "2026-06-05T14:06:12.562Z",
|
"lastRecalledAt": "2026-06-14T07:14:40.970Z",
|
||||||
"queryHashes": [
|
"queryHashes": [
|
||||||
"5f57ba3c20a6",
|
"5f57ba3c20a6",
|
||||||
"b76e8457b2ee",
|
"b76e8457b2ee",
|
||||||
"4354c1e39886",
|
"4354c1e39886",
|
||||||
"70f4bbaea7b1"
|
"70f4bbaea7b1",
|
||||||
|
"d26345ebc273",
|
||||||
|
"cd28f28f1a7c"
|
||||||
],
|
],
|
||||||
"recallDays": [
|
"recallDays": [
|
||||||
"2026-06-03",
|
"2026-06-03",
|
||||||
"2026-06-05"
|
"2026-06-05",
|
||||||
|
"2026-06-14"
|
||||||
],
|
],
|
||||||
"conceptTags": [
|
"conceptTags": [
|
||||||
"备份",
|
"备份",
|
||||||
@ -601,18 +604,20 @@
|
|||||||
"endLine": 33,
|
"endLine": 33,
|
||||||
"source": "memory",
|
"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`",
|
"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,
|
"dailyCount": 0,
|
||||||
"groundedCount": 0,
|
"groundedCount": 0,
|
||||||
"totalScore": 1,
|
"totalScore": 2,
|
||||||
"maxScore": 1,
|
"maxScore": 1,
|
||||||
"firstRecalledAt": "2026-06-05T00:46:22.699Z",
|
"firstRecalledAt": "2026-06-05T00:46:22.699Z",
|
||||||
"lastRecalledAt": "2026-06-05T00:46:22.699Z",
|
"lastRecalledAt": "2026-06-14T06:58:06.164Z",
|
||||||
"queryHashes": [
|
"queryHashes": [
|
||||||
"34106cf619c4"
|
"34106cf619c4",
|
||||||
|
"6769ba9ebb36"
|
||||||
],
|
],
|
||||||
"recallDays": [
|
"recallDays": [
|
||||||
"2026-06-05"
|
"2026-06-05",
|
||||||
|
"2026-06-14"
|
||||||
],
|
],
|
||||||
"conceptTags": [
|
"conceptTags": [
|
||||||
"联报退费率最高49.2",
|
"联报退费率最高49.2",
|
||||||
@ -624,6 +629,68 @@
|
|||||||
"全角色无行课退费率75.9",
|
"全角色无行课退费率75.9",
|
||||||
"76.0"
|
"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≥C,pre怀疑#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
189
scripts/check_gap_57.py
Normal 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
173
scripts/check_gap_57_v2.py
Normal 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
197
scripts/check_gap_57_v3.py
Normal 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
193
scripts/check_gap_57_v4.py
Normal 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
147
scripts/check_gap_57_v5.py
Normal 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
172
scripts/check_gap_57_v6.py
Normal 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','')}")
|
||||||
Loading…
Reference in New Issue
Block a user