package handler import ( "strconv" "strings" "github.com/gin-gonic/gin" "apskel-pos-be/internal/constants" "apskel-pos-be/internal/contract" "apskel-pos-be/internal/service" "apskel-pos-be/internal/util" ) // The header exchanges and transfers require (docs/prd-point-coin.md F4, F5), and the // X- form the rest of the API uses, which is accepted too. const ( idempotencyKeyHeader = "Idempotency-Key" legacyIdempotencyKeyHeader = "X-Idempotency-Key" ) // CustomerWalletHandler serves what the customer app does with its own wallet. Bodies // hold the PIN, so they are never logged. type CustomerWalletHandler struct { wallets service.CustomerWalletService } func NewCustomerWalletHandler(wallets service.CustomerWalletService) *CustomerWalletHandler { return &CustomerWalletHandler{wallets: wallets} } // PreviewExchange is GET /customer/wallet/exchange/preview?coins=. func (h *CustomerWalletHandler) PreviewExchange(c *gin.Context) { customerID, ok := customerIDFromGin(c, "CustomerWalletHandler::PreviewExchange") if !ok { return } var coins int64 if raw := c.Query("coins"); raw != "" { var err error coins, err = strconv.ParseInt(raw, 10, 64) if err != nil { util.HandleResponse(c.Writer, c.Request, contract.BuildErrorResponse([]*contract.ResponseError{ contract.NewResponseError(constants.MalformedFieldErrorCode, constants.RequestEntity, "coins must be a whole number"), }), "CustomerWalletHandler::PreviewExchange") return } } util.HandleResponse(c.Writer, c.Request, h.wallets.PreviewExchange(c.Request.Context(), customerID, coins), "CustomerWalletHandler::PreviewExchange") } // Exchange is POST /customer/wallet/exchange. func (h *CustomerWalletHandler) Exchange(c *gin.Context) { customerID, ok := customerIDFromGin(c, "CustomerWalletHandler::Exchange") if !ok { return } var req contract.ExchangeCoinsRequest if !bindPinRequest(c, &req, "CustomerWalletHandler::Exchange") { return } util.HandleResponse(c.Writer, c.Request, h.wallets.Exchange(c.Request.Context(), customerID, &req, idempotencyKey(c), pinRequestInfo(c)), "CustomerWalletHandler::Exchange") } func idempotencyKey(c *gin.Context) string { if key := strings.TrimSpace(c.GetHeader(idempotencyKeyHeader)); key != "" { return key } return strings.TrimSpace(c.GetHeader(legacyIdempotencyKeyHeader)) }