Mauricio Araujo 2 anni fa
parent
commit
d49355f553

+ 9 - 11
api/server/handlers/billing/invoices.go

@@ -24,7 +24,7 @@ func NewListCustomerInvoicesHandler(
 	writer shared.ResultWriter,
 ) *ListCustomerInvoicesHandler {
 	return &ListCustomerInvoicesHandler{
-		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, decoderValidator, writer),
+		PorterHandlerReadWriter: handlers.NewDefaultPorterHandler(config, nil, writer),
 	}
 }
 
@@ -35,24 +35,22 @@ func (c *ListCustomerInvoicesHandler) ServeHTTP(w http.ResponseWriter, r *http.R
 	proj, _ := ctx.Value(types.ProjectScope).(*models.Project)
 
 	telemetry.WithAttributes(span,
-		telemetry.AttributeKV{Key: "billing-config-exists", Value: c.Config().BillingManager.StripeConfigLoaded},
-		telemetry.AttributeKV{Key: "billing-enabled", Value: proj.GetFeatureFlag(models.BillingEnabled, c.Config().LaunchDarklyClient)},
+		telemetry.AttributeKV{Key: "lago-config-exists", Value: c.Config().BillingManager.LagoConfigLoaded},
+		telemetry.AttributeKV{Key: "lago-enabled", Value: proj.GetFeatureFlag(models.LagoEnabled, c.Config().LaunchDarklyClient)},
 		telemetry.AttributeKV{Key: "porter-cloud-enabled", Value: proj.EnableSandbox},
 	)
 
-	if !c.Config().BillingManager.StripeConfigLoaded || !proj.GetFeatureFlag(models.BillingEnabled, c.Config().LaunchDarklyClient) {
+	if !c.Config().BillingManager.LagoConfigLoaded || !proj.GetFeatureFlag(models.LagoEnabled, c.Config().LaunchDarklyClient) {
 		c.WriteResult(w, r, "")
 		return
 	}
 
-	req := &types.ListCustomerInvoicesRequest{}
-
-	if ok := c.DecodeAndValidate(w, r, req); !ok {
-		err := telemetry.Error(ctx, span, nil, "error decoding list customer usage request")
-		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusBadRequest))
+	invoices, err := c.Config().BillingManager.LagoClient.ListCustomerFinalizedInvoices(ctx, proj.ID, proj.EnableSandbox)
+	if err != nil {
+		err = telemetry.Error(ctx, span, err, "error listing invoices")
+		c.HandleAPIError(w, r, apierrors.NewErrPassThroughToClient(err, http.StatusInternalServerError))
 		return
 	}
 
-	// Write the response to the frontend
-	c.WriteResult(w, r, "invoices")
+	c.WriteResult(w, r, invoices)
 }

+ 0 - 15
api/types/billing_stripe.go

@@ -10,18 +10,3 @@ type PaymentMethod struct {
 	ExpYear      int64  `json:"exp_year"`
 	Default      bool   `json:"is_default"`
 }
-
-// Invoice represents an invoice in the billing system.
-type Invoice struct {
-	// The URL to view the hosted invoice.
-	HostedInvoiceURL string `json:"hosted_invoice_url"`
-	// The status of the invoice.
-	Status string `json:"status"`
-	// RFC 3339 timestamp for when the invoice was created.
-	Created string `json:"created"`
-}
-
-// ListCustomerInvoicesRequest is the request to list invoices for a customer
-type ListCustomerInvoicesRequest struct {
-	Status string `schema:"status"`
-}

+ 10 - 0
api/types/billing_usage.go

@@ -62,3 +62,13 @@ type Wallet struct {
 	OngoingBalanceCents      int    `json:"ongoing_balance_cents,omitempty"`
 	OngoingUsageBalanceCents int    `json:"ongoing_usage_balance_cents,omitempty"`
 }
+
+// Invoice represents an invoice in the billing system.
+type Invoice struct {
+	// The URL to view the hosted invoice.
+	HostedInvoiceURL string `json:"hosted_invoice_url"`
+	// The status of the invoice.
+	Status string `json:"status"`
+	// RFC 3339 timestamp for when the invoice was created.
+	Created string `json:"created"`
+}

+ 1 - 3
dashboard/src/lib/hooks/useLago.ts

@@ -208,9 +208,7 @@ export const useCustomerInvoices = (): TGetInvoices => {
       try {
         const res = await api.getCustomerInvoices(
           "<token>",
-          {
-            status: "paid",
-          },
+          {},
           { project_id: currentProject.id }
         );
 

+ 0 - 1
dashboard/src/main/home/project-settings/BillingPage.tsx

@@ -18,7 +18,6 @@ import Text from "components/porter/Text";
 import {
   useCustomerInvoices,
   useCustomerPlan,
-  useCustomerUsage,
   usePorterCredits,
   useReferralDetails,
 } from "lib/hooks/useLago";

+ 1 - 3
dashboard/src/shared/api.tsx

@@ -3566,9 +3566,7 @@ const getCustomerCosts = baseApi<
 );
 
 const getCustomerInvoices = baseApi<
-  {
-    status: string;
-  },
+  {},
   {
     project_id?: number;
   }

+ 35 - 3
internal/billing/usage.go

@@ -383,14 +383,46 @@ func (m LagoClient) IngestEvents(ctx context.Context, subscriptionID string, eve
 	return nil
 }
 
-// ListCustomerInvoices will return all invoices for the customer with the given status
-func (s StripeClient) ListCustomerInvoices(ctx context.Context, projectID uint) (invoiceList []types.Invoice, err error) {
-	ctx, span := telemetry.NewSpan(ctx, "populate-invoice-urls")
+// ListCustomerFinalizedInvoices will return all finalized invoices for the customer
+func (m LagoClient) ListCustomerFinalizedInvoices(ctx context.Context, projectID uint, enableSandbox bool) (invoiceList []types.Invoice, err error) {
+	ctx, span := telemetry.NewSpan(ctx, "list-customer-invoices")
 	defer span.End()
 
 	if projectID == 0 {
 		return invoiceList, telemetry.Error(ctx, span, err, "project id cannot be empty")
 	}
+
+	customerID := m.generateLagoID(CustomerIDPrefix, projectID, enableSandbox)
+	invoiceListInput := &lago.InvoiceListInput{
+		ExternalCustomerID: customerID,
+		Status:             lago.InvoiceStatusFinalized,
+	}
+
+	invoices, lagoErr := m.client.Invoice().GetList(ctx, invoiceListInput)
+	if lagoErr != nil {
+		return invoiceList, telemetry.Error(ctx, span, fmt.Errorf(lagoErr.ErrorCode), "failed to list invoices")
+	}
+
+	for _, invoice := range invoices.Invoices {
+		invoiceReq, lagoErr := m.client.Invoice().Download(ctx, invoice.LagoID.String())
+		if lagoErr != nil {
+			return invoiceList, telemetry.Error(ctx, span, fmt.Errorf(lagoErr.ErrorCode), "failed to download invoice")
+		}
+
+		var fileURL string
+		if invoiceReq == nil {
+			fileURL = invoice.FileURL
+		} else {
+			fileURL = invoiceReq.FileURL
+		}
+
+		invoiceList = append(invoiceList, types.Invoice{
+			HostedInvoiceURL: fileURL,
+			Status:           string(invoice.Status),
+			Created:          invoice.IssuingDate,
+		})
+	}
+
 	return invoiceList, nil
 }