package chapa import ( "bytes" "context" "encoding/json" "fmt" "io" "net/http" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" ) type ChapaClient interface { IssuePayment(ctx context.Context, payload domain.ChapaTransferPayload) (bool, error) InitPayment(ctx context.Context, req domain.InitPaymentRequest) (string, error) FetchBanks() ([]domain.ChapaSupportedBank, error) } type Client struct { BaseURL string SecretKey string HTTPClient *http.Client UserAgent string } func NewClient(baseURL, secretKey string) *Client { return &Client{ BaseURL: baseURL, SecretKey: secretKey, HTTPClient: http.DefaultClient, UserAgent: "FortuneBet/1.0", } } func (c *Client) IssuePayment(ctx context.Context, payload domain.ChapaTransferPayload) (bool, error) { payloadBytes, err := json.Marshal(payload) if err != nil { return false, fmt.Errorf("failed to serialize payload: %w", err) } req, err := http.NewRequestWithContext(ctx, "POST", c.BaseURL+"/transfers", bytes.NewBuffer(payloadBytes)) if err != nil { return false, fmt.Errorf("failed to create HTTP request: %w", err) } req.Header.Set("Authorization", "Bearer "+c.SecretKey) req.Header.Set("Content-Type", "application/json") resp, err := c.HTTPClient.Do(req) if err != nil { return false, fmt.Errorf("chapa HTTP request failed: %w", err) } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) if resp.StatusCode >= 200 && resp.StatusCode < 300 { return true, nil } return false, fmt.Errorf("chapa error: status %d, body: %s", resp.StatusCode, string(body)) } // service/chapa_service.go func (c *Client) InitPayment(ctx context.Context, req domain.InitPaymentRequest) (string, error) { payloadBytes, err := json.Marshal(req) if err != nil { return "", fmt.Errorf("failed to serialize payload: %w", err) } httpReq, err := http.NewRequestWithContext(ctx, "POST", c.BaseURL+"/transaction/initialize", bytes.NewBuffer(payloadBytes)) if err != nil { return "", fmt.Errorf("failed to create HTTP request: %w", err) } httpReq.Header.Set("Authorization", "Bearer "+c.SecretKey) httpReq.Header.Set("Content-Type", "application/json") resp, err := c.HTTPClient.Do(httpReq) if err != nil { return "", fmt.Errorf("chapa HTTP request failed: %w", err) } defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) if resp.StatusCode < 200 || resp.StatusCode >= 300 { return "", fmt.Errorf("chapa error: status %d, body: %s", resp.StatusCode, string(body)) } var response struct { Data struct { CheckoutURL string `json:"checkout_url"` } `json:"data"` } if err := json.Unmarshal(body, &response); err != nil { return "", fmt.Errorf("failed to parse chapa response: %w", err) } return response.Data.CheckoutURL, nil } func (c *Client) FetchBanks() ([]domain.ChapaSupportedBank, error) { req, _ := http.NewRequest("GET", c.BaseURL+"/banks", nil) req.Header.Set("Authorization", "Bearer "+c.SecretKey) fmt.Printf("\n\nbase URL is: %s\n\n", c.BaseURL) res, err := c.HTTPClient.Do(req) if err != nil { return nil, err } defer res.Body.Close() var resp struct { Message string `json:"message"` Data []domain.ChapaSupportedBank `json:"data"` } if err := json.NewDecoder(res.Body).Decode(&resp); err != nil { return nil, err } fmt.Printf("\n\nclient fetched banks: %+v\n\n", resp.Data) return resp.Data, nil }