package application import ( "context" "time" "git.coopgo.io/coopgo-platform/mobility-accounts/grpcapi" mobilityaccountsstorage "git.coopgo.io/coopgo-platform/mobility-accounts/storage" "github.com/rs/zerolog/log" ) func (h *ApplicationHandler) CreditWallet(ctx context.Context, userid string, amount float64, paymentMethod string, description string) error { account, err := h.services.GetAccount(userid) if err != nil { log.Error().Err(err).Msg("could not retrieve account") return err } // Initialize wallet if it doesn't exist if account.Data["wallet"] == nil { account.Data["wallet"] = float64(0) } // Initialize wallet history if it doesn't exist if account.Data["wallet_history"] == nil { account.Data["wallet_history"] = []map[string]interface{}{} } // Determine operation type based on amount sign operationType := "credit" if amount < 0 { operationType = "debit" } // Create wallet operation record operation := map[string]interface{}{ "timestamp": time.Now().Format(time.RFC3339), "amount": amount, "payment_method": paymentMethod, "description": description, "operation_type": operationType, } // Add operation to history var history []map[string]interface{} if existingHistory, ok := account.Data["wallet_history"].([]interface{}); ok { // Convert []interface{} to []map[string]interface{} for _, item := range existingHistory { if historyItem, ok := item.(map[string]interface{}); ok { history = append(history, historyItem) } } } else if existingHistory, ok := account.Data["wallet_history"].([]map[string]interface{}); ok { history = existingHistory } history = append(history, operation) account.Data["wallet_history"] = history log.Debug(). Str("userid", userid). Float64("amount", amount). Str("paymentMethod", paymentMethod). Str("description", description). Int("historyCount", len(history)). Msg("Adding operation to wallet history") // Note: wallet balance is NOT updated here - it remains as initial amount // Balance is calculated from initial amount + sum of all operations accountproto, err := grpcapi.AccountFromStorageType(&account) if err != nil { log.Error().Err(err).Msg("account type transformation issue") return err } _, err = h.services.GRPC.MobilityAccounts.UpdateData(ctx, &grpcapi.UpdateDataRequest{ Account: accountproto, }) if err != nil { log.Error().Err(err).Msg("account update issue") return err } log.Info(). Str("userid", userid). Float64("amount", amount). Str("payment_method", paymentMethod). Str("description", description). Msg("Wallet credited successfully") return nil } // calculateWalletBalance calculates the current wallet balance from initial amount + all operations func (h *ApplicationHandler) calculateWalletBalance(account mobilityaccountsstorage.Account) float64 { // Return 0 if account data is nil if account.Data == nil { log.Debug().Msg("calculateWalletBalance: account.Data is nil, returning 0") return float64(0) } // Get initial wallet amount (default to 0 if not set) initialAmount := float64(0) if walletValue, exists := account.Data["wallet"]; exists && walletValue != nil { if val, ok := walletValue.(float64); ok { initialAmount = val } } // Calculate total from all operations operationsTotal := float64(0) operationCount := 0 if historyValue, exists := account.Data["wallet_history"]; exists && historyValue != nil { var operations []map[string]interface{} // Handle both []interface{} and []map[string]interface{} types if history, ok := historyValue.([]interface{}); ok { for _, item := range history { if operation, ok := item.(map[string]interface{}); ok { operations = append(operations, operation) } } } else if history, ok := historyValue.([]map[string]interface{}); ok { operations = history } for _, operation := range operations { if amount, ok := operation["amount"].(float64); ok { operationsTotal += amount operationCount++ } } } result := initialAmount + operationsTotal log.Debug(). Str("accountId", account.ID). Float64("initialAmount", initialAmount). Float64("operationsTotal", operationsTotal). Int("operationCount", operationCount). Float64("result", result). Msg("calculateWalletBalance") return result }