|
8 | 8 | "context"
|
9 | 9 | "github.com/gitpod-io/gitpod/usage/pkg/contentservice"
|
10 | 10 | "fmt"
|
| 11 | + "google.golang.org/protobuf/types/known/timestamppb" |
11 | 12 | "math"
|
12 | 13 | "time"
|
13 | 14 |
|
@@ -67,31 +68,74 @@ func (s *BillingService) UpdateInvoices(ctx context.Context, in *v1.UpdateInvoic
|
67 | 68 | }
|
68 | 69 |
|
69 | 70 | func (s *BillingService) FinalizeInvoice(ctx context.Context, in *v1.FinalizeInvoiceRequest) (*v1.FinalizeInvoiceResponse, error) {
|
70 |
| - log.Infof("Finalizing invoice for invoice %q", in.GetInvoiceId()) |
| 71 | + logger := log.WithField("invoice_id", in.GetInvoiceId()) |
71 | 72 |
|
72 | 73 | if in.GetInvoiceId() == "" {
|
73 | 74 | return nil, status.Errorf(codes.InvalidArgument, "Missing InvoiceID")
|
74 | 75 | }
|
75 | 76 |
|
76 |
| - invoiceID := in.GetInvoiceId() |
77 |
| - |
78 |
| - invoice, err := s.stripeClient.GetInvoice(ctx, invoiceID) |
| 77 | + invoice, err := s.stripeClient.GetInvoice(ctx, in.GetInvoiceId()) |
79 | 78 | if err != nil {
|
80 |
| - return nil, status.Errorf(codes.NotFound, "Failed to get invoice with ID %s: %s", invoiceID, err.Error()) |
| 79 | + logger.WithError(err).Error("Failed to retrieve invoice from Stripe.") |
| 80 | + return nil, status.Errorf(codes.NotFound, "Failed to get invoice with ID %s: %s", in.GetInvoiceId(), err.Error()) |
81 | 81 | }
|
82 | 82 |
|
83 | 83 | reportID, found := invoice.Metadata[stripe.ReportIDMetadataKey]
|
84 | 84 | if !found {
|
85 |
| - return nil, status.Errorf(codes.NotFound, "Invoice %s does not contain reportID", invoiceID) |
| 85 | + logger.Error("Failed to find report ID metadata on invoice from Stripe.") |
| 86 | + return nil, status.Errorf(codes.NotFound, "Invoice %s does not contain reportID", in.GetInvoiceId()) |
| 87 | + } |
| 88 | + logger = logger.WithField("report_id", reportID) |
| 89 | + |
| 90 | + subscription := invoice.Subscription |
| 91 | + if subscription == nil { |
| 92 | + logger.Error("No subscription information available for invoice.") |
| 93 | + return nil, status.Errorf(codes.Internal, "Failed to retrieve subscription details from invoice.") |
86 | 94 | }
|
87 | 95 |
|
| 96 | + teamID, found := subscription.Metadata[stripe.TeamIDMetadataKey] |
| 97 | + if !found { |
| 98 | + logger.Error("Failed to find teamID from subscription metadata.") |
| 99 | + return nil, status.Errorf(codes.Internal, "Failed to extra teamID from Stripe subscription.") |
| 100 | + } |
| 101 | + logger = logger.WithField("team_id", teamID) |
| 102 | + |
| 103 | + attributionID := db.NewTeamAttributionID(teamID) |
| 104 | + |
| 105 | + // To support individual `user`s, we'll need to also extract the `userId` from metadata here and handle separately. |
| 106 | + |
88 | 107 | report, err := s.contentService.DownloadUsageReport(ctx, reportID)
|
89 | 108 | if err != nil {
|
| 109 | + logger.WithError(err).Error("Failed to retrieve usage report from content service.") |
90 | 110 | return nil, status.Errorf(codes.Internal, "Failed to download usage report.")
|
91 | 111 | }
|
92 | 112 |
|
93 |
| - // need to identify which AttributionID this finalize invoice event is for, how do we do that? |
94 |
| - fmt.Println(report) |
| 113 | + for _, session := range report { |
| 114 | + if session.AttributionID == attributionID { |
| 115 | + |
| 116 | + } |
| 117 | + } |
| 118 | + |
| 119 | + invoicedSessions := report.FilterToAttributionID(attributionID) |
| 120 | + var errors []error |
| 121 | + for _, session := range invoicedSessions { |
| 122 | + _, err := s.SetBilledSession(ctx, &v1.SetBilledSessionRequest{ |
| 123 | + InstanceId: session.InstanceID.String(), |
| 124 | + From: timestamppb.New(session.StartedAt), |
| 125 | + System: v1.System_SYSTEM_STRIPE, |
| 126 | + }) |
| 127 | + if err != nil { |
| 128 | + logger.WithField("workspace_instance_id", session.InstanceID).WithError(err).Error("Failed to mark session as billed by Stripe.") |
| 129 | + errors = append(errors, err) |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + if len(errors) != 0 { |
| 134 | + logger.Errorf("Failed to mark %d sessions as billed. You have to update them manually!") |
| 135 | + // TODO(milan): Add metrics and alert on this! |
| 136 | + |
| 137 | + return nil, status.Errorf(codes.Internal, "Failed to mark %d sessions as billed by stripe.") |
| 138 | + } |
95 | 139 |
|
96 | 140 | return &v1.FinalizeInvoiceResponse{}, nil
|
97 | 141 | }
|
|
0 commit comments