diff --git a/CommonServer/Services/BillingService.ts b/CommonServer/Services/BillingService.ts index e065ce026e..a481299954 100644 --- a/CommonServer/Services/BillingService.ts +++ b/CommonServer/Services/BillingService.ts @@ -115,7 +115,7 @@ export class BillingService extends BaseService { public async subscribeToMeteredPlan(data: { projectId: ObjectID; customerId: string; - serverMeteredPlans: Array ; + serverMeteredPlans: Array ; trialDate: Date | null; defaultPaymentMethodId?: string | undefined; promoCode?: string | undefined; @@ -127,9 +127,9 @@ export class BillingService extends BaseService { customer: data.customerId, items: data.serverMeteredPlans.map( - (item: typeof ServerMeteredPlan) => { + (item: ServerMeteredPlan) => { return { - price: item.getMeteredPlan()?.getPriceId(), + price: item.getPriceId(), }; } ), @@ -195,7 +195,7 @@ export class BillingService extends BaseService { public async subscribeToPlan(data: { projectId: ObjectID; customerId: string; - serverMeteredPlans: Array; + serverMeteredPlans: Array; plan: SubscriptionPlan; quantity: number; isYearly: boolean; @@ -313,7 +313,7 @@ export class BillingService extends BaseService { public async addOrUpdateMeteredPricingOnSubscription( subscriptionId: string, - meteredPlan: MeteredPlan, + serverMeteredPlan: ServerMeteredPlan, quantity: number ): Promise { if (!this.isBillingEnabled()) { @@ -337,7 +337,7 @@ export class BillingService extends BaseService { const pricingExists: boolean = subscription.items.data.some( (item: SubscriptionItem) => { - return item.price?.id === meteredPlan.getPriceId(); + return item.price?.id === serverMeteredPlan.getPriceId(); } ); @@ -345,7 +345,7 @@ export class BillingService extends BaseService { // update the quantity. const subscriptionItemId: string | undefined = subscription.items.data.find((item: SubscriptionItem) => { - return item.price?.id === meteredPlan.getPriceId(); + return item.price?.id === serverMeteredPlan.getPriceId(); })?.id; if (!subscriptionItemId) { @@ -366,7 +366,7 @@ export class BillingService extends BaseService { const subscriptionItem: SubscriptionItem = await this.stripe.subscriptionItems.create({ subscription: subscriptionId, - price: meteredPlan.getPriceId(), + price: serverMeteredPlan.getPriceId(), }); // use stripe usage based api to update the quantity. @@ -470,7 +470,7 @@ export class BillingService extends BaseService { projectId: ObjectID; subscriptionId: string; meteredSubscriptionId: string; - serverMeteredPlans: Array; + serverMeteredPlans: Array; newPlan: SubscriptionPlan; quantity: number; isYearly: boolean; diff --git a/CommonServer/Tests/Services/BillingService.test.ts b/CommonServer/Tests/Services/BillingService.test.ts index ce546fa40c..8ffee8e9a4 100644 --- a/CommonServer/Tests/Services/BillingService.test.ts +++ b/CommonServer/Tests/Services/BillingService.test.ts @@ -641,11 +641,11 @@ describe('BillingService', () => { it('should throw if billing is not enabled', async () => { const subscriptionItem: SubscriptionItem | undefined = mockSubscription.items.data[0]; - const meteredPlan: MeteredPlan = new MeteredPlan( - subscriptionItem?.price?.id || '', - 100, - 'unit' - ); + const meteredPlan: MeteredPlan = new MeteredPlan({ + priceId: subscriptionItem?.price?.id || '', + pricePerUnitInUSD: 100, + unitName: 'unit' + }); billingService = mockIsBillingEnabled(false); @@ -661,11 +661,11 @@ describe('BillingService', () => { it('should successfully add metered pricing to a subscription', async () => { const subscriptionItem: SubscriptionItem | undefined = mockSubscription.items.data[0]; - const meteredPlan: MeteredPlan = new MeteredPlan( - subscriptionItem?.price?.id || '', - 100, - 'unit' - ); + const meteredPlan: MeteredPlan = new MeteredPlan({ + priceId: subscriptionItem?.price?.id || '', + pricePerUnitInUSD: 100, + unitName: 'unit' + }); mockSubscription.items.data = []; @@ -702,11 +702,11 @@ describe('BillingService', () => { it('should successfully update existing metered pricing on a subscription', async () => { const subscriptionItem: SubscriptionItem | undefined = mockSubscription.items.data[0]; - const meteredPlan: MeteredPlan = new MeteredPlan( - subscriptionItem?.price?.id || '', - 100, - 'unit' - ); + const meteredPlan: MeteredPlan = new MeteredPlan({ + priceId: subscriptionItem?.price?.id || '', + pricePerUnitInUSD: 100, + unitName: 'unit' + }); mockStripe.subscriptions.retrieve = jest .fn() @@ -734,11 +734,11 @@ describe('BillingService', () => { it('should handle non-existent subscription', async () => { const subscriptionItem: SubscriptionItem | undefined = mockSubscription.items.data[0]; - const meteredPlan: MeteredPlan = new MeteredPlan( - subscriptionItem?.price?.id || '', - 100, - 'unit' - ); + const meteredPlan: MeteredPlan = new MeteredPlan({ + priceId: subscriptionItem?.price?.id || '', + pricePerUnitInUSD: 100, + unitName: 'unit' + }); const subscriptionId: string = 'sub_nonexistent'; mockStripe.subscriptions.retrieve = jest diff --git a/CommonServer/Tests/TestingUtils/Services/Types.ts b/CommonServer/Tests/TestingUtils/Services/Types.ts index 5f6dd64404..39add74014 100644 --- a/CommonServer/Tests/TestingUtils/Services/Types.ts +++ b/CommonServer/Tests/TestingUtils/Services/Types.ts @@ -22,7 +22,7 @@ export type CouponData = { export type Subscription = { projectId: ObjectID; customerId: string; - serverMeteredPlans: Array; + serverMeteredPlans: Array; promoCode?: string; defaultPaymentMethodId?: string; trialDate: Date; @@ -31,7 +31,7 @@ export type Subscription = { export type MeteredSubscription = { projectId: ObjectID; customerId: string; - serverMeteredPlans: Array; + serverMeteredPlans: Array; plan: SubscriptionPlan; quantity: number; isYearly: boolean; @@ -44,7 +44,7 @@ export type ChangePlan = { projectId: ObjectID; subscriptionId: string; meteredSubscriptionId: string; - serverMeteredPlans: Array; + serverMeteredPlans: Array; newPlan: SubscriptionPlan; quantity: number; isYearly: boolean; diff --git a/CommonServer/Types/Billing/MeteredPlan/ActiveMonitoringMeteredPlan.ts b/CommonServer/Types/Billing/MeteredPlan/ActiveMonitoringMeteredPlan.ts index 9cdfd03da9..4286b1a6f9 100644 --- a/CommonServer/Types/Billing/MeteredPlan/ActiveMonitoringMeteredPlan.ts +++ b/CommonServer/Types/Billing/MeteredPlan/ActiveMonitoringMeteredPlan.ts @@ -1,5 +1,3 @@ -import MeteredPlan from 'Common/Types/Billing/MeteredPlan'; -import MeteredPlanUtil from './MeteredPlanUtil'; import ServerMeteredPlan from './ServerMeteredPlan'; import ObjectID from 'Common/Types/ObjectID'; import MonitorService from '../../../Services/MonitorService'; @@ -7,18 +5,16 @@ import QueryHelper from '../../Database/QueryHelper'; import MonitorType from 'Common/Types/Monitor/MonitorType'; import PositiveNumber from 'Common/Types/PositiveNumber'; import ProjectService from '../../../Services/ProjectService'; -import BillingService from '../../../Services/BillingService'; +import BillingService, { MeteredPlanName } from '../../../Services/BillingService'; import Project from 'Model/Models/Project'; export default class ActiveMonitoringMeteredPlan extends ServerMeteredPlan { - public static override getMeteredPlan(): MeteredPlan { - const meteredPlan: MeteredPlan = - MeteredPlanUtil.getMeteredPlan('ACTIVE_MONITORING'); - this.meteredPlan = meteredPlan; - return meteredPlan; + + public override getMeteredPlanName(): MeteredPlanName { + return MeteredPlanName.ActiveMonitoring; } - public static override async reportQuantityToBillingProvider( + public override async reportQuantityToBillingProvider( projectId: ObjectID, options?: { meteredPlanSubscriptionId?: string | undefined; @@ -66,7 +62,7 @@ export default class ActiveMonitoringMeteredPlan extends ServerMeteredPlan { await BillingService.addOrUpdateMeteredPricingOnSubscription( (options?.meteredPlanSubscriptionId as string) || (project.paymentProviderMeteredSubscriptionId as string), - ActiveMonitoringMeteredPlan.getMeteredPlan(), + this, count.toNumber() ); } diff --git a/CommonServer/Types/Billing/MeteredPlan/AllMeteredPlans.ts b/CommonServer/Types/Billing/MeteredPlan/AllMeteredPlans.ts index 7a3c88d908..cb06b5877e 100644 --- a/CommonServer/Types/Billing/MeteredPlan/AllMeteredPlans.ts +++ b/CommonServer/Types/Billing/MeteredPlan/AllMeteredPlans.ts @@ -1,10 +1,13 @@ import ActiveMonitoringMeteredPlan from './ActiveMonitoringMeteredPlan'; -import LogsDataIngestMeteredPlan from './LogsDataIngestMeteredPlan'; import ServerMeteredPlan from './ServerMeteredPlan'; +import TelemetryMeteredPlan from './TelemetryMeteredPlan'; +import { ProductType } from 'Model/Models/UsageBilling'; -const AllMeteredPlans: Array = [ - ActiveMonitoringMeteredPlan, - LogsDataIngestMeteredPlan, +const AllMeteredPlans: Array = [ + new ActiveMonitoringMeteredPlan(), + new TelemetryMeteredPlan(ProductType.Logs), + new TelemetryMeteredPlan(ProductType.Metrics), + new TelemetryMeteredPlan(ProductType.Traces), ]; export default AllMeteredPlans; diff --git a/CommonServer/Types/Billing/MeteredPlan/ServerMeteredPlan.ts b/CommonServer/Types/Billing/MeteredPlan/ServerMeteredPlan.ts index b6cebcd7ef..c6e379d14d 100644 --- a/CommonServer/Types/Billing/MeteredPlan/ServerMeteredPlan.ts +++ b/CommonServer/Types/Billing/MeteredPlan/ServerMeteredPlan.ts @@ -1,20 +1,19 @@ -import MeteredPlan from 'Common/Types/Billing/MeteredPlan'; -import BadDataException from 'Common/Types/Exception/BadDataException'; import NotImplementedException from 'Common/Types/Exception/NotImplementedException'; import ObjectID from 'Common/Types/ObjectID'; +import BillingService, { MeteredPlanName } from '../../../Services/BillingService'; +import MeteredPlan from 'Common/Types/Billing/MeteredPlan'; export default class ServerMeteredPlan { - public static meteredPlan: MeteredPlan | undefined = undefined; - - public static getMeteredPlan(): MeteredPlan { - if (!this.meteredPlan) { - throw new BadDataException('Metered plan not found'); - } - - return this.meteredPlan; + + public getMeteredPlanName(): MeteredPlanName { + throw new NotImplementedException(); } - public static async reportQuantityToBillingProvider( + public getMeteredPlan(projectId: ObjectID): MeteredPlan { + throw new NotImplementedException(); + } + + public async reportQuantityToBillingProvider( _projectId: ObjectID, _options: { meteredPlanSubscriptionId?: string | undefined; @@ -22,4 +21,8 @@ export default class ServerMeteredPlan { ): Promise { throw new NotImplementedException(); } + + public getPriceId(): string { + return BillingService.getMeteredPlanPriceId(this.getMeteredPlanName()); + } } diff --git a/CommonServer/Types/Billing/MeteredPlan/LogsDataIngestMeteredPlan.ts b/CommonServer/Types/Billing/MeteredPlan/TelemetryMeteredPlan.ts similarity index 78% rename from CommonServer/Types/Billing/MeteredPlan/LogsDataIngestMeteredPlan.ts rename to CommonServer/Types/Billing/MeteredPlan/TelemetryMeteredPlan.ts index 6b1b9d4ad1..4de4c782ad 100644 --- a/CommonServer/Types/Billing/MeteredPlan/LogsDataIngestMeteredPlan.ts +++ b/CommonServer/Types/Billing/MeteredPlan/TelemetryMeteredPlan.ts @@ -1,23 +1,36 @@ -import MeteredPlan from 'Common/Types/Billing/MeteredPlan'; -import MeteredPlanUtil from './MeteredPlanUtil'; import ServerMeteredPlan from './ServerMeteredPlan'; import ObjectID from 'Common/Types/ObjectID'; import ProjectService from '../../../Services/ProjectService'; -import BillingService from '../../../Services/BillingService'; +import BillingService, { MeteredPlanName } from '../../../Services/BillingService'; import Project from 'Model/Models/Project'; import UsageBilling, { ProductType } from 'Model/Models/UsageBilling'; import UsageBillingService from '../../../Services/UsageBillingService'; import OneUptimeDate from 'Common/Types/Date'; -export default class LogsDataIngestMeteredPlan extends ServerMeteredPlan { - public static override getMeteredPlan(): MeteredPlan { - const meteredPlan: MeteredPlan = - MeteredPlanUtil.getMeteredPlan('LOGS_DATA_INGEST'); - this.meteredPlan = meteredPlan; - return meteredPlan; +export default class TelemetryMeteredPlan extends ServerMeteredPlan { + + + + private _prodyctType!: ProductType; + public get prodyctType() : ProductType { + return this._prodyctType; + } + public set prodyctType(v : ProductType) { + this._prodyctType = v; + } + + + public constructor(productType: ProductType) { + super(); + this.prodyctType = productType; } - public static override async reportQuantityToBillingProvider( + + public override getMeteredPlanName(): MeteredPlanName { + return MeteredPlanName.LogsDataIngestion; + } + + public override async reportQuantityToBillingProvider( projectId: ObjectID, options?: { meteredPlanSubscriptionId?: string | undefined; @@ -62,7 +75,7 @@ export default class LogsDataIngestMeteredPlan extends ServerMeteredPlan { await BillingService.addOrUpdateMeteredPricingOnSubscription( (options?.meteredPlanSubscriptionId as string) || (project.paymentProviderMeteredSubscriptionId as string), - LogsDataIngestMeteredPlan.getMeteredPlan(), + this, usageBilling.usageCount );