Mauricio Araujo 2 лет назад
Родитель
Сommit
dd2a193f47

+ 45 - 0
api/server/handlers/billing/invoices.go

@@ -0,0 +1,45 @@
+package billing
+
+import (
+	"fmt"
+	"net/http"
+
+	"github.com/porter-dev/porter/api/server/handlers"
+	"github.com/porter-dev/porter/api/server/shared"
+	"github.com/porter-dev/porter/api/server/shared/apierrors"
+	"github.com/porter-dev/porter/api/server/shared/config"
+	"github.com/porter-dev/porter/api/types"
+	"github.com/porter-dev/porter/internal/models"
+	"github.com/porter-dev/porter/internal/telemetry"
+)
+
+// ListCustomerInvoicesHandler is a handler for listing payment methods
+type ListCustomerInvoicesHandler struct {
+	handlers.PorterHandlerWriter
+}
+
+// NewListBillingHandler will create a new ListBillingHandler
+func NewListCustomerInvoicesHandler(
+	config *config.Config,
+	writer shared.ResultWriter,
+) *ListCustomerInvoicesHandler {
+	return &ListCustomerInvoicesHandler{
+		PorterHandlerWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
+	}
+}
+
+func (c *ListCustomerInvoicesHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
+	ctx, span := telemetry.NewSpan(r.Context(), "serve-list-payment-methods")
+	defer span.End()
+
+	proj, _ := ctx.Value(types.ProjectScope).(*models.Project)
+
+	invoices, err := c.Config().BillingManager.MetronomeClient.ListInvoices(ctx, proj.UsageID)
+	if err != nil {
+		err := telemetry.Error(ctx, span, err, "error listing payment method")
+		c.HandleAPIError(w, r, apierrors.NewErrInternal(fmt.Errorf("error listing payment method: %w", err)))
+		return
+	}
+
+	c.WriteResult(w, r, invoices)
+}

+ 12 - 0
api/types/billing_metronome.go

@@ -196,3 +196,15 @@ type BillingEvent struct {
 	TransactionID string                 `json:"transaction_id"`
 	Timestamp     string                 `json:"timestamp"`
 }
+
+// Invoice represents a Metronome invoice.
+type Invoice struct {
+	ID             uuid.UUID  `json:"id"`
+	CustomerID     uuid.UUID  `json:"customer_id"`
+	CreditType     CreditType `json:"credit_type"`
+	StartTimestamp string     `json:"start_timestamp"`
+	EndTimestamp   string     `json:"end_timestamp"`
+	Status         string     `json:"status"`
+	Total          float64    `json:"total"`
+	Type           string     `json:"type"`
+}

+ 21 - 0
internal/billing/metronome.go

@@ -356,6 +356,27 @@ func (m MetronomeClient) ListCustomerUsage(ctx context.Context, customerID uuid.
 	return usage, nil
 }
 
+func (m MetronomeClient) ListCustomerInvoices(ctx context.Context, customerID uuid.UUID, status string, startingOn string, endingBefore string) (invoices []types.Invoice, err error) {
+	ctx, span := telemetry.NewSpan(ctx, "list-customer-invoices")
+	defer span.End()
+
+	if customerID == uuid.Nil {
+		return invoices, telemetry.Error(ctx, span, err, "customer id empty")
+	}
+
+	path := fmt.Sprintf("/customers/%s/invoices?status=%s&starting_on=%s&ending_before=%s", customerID, status, startingOn, endingBefore)
+	var result struct {
+		Data []types.Invoice `json:"data"`
+	}
+
+	_, err = m.do(http.MethodGet, path, nil, &result)
+	if err != nil {
+		return invoices, telemetry.Error(ctx, span, err, "failed to list customer invoices")
+	}
+
+	return invoices, nil
+}
+
 // IngestEvents sends a list of billing events to Metronome's ingest endpoint
 func (m MetronomeClient) IngestEvents(ctx context.Context, events []types.BillingEvent) (err error) {
 	ctx, span := telemetry.NewSpan(ctx, "ingets-billing-events")