diff --git a/components/server/ee/src/billing/billing-service.ts b/components/server/ee/src/billing/billing-service.ts index 1b417c05aa4ca0..d9fbae5a6302a9 100644 --- a/components/server/ee/src/billing/billing-service.ts +++ b/components/server/ee/src/billing/billing-service.ts @@ -40,13 +40,10 @@ export class BillingService { }; } - const now = new Date(); - const currentBalance = await this.usageService.listUsage({ + const getBalanceResponse = await this.usageService.getBalance({ attributionId: AttributionId.render(attributionId), - from: now, - to: now, }); - const currentInvoiceCredits = currentBalance.creditBalanceAtEnd | 0; + const currentInvoiceCredits = getBalanceResponse.credits; if (currentInvoiceCredits >= (costCenter.spendingLimit || 0)) { log.info({ userId: user.id }, "Usage limit reached", { attributionId, diff --git a/components/usage-api/go/v1/usage.pb.go b/components/usage-api/go/v1/usage.pb.go index 15293e799f1188..6637070360b1c7 100644 --- a/components/usage-api/go/v1/usage.pb.go +++ b/components/usage-api/go/v1/usage.pb.go @@ -160,7 +160,7 @@ func (x CostCenter_BillingStrategy) Number() protoreflect.EnumNumber { // Deprecated: Use CostCenter_BillingStrategy.Descriptor instead. func (CostCenter_BillingStrategy) EnumDescriptor() ([]byte, []int) { - return file_usage_v1_usage_proto_rawDescGZIP(), []int{11, 0} + return file_usage_v1_usage_proto_rawDescGZIP(), []int{13, 0} } type ReconcileUsageRequest struct { @@ -736,6 +736,100 @@ func (*SetCostCenterResponse) Descriptor() ([]byte, []int) { return file_usage_v1_usage_proto_rawDescGZIP(), []int{8} } +type GetBalanceRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + AttributionId string `protobuf:"bytes,1,opt,name=attribution_id,json=attributionId,proto3" json:"attribution_id,omitempty"` +} + +func (x *GetBalanceRequest) Reset() { + *x = GetBalanceRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_usage_v1_usage_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBalanceRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBalanceRequest) ProtoMessage() {} + +func (x *GetBalanceRequest) ProtoReflect() protoreflect.Message { + mi := &file_usage_v1_usage_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBalanceRequest.ProtoReflect.Descriptor instead. +func (*GetBalanceRequest) Descriptor() ([]byte, []int) { + return file_usage_v1_usage_proto_rawDescGZIP(), []int{9} +} + +func (x *GetBalanceRequest) GetAttributionId() string { + if x != nil { + return x.AttributionId + } + return "" +} + +type GetBalanceResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Credits float64 `protobuf:"fixed64,4,opt,name=credits,proto3" json:"credits,omitempty"` +} + +func (x *GetBalanceResponse) Reset() { + *x = GetBalanceResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_usage_v1_usage_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GetBalanceResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GetBalanceResponse) ProtoMessage() {} + +func (x *GetBalanceResponse) ProtoReflect() protoreflect.Message { + mi := &file_usage_v1_usage_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GetBalanceResponse.ProtoReflect.Descriptor instead. +func (*GetBalanceResponse) Descriptor() ([]byte, []int) { + return file_usage_v1_usage_proto_rawDescGZIP(), []int{10} +} + +func (x *GetBalanceResponse) GetCredits() float64 { + if x != nil { + return x.Credits + } + return 0 +} + type GetCostCenterRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -747,7 +841,7 @@ type GetCostCenterRequest struct { func (x *GetCostCenterRequest) Reset() { *x = GetCostCenterRequest{} if protoimpl.UnsafeEnabled { - mi := &file_usage_v1_usage_proto_msgTypes[9] + mi := &file_usage_v1_usage_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -760,7 +854,7 @@ func (x *GetCostCenterRequest) String() string { func (*GetCostCenterRequest) ProtoMessage() {} func (x *GetCostCenterRequest) ProtoReflect() protoreflect.Message { - mi := &file_usage_v1_usage_proto_msgTypes[9] + mi := &file_usage_v1_usage_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -773,7 +867,7 @@ func (x *GetCostCenterRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCostCenterRequest.ProtoReflect.Descriptor instead. func (*GetCostCenterRequest) Descriptor() ([]byte, []int) { - return file_usage_v1_usage_proto_rawDescGZIP(), []int{9} + return file_usage_v1_usage_proto_rawDescGZIP(), []int{11} } func (x *GetCostCenterRequest) GetAttributionId() string { @@ -794,7 +888,7 @@ type GetCostCenterResponse struct { func (x *GetCostCenterResponse) Reset() { *x = GetCostCenterResponse{} if protoimpl.UnsafeEnabled { - mi := &file_usage_v1_usage_proto_msgTypes[10] + mi := &file_usage_v1_usage_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -807,7 +901,7 @@ func (x *GetCostCenterResponse) String() string { func (*GetCostCenterResponse) ProtoMessage() {} func (x *GetCostCenterResponse) ProtoReflect() protoreflect.Message { - mi := &file_usage_v1_usage_proto_msgTypes[10] + mi := &file_usage_v1_usage_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -820,7 +914,7 @@ func (x *GetCostCenterResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetCostCenterResponse.ProtoReflect.Descriptor instead. func (*GetCostCenterResponse) Descriptor() ([]byte, []int) { - return file_usage_v1_usage_proto_rawDescGZIP(), []int{10} + return file_usage_v1_usage_proto_rawDescGZIP(), []int{12} } func (x *GetCostCenterResponse) GetCostCenter() *CostCenter { @@ -845,7 +939,7 @@ type CostCenter struct { func (x *CostCenter) Reset() { *x = CostCenter{} if protoimpl.UnsafeEnabled { - mi := &file_usage_v1_usage_proto_msgTypes[11] + mi := &file_usage_v1_usage_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -858,7 +952,7 @@ func (x *CostCenter) String() string { func (*CostCenter) ProtoMessage() {} func (x *CostCenter) ProtoReflect() protoreflect.Message { - mi := &file_usage_v1_usage_proto_msgTypes[11] + mi := &file_usage_v1_usage_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -871,7 +965,7 @@ func (x *CostCenter) ProtoReflect() protoreflect.Message { // Deprecated: Use CostCenter.ProtoReflect.Descriptor instead. func (*CostCenter) Descriptor() ([]byte, []int) { - return file_usage_v1_usage_proto_rawDescGZIP(), []int{11} + return file_usage_v1_usage_proto_rawDescGZIP(), []int{13} } func (x *CostCenter) GetAttributionId() string { @@ -996,61 +1090,72 @@ var file_usage_v1_usage_proto_rawDesc = []byte{ 0x0b, 0x32, 0x14, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x63, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x17, 0x0a, 0x15, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, - 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3d, 0x0a, 0x14, - 0x47, 0x65, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x4e, 0x0a, 0x15, 0x47, - 0x65, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x35, 0x0a, 0x0b, 0x63, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x65, 0x6e, - 0x74, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x75, 0x73, 0x61, 0x67, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x52, - 0x0a, 0x63, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0xbf, 0x02, 0x0a, 0x0a, - 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x74, - 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, - 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x69, - 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x70, 0x65, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x4f, 0x0a, 0x10, 0x62, 0x69, 0x6c, 0x6c, - 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x0e, 0x32, 0x24, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, - 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, - 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x52, 0x0f, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, - 0x67, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x46, 0x0a, 0x11, 0x6e, 0x65, 0x78, - 0x74, 0x5f, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, - 0x52, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, - 0x65, 0x22, 0x4a, 0x0a, 0x0f, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x61, - 0x74, 0x65, 0x67, 0x79, 0x12, 0x1b, 0x0a, 0x17, 0x42, 0x49, 0x4c, 0x4c, 0x49, 0x4e, 0x47, 0x5f, - 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x50, 0x45, 0x10, - 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x42, 0x49, 0x4c, 0x4c, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x52, - 0x41, 0x54, 0x45, 0x47, 0x59, 0x5f, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10, 0x01, 0x32, 0xd5, 0x02, - 0x0a, 0x0c, 0x55, 0x73, 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, - 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, - 0x1e, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x3a, 0x0a, 0x11, + 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, + 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x2e, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x42, + 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, + 0x0a, 0x07, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, + 0x07, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x22, 0x3d, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x43, + 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x4e, 0x0a, 0x15, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x35, 0x0a, 0x0b, 0x63, 0x6f, 0x73, 0x74, 0x5f, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x63, 0x6f, 0x73, + 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0xbf, 0x02, 0x0a, 0x0a, 0x43, 0x6f, 0x73, 0x74, + 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x61, 0x74, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x25, 0x0a, + 0x0e, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x4c, + 0x69, 0x6d, 0x69, 0x74, 0x12, 0x4f, 0x0a, 0x10, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x5f, + 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x24, + 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x2e, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x61, + 0x74, 0x65, 0x67, 0x79, 0x52, 0x0f, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, + 0x61, 0x74, 0x65, 0x67, 0x79, 0x12, 0x46, 0x0a, 0x11, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x62, 0x69, + 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x6e, 0x65, + 0x78, 0x74, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x4a, 0x0a, + 0x0f, 0x42, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x72, 0x61, 0x74, 0x65, 0x67, 0x79, + 0x12, 0x1b, 0x0a, 0x17, 0x42, 0x49, 0x4c, 0x4c, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x52, 0x41, + 0x54, 0x45, 0x47, 0x59, 0x5f, 0x53, 0x54, 0x52, 0x49, 0x50, 0x45, 0x10, 0x00, 0x12, 0x1a, 0x0a, + 0x16, 0x42, 0x49, 0x4c, 0x4c, 0x49, 0x4e, 0x47, 0x5f, 0x53, 0x54, 0x52, 0x41, 0x54, 0x45, 0x47, + 0x59, 0x5f, 0x4f, 0x54, 0x48, 0x45, 0x52, 0x10, 0x01, 0x32, 0xa0, 0x03, 0x0a, 0x0c, 0x55, 0x73, + 0x61, 0x67, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x52, 0x0a, 0x0d, 0x47, 0x65, + 0x74, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x75, 0x73, + 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x75, 0x73, + 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, + 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x52, + 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, + 0x1e, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1f, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x6f, + 0x1f, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x00, 0x12, 0x52, 0x0a, 0x0d, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, - 0x74, 0x65, 0x72, 0x12, 0x1e, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x65, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x65, 0x74, 0x43, 0x6f, 0x73, 0x74, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x55, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, - 0x69, 0x6c, 0x65, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, - 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x55, 0x73, 0x61, - 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x75, 0x73, 0x61, 0x67, - 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x55, 0x73, - 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, - 0x09, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x2e, 0x75, 0x73, 0x61, - 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, - 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x2a, 0x5a, 0x28, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, - 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x69, - 0x74, 0x70, 0x6f, 0x64, 0x2f, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2d, 0x61, 0x70, 0x69, 0x2f, 0x76, - 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x22, 0x00, 0x12, 0x55, 0x0a, 0x0e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x55, + 0x73, 0x61, 0x67, 0x65, 0x12, 0x1f, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, + 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, + 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x6e, 0x63, 0x69, 0x6c, 0x65, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x46, 0x0a, 0x09, 0x4c, 0x69, 0x73, + 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1a, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, + 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, + 0x73, 0x74, 0x55, 0x73, 0x61, 0x67, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x49, 0x0a, 0x0a, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x12, + 0x1b, 0x2e, 0x75, 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, + 0x6c, 0x61, 0x6e, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x75, + 0x73, 0x61, 0x67, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x42, 0x61, 0x6c, 0x61, 0x6e, + 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x2a, 0x5a, 0x28, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, + 0x64, 0x2d, 0x69, 0x6f, 0x2f, 0x67, 0x69, 0x74, 0x70, 0x6f, 0x64, 0x2f, 0x75, 0x73, 0x61, 0x67, + 0x65, 0x2d, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1066,7 +1171,7 @@ func file_usage_v1_usage_proto_rawDescGZIP() []byte { } var file_usage_v1_usage_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_usage_v1_usage_proto_msgTypes = make([]protoimpl.MessageInfo, 12) +var file_usage_v1_usage_proto_msgTypes = make([]protoimpl.MessageInfo, 14) var file_usage_v1_usage_proto_goTypes = []interface{}{ (ListUsageRequest_Ordering)(0), // 0: usage.v1.ListUsageRequest.Ordering (Usage_Kind)(0), // 1: usage.v1.Usage.Kind @@ -1080,36 +1185,40 @@ var file_usage_v1_usage_proto_goTypes = []interface{}{ (*Usage)(nil), // 9: usage.v1.Usage (*SetCostCenterRequest)(nil), // 10: usage.v1.SetCostCenterRequest (*SetCostCenterResponse)(nil), // 11: usage.v1.SetCostCenterResponse - (*GetCostCenterRequest)(nil), // 12: usage.v1.GetCostCenterRequest - (*GetCostCenterResponse)(nil), // 13: usage.v1.GetCostCenterResponse - (*CostCenter)(nil), // 14: usage.v1.CostCenter - (*timestamppb.Timestamp)(nil), // 15: google.protobuf.Timestamp + (*GetBalanceRequest)(nil), // 12: usage.v1.GetBalanceRequest + (*GetBalanceResponse)(nil), // 13: usage.v1.GetBalanceResponse + (*GetCostCenterRequest)(nil), // 14: usage.v1.GetCostCenterRequest + (*GetCostCenterResponse)(nil), // 15: usage.v1.GetCostCenterResponse + (*CostCenter)(nil), // 16: usage.v1.CostCenter + (*timestamppb.Timestamp)(nil), // 17: google.protobuf.Timestamp } var file_usage_v1_usage_proto_depIdxs = []int32{ - 15, // 0: usage.v1.ReconcileUsageRequest.from:type_name -> google.protobuf.Timestamp - 15, // 1: usage.v1.ReconcileUsageRequest.to:type_name -> google.protobuf.Timestamp - 15, // 2: usage.v1.ListUsageRequest.from:type_name -> google.protobuf.Timestamp - 15, // 3: usage.v1.ListUsageRequest.to:type_name -> google.protobuf.Timestamp + 17, // 0: usage.v1.ReconcileUsageRequest.from:type_name -> google.protobuf.Timestamp + 17, // 1: usage.v1.ReconcileUsageRequest.to:type_name -> google.protobuf.Timestamp + 17, // 2: usage.v1.ListUsageRequest.from:type_name -> google.protobuf.Timestamp + 17, // 3: usage.v1.ListUsageRequest.to:type_name -> google.protobuf.Timestamp 0, // 4: usage.v1.ListUsageRequest.order:type_name -> usage.v1.ListUsageRequest.Ordering 5, // 5: usage.v1.ListUsageRequest.pagination:type_name -> usage.v1.PaginatedRequest 9, // 6: usage.v1.ListUsageResponse.usage_entries:type_name -> usage.v1.Usage 6, // 7: usage.v1.ListUsageResponse.pagination:type_name -> usage.v1.PaginatedResponse - 15, // 8: usage.v1.Usage.effective_time:type_name -> google.protobuf.Timestamp + 17, // 8: usage.v1.Usage.effective_time:type_name -> google.protobuf.Timestamp 1, // 9: usage.v1.Usage.kind:type_name -> usage.v1.Usage.Kind - 14, // 10: usage.v1.SetCostCenterRequest.cost_center:type_name -> usage.v1.CostCenter - 14, // 11: usage.v1.GetCostCenterResponse.cost_center:type_name -> usage.v1.CostCenter + 16, // 10: usage.v1.SetCostCenterRequest.cost_center:type_name -> usage.v1.CostCenter + 16, // 11: usage.v1.GetCostCenterResponse.cost_center:type_name -> usage.v1.CostCenter 2, // 12: usage.v1.CostCenter.billing_strategy:type_name -> usage.v1.CostCenter.BillingStrategy - 15, // 13: usage.v1.CostCenter.next_billing_time:type_name -> google.protobuf.Timestamp - 12, // 14: usage.v1.UsageService.GetCostCenter:input_type -> usage.v1.GetCostCenterRequest + 17, // 13: usage.v1.CostCenter.next_billing_time:type_name -> google.protobuf.Timestamp + 14, // 14: usage.v1.UsageService.GetCostCenter:input_type -> usage.v1.GetCostCenterRequest 10, // 15: usage.v1.UsageService.SetCostCenter:input_type -> usage.v1.SetCostCenterRequest 3, // 16: usage.v1.UsageService.ReconcileUsage:input_type -> usage.v1.ReconcileUsageRequest 7, // 17: usage.v1.UsageService.ListUsage:input_type -> usage.v1.ListUsageRequest - 13, // 18: usage.v1.UsageService.GetCostCenter:output_type -> usage.v1.GetCostCenterResponse - 11, // 19: usage.v1.UsageService.SetCostCenter:output_type -> usage.v1.SetCostCenterResponse - 4, // 20: usage.v1.UsageService.ReconcileUsage:output_type -> usage.v1.ReconcileUsageResponse - 8, // 21: usage.v1.UsageService.ListUsage:output_type -> usage.v1.ListUsageResponse - 18, // [18:22] is the sub-list for method output_type - 14, // [14:18] is the sub-list for method input_type + 12, // 18: usage.v1.UsageService.GetBalance:input_type -> usage.v1.GetBalanceRequest + 15, // 19: usage.v1.UsageService.GetCostCenter:output_type -> usage.v1.GetCostCenterResponse + 11, // 20: usage.v1.UsageService.SetCostCenter:output_type -> usage.v1.SetCostCenterResponse + 4, // 21: usage.v1.UsageService.ReconcileUsage:output_type -> usage.v1.ReconcileUsageResponse + 8, // 22: usage.v1.UsageService.ListUsage:output_type -> usage.v1.ListUsageResponse + 13, // 23: usage.v1.UsageService.GetBalance:output_type -> usage.v1.GetBalanceResponse + 19, // [19:24] is the sub-list for method output_type + 14, // [14:19] is the sub-list for method input_type 14, // [14:14] is the sub-list for extension type_name 14, // [14:14] is the sub-list for extension extendee 0, // [0:14] is the sub-list for field type_name @@ -1230,7 +1339,7 @@ func file_usage_v1_usage_proto_init() { } } file_usage_v1_usage_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCostCenterRequest); i { + switch v := v.(*GetBalanceRequest); i { case 0: return &v.state case 1: @@ -1242,7 +1351,7 @@ func file_usage_v1_usage_proto_init() { } } file_usage_v1_usage_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*GetCostCenterResponse); i { + switch v := v.(*GetBalanceResponse); i { case 0: return &v.state case 1: @@ -1254,6 +1363,30 @@ func file_usage_v1_usage_proto_init() { } } file_usage_v1_usage_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetCostCenterRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_usage_v1_usage_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GetCostCenterResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_usage_v1_usage_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CostCenter); i { case 0: return &v.state @@ -1272,7 +1405,7 @@ func file_usage_v1_usage_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_usage_v1_usage_proto_rawDesc, NumEnums: 3, - NumMessages: 12, + NumMessages: 14, NumExtensions: 0, NumServices: 1, }, diff --git a/components/usage-api/go/v1/usage_grpc.pb.go b/components/usage-api/go/v1/usage_grpc.pb.go index 6dea5c3db7e9ee..e2efa1de9af648 100644 --- a/components/usage-api/go/v1/usage_grpc.pb.go +++ b/components/usage-api/go/v1/usage_grpc.pb.go @@ -34,6 +34,8 @@ type UsageServiceClient interface { ReconcileUsage(ctx context.Context, in *ReconcileUsageRequest, opts ...grpc.CallOption) (*ReconcileUsageResponse, error) // ListUsage retrieves all usage for the specified attributionId and theb given time range ListUsage(ctx context.Context, in *ListUsageRequest, opts ...grpc.CallOption) (*ListUsageResponse, error) + // GetBalance returns the current credits balance for the given attributionId + GetBalance(ctx context.Context, in *GetBalanceRequest, opts ...grpc.CallOption) (*GetBalanceResponse, error) } type usageServiceClient struct { @@ -80,6 +82,15 @@ func (c *usageServiceClient) ListUsage(ctx context.Context, in *ListUsageRequest return out, nil } +func (c *usageServiceClient) GetBalance(ctx context.Context, in *GetBalanceRequest, opts ...grpc.CallOption) (*GetBalanceResponse, error) { + out := new(GetBalanceResponse) + err := c.cc.Invoke(ctx, "/usage.v1.UsageService/GetBalance", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // UsageServiceServer is the server API for UsageService service. // All implementations must embed UnimplementedUsageServiceServer // for forward compatibility @@ -92,6 +103,8 @@ type UsageServiceServer interface { ReconcileUsage(context.Context, *ReconcileUsageRequest) (*ReconcileUsageResponse, error) // ListUsage retrieves all usage for the specified attributionId and theb given time range ListUsage(context.Context, *ListUsageRequest) (*ListUsageResponse, error) + // GetBalance returns the current credits balance for the given attributionId + GetBalance(context.Context, *GetBalanceRequest) (*GetBalanceResponse, error) mustEmbedUnimplementedUsageServiceServer() } @@ -111,6 +124,9 @@ func (UnimplementedUsageServiceServer) ReconcileUsage(context.Context, *Reconcil func (UnimplementedUsageServiceServer) ListUsage(context.Context, *ListUsageRequest) (*ListUsageResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method ListUsage not implemented") } +func (UnimplementedUsageServiceServer) GetBalance(context.Context, *GetBalanceRequest) (*GetBalanceResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetBalance not implemented") +} func (UnimplementedUsageServiceServer) mustEmbedUnimplementedUsageServiceServer() {} // UnsafeUsageServiceServer may be embedded to opt out of forward compatibility for this service. @@ -196,6 +212,24 @@ func _UsageService_ListUsage_Handler(srv interface{}, ctx context.Context, dec f return interceptor(ctx, in, info, handler) } +func _UsageService_GetBalance_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(GetBalanceRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(UsageServiceServer).GetBalance(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/usage.v1.UsageService/GetBalance", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(UsageServiceServer).GetBalance(ctx, req.(*GetBalanceRequest)) + } + return interceptor(ctx, in, info, handler) +} + // UsageService_ServiceDesc is the grpc.ServiceDesc for UsageService service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -219,6 +253,10 @@ var UsageService_ServiceDesc = grpc.ServiceDesc{ MethodName: "ListUsage", Handler: _UsageService_ListUsage_Handler, }, + { + MethodName: "GetBalance", + Handler: _UsageService_GetBalance_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "usage/v1/usage.proto", diff --git a/components/usage-api/typescript/src/usage/v1/usage.pb.ts b/components/usage-api/typescript/src/usage/v1/usage.pb.ts index f1c5ec748e2b87..09c077c656c878 100644 --- a/components/usage-api/typescript/src/usage/v1/usage.pb.ts +++ b/components/usage-api/typescript/src/usage/v1/usage.pb.ts @@ -174,6 +174,14 @@ export interface SetCostCenterRequest { export interface SetCostCenterResponse { } +export interface GetBalanceRequest { + attributionId: string; +} + +export interface GetBalanceResponse { + credits: number; +} + export interface GetCostCenterRequest { attributionId: string; } @@ -865,6 +873,100 @@ export const SetCostCenterResponse = { }, }; +function createBaseGetBalanceRequest(): GetBalanceRequest { + return { attributionId: "" }; +} + +export const GetBalanceRequest = { + encode(message: GetBalanceRequest, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.attributionId !== "") { + writer.uint32(10).string(message.attributionId); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): GetBalanceRequest { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseGetBalanceRequest(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: + message.attributionId = reader.string(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }, + + fromJSON(object: any): GetBalanceRequest { + return { attributionId: isSet(object.attributionId) ? String(object.attributionId) : "" }; + }, + + toJSON(message: GetBalanceRequest): unknown { + const obj: any = {}; + message.attributionId !== undefined && (obj.attributionId = message.attributionId); + return obj; + }, + + fromPartial(object: DeepPartial): GetBalanceRequest { + const message = createBaseGetBalanceRequest(); + message.attributionId = object.attributionId ?? ""; + return message; + }, +}; + +function createBaseGetBalanceResponse(): GetBalanceResponse { + return { credits: 0 }; +} + +export const GetBalanceResponse = { + encode(message: GetBalanceResponse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { + if (message.credits !== 0) { + writer.uint32(33).double(message.credits); + } + return writer; + }, + + decode(input: _m0.Reader | Uint8Array, length?: number): GetBalanceResponse { + const reader = input instanceof _m0.Reader ? input : new _m0.Reader(input); + let end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseGetBalanceResponse(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 4: + message.credits = reader.double(); + break; + default: + reader.skipType(tag & 7); + break; + } + } + return message; + }, + + fromJSON(object: any): GetBalanceResponse { + return { credits: isSet(object.credits) ? Number(object.credits) : 0 }; + }, + + toJSON(message: GetBalanceResponse): unknown { + const obj: any = {}; + message.credits !== undefined && (obj.credits = message.credits); + return obj; + }, + + fromPartial(object: DeepPartial): GetBalanceResponse { + const message = createBaseGetBalanceResponse(); + message.credits = object.credits ?? 0; + return message; + }, +}; + function createBaseGetCostCenterRequest(): GetCostCenterRequest { return { attributionId: "" }; } @@ -1087,6 +1189,15 @@ export const UsageServiceDefinition = { responseStream: false, options: {}, }, + /** GetBalance returns the current credits balance for the given attributionId */ + getBalance: { + name: "GetBalance", + requestType: GetBalanceRequest, + requestStream: false, + responseType: GetBalanceResponse, + responseStream: false, + options: {}, + }, }, } as const; @@ -1108,6 +1219,11 @@ export interface UsageServiceServiceImplementation { ): Promise>; /** ListUsage retrieves all usage for the specified attributionId and theb given time range */ listUsage(request: ListUsageRequest, context: CallContext & CallContextExt): Promise>; + /** GetBalance returns the current credits balance for the given attributionId */ + getBalance( + request: GetBalanceRequest, + context: CallContext & CallContextExt, + ): Promise>; } export interface UsageServiceClient { @@ -1128,6 +1244,11 @@ export interface UsageServiceClient { ): Promise; /** ListUsage retrieves all usage for the specified attributionId and theb given time range */ listUsage(request: DeepPartial, options?: CallOptions & CallOptionsExt): Promise; + /** GetBalance returns the current credits balance for the given attributionId */ + getBalance( + request: DeepPartial, + options?: CallOptions & CallOptionsExt, + ): Promise; } export interface DataLoaderOptions { diff --git a/components/usage-api/usage/v1/usage.proto b/components/usage-api/usage/v1/usage.proto index c25819c458315d..534beb03506596 100644 --- a/components/usage-api/usage/v1/usage.proto +++ b/components/usage-api/usage/v1/usage.proto @@ -19,6 +19,9 @@ service UsageService { // ListUsage retrieves all usage for the specified attributionId and theb given time range rpc ListUsage(ListUsageRequest) returns (ListUsageResponse) {} + + // GetBalance returns the current credits balance for the given attributionId + rpc GetBalance(GetBalanceRequest) returns (GetBalanceResponse) {} } message ReconcileUsageRequest { @@ -98,6 +101,14 @@ message SetCostCenterRequest { message SetCostCenterResponse { } +message GetBalanceRequest { + string attribution_id = 1; +} + +message GetBalanceResponse { + double credits = 4; +} + message GetCostCenterRequest { string attribution_id = 1; } diff --git a/components/usage/pkg/apiv1/usage.go b/components/usage/pkg/apiv1/usage.go index 3b36f14eb11a3a..eb5748f4431d9c 100644 --- a/components/usage/pkg/apiv1/usage.go +++ b/components/usage/pkg/apiv1/usage.go @@ -156,6 +156,20 @@ func (s *UsageService) ListUsage(ctx context.Context, in *v1.ListUsageRequest) ( }, nil } +func (s *UsageService) GetBalance(ctx context.Context, in *v1.GetBalanceRequest) (*v1.GetBalanceResponse, error) { + attrId, err := db.ParseAttributionID(in.AttributionId) + if err != nil { + return nil, err + } + credits, err := db.GetBalance(ctx, s.conn, attrId) + if err != nil { + return nil, err + } + return &v1.GetBalanceResponse{ + Credits: credits.ToCredits(), + }, nil +} + func (s *UsageService) GetCostCenter(ctx context.Context, in *v1.GetCostCenterRequest) (*v1.GetCostCenterResponse, error) { if in.AttributionId == "" { return nil, status.Errorf(codes.InvalidArgument, "Empty attributionId") diff --git a/components/usage/pkg/db/usage.go b/components/usage/pkg/db/usage.go index 0ff8eaaa3f3ec7..7e366766b1e588 100644 --- a/components/usage/pkg/db/usage.go +++ b/components/usage/pkg/db/usage.go @@ -207,6 +207,30 @@ type Balance struct { CreditCents CreditCents `gorm:"column:creditCents;type:bigint;" json:"creditCents"` } +func GetBalance(ctx context.Context, conn *gorm.DB, attributionId AttributionID) (CreditCents, error) { + rows, err := conn.WithContext(ctx). + Model(&Usage{}). + Select("sum(creditCents) as balance"). + Where("attributionId = ?", string(attributionId)). + Group("attributionId"). + Rows() + if err != nil { + return 0, fmt.Errorf("failed to get rows for list balance query: %w", err) + } + defer rows.Close() + + if !rows.Next() { + return 0, nil + } + + var balance CreditCents + err = conn.ScanRows(rows, &balance) + if err != nil { + return 0, fmt.Errorf("failed to scan row: %w", err) + } + return balance, nil +} + func ListBalance(ctx context.Context, conn *gorm.DB) ([]Balance, error) { var balances []Balance rows, err := conn.WithContext(ctx). diff --git a/components/usage/pkg/db/usage_test.go b/components/usage/pkg/db/usage_test.go index c0935c7ce0e85a..42a76efc86e8dd 100644 --- a/components/usage/pkg/db/usage_test.go +++ b/components/usage/pkg/db/usage_test.go @@ -322,3 +322,37 @@ func TestListBalance(t *testing.T) { CreditCents: -50, }) } + +func TestGetBalance(t *testing.T) { + teamAttributionID := db.NewTeamAttributionID(uuid.New().String()) + userAttributionID := db.NewUserAttributionID(uuid.New().String()) + + conn := dbtest.ConnectForTests(t) + dbtest.CreateUsageRecords(t, conn, + dbtest.NewUsage(t, db.Usage{ + AttributionID: teamAttributionID, + CreditCents: 100, + }), + dbtest.NewUsage(t, db.Usage{ + AttributionID: teamAttributionID, + CreditCents: 900, + }), + dbtest.NewUsage(t, db.Usage{ + AttributionID: userAttributionID, + CreditCents: 450, + }), + dbtest.NewUsage(t, db.Usage{ + AttributionID: userAttributionID, + CreditCents: -500, + Kind: db.InvoiceUsageKind, + }), + ) + + teamBalance, err := db.GetBalance(context.Background(), conn, teamAttributionID) + require.NoError(t, err) + require.EqualValues(t, 1000, int(teamBalance)) + + userBalance, err := db.GetBalance(context.Background(), conn, userAttributionID) + require.NoError(t, err) + require.EqualValues(t, -50, int(userBalance)) +}