When a refund row in an uploaded Alipay bill has no matching expense row in the same batch (because the original purchase was uploaded in a prior batch), the refund is now reconciled against the stored record in bills_cleaned rather than being silently discarded. Changes: - analyzer/cleaners/base.py: add unresolved_refunds list to BaseCleaner - analyzer/cleaners/alipay.py: _aggregate_refunds stores full refund metadata (dict); _process_expenses tracks matched keys and populates self.unresolved_refunds for unmatched refunds - analyzer/server.py: thread unresolved_refunds through do_clean, CleanResponse, and both /clean endpoints - server/adapter/adapter.go: add UnresolvedRefund type and field to CleanResult - server/adapter/http/cleaner.go: deserialize unresolved_refunds from Python response and populate CleanResult - server/repository/repository.go: add ReconcileRefund to BillRepository interface - server/repository/mongo/repository.go: implement ReconcileRefund — full refund soft-deletes the bill, partial refund reduces amount and appends remark with original amount and refund order number - server/handler/upload.go: capture clean result and call ReconcileRefund for each unresolved refund after saving cleaned bills - server/model/response.go: add ReconciledRefundCount to UploadData Also: add CLAUDE.md (@AGENTS.md), update AGENTS.md, fix DailyTrendChart missing-date gap by filling zero-expense dates in daily map. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
BillAI Web
BillAI 的前端 Web 应用,基于 SvelteKit + Tailwind,提供账单分析/复核/管理等界面。
开发
yarn install
yarn dev
常用命令:
yarn check
yarn lint
yarn format
构建
yarn build
yarn preview
API 访问
- 开发环境下通过 SvelteKit/Vite 代理访问后端(统一使用相对路径,例如
/api/...) - Docker 部署时由
docker-compose.yaml将前端容器与后端容器联通
说明
前端展示层使用统一账单模型 UIBill(camelCase 字段 + amount:number),分析链路与详情编辑弹窗避免多种账单类型混用。