From 162742a4cd61fee740f41aca6ce893dafd37e947 Mon Sep 17 00:00:00 2001 From: 12975 <1297598740@qq.com> Date: Thu, 29 Jan 2026 22:32:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E4=BA=A4=E6=98=93?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=92=8CAI=E8=AE=B0=E8=B4=A6=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=EF=BC=8C=E5=AE=9E=E7=8E=B0=E4=BA=A4=E6=98=93=E7=9A=84?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E3=80=81=E9=AA=8C=E8=AF=81=E5=8F=8A=E8=B4=A6?= =?UTF-8?q?=E6=88=B7=E4=BD=99=E9=A2=9D=E6=9B=B4=E6=96=B0=E9=80=BB=E8=BE=91?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/service/ai_bookkeeping_service.go | 7 ++++--- internal/service/transaction_service.go | 12 ++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/internal/service/ai_bookkeeping_service.go b/internal/service/ai_bookkeeping_service.go index 960c027..8816a12 100644 --- a/internal/service/ai_bookkeeping_service.go +++ b/internal/service/ai_bookkeeping_service.go @@ -462,8 +462,9 @@ func (s *LLMService) ParseIntent(ctx context.Context, text string, history []Cha 1. 金额:提取数字,如"6元"=6,"十五"=15 2. 分类:根据内容推断,如"奶茶/咖啡/吃饭"=餐饮,"打车/地铁"=交通,"买衣服"=购物 3. 类型:默认expense(支出),除非明确说"收入/工资/奖金/红包" -4. 日期:默认使用今天的日期(%s),除非用户明确指定其他日期 -5. 备注:提取关键描述 +4. 金额:提取明确的数字。如果用户未提及具体金额(如只说"想吃炸鸡"),amount字段必须返回 0 +5. 日期:默认使用今天的日期(%s),除非用户明确指定其他日期 +6. 备注:提取关键描述 直接返回JSON,不要解释: {"amount":数字,"category":"分类","type":"expense或income","note":"备注","date":"YYYY-MM-DD","message":"简短确认"} @@ -1257,7 +1258,7 @@ func (s *AIBookkeepingService) getDefaultCategory(userID uint, txType string) (* // getMissingFields returns list of missing required fields func (s *AIBookkeepingService) getMissingFields(params *AITransactionParams) []string { var missing []string - if params.Amount == nil { + if params.Amount == nil || *params.Amount <= 0 { missing = append(missing, "amount") } if params.CategoryID == nil && params.Category == "" { diff --git a/internal/service/transaction_service.go b/internal/service/transaction_service.go index aa9d13a..1ed3357 100644 --- a/internal/service/transaction_service.go +++ b/internal/service/transaction_service.go @@ -351,6 +351,9 @@ func (s *TransactionService) UpdateTransaction(userID, id uint, input Transactio // Step 1: Reverse the old transaction's effect on balances oldReversedBalance := calculateNewBalance(oldAccount.Balance, existingTxn.Amount, existingTxn.Type, false) + if !oldAccount.IsCredit && oldReversedBalance < 0 { + return fmt.Errorf("%w: update would cause negative balance in account '%s'", ErrInsufficientBalance, oldAccount.Name) + } if err := txAccountRepo.UpdateBalance(userID, existingTxn.AccountID, oldReversedBalance); err != nil { return fmt.Errorf("failed to reverse old account balance: %w", err) } @@ -358,6 +361,9 @@ func (s *TransactionService) UpdateTransaction(userID, id uint, input Transactio // Reverse old transfer destination if applicable if oldToAccount != nil { oldToReversedBalance := oldToAccount.Balance - existingTxn.Amount + if !oldToAccount.IsCredit && oldToReversedBalance < 0 { + return fmt.Errorf("%w: update would cause negative balance in old destination account '%s'", ErrInsufficientBalance, oldToAccount.Name) + } if err := txAccountRepo.UpdateBalance(userID, *existingTxn.ToAccountID, oldToReversedBalance); err != nil { return fmt.Errorf("failed to reverse old destination account balance: %w", err) } @@ -449,6 +455,9 @@ func (s *TransactionService) DeleteTransaction(userID, id uint) error { // Reverse the transaction's effect on balance reversedBalance := calculateNewBalance(account.Balance, existingTxn.Amount, existingTxn.Type, false) + if !account.IsCredit && reversedBalance < 0 { + return fmt.Errorf("%w: deletion would cause negative balance in account '%s'", ErrInsufficientBalance, account.Name) + } if err := txAccountRepo.UpdateBalance(userID, existingTxn.AccountID, reversedBalance); err != nil { return fmt.Errorf("failed to reverse account balance: %w", err) } @@ -461,6 +470,9 @@ func (s *TransactionService) DeleteTransaction(userID, id uint) error { } if toAccount != nil { reversedToBalance := toAccount.Balance - existingTxn.Amount + if !toAccount.IsCredit && reversedToBalance < 0 { + return fmt.Errorf("%w: deletion would cause negative balance in destination account '%s'", ErrInsufficientBalance, toAccount.Name) + } if err := txAccountRepo.UpdateBalance(userID, *existingTxn.ToAccountID, reversedToBalance); err != nil { return fmt.Errorf("failed to reverse destination account balance: %w", err) }