feat: implement cross-batch Alipay refund reconciliation
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>
This commit is contained in:
@@ -199,6 +199,20 @@
|
||||
dayData.set(category, (dayData.get(category) || 0) + amount);
|
||||
});
|
||||
|
||||
// 填充缺失的日期(零支出日期)
|
||||
const now = new Date();
|
||||
const allDates: string[] = [];
|
||||
const cursor = new Date(cutoffDate);
|
||||
while (cursor <= now) {
|
||||
allDates.push(formatLocalDate(cursor));
|
||||
cursor.setDate(cursor.getDate() + 1);
|
||||
}
|
||||
allDates.forEach(dateStr => {
|
||||
if (!dailyMap.has(dateStr)) {
|
||||
dailyMap.set(dateStr, new Map());
|
||||
}
|
||||
});
|
||||
|
||||
const dayCount = dailyMap.size;
|
||||
|
||||
// 根据天数决定聚合粒度
|
||||
|
||||
Reference in New Issue
Block a user