update minimum top-up and fix some sync issues between client and server

This commit is contained in:
Keiran 2025-08-07 20:03:37 +01:00
parent 10e0c22108
commit 3cde1ffb63
4 changed files with 76 additions and 10 deletions

View File

@ -45,12 +45,14 @@ func main() {
e.GET("/", h.RootHandler)
e.POST("/api/accounts", h.CreateAccountHandler)
e.POST("/api/payments/by-account", h.CreatePaymentByAccountNumberHandler)
api := e.Group("/api")
api.Use(h.AuthMiddleware)
api.GET("/account", h.GetAccountHandler)
api.POST("/payments", h.CreatePaymentHandler)
api.POST("/topup", h.CreateTopUpHandler)
api.GET("/payments", h.GetPaymentsHandler)
api.GET("/payments/:id", h.GetPaymentHandler)
api.POST("/payments/:id/confirm", h.ConfirmPaymentHandler)

View File

@ -47,14 +47,17 @@ func newAccountCreateCmd() *cobra.Command {
}
config.AccountNumber = account.AccountNumber
config.AccessToken = account.AccessToken
if err := config.Save(); err != nil {
return fmt.Errorf("failed to save config: %w", err)
}
fmt.Printf("Account created successfully!\n")
fmt.Printf("Account Number: %s\n", account.AccountNumber)
fmt.Printf("Access Token: %s\n", account.AccessToken)
fmt.Printf("Status: %s\n", getAccountStatus(account))
fmt.Printf("\nTo activate your account, add funds using: tcman account top-up\n")
fmt.Printf("\nIMPORTANT: Save your account number and access token!\n")
fmt.Printf("You are now logged in. Add funds using: tcman account top-up 1\n")
return nil
},
@ -142,17 +145,18 @@ func newAccountInfoCmd() *cobra.Command {
func newAccountTopUpCmd() *cobra.Command {
return &cobra.Command{
Use: "top-up <amount>",
Use: "top-up <amount> [account-number]",
Short: "Add funds to your account via Bitcoin",
Args: cobra.ExactArgs(1),
Long: "Add funds to your account. If logged in, uses your account. If not logged in, provide account number.",
Args: cobra.RangeArgs(1, 2),
RunE: func(cmd *cobra.Command, args []string) error {
amount, err := strconv.ParseFloat(args[0], 64)
if err != nil {
return fmt.Errorf("invalid amount: %w", err)
}
if amount < 5.0 {
return fmt.Errorf("minimum top-up amount is $5.00 USD")
if amount < 1.0 {
return fmt.Errorf("minimum top-up amount is $1.00 USD")
}
config, err := LoadConfig()
@ -160,20 +164,29 @@ func newAccountTopUpCmd() *cobra.Command {
return fmt.Errorf("failed to load config: %w", err)
}
if !config.IsAuthenticated() {
return fmt.Errorf("not logged in. Use 'tcman account login' or 'tcman account create'")
var accountNumber string
if len(args) == 2 {
accountNumber = args[1]
} else if config.IsAuthenticated() {
accountNumber = config.AccountNumber
} else if config.AccountNumber != "" {
accountNumber = config.AccountNumber
} else {
return fmt.Errorf("account number required. Usage: tcman account top-up <amount> <account-number>")
}
client := NewClient(config.ServerURL, config.AccessToken)
client := NewClient(config.ServerURL, "")
ctx := context.Background()
payment, err := client.CreatePayment(ctx, amount)
payment, err := client.CreatePaymentByAccountNumber(ctx, accountNumber, amount)
if err != nil {
return fmt.Errorf("failed to create payment: %w", err)
}
fmt.Printf("Bitcoin Payment Created:\n")
fmt.Printf(" Payment ID: %d\n", payment.ID)
fmt.Printf(" Account: %s\n", accountNumber)
fmt.Printf(" Amount: $%.2f USD (%.8f BTC)\n", payment.USDAmount, payment.BTCAmount)
fmt.Printf(" Address: %s\n", payment.BTCAddress)
fmt.Printf(" Status: %s\n", strings.ToUpper(payment.Status))
@ -181,7 +194,7 @@ func newAccountTopUpCmd() *cobra.Command {
fmt.Printf(" Expires: %s\n", payment.ExpiresAt.Format("2006-01-02 15:04:05"))
}
fmt.Printf("\nSend exactly %.8f BTC to the address above.\n", payment.BTCAmount)
fmt.Printf("Check payment status with: tcman account payments\n")
fmt.Printf("Your payment will be confirmed manually after Bitcoin is received.\n")
return nil
},

View File

@ -19,6 +19,7 @@ type Client struct {
type Account struct {
ID int64 `json:"id"`
AccountNumber string `json:"accountNumber"`
AccessToken string `json:"accessToken,omitempty"`
BalanceUSD float64 `json:"balanceUsd"`
IsActive bool `json:"isActive"`
CreatedAt time.Time `json:"createdAt"`
@ -134,6 +135,16 @@ func (c *Client) CreatePayment(ctx context.Context, usdAmount float64) (*Payment
return &payment, err
}
func (c *Client) CreatePaymentByAccountNumber(ctx context.Context, accountNumber string, usdAmount float64) (*Payment, error) {
req := map[string]interface{}{
"account_number": accountNumber,
"usd_amount": usdAmount,
}
var payment Payment
err := c.makeRequest(ctx, "POST", "/api/payments/by-account", req, &payment)
return &payment, err
}
func (c *Client) GetPayment(ctx context.Context, paymentID int64) (*Payment, error) {
var payment Payment
path := fmt.Sprintf("/api/payments/%d", paymentID)

View File

@ -62,6 +62,28 @@ func (h *Handlers) CreateAccountHandler(c echo.Context) error {
return c.JSON(201, account)
}
func (h *Handlers) CreatePaymentByAccountNumberHandler(c echo.Context) error {
var req struct {
AccountNumber string `json:"account_number"`
USDAmount float64 `json:"usd_amount"`
}
if err := c.Bind(&req); err != nil || req.USDAmount < 1.0 || req.AccountNumber == "" {
return c.JSON(400, map[string]string{"error": "Account number required and minimum payment amount is $1.00 USD"})
}
account, err := h.accountService.GetAccountByNumber(context.Background(), req.AccountNumber)
if err != nil {
return c.JSON(404, map[string]string{"error": "Account not found"})
}
payment, err := h.accountService.CreatePayment(context.Background(), account.ID, req.USDAmount)
if err != nil {
return c.JSON(500, map[string]string{"error": "Failed to create payment"})
}
return c.JSON(201, payment)
}
func (h *Handlers) GetAccountHandler(c echo.Context) error {
account := c.Get("account").(*db.Account)
return c.JSON(200, account)
@ -85,6 +107,24 @@ func (h *Handlers) CreatePaymentHandler(c echo.Context) error {
return c.JSON(201, payment)
}
func (h *Handlers) CreateTopUpHandler(c echo.Context) error {
account := c.Get("account").(*db.Account)
var req struct {
USDAmount float64 `json:"usd_amount"`
}
if err := c.Bind(&req); err != nil || req.USDAmount < 1.0 {
return c.JSON(400, map[string]string{"error": "Minimum top-up amount is $1.00 USD"})
}
payment, err := h.accountService.CreatePayment(context.Background(), account.ID, req.USDAmount)
if err != nil {
return c.JSON(500, map[string]string{"error": "Failed to create top-up"})
}
return c.JSON(201, payment)
}
func (h *Handlers) GetPaymentHandler(c echo.Context) error {
paymentID, err := strconv.ParseInt(c.Param("id"), 10, 64)
if err != nil {