feat: 新增交易服务和AI记账服务,实现交易的创建、验证及账户余额更新逻辑。
This commit is contained in:
@@ -462,8 +462,9 @@ func (s *LLMService) ParseIntent(ctx context.Context, text string, history []Cha
|
|||||||
1. 金额:提取数字,如"6元"=6,"十五"=15
|
1. 金额:提取数字,如"6元"=6,"十五"=15
|
||||||
2. 分类:根据内容推断,如"奶茶/咖啡/吃饭"=餐饮,"打车/地铁"=交通,"买衣服"=购物
|
2. 分类:根据内容推断,如"奶茶/咖啡/吃饭"=餐饮,"打车/地铁"=交通,"买衣服"=购物
|
||||||
3. 类型:默认expense(支出),除非明确说"收入/工资/奖金/红包"
|
3. 类型:默认expense(支出),除非明确说"收入/工资/奖金/红包"
|
||||||
4. 日期:默认使用今天的日期(%s),除非用户明确指定其他日期
|
4. 金额:提取明确的数字。如果用户未提及具体金额(如只说"想吃炸鸡"),amount字段必须返回 0
|
||||||
5. 备注:提取关键描述
|
5. 日期:默认使用今天的日期(%s),除非用户明确指定其他日期
|
||||||
|
6. 备注:提取关键描述
|
||||||
|
|
||||||
直接返回JSON,不要解释:
|
直接返回JSON,不要解释:
|
||||||
{"amount":数字,"category":"分类","type":"expense或income","note":"备注","date":"YYYY-MM-DD","message":"简短确认"}
|
{"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
|
// getMissingFields returns list of missing required fields
|
||||||
func (s *AIBookkeepingService) getMissingFields(params *AITransactionParams) []string {
|
func (s *AIBookkeepingService) getMissingFields(params *AITransactionParams) []string {
|
||||||
var missing []string
|
var missing []string
|
||||||
if params.Amount == nil {
|
if params.Amount == nil || *params.Amount <= 0 {
|
||||||
missing = append(missing, "amount")
|
missing = append(missing, "amount")
|
||||||
}
|
}
|
||||||
if params.CategoryID == nil && params.Category == "" {
|
if params.CategoryID == nil && params.Category == "" {
|
||||||
|
|||||||
@@ -351,6 +351,9 @@ func (s *TransactionService) UpdateTransaction(userID, id uint, input Transactio
|
|||||||
|
|
||||||
// Step 1: Reverse the old transaction's effect on balances
|
// Step 1: Reverse the old transaction's effect on balances
|
||||||
oldReversedBalance := calculateNewBalance(oldAccount.Balance, existingTxn.Amount, existingTxn.Type, false)
|
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 {
|
if err := txAccountRepo.UpdateBalance(userID, existingTxn.AccountID, oldReversedBalance); err != nil {
|
||||||
return fmt.Errorf("failed to reverse old account balance: %w", err)
|
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
|
// Reverse old transfer destination if applicable
|
||||||
if oldToAccount != nil {
|
if oldToAccount != nil {
|
||||||
oldToReversedBalance := oldToAccount.Balance - existingTxn.Amount
|
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 {
|
if err := txAccountRepo.UpdateBalance(userID, *existingTxn.ToAccountID, oldToReversedBalance); err != nil {
|
||||||
return fmt.Errorf("failed to reverse old destination account balance: %w", err)
|
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
|
// Reverse the transaction's effect on balance
|
||||||
reversedBalance := calculateNewBalance(account.Balance, existingTxn.Amount, existingTxn.Type, false)
|
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 {
|
if err := txAccountRepo.UpdateBalance(userID, existingTxn.AccountID, reversedBalance); err != nil {
|
||||||
return fmt.Errorf("failed to reverse account balance: %w", err)
|
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 {
|
if toAccount != nil {
|
||||||
reversedToBalance := toAccount.Balance - existingTxn.Amount
|
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 {
|
if err := txAccountRepo.UpdateBalance(userID, *existingTxn.ToAccountID, reversedToBalance); err != nil {
|
||||||
return fmt.Errorf("failed to reverse destination account balance: %w", err)
|
return fmt.Errorf("failed to reverse destination account balance: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user