Files
telecom-platform/apps/cli/internal/api/client.go
T
nutcas3 d921270f67 feat: Add API client with billing endpoints and enhance billing command with styled UI integration
- Add Client struct with baseURL, apiKey, and httpClient with 30s timeout
- Add data models: Invoice, Payment, Subscriber, GenerateInvoiceRequest, GenerateInvoiceResponse
- Add GetInvoices to retrieve invoices from /api/v1/invoices endpoint
- Add GetPayments to retrieve payments from /api/v1/payments endpoint
- Add GenerateInvoice to create invoices via /api/v1/invoices/generate endpoint
- Add IsConn
2026-04-17 16:13:11 +03:00

206 lines
5.4 KiB
Go

package api
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"github.com/nutcas3/telecom-platform/apps/cli/internal/config"
)
// Client represents the API client for the telecom platform
type Client struct {
baseURL string
apiKey string
httpClient *http.Client
}
// NewClient creates a new API client
func NewClient(cfg *config.Config) *Client {
return &Client{
baseURL: cfg.APIEndpoint,
apiKey: cfg.APIToken,
httpClient: &http.Client{
Timeout: 30 * time.Second,
},
}
}
// Invoice represents an invoice from the API
type Invoice struct {
ID string `json:"id"`
SubscriberID string `json:"subscriber_id"`
Amount float64 `json:"amount"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
DueDate time.Time `json:"due_date"`
PaidAt *time.Time `json:"paid_at,omitempty"`
Subscriber Subscriber `json:"subscriber"`
}
// Payment represents a payment from the API
type Payment struct {
ID string `json:"id"`
InvoiceID string `json:"invoice_id"`
Amount float64 `json:"amount"`
Method string `json:"method"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
ProcessedAt *time.Time `json:"processed_at,omitempty"`
}
// Subscriber represents a subscriber from the API
type Subscriber struct {
ID uint `json:"id"`
IMSI string `json:"imsi"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
Email string `json:"email"`
Status string `json:"status"`
}
// GetInvoices retrieves invoices from the API
func (c *Client) GetInvoices() ([]Invoice, error) {
url := fmt.Sprintf("%s/api/v1/invoices", c.baseURL)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+c.apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to make request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
}
var response struct {
Data []Invoice `json:"data"`
}
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}
return response.Data, nil
}
// GetPayments retrieves payments from the API
func (c *Client) GetPayments() ([]Payment, error) {
url := fmt.Sprintf("%s/api/v1/payments", c.baseURL)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+c.apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to make request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
}
var response struct {
Data []Payment `json:"data"`
}
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}
return response.Data, nil
}
// GenerateInvoiceRequest represents a request to generate an invoice
type GenerateInvoiceRequest struct {
SubscriberID string `json:"subscriber_id"`
}
// GenerateInvoiceResponse represents a response from generating an invoice
type GenerateInvoiceResponse struct {
ID string `json:"id"`
Amount float64 `json:"amount"`
Status string `json:"status"`
CreatedAt time.Time `json:"created_at"`
DueDate time.Time `json:"due_date"`
}
// GenerateInvoice generates a new invoice for a subscriber
func (c *Client) GenerateInvoice(subscriberID string) (*GenerateInvoiceResponse, error) {
url := fmt.Sprintf("%s/api/v1/invoices/generate", c.baseURL)
request := GenerateInvoiceRequest{
SubscriberID: subscriberID,
}
jsonData, err := json.Marshal(request)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %w", err)
}
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+c.apiKey)
req.Header.Set("Content-Type", "application/json")
resp, err := c.httpClient.Do(req)
if err != nil {
return nil, fmt.Errorf("failed to make request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusCreated {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
}
var response GenerateInvoiceResponse
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
return nil, fmt.Errorf("failed to decode response: %w", err)
}
return &response, nil
}
// IsConnected checks if the API server is reachable
func (c *Client) IsConnected() bool {
url := fmt.Sprintf("%s/health", c.baseURL)
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return false
}
req.Header.Set("Authorization", "Bearer "+c.apiKey)
resp, err := c.httpClient.Do(req)
if err != nil {
return false
}
defer resp.Body.Close()
return resp.StatusCode == http.StatusOK
}