① 一句话架构:发票 4 大模型 🏗️
| 模型 | 字段 | 精度 |
|---|---|---|
| 发票头 | 号码、日期、买方、卖方 | 文本 |
| 商品行 | 名称、数量、单价、税率 | 金额 Decimal |
| 价税合计 | 不含税、税额、含税 | Decimal 2 位 |
| PDF 版式 | 二维码、章、水印 | 版式文件 |
口诀:“头行税,PDF,Decimal 无误差” 🎵
② 模型层:发票头 + 商品行(Decimal)💰
from decimal import Decimal, ROUND_HALF_UP
class InvoiceItem:
def __init__(self, name: str, qty: int, price: Decimal, tax_rate: Decimal):
self.name = name
self.qty = qty
self.price = price
self.tax_rate = tax_rate
@property
def amount(self) -> Decimal:
"""不含税金额"""
return (self.qty * self.price).quantize(Decimal('0.01'), ROUND_HALF_UP)
@property
def tax(self) -> Decimal:
"""税额"""
return (self.amount * self.tax_rate).quantize(Decimal('0.01'), ROUND_HALF_UP)
@property
def total(self) -> Decimal:
"""含税金额"""
return self.amount + self.tax
③ 发票头:自动编号 + 日期 📅
import datetime, uuid
class InvoiceHeader:
def __init__(self, buyer: str, seller: str):
self.number = str(uuid.uuid4())[:8] # 模拟号码
self.date = datetime.date.today()
self.buyer = buyer
self.seller = seller
self.items: list[InvoiceItem] = []
def add_item(self, item: InvoiceItem):
self.items.append(item)
@property
def total_amount(self) -> Decimal:
return sum(i.amount for i in self.items)
@property
def total_tax(self) -> Decimal:
return sum(i.tax for i in self.items)
@property
def total_with_tax(self) -> Decimal:
return self.total_amount + self.total_tax
④ 使用演示:10 行开票 🚀
if __name__ == "__main__":
inv = InvoiceHeader("买方公司", "卖方公司")
inv.add_item(InvoiceItem("咖啡", 2, Decimal('35.00'), Decimal('0.13'))) # 13% 税率
inv.add_item(InvoiceItem("三明治", 1, Decimal('78.00'), Decimal('0.13')))
print(f"发票号:{inv.number}")
print(f"不含税:{inv.total_amount}")
print(f"税额:{inv.total_tax}")
print(f"含税:{inv.total_with_tax}")
运行:
python invoice_demo.py→ 输出发票摘要!
⑤ PDF 版式:模板 + 二维码 + 章 🖨️
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import A4
import qrcode
def make_pdf(invoice: InvoiceHeader, filename: str):
c = canvas.Canvas(filename, pagesize=A4)
width, height = A4
# 标题
c.setFont("Helvetica-Bold", 20)
c.drawString(50, height - 50, "电子发票")
# 发票头
c.setFont("Helvetica", 12)
c.drawString(50, height - 100, f"发票号:{invoice.number}")
c.drawString(50, height - 120, f"日期:{invoice.date}")
c.drawString(50, height - 140, f"买方:{invoice.buyer}")
c.drawString(50, height - 160, f"卖方:{invoice.seller}")
# 商品行
y = height - 200
for i, item in enumerate(invoice.items):
c.drawString(50, y - i * 20, f"{item.name} ×{item.qty} {item.amount} + {item.tax} = {item.total}")
# 价税合计
c.setFont("Helvetica-Bold", 14)
c.drawString(50, y - len(invoice.items) * 20 - 40, f"不含税:{invoice.total_amount}")
c.drawString(50, y - len(invoice.items) * 20 - 60, f"税额:{invoice.total_tax}")
c.drawString(50, y - len(invoice.items) * 20 - 80, f"含税:{invoice.total_with_tax}")
# 二维码
qr = qrcode.make(invoice.number)
qr.save("qr.png")
c.drawImage("qr.png", width - 150, height - 200, width=100, height=100)
c.save()
运行:
make_pdf(inv, "invoice.pdf")→ 生成正式发票!
⑥ 批量导出:CSV + 彩虹金额 🌈
import pandas as pd
def export_csv(invoice: InvoiceHeader, filename: str):
df = pd.DataFrame([
{
"发票号": invoice.number,
"商品": item.name,
"数量": item.qty,
"单价": item.price,
"税率": item.tax_rate,
"不含税": item.amount,
"税额": item.tax,
"含税": item.total,
}
for item in invoice.items
])
df.to_csv(filename, index=False, float_format="%.2f")
print(f"✅ 已导出:{filename}")
# 使用
export_csv(inv, "invoice.csv")
⑦ 彩蛋:终端彩虹发票(15 行)🌈
import random, math, os
from decimal import Decimal
def rainbow_invoice(invoice: InvoiceHeader):
os.system('clear||cls')
for i, item in enumerate(invoice.items):
r = int(255 * (1 + math.cos(i * 2 * math.pi / len(invoice.items))) / 2)
g = int(255 * (1 + math.cos(i * 2 * math.pi / len(invoice.items) + 2)) / 2)
b = int(255 * (1 + math.cos(i * 2 * math.pi / len(invoice.items) + 4)) / 2)
print(f"\033[38;2;{r};{g};{b}m{item.name} ×{item.qty} = {item.total}\033[0m")
print(f"\033[1m\033[36m含税:{invoice.total_with_tax}\033[0m")
# 使用
rainbow_invoice(inv)
运行:
python rainbow_invoice.py→ 彩虹渐变发票!
⑧ 万能解毒剂:检查清单 ✅
| 场景 | 解毒法 |
|---|---|
| 金额存储 | int 分厘 或 Decimal |
| 税率计算 | quantize(Decimal('0.01'), ROUND_HALF_UP) |
| 批量导出 | pandas.to_csv(float_format='%.2f') |
| PDF 版式 | reportlab + qrcode |
⑨ 彩蛋:打包 EXE(一键发送)📦
pip install pyinstaller
pyinstaller -F invoice_demo.py
# dist/invoice_demo.exe 直接发