📦 Tyche — Goddess of Fortune — 泰克 — 命运女神
v1.0.0从简单的CSV客户列表生成专业发票,跟踪付款和逾期状态,计算滞纳金,并发送自动提醒。
运行时依赖
安装命令
点击复制技能文档
⚖️ Tyche — Invoice & Fortune Engine & Payments v1.0 ⚡ 快速开始 创建一个 CSV 文件,包含以下列:client_name、client_email、description、amount、due_date、status 设置 INVOICES_FILE 为您的 CSV 文件路径 设置 YOUR_NAME、YOUR_EMAIL 运行 — 自动生成发票和过期提醒 您将获得: 每个未付发票的单独 invoice_[INV-XXXX]_[client].md 文件 — 可以发送或转换为 PDF 可选的滞纳金计算 — 当 LATE_FEE_RATE 设置时,自动添加到发票总额 每个发票的付款方式部分 — 银行详情、PayPal 或其他付款方式 过期状态报告:哪些发票已过期,过期天数 3 级提醒模板:友好提醒、严格提醒、最终通知 运行收入跟踪器:已付款 vs 未付款 注意:⚖️ Tyche — Invoice & Fortune Engine 编号(INV-0001、INV-0002、…)在每次运行时根据 CSV 文件中的行顺序顺序分配。为了保持编号的一致性,请在 CSV 文件中添加 inv_number 列。 🔒 安全 完全在本地运行。无数据传输。 步骤 1 — 安装 pip3 install rich --break-system-packages --quiet 步骤 2 — 生成发票和付款提醒 导入 os、csv、re 从 datetime 导入 datetime、timedelta 从 rich.console 导入 Console 从 rich.table 导入 Table 从 rich.panel 导入 Panel 从 rich 导入 box console = Console() INVOICES_FILE = os.environ.get("INVOICES_FILE", "") YOUR_NAME = os.environ.get("YOUR_NAME", "Your Name / Company") YOUR_EMAIL = os.environ.get("YOUR_EMAIL", "your@email.com") YOUR_ADDRESS = os.environ.get("YOUR_ADDRESS", "") PAYMENT_TERMS = os.environ.get("PAYMENT_TERMS", "Net 30") CURRENCY = os.environ.get("CURRENCY", "USD") try: TAX_RATE = float(os.environ.get("TAX_RATE", "0")) except ValueError: console.print("[yellow]⚠️ TAX_RATE 必须是数字 — 默认为 0[/yellow]") TAX_RATE = 0.0 try: LATE_FEE_RATE = float(os.environ.get("LATE_FEE_RATE", "0")) except ValueError: console.print("[yellow]⚠️ LATE_FEE_RATE 必须是数字 — 默认为 0[/yellow]") LATE_FEE_RATE = 0.0 PAYMENT_METHOD = os.environ.get("PAYMENT_METHOD", "") CURRENCY_SYMBOL = {"USD":"$","EUR":"€","GBP":"£","CAD":"CA$","AUD":"AU$"}.get(CURRENCY,"$") invoices = [] def _parse_amount(raw: str) -> float: """去除非数字字符,防止多个小数点,返回浮点数。」 cleaned = re.sub(r"[^0-9.]", "", raw) 或 "0" return float(cleaned) 如果 cleaned.count(".") <= 1 否则 0.0 if INVOICES_FILE 和 os.path.exists(INVOICES_FILE): with open(INVOICES_FILE, encoding="utf-8", errors="replace") as f: reader = csv.DictReader(f) for i, row in enumerate(reader, 1): invoices.append({ "inv_number": row.get("inv_number", f"INV-{i:04d}"), "client_name": row.get("client_name","Client"), "client_email": row.get("client_email",""), "description": row.get("description","Services rendered"), "amount": _parse_amount(row.get("amount", "0")), "due_date": row.get("due_date",""), "status": row.get("status","unpaid").lower(), }) else: console.print("[yellow]未设置 INVOICES_FILE。使用演示数据。[/yellow]") today = datetime.now() invoices = [ {"inv_number":"INV-0001","client_name":"Acme Corp","client_email":"acme@example.com","description":"Website redesign — Phase 1","amount":3500,"due_date":(today-timedelta(days=45)).strftime("%Y-%m-%d"),"status":"unpaid"}, {"inv_number":"INV-0002","client_name":"Beta LLC","client_email":"beta@example.com","description":"SEO audit and strategy","amount":1200,"due_date":(today-timedelta(days=10)).strftime("%Y-%m-%d"),"status":"unpaid"}, {"inv_number":"INV-0003","client_name":"Gamma Inc","client_email":"gamma@example.com","description":"Monthly retainer — April","amount":2000,"due_date":(today+timedelta(days=15)).strftime("%Y-%m-%d"),"status":"unpaid"}, {"inv_number":"INV-0004","client_name":"Delta Co","client_email":"delta@example.com","description":"Brand identity package","amount":4000,"due_date":(today-timedelta(days=5)).strftime("%Y-%m-%d"),"status":"paid"}, ] today = datetime.now().date() for inv in invoices: try: due = datetime.strptime(inv["due_date"], "%Y-%m-%d").date() days_overdue = (today - due).days except Exception: due = today days_overdue = 0 inv["due_date_parsed"] = due inv["days_overdue"] = days_overdue inv["is_overdue"] = days_overdue > 0 和 inv["status"] != "paid" tax = inv["amount"] TAX_RATE / 100 # Late fee: compound monthly (days_overdue / 30 months) late_fee = 0.0 if LATE_FEE_RATE > 0 和 inv["is_overdue"]: months_late = days_overdue / 30 late_fee = inv["amount"] (LATE_FEE_RATE / 100) * months_late inv["tax"] = tax inv["late_fee"] = round(late_fee, 2) inv["total"] = inv["amount"] + tax + late_fee