版本:2026-10-23 v1.0 · 适用所有垂直站
输出:PDF / HTML / 邮件正文,统一格式
/opt/golddigger-textile/api/templates/monthly_statement.fdf)
%FDF-1.2
%âãÏÓ
1 0 obj
<<
/FDF
/Fields [
<<
/V (201)
/T (year)
<<
/V (11)
/T (month)
<<
/V (GoldDigger Textile 月度对账单)
/T (title)
<<
/V (6799)
/T (agent_code)
<<
/V (王芳代理)
/T (agent_name)
<<
/V (盛泽家纺代理 · Vietnam)
/T (agent_label)
<<
/V (25% L1+33% L1+=33%)
/T (rate_label)
<<
/V (6799 → 1983 → 6944)
/T (downline_chain)
<<
/V (6799)
/T (referral_code)
<<
/V (L1+ 达标代理 · 永久 33% 锁定)
/T (level_label)
<<
/V (true)
/T (bonus_unlocked)
<<
/V (3338.50)
/T (ytd_sales_prev)
<<
/V (55480.50)
/T (ytd_sales_current)
<<
/V (1499.25)
/T (ytd_nested_prev)
<<
/V (1499.25)
/T (ytd_nested_current)
<<
/V ([{sale_id,buyer_id,date,sku,amount_usd,discount_usd,rate,final_usd,...}])
/T (sales_detail_json)
<<
/V (14573.43)
/T (direct_commission)
<<
/V (49.98)
/T (nested_commission)
<<
/V (14623.41)
/T (total_commission)
<<
/V (0)
/T (withholding_tax)
<<
/V (14623.41)
/T (net_payment)
<<
/V (2043.42)
/T (usd_equivalent)
<<
/V (7.15)
/T (exchange_rate)
<<
/V (wfang@shengze-textile.example.com)
/T (agent_email)
<<
/V (+86-138-1111-2222)
/T (agent_whatsapp)
<<
/V (XXX Bank / SWIFT XXX / Account XXX)
/T (agent_bank_info)
<<
/V (2026-11-15)
/T (settlement_date)
<<
/V (2026-11-01)
/T (statement_date)
<<
/V (王芳)
/T (agent_recipient_name)
<<
/V (Hanoi, Vietnam)
/T (agent_recipient_address)
<<
/V (uuid-or-signature-placeholder)
/T (signature)
<<
/V (GoldDigger Textile Platform · factorihub@outlook.com)
/T (platform_signature)
>>
/T (monthly_statement_golddigger_v1)
endobj
trailer
<<
/Root 1 0 R
>>
%%EOF
| 字段 | 类型 | 来源 | 示例 |
|---|---|---|---|
| year | int | 当前自然年 | 2026 |
| month | int | 当前自然月 | 11 |
| title | str | 固定 | "GoldDigger Textile 月度对账单" |
| agent_code | str | agents.json | "6799" |
| agent_name | str | agents.json.name_cn | "王芳代理" |
| agent_label | str | 拼接 | "盛泽家纺代理 · Vietnam" |
| rate_label | str | 拼接 | "25% L1+33% L1+=33%" |
| downline_chain | str | 上线链 | "6799 → 1983 → 6944" |
| referral_code | str | agents.json | "6799" |
| level_label | str | 自动判断 | "L1+ 达标代理 · 永久 33% 锁定" |
| bonus_unlocked | bool | ytd ≥ ¥10,000 | true |
| ytd_sales_prev | float | 上月 ytd_sales | 3338.50 |
| ytd_sales_current | float | 本月 ytd_sales | 55480.50 |
| ytd_nested_prev | float | 上月 ytd_nested | 1499.25 |
| ytd_nested_current | float | 本月 ytd_nested | 1499.25 |
| sales_detail_json | str | sales.json | "[{...}]" |
| direct_commission | float | 计算 | 14573.43 |
| nested_commission | float | 计算 | 49.98 |
| total_commission | float | 直接 + 嵌套 | 14623.41 |
| withholding_tax | float | 海外代扣(0/5/10%) | 0 |
| net_payment | float | 总 - 税 | 14623.41 |
| usd_equivalent | float | 汇率换算 | 2043.42 |
| exchange_rate | float | 7.15 | 7.15 |
| agent_email | str | agents.json | "..." |
| agent_whatsapp | str | agents.json | "..." |
| agent_bank_info | str | 拼接 | "XXX Bank / SWIFT XXX / Account XXX" |
| settlement_date | date | 每月 15 日 | "2026-11-15" |
| statement_date | date | 每月 1 日 | "2026-11-01" |
| agent_recipient_name | str | 拼接 | "王芳" |
| agent_recipient_address | str | agents.json | "Hanoi, Vietnam" |
| signature | str | uuid 或留空 | 签字占位 |
| platform_signature | str | 固定 | "GoldDigger Textile Platform · factorihub@outlook.com" |
# 月对账单渲染
import jinja2
import pdfkit
from datetime import datetime
# 数据
ctx = {
"year": 2026, "month": 11,
"agent_code": "6799", "agent_name": "王芳代理",
# ... 22 个字段
}
# 模板(HTML + CSS)
html = jinja2.Template("""
<!DOCTYPE html>
<html>
<head>
<style>
@page {{ size: A4; margin: 18mm; }}
body {{ font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif; font-size: 11px; }}
.title {{ font-size: 22px; font-weight: 900; color: #F59E0B; }}
.kpi-row {{ display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; }}
.kpi {{ padding: 14px; background: rgba(14,116,144,.1); border-radius: 8px; }}
.kpi-num {{ font-size: 26px; font-weight: 900; color: #F59E0B; }}
table {{ width: 100%; border-collapse: collapse; margin-top: 10px; }}
th, td {{ padding: 6px 9px; border-bottom: 1px solid #E5E7EB; text-align: left; }}
th {{ background: #0E7490; color: #fff; font-size: 10.5px; }}
.fdf {{ font-size: 9.5px; color: #94A3B8; margin-top: 20px; }}
</style>
</head>
<body>
<div class="title">GoldDigger Textile 月度对账单</div>
<div>代理商:{{ agent_name }} ({{ agent_code }}) · 等级:{{ level_label }}</div>
<div>月份:{{ year }}-{{ month:02d }} · 对账日:{{ statement_date }} · 打款日:{{ settlement_date }}</div>
<div class="kpi-row">
<div class="kpi">
<div class="kpi-num">¥{{ '{:,.2f}'.format(direct_commission) }}</div>
<div>直接佣金</div>
</div>
<div class="kpi">
<div class="kpi-num">¥{{ '{:,.2f}'.format(nested_commission) }}</div>
<div>嵌套佣金(2 级)</div>
</div>
<div class="kpi">
<div class="kpi-num">¥{{ '{:,.2f}'.format(total_commission) }}</div>
<div>月总佣金</div>
</div>
</div>
<h3>累计 YTD</h3>
<table>
<tr><th>项目</th><th>上月</th><th>本月</th></tr>
<tr><td>ytd_sales(自己推)</td><td>¥{{ '{:,.2f}'.format(ytd_sales_prev) }}</td><td>¥{{ '{:,.2f}'.format(ytd_sales_current) }}</td></tr>
<tr><td>ytd_nested(下线嵌套)</td><td>¥{{ '{:,.2f}'.format(ytd_nested_prev) }}</td><td>¥{{ '{:,.2f}'.format(ytd_nested_current) }}</td></tr>
</table>
<h3>订单明细({{ '{:d}'.format(sales|length) }} 笔)</h3>
<table>
<tr><th>日期</th><th>客户</th><th>SKU</th><th>原价</th><th>折扣</th><th>实付</th><th>佣金率</th></tr>
{% for s in sales %}
<tr>
<td>{{ s.date }}</td>
<td>{{ s.buyer_id }}</td>
<td>{{ s.sku }}</td>
<td>¥{{ '{:,.2f}'.format(s.amount_usd) }}</td>
<td>¥{{ '{:,.2f}'.format(s.discount_usd) }}</td>
<td>¥{{ '{:,.2f}'.format(s.final_usd) }}</td>
<td>{{ '{:.0%}'.format(s.rate) }}</td>
</tr>
{% endfor %}
</table>
<h3>打款信息</h3>
<div>收款人:{{ agent_recipient_name }} · {{ agent_recipient_address }}</div>
<div>Email:{{ agent_email }} · WhatsApp:{{ agent_whatsapp }}</div>
<div>银行:{{ agent_bank_info }}</div>
<div class="fdf">本对账单由 GoldDigger SI Agent 自动生成 · 平台签名:{{ platform_signature }}</div>
</body>
</html>
""").render(**ctx)
pdfkit.from_string(html, "statement_6799_2026-11.pdf", options={"page-size": "A4"})
# server/api/statement_pdf.py
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table
def gen_statement_pdf(ctx, out_path):
doc = SimpleDocTemplate(out_path, pagesize=A4)
styles = getSampleStyleSheet()
elems = []
elems.append(Paragraph(f"<b>GoldDigger Textile 月度对账单 · {ctx['year']}-{ctx['month']:02d}</b>", styles["Title"]))
# ... 22 字段
doc.build(elems)
# direct_commission
direct = sum(
s["discount_usd"]
for s in sales
if s["status"] == "paid" and not s.get("refunded", False)
)
# nested_commission
nested = sum(
s["discount_usd"] * NESTED_RATES[d - 1] # 1 级 5% / 2 级 3%
for s in sales
for d, upline in enumerate(_get_upchain(s["agent_code"], 1), start=1)
if d <= MAX_DEPTH
)
# total
total = direct + nested
# withholding_tax(海外代扣)
if agent["country"] in OVERSEAS_NO_TAX:
tax = 0
elif total < 800:
tax = 0
elif total < 5000:
tax = total * 0.05
else:
tax = total * 0.10
net = total - tax
# usd_equivalent
usd = net / EXCHANGE_RATES.get(agent["country"], 7.15)
| 日期 | 动作 | 责任 |
|---|---|---|
| 1 日 00:00 | 系统 cron 跑 gen_monthly_statement.py | 系统 |
| 1 日 09:00 | 邮件推送 PDF + HTML + JSON 给代理 | 系统 |
| 1-3 日 | 代理在 dashboard 自助确认 | 代理 |
| 4-7 日 | 平台财务复核 | 平台 |
| 8 日 | 系统自动签名 + 加 FDF 表单 | 系统 |
| 8-10 日 | 代理确认 → 双方签字(uuid + 时间戳) | 代理 |
| 11-14 日 | 财务复核 + 准备打款 | 平台 |
| 15 日 | T+15 银行打款 | 平台 |
P1 排期(3 周内): 月对账单 PDF 自动生成 + 邮件推送 + 平台签名
P1 排期(4 周内): 月打款自动化(银行 API / Wise / 银企直连)
P2 排期(1 月内): 代理 dashboard 自助确认 + 签字 + 争议
P2 排期(2 月内): 月对账发票自动开具
| 文件 | 路径 | 作用 |
|---|---|---|
| 模板 FDF | /opt/golddigger-textile/api/templates/monthly_statement.fdf | FDF 表单定义 |
| HTML 模板 | /opt/golddigger-textile/api/templates/monthly_statement.html.j2 | Jinja2 模板 |
| 生成器 | /opt/golddigger-textile/api/gen_monthly_statement.py | 自动生成 + 邮件推送 |
| 渲染器 | /opt/golddigger-textile/api/render_statement.py | HTML→PDF 渲染 |
def test_monthly_statement():
# 模拟 6799 在 2026-11 月的 5 笔销售
sales = [
{"sale_id": "s1", "buyer_id": "buyer-1", "date": "2026-11-02", "sku": "Pro-年费", "amount_usd": 1999, "discount_usd": 499.75, "rate": 0.25, "final_usd": 1499.25},
{"sale_id": "s2", "buyer_id": "buyer-2", "date": "2026-11-05", "sku": "Pro-年费", "amount_usd": 1999, "discount_usd": 499.75, "rate": 0.25, "final_usd": 1499.25},
{"sale_id": "s3", "buyer_id": "buyer-3", "date": "2026-11-10", "sku": "蒸馏 100 次", "amount_usd": 199, "discount_usd": 49.75, "rate": 0.25, "final_usd": 149.25},
{"sale_id": "s4", "buyer_id": "buyer-4", "date": "2026-11-15", "sku": "Pro-年费", "amount_usd": 1999, "discount_usd": 499.75, "rate": 0.25, "final_usd": 1499.25},
{"sale_id": "s5", "buyer_id": "buyer-5", "date": "2026-11-20", "sku": "蒸馏 50 次", "amount_usd": 99, "discount_usd": 24.75, "rate": 0.25, "final_usd": 74.25},
]
direct = sum(s["discount_usd"] for s in sales) # 1573.75
# 假设 6799 有 1 个下线 1983,1983 当月卖 1 笔 ¥1999
nested_1 = 1999 * 0.25 * 0.05 # 24.99
# 假设 1983 有 1 个下线 6944,6944 当月卖 1 笔 ¥1999
nested_2 = 1999 * 0.25 * 0.03 # 14.99
total = direct + nested_1 + nested_2 # 1613.73
tax = 0 # 海外
assert total == 1573.75 + 24.99 + 14.99
print(f" ✅ 月对账单:直接 ¥{direct} + 嵌套 ¥{nested_1 + nested_2} = ¥{total}")
附录 A · 配套文件
business/DISTRIBUTION_PLAN.md · 16.4KB · 内部商业方案 v1.2business/MARKETING_INTRO.md · 13KB · 客户友好版business/STATEMENT_TEMPLATE.md · 本文件下一步: 1) 实现 gen_monthly_statement.py (P1, 2-3 周),2) 邮件推送模板(P1, 1 周),3) PDF 签名(P1, 1 周)。