forked from grassrootseconomics/visedriver
		
	added transactions functions
This commit is contained in:
		
							parent
							
								
									bfcdd79f33
								
							
						
					
					
						commit
						1d82bc2261
					
				
							
								
								
									
										115
									
								
								common/transfer_statements.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								common/transfer_statements.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,115 @@ | ||||
| package common | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"git.grassecon.net/urdt/ussd/internal/storage" | ||||
| 	dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" | ||||
| ) | ||||
| 
 | ||||
| // TransferMetadata helps organize data fields
 | ||||
| type TransferMetadata struct { | ||||
| 	Senders        string | ||||
| 	Recipients     string | ||||
| 	TransferValues string | ||||
| 	Addresses      string | ||||
| 	TxHashes       string | ||||
| 	Dates          string | ||||
| 	Symbols        string | ||||
| 	Decimals       string | ||||
| } | ||||
| 
 | ||||
| // ProcessTransfers converts transfers into formatted strings
 | ||||
| func ProcessTransfers(transfers []dataserviceapi.Last10TxResponse) TransferMetadata { | ||||
| 	var data TransferMetadata | ||||
| 	var senders, recipients, transferValues, addresses, txHashes, dates, symbols, decimals []string | ||||
| 
 | ||||
| 	for _, t := range transfers { | ||||
| 		senders = append(senders, t.Sender) | ||||
| 		recipients = append(recipients, t.Recipient) | ||||
| 
 | ||||
| 		// Scale down the amount
 | ||||
| 		scaledBalance := ScaleDownBalance(t.TransferValue, t.TokenDecimals) | ||||
| 		transferValues = append(transferValues, scaledBalance) | ||||
| 
 | ||||
| 		addresses = append(addresses, t.ContractAddress) | ||||
| 		txHashes = append(txHashes, t.TxHash) | ||||
| 		dates = append(dates, fmt.Sprintf("%s", t.DateBlock)) | ||||
| 		symbols = append(symbols, t.TokenSymbol) | ||||
| 		decimals = append(decimals, t.TokenDecimals) | ||||
| 	} | ||||
| 
 | ||||
| 	data.Senders = strings.Join(senders, "\n") | ||||
| 	data.Recipients = strings.Join(recipients, "\n") | ||||
| 	data.TransferValues = strings.Join(transferValues, "\n") | ||||
| 	data.Addresses = strings.Join(addresses, "\n") | ||||
| 	data.TxHashes = strings.Join(txHashes, "\n") | ||||
| 	data.Dates = strings.Join(dates, "\n") | ||||
| 	data.Symbols = strings.Join(symbols, "\n") | ||||
| 	data.Decimals = strings.Join(decimals, "\n") | ||||
| 
 | ||||
| 	return data | ||||
| } | ||||
| 
 | ||||
| // GetTransferData retrieves and matches transfer data
 | ||||
| // returns a formatted string of the full transaction/statement
 | ||||
| func GetTransferData(ctx context.Context, db storage.PrefixDb, publicKey string, index int) (string, error) { | ||||
| 	keys := []string{"txfrom", "txto", "txval", "txaddr", "txhash", "txdate", "txsym"} | ||||
| 	data := make(map[string]string) | ||||
| 
 | ||||
| 	for _, key := range keys { | ||||
| 		value, err := db.Get(ctx, []byte(key)) | ||||
| 		if err != nil { | ||||
| 			return "", fmt.Errorf("failed to get %s: %v", key, err) | ||||
| 		} | ||||
| 		data[key] = string(value) | ||||
| 	} | ||||
| 
 | ||||
| 	// Split the data
 | ||||
| 	senders := strings.Split(string(data["txfrom"]), "\n") | ||||
| 	recipients := strings.Split(string(data["txto"]), "\n") | ||||
| 	values := strings.Split(string(data["txval"]), "\n") | ||||
| 	addresses := strings.Split(string(data["txaddr"]), "\n") | ||||
| 	hashes := strings.Split(string(data["txhash"]), "\n") | ||||
| 	dates := strings.Split(string(data["txdate"]), "\n") | ||||
| 	syms := strings.Split(string(data["txsym"]), "\n") | ||||
| 
 | ||||
| 	// Adjust for 0-based indexing
 | ||||
| 	i := index - 1 | ||||
| 	transactionType := "received" | ||||
| 	party := fmt.Sprintf("from: %s", strings.TrimSpace(senders[i])) | ||||
| 	if strings.TrimSpace(senders[i]) == publicKey { | ||||
| 		transactionType = "sent" | ||||
| 		party = fmt.Sprintf("to: %s", strings.TrimSpace(recipients[i])) | ||||
| 	} | ||||
| 
 | ||||
| 	formattedDate := formatDate(strings.TrimSpace(dates[i])) | ||||
| 
 | ||||
| 	// Build the full transaction detail
 | ||||
| 	detail := fmt.Sprintf( | ||||
| 		"%s %s %s\n%s\ncontract address: %s\ntxhash: %s\ndate: %s", | ||||
| 		transactionType, | ||||
| 		strings.TrimSpace(values[i]), | ||||
| 		strings.TrimSpace(syms[i]), | ||||
| 		party, | ||||
| 		strings.TrimSpace(addresses[i]), | ||||
| 		strings.TrimSpace(hashes[i]), | ||||
| 		formattedDate, | ||||
| 	) | ||||
| 
 | ||||
| 	return detail, nil | ||||
| } | ||||
| 
 | ||||
| // Helper function to format date in desired output
 | ||||
| func formatDate(dateStr string) string { | ||||
| 	fmt.Println(dateStr) | ||||
| 	parsedDate, err := time.Parse("2006-01-02 15:04:05 -0700 MST", dateStr) | ||||
| 	if err != nil { | ||||
| 		fmt.Println("Error parsing date:", err) | ||||
| 		return "" | ||||
| 	} | ||||
| 	return parsedDate.Format("2006-01-02 03:04:05 PM") | ||||
| } | ||||
| @ -118,7 +118,9 @@ func (ls *LocalHandlerService) GetHandler(accountService remote.AccountServiceIn | ||||
| 	ls.DbRs.AddLocalFunc("reset_others_pin", ussdHandlers.ResetOthersPin) | ||||
| 	ls.DbRs.AddLocalFunc("save_others_temporary_pin", ussdHandlers.SaveOthersTemporaryPin) | ||||
| 	ls.DbRs.AddLocalFunc("get_current_profile_info", ussdHandlers.GetCurrentProfileInfo) | ||||
| 	ls.DbRs.AddLocalFunc("get_transactions", ussdHandlers.GetTransactions) | ||||
| 	ls.DbRs.AddLocalFunc("check_transactions", ussdHandlers.CheckTransactions) | ||||
| 	ls.DbRs.AddLocalFunc("get_transactions", ussdHandlers.GetTransactionsList) | ||||
| 	ls.DbRs.AddLocalFunc("view_statement", ussdHandlers.ViewTransactionStatement) | ||||
| 
 | ||||
| 	return ussdHandlers, nil | ||||
| } | ||||
|  | ||||
| @ -1634,11 +1634,171 @@ func (h *Handlers) GetVoucherDetails(ctx context.Context, sym string, input []by | ||||
| 	return res, nil | ||||
| } | ||||
| 
 | ||||
| // GetTransactions retrieves the transactions from the API using the "PublicKey"
 | ||||
| func (h *Handlers) GetTransactions(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||
| // CheckTransactions retrieves the transactions from the API using the "PublicKey" and stores to prefixDb
 | ||||
| func (h *Handlers) CheckTransactions(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||
| 	var res resource.Result | ||||
| 	sessionId, ok := ctx.Value("SessionId").(string) | ||||
| 	if !ok { | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| 	} | ||||
| 
 | ||||
| 	res.Content = "Transaction list" | ||||
| 	flag_no_transfers, _ := h.flagManager.GetFlag("flag_no_transfers") | ||||
| 	flag_api_error, _ := h.flagManager.GetFlag("flag_api_error") | ||||
| 
 | ||||
| 	store := h.userdataStore | ||||
| 	publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) | ||||
| 	if err != nil { | ||||
| 		logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) | ||||
| 		return res, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Fetch transactions from the API using the public key
 | ||||
| 	transactionsResp, err := h.accountService.FetchTransactions(ctx, string(publicKey)) | ||||
| 	if err != nil { | ||||
| 		res.FlagSet = append(res.FlagSet, flag_api_error) | ||||
| 		logg.ErrorCtxf(ctx, "failed on FetchTransactions", "error", err) | ||||
| 		return res, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Return if there are no transactions
 | ||||
| 	if len(transactionsResp) == 0 { | ||||
| 		res.FlagSet = append(res.FlagSet, flag_no_transfers) | ||||
| 		return res, nil | ||||
| 	} | ||||
| 
 | ||||
| 	data := common.ProcessTransfers(transactionsResp) | ||||
| 
 | ||||
| 	// Store all transaction data
 | ||||
| 	dataMap := map[string]string{ | ||||
| 		"txfrom": data.Senders, | ||||
| 		"txto":   data.Recipients, | ||||
| 		"txval":  data.TransferValues, | ||||
| 		"txaddr": data.Addresses, | ||||
| 		"txhash": data.TxHashes, | ||||
| 		"txdate": data.Dates, | ||||
| 		"txsym":  data.Symbols, | ||||
| 		"txdeci": data.Decimals, | ||||
| 	} | ||||
| 
 | ||||
| 	for key, value := range dataMap { | ||||
| 		if err := h.prefixDb.Put(ctx, []byte(key), []byte(value)); err != nil { | ||||
| 			logg.ErrorCtxf(ctx, "failed to write to prefixDb", "error", err) | ||||
| 			return res, err | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	res.FlagReset = append(res.FlagReset, flag_no_transfers) | ||||
| 
 | ||||
| 	return res, nil | ||||
| } | ||||
| 
 | ||||
| // GetTransactionsList fetches the list of transactions and formats them
 | ||||
| func (h *Handlers) GetTransactionsList(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||
| 	var res resource.Result | ||||
| 	sessionId, ok := ctx.Value("SessionId").(string) | ||||
| 	if !ok { | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| 	} | ||||
| 	store := h.userdataStore | ||||
| 	publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) | ||||
| 	if err != nil { | ||||
| 		logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) | ||||
| 		return res, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Read transactions from the store and format them
 | ||||
| 	TransactionSenders, err := h.prefixDb.Get(ctx, []byte("txfrom")) | ||||
| 	if err != nil { | ||||
| 		logg.ErrorCtxf(ctx, "Failed to read the TransactionSenders from prefixDb", "error", err) | ||||
| 		return res, err | ||||
| 	} | ||||
| 	TransactionSyms, err := h.prefixDb.Get(ctx, []byte("txsym")) | ||||
| 	if err != nil { | ||||
| 		logg.ErrorCtxf(ctx, "Failed to read the TransactionSyms from prefixDb", "error", err) | ||||
| 		return res, err | ||||
| 	} | ||||
| 	TransactionValues, err := h.prefixDb.Get(ctx, []byte("txval")) | ||||
| 	if err != nil { | ||||
| 		logg.ErrorCtxf(ctx, "Failed to read the TransactionValues from prefixDb", "error", err) | ||||
| 		return res, err | ||||
| 	} | ||||
| 	TransactionDates, err := h.prefixDb.Get(ctx, []byte("txdate")) | ||||
| 	if err != nil { | ||||
| 		logg.ErrorCtxf(ctx, "Failed to read the TransactionDates from prefixDb", "error", err) | ||||
| 		return res, err | ||||
| 	} | ||||
| 
 | ||||
| 	// Parse the data
 | ||||
| 	senders := strings.Split(string(TransactionSenders), "\n") | ||||
| 	syms := strings.Split(string(TransactionSyms), "\n") | ||||
| 	values := strings.Split(string(TransactionValues), "\n") | ||||
| 	dates := strings.Split(string(TransactionDates), "\n") | ||||
| 
 | ||||
| 	var formattedTransactions []string | ||||
| 	for i := 0; i < len(senders); i++ { | ||||
| 		sender := strings.TrimSpace(senders[i]) | ||||
| 		sym := strings.TrimSpace(syms[i]) | ||||
| 		value := strings.TrimSpace(values[i]) | ||||
| 		date := strings.Split(strings.TrimSpace(dates[i]), " ")[0] | ||||
| 
 | ||||
| 		status := "received" | ||||
| 		if sender == string(publicKey) { | ||||
| 			status = "sent" | ||||
| 		} | ||||
| 
 | ||||
| 		formattedTransactions = append(formattedTransactions, fmt.Sprintf("%d:%s %s %s %s", i+1, status, value, sym, date)) | ||||
| 	} | ||||
| 
 | ||||
| 	res.Content = strings.Join(formattedTransactions, "\n") | ||||
| 
 | ||||
| 	return res, nil | ||||
| } | ||||
| 
 | ||||
| // ViewTransactionStatement retrieves the token holding and balance from the subprefixDB
 | ||||
| // and displays it to the user for them to select it
 | ||||
| func (h *Handlers) ViewTransactionStatement(ctx context.Context, sym string, input []byte) (resource.Result, error) { | ||||
| 	var res resource.Result | ||||
| 	sessionId, ok := ctx.Value("SessionId").(string) | ||||
| 	if !ok { | ||||
| 		return res, fmt.Errorf("missing session") | ||||
| 	} | ||||
| 	store := h.userdataStore | ||||
| 	publicKey, err := store.ReadEntry(ctx, sessionId, common.DATA_PUBLIC_KEY) | ||||
| 	if err != nil { | ||||
| 		logg.ErrorCtxf(ctx, "failed to read publicKey entry with", "key", common.DATA_PUBLIC_KEY, "error", err) | ||||
| 		return res, err | ||||
| 	} | ||||
| 
 | ||||
| 	flag_incorrect_statement, _ := h.flagManager.GetFlag("flag_incorrect_statement") | ||||
| 
 | ||||
| 	inputStr := string(input) | ||||
| 	if inputStr == "0" || inputStr == "99" || inputStr == "11" || inputStr == "22" { | ||||
| 		res.FlagReset = append(res.FlagReset, flag_incorrect_statement) | ||||
| 		return res, nil | ||||
| 	} | ||||
| 
 | ||||
| 	// Convert input string to integer
 | ||||
| 	index, err := strconv.Atoi(strings.TrimSpace(inputStr)) | ||||
| 	if err != nil { | ||||
| 		return res, fmt.Errorf("invalid input: must be a number between 1 and 10") | ||||
| 	} | ||||
| 
 | ||||
| 	if index < 1 || index > 10 { | ||||
| 		return res, fmt.Errorf("invalid input: index must be between 1 and 10") | ||||
| 	} | ||||
| 
 | ||||
| 	statement, err := common.GetTransferData(ctx, h.prefixDb, string(publicKey), index) | ||||
| 	if err != nil { | ||||
| 		return res, fmt.Errorf("failed to retrieve transfer data: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	if statement == "" { | ||||
| 		res.FlagSet = append(res.FlagSet, flag_incorrect_statement) | ||||
| 		return res, nil | ||||
| 	} | ||||
| 
 | ||||
| 	res.FlagReset = append(res.FlagReset, flag_incorrect_statement) | ||||
| 	res.Content = statement | ||||
| 
 | ||||
| 	return res, nil | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user