fix preprod
Some checks failed
CD Preprod / Backend — Lint (push) Successful in 10m27s
CD Preprod / Frontend — Lint & Type-check (push) Successful in 10m55s
CD Preprod / Backend — Unit Tests (push) Successful in 10m10s
CD Preprod / Frontend — Unit Tests (push) Successful in 10m33s
CD Preprod / Backend — Integration Tests (push) Successful in 10m6s
CD Preprod / Build Backend (push) Successful in 16m5s
CD Preprod / Build Frontend (push) Successful in 35m0s
CD Preprod / Deploy to Preprod (push) Failing after 1s
CD Preprod / Smoke Tests (push) Has been skipped
CD Preprod / Notify Success (push) Has been skipped
CD Preprod / Notify Failure (push) Has been skipped

This commit is contained in:
David 2026-04-04 17:58:36 +02:00
parent fe7cd1f792
commit 72141c5f68
3 changed files with 178 additions and 157 deletions

View File

@ -21,12 +21,12 @@ describe('Subscription Entity', () => {
};
describe('create', () => {
it('should create a subscription with default FREE plan', () => {
it('should create a subscription with default BRONZE plan', () => {
const subscription = createValidSubscription();
expect(subscription.id).toBe('sub-123');
expect(subscription.organizationId).toBe('org-123');
expect(subscription.plan.value).toBe('FREE');
expect(subscription.plan.value).toBe('BRONZE');
expect(subscription.status.value).toBe('ACTIVE');
expect(subscription.cancelAtPeriodEnd).toBe(false);
});
@ -35,10 +35,10 @@ describe('Subscription Entity', () => {
const subscription = Subscription.create({
id: 'sub-123',
organizationId: 'org-123',
plan: SubscriptionPlan.starter(),
plan: SubscriptionPlan.silver(),
});
expect(subscription.plan.value).toBe('STARTER');
expect(subscription.plan.value).toBe('SILVER');
});
it('should create a subscription with Stripe IDs', () => {
@ -59,7 +59,7 @@ describe('Subscription Entity', () => {
const subscription = Subscription.fromPersistence({
id: 'sub-123',
organizationId: 'org-123',
plan: 'PRO',
plan: 'GOLD',
status: 'ACTIVE',
stripeCustomerId: 'cus_123',
stripeSubscriptionId: 'sub_stripe_123',
@ -71,57 +71,57 @@ describe('Subscription Entity', () => {
});
expect(subscription.id).toBe('sub-123');
expect(subscription.plan.value).toBe('PRO');
expect(subscription.plan.value).toBe('GOLD');
expect(subscription.status.value).toBe('ACTIVE');
expect(subscription.cancelAtPeriodEnd).toBe(true);
});
});
describe('maxLicenses', () => {
it('should return correct limits for FREE plan', () => {
it('should return correct limits for BRONZE plan', () => {
const subscription = createValidSubscription();
expect(subscription.maxLicenses).toBe(2);
expect(subscription.maxLicenses).toBe(1);
});
it('should return correct limits for STARTER plan', () => {
it('should return correct limits for SILVER plan', () => {
const subscription = Subscription.create({
id: 'sub-123',
organizationId: 'org-123',
plan: SubscriptionPlan.starter(),
plan: SubscriptionPlan.silver(),
});
expect(subscription.maxLicenses).toBe(5);
});
it('should return correct limits for PRO plan', () => {
it('should return correct limits for GOLD plan', () => {
const subscription = Subscription.create({
id: 'sub-123',
organizationId: 'org-123',
plan: SubscriptionPlan.pro(),
plan: SubscriptionPlan.gold(),
});
expect(subscription.maxLicenses).toBe(20);
});
it('should return -1 for ENTERPRISE plan (unlimited)', () => {
it('should return -1 for PLATINIUM plan (unlimited)', () => {
const subscription = Subscription.create({
id: 'sub-123',
organizationId: 'org-123',
plan: SubscriptionPlan.enterprise(),
plan: SubscriptionPlan.platinium(),
});
expect(subscription.maxLicenses).toBe(-1);
});
});
describe('isUnlimited', () => {
it('should return false for FREE plan', () => {
it('should return false for BRONZE plan', () => {
const subscription = createValidSubscription();
expect(subscription.isUnlimited()).toBe(false);
});
it('should return true for ENTERPRISE plan', () => {
it('should return true for PLATINIUM plan', () => {
const subscription = Subscription.create({
id: 'sub-123',
organizationId: 'org-123',
plan: SubscriptionPlan.enterprise(),
plan: SubscriptionPlan.platinium(),
});
expect(subscription.isUnlimited()).toBe(true);
});
@ -137,7 +137,7 @@ describe('Subscription Entity', () => {
const subscription = Subscription.fromPersistence({
id: 'sub-123',
organizationId: 'org-123',
plan: 'FREE',
plan: 'BRONZE',
status: 'TRIALING',
stripeCustomerId: null,
stripeSubscriptionId: null,
@ -154,7 +154,7 @@ describe('Subscription Entity', () => {
const subscription = Subscription.fromPersistence({
id: 'sub-123',
organizationId: 'org-123',
plan: 'FREE',
plan: 'BRONZE',
status: 'CANCELED',
stripeCustomerId: null,
stripeSubscriptionId: null,
@ -170,21 +170,20 @@ describe('Subscription Entity', () => {
describe('canAllocateLicenses', () => {
it('should return true when licenses are available', () => {
const subscription = createValidSubscription();
const subscription = createValidSubscription(); // BRONZE = 1 license
expect(subscription.canAllocateLicenses(0, 1)).toBe(true);
expect(subscription.canAllocateLicenses(1, 1)).toBe(true);
});
it('should return false when no licenses available', () => {
const subscription = createValidSubscription();
expect(subscription.canAllocateLicenses(2, 1)).toBe(false); // FREE has 2 licenses
expect(subscription.canAllocateLicenses(1, 1)).toBe(false); // BRONZE has 1 license max
});
it('should always return true for ENTERPRISE plan', () => {
it('should always return true for PLATINIUM plan', () => {
const subscription = Subscription.create({
id: 'sub-123',
organizationId: 'org-123',
plan: SubscriptionPlan.enterprise(),
plan: SubscriptionPlan.platinium(),
});
expect(subscription.canAllocateLicenses(1000, 100)).toBe(true);
});
@ -193,7 +192,7 @@ describe('Subscription Entity', () => {
const subscription = Subscription.fromPersistence({
id: 'sub-123',
organizationId: 'org-123',
plan: 'FREE',
plan: 'BRONZE',
status: 'CANCELED',
stripeCustomerId: null,
stripeSubscriptionId: null,
@ -208,23 +207,23 @@ describe('Subscription Entity', () => {
});
describe('canUpgradeTo', () => {
it('should allow upgrade from FREE to STARTER', () => {
it('should allow upgrade from BRONZE to SILVER', () => {
const subscription = createValidSubscription();
expect(subscription.canUpgradeTo(SubscriptionPlan.starter())).toBe(true);
expect(subscription.canUpgradeTo(SubscriptionPlan.silver())).toBe(true);
});
it('should allow upgrade from FREE to PRO', () => {
it('should allow upgrade from BRONZE to GOLD', () => {
const subscription = createValidSubscription();
expect(subscription.canUpgradeTo(SubscriptionPlan.pro())).toBe(true);
expect(subscription.canUpgradeTo(SubscriptionPlan.gold())).toBe(true);
});
it('should not allow downgrade via canUpgradeTo', () => {
const subscription = Subscription.create({
id: 'sub-123',
organizationId: 'org-123',
plan: SubscriptionPlan.starter(),
plan: SubscriptionPlan.silver(),
});
expect(subscription.canUpgradeTo(SubscriptionPlan.free())).toBe(false);
expect(subscription.canUpgradeTo(SubscriptionPlan.bronze())).toBe(false);
});
});
@ -233,34 +232,34 @@ describe('Subscription Entity', () => {
const subscription = Subscription.create({
id: 'sub-123',
organizationId: 'org-123',
plan: SubscriptionPlan.starter(),
plan: SubscriptionPlan.silver(),
});
expect(subscription.canDowngradeTo(SubscriptionPlan.free(), 1)).toBe(true);
expect(subscription.canDowngradeTo(SubscriptionPlan.bronze(), 1)).toBe(true);
});
it('should prevent downgrade when user count exceeds new plan', () => {
const subscription = Subscription.create({
id: 'sub-123',
organizationId: 'org-123',
plan: SubscriptionPlan.starter(),
plan: SubscriptionPlan.silver(),
});
expect(subscription.canDowngradeTo(SubscriptionPlan.free(), 5)).toBe(false);
expect(subscription.canDowngradeTo(SubscriptionPlan.bronze(), 5)).toBe(false);
});
});
describe('updatePlan', () => {
it('should update to new plan when valid', () => {
const subscription = createValidSubscription();
const updated = subscription.updatePlan(SubscriptionPlan.starter(), 1);
const updated = subscription.updatePlan(SubscriptionPlan.silver(), 1);
expect(updated.plan.value).toBe('STARTER');
expect(updated.plan.value).toBe('SILVER');
});
it('should throw when subscription is not active', () => {
const subscription = Subscription.fromPersistence({
id: 'sub-123',
organizationId: 'org-123',
plan: 'FREE',
plan: 'BRONZE',
status: 'CANCELED',
stripeCustomerId: null,
stripeSubscriptionId: null,
@ -271,7 +270,7 @@ describe('Subscription Entity', () => {
updatedAt: new Date(),
});
expect(() => subscription.updatePlan(SubscriptionPlan.starter(), 0)).toThrow(
expect(() => subscription.updatePlan(SubscriptionPlan.silver(), 0)).toThrow(
SubscriptionNotActiveException
);
});
@ -280,10 +279,10 @@ describe('Subscription Entity', () => {
const subscription = Subscription.create({
id: 'sub-123',
organizationId: 'org-123',
plan: SubscriptionPlan.pro(),
plan: SubscriptionPlan.gold(),
});
expect(() => subscription.updatePlan(SubscriptionPlan.starter(), 10)).toThrow(
expect(() => subscription.updatePlan(SubscriptionPlan.silver(), 10)).toThrow(
InvalidSubscriptionDowngradeException
);
});
@ -341,7 +340,7 @@ describe('Subscription Entity', () => {
const subscription = Subscription.fromPersistence({
id: 'sub-123',
organizationId: 'org-123',
plan: 'STARTER',
plan: 'SILVER',
status: 'ACTIVE',
stripeCustomerId: 'cus_123',
stripeSubscriptionId: 'sub_123',
@ -368,17 +367,17 @@ describe('Subscription Entity', () => {
});
describe('isFree and isPaid', () => {
it('should return true for isFree when FREE plan', () => {
it('should return true for isFree when BRONZE plan', () => {
const subscription = createValidSubscription();
expect(subscription.isFree()).toBe(true);
expect(subscription.isPaid()).toBe(false);
});
it('should return true for isPaid when STARTER plan', () => {
it('should return true for isPaid when SILVER plan', () => {
const subscription = Subscription.create({
id: 'sub-123',
organizationId: 'org-123',
plan: SubscriptionPlan.starter(),
plan: SubscriptionPlan.silver(),
});
expect(subscription.isFree()).toBe(false);
expect(subscription.isPaid()).toBe(true);
@ -397,7 +396,7 @@ describe('Subscription Entity', () => {
expect(obj.id).toBe('sub-123');
expect(obj.organizationId).toBe('org-123');
expect(obj.plan).toBe('FREE');
expect(obj.plan).toBe('BRONZE');
expect(obj.status).toBe('ACTIVE');
expect(obj.stripeCustomerId).toBe('cus_123');
});

View File

@ -8,31 +8,56 @@ import { SubscriptionPlan } from './subscription-plan.vo';
describe('SubscriptionPlan Value Object', () => {
describe('static factory methods', () => {
it('should create FREE plan', () => {
it('should create BRONZE plan via bronze()', () => {
const plan = SubscriptionPlan.bronze();
expect(plan.value).toBe('BRONZE');
});
it('should create SILVER plan via silver()', () => {
const plan = SubscriptionPlan.silver();
expect(plan.value).toBe('SILVER');
});
it('should create GOLD plan via gold()', () => {
const plan = SubscriptionPlan.gold();
expect(plan.value).toBe('GOLD');
});
it('should create PLATINIUM plan via platinium()', () => {
const plan = SubscriptionPlan.platinium();
expect(plan.value).toBe('PLATINIUM');
});
it('should create BRONZE plan via free() alias', () => {
const plan = SubscriptionPlan.free();
expect(plan.value).toBe('FREE');
expect(plan.value).toBe('BRONZE');
});
it('should create STARTER plan', () => {
it('should create SILVER plan via starter() alias', () => {
const plan = SubscriptionPlan.starter();
expect(plan.value).toBe('STARTER');
expect(plan.value).toBe('SILVER');
});
it('should create PRO plan', () => {
it('should create GOLD plan via pro() alias', () => {
const plan = SubscriptionPlan.pro();
expect(plan.value).toBe('PRO');
expect(plan.value).toBe('GOLD');
});
it('should create ENTERPRISE plan', () => {
it('should create PLATINIUM plan via enterprise() alias', () => {
const plan = SubscriptionPlan.enterprise();
expect(plan.value).toBe('ENTERPRISE');
expect(plan.value).toBe('PLATINIUM');
});
});
describe('create', () => {
it('should create plan from valid type', () => {
const plan = SubscriptionPlan.create('STARTER');
expect(plan.value).toBe('STARTER');
it('should create plan from valid type SILVER', () => {
const plan = SubscriptionPlan.create('SILVER');
expect(plan.value).toBe('SILVER');
});
it('should create plan from valid type BRONZE', () => {
const plan = SubscriptionPlan.create('BRONZE');
expect(plan.value).toBe('BRONZE');
});
it('should throw for invalid plan type', () => {
@ -41,9 +66,29 @@ describe('SubscriptionPlan Value Object', () => {
});
describe('fromString', () => {
it('should create plan from lowercase string', () => {
it('should create SILVER from lowercase "silver"', () => {
const plan = SubscriptionPlan.fromString('silver');
expect(plan.value).toBe('SILVER');
});
it('should map legacy "starter" to SILVER', () => {
const plan = SubscriptionPlan.fromString('starter');
expect(plan.value).toBe('STARTER');
expect(plan.value).toBe('SILVER');
});
it('should map legacy "free" to BRONZE', () => {
const plan = SubscriptionPlan.fromString('free');
expect(plan.value).toBe('BRONZE');
});
it('should map legacy "pro" to GOLD', () => {
const plan = SubscriptionPlan.fromString('pro');
expect(plan.value).toBe('GOLD');
});
it('should map legacy "enterprise" to PLATINIUM', () => {
const plan = SubscriptionPlan.fromString('enterprise');
expect(plan.value).toBe('PLATINIUM');
});
it('should throw for invalid string', () => {
@ -52,146 +97,150 @@ describe('SubscriptionPlan Value Object', () => {
});
describe('maxLicenses', () => {
it('should return 2 for FREE plan', () => {
const plan = SubscriptionPlan.free();
expect(plan.maxLicenses).toBe(2);
it('should return 1 for BRONZE plan', () => {
const plan = SubscriptionPlan.bronze();
expect(plan.maxLicenses).toBe(1);
});
it('should return 5 for STARTER plan', () => {
const plan = SubscriptionPlan.starter();
it('should return 5 for SILVER plan', () => {
const plan = SubscriptionPlan.silver();
expect(plan.maxLicenses).toBe(5);
});
it('should return 20 for PRO plan', () => {
const plan = SubscriptionPlan.pro();
it('should return 20 for GOLD plan', () => {
const plan = SubscriptionPlan.gold();
expect(plan.maxLicenses).toBe(20);
});
it('should return -1 (unlimited) for ENTERPRISE plan', () => {
const plan = SubscriptionPlan.enterprise();
it('should return -1 (unlimited) for PLATINIUM plan', () => {
const plan = SubscriptionPlan.platinium();
expect(plan.maxLicenses).toBe(-1);
});
});
describe('isUnlimited', () => {
it('should return false for FREE plan', () => {
expect(SubscriptionPlan.free().isUnlimited()).toBe(false);
it('should return false for BRONZE plan', () => {
expect(SubscriptionPlan.bronze().isUnlimited()).toBe(false);
});
it('should return false for STARTER plan', () => {
expect(SubscriptionPlan.starter().isUnlimited()).toBe(false);
it('should return false for SILVER plan', () => {
expect(SubscriptionPlan.silver().isUnlimited()).toBe(false);
});
it('should return false for PRO plan', () => {
expect(SubscriptionPlan.pro().isUnlimited()).toBe(false);
it('should return false for GOLD plan', () => {
expect(SubscriptionPlan.gold().isUnlimited()).toBe(false);
});
it('should return true for ENTERPRISE plan', () => {
expect(SubscriptionPlan.enterprise().isUnlimited()).toBe(true);
it('should return true for PLATINIUM plan', () => {
expect(SubscriptionPlan.platinium().isUnlimited()).toBe(true);
});
});
describe('isPaid', () => {
it('should return false for FREE plan', () => {
expect(SubscriptionPlan.free().isPaid()).toBe(false);
it('should return false for BRONZE plan', () => {
expect(SubscriptionPlan.bronze().isPaid()).toBe(false);
});
it('should return true for STARTER plan', () => {
expect(SubscriptionPlan.starter().isPaid()).toBe(true);
it('should return true for SILVER plan', () => {
expect(SubscriptionPlan.silver().isPaid()).toBe(true);
});
it('should return true for PRO plan', () => {
expect(SubscriptionPlan.pro().isPaid()).toBe(true);
it('should return true for GOLD plan', () => {
expect(SubscriptionPlan.gold().isPaid()).toBe(true);
});
it('should return true for ENTERPRISE plan', () => {
expect(SubscriptionPlan.enterprise().isPaid()).toBe(true);
it('should return true for PLATINIUM plan', () => {
expect(SubscriptionPlan.platinium().isPaid()).toBe(true);
});
});
describe('isFree', () => {
it('should return true for FREE plan', () => {
expect(SubscriptionPlan.free().isFree()).toBe(true);
it('should return true for BRONZE plan', () => {
expect(SubscriptionPlan.bronze().isFree()).toBe(true);
});
it('should return false for STARTER plan', () => {
expect(SubscriptionPlan.starter().isFree()).toBe(false);
it('should return false for SILVER plan', () => {
expect(SubscriptionPlan.silver().isFree()).toBe(false);
});
});
describe('canAccommodateUsers', () => {
it('should return true for FREE plan with 2 users', () => {
expect(SubscriptionPlan.free().canAccommodateUsers(2)).toBe(true);
it('should return true for BRONZE plan with 1 user', () => {
expect(SubscriptionPlan.bronze().canAccommodateUsers(1)).toBe(true);
});
it('should return false for FREE plan with 3 users', () => {
expect(SubscriptionPlan.free().canAccommodateUsers(3)).toBe(false);
it('should return false for BRONZE plan with 2 users', () => {
expect(SubscriptionPlan.bronze().canAccommodateUsers(2)).toBe(false);
});
it('should return true for STARTER plan with 5 users', () => {
expect(SubscriptionPlan.starter().canAccommodateUsers(5)).toBe(true);
it('should return true for SILVER plan with 5 users', () => {
expect(SubscriptionPlan.silver().canAccommodateUsers(5)).toBe(true);
});
it('should always return true for ENTERPRISE plan', () => {
expect(SubscriptionPlan.enterprise().canAccommodateUsers(1000)).toBe(true);
it('should always return true for PLATINIUM plan', () => {
expect(SubscriptionPlan.platinium().canAccommodateUsers(1000)).toBe(true);
});
});
describe('canUpgradeTo', () => {
it('should allow upgrade from FREE to STARTER', () => {
expect(SubscriptionPlan.free().canUpgradeTo(SubscriptionPlan.starter())).toBe(true);
it('should allow upgrade from BRONZE to SILVER', () => {
expect(SubscriptionPlan.bronze().canUpgradeTo(SubscriptionPlan.silver())).toBe(true);
});
it('should allow upgrade from FREE to PRO', () => {
expect(SubscriptionPlan.free().canUpgradeTo(SubscriptionPlan.pro())).toBe(true);
it('should allow upgrade from BRONZE to GOLD', () => {
expect(SubscriptionPlan.bronze().canUpgradeTo(SubscriptionPlan.gold())).toBe(true);
});
it('should allow upgrade from FREE to ENTERPRISE', () => {
expect(SubscriptionPlan.free().canUpgradeTo(SubscriptionPlan.enterprise())).toBe(true);
it('should allow upgrade from BRONZE to PLATINIUM', () => {
expect(SubscriptionPlan.bronze().canUpgradeTo(SubscriptionPlan.platinium())).toBe(true);
});
it('should allow upgrade from STARTER to PRO', () => {
expect(SubscriptionPlan.starter().canUpgradeTo(SubscriptionPlan.pro())).toBe(true);
it('should allow upgrade from SILVER to GOLD', () => {
expect(SubscriptionPlan.silver().canUpgradeTo(SubscriptionPlan.gold())).toBe(true);
});
it('should not allow downgrade from STARTER to FREE', () => {
expect(SubscriptionPlan.starter().canUpgradeTo(SubscriptionPlan.free())).toBe(false);
it('should not allow downgrade from SILVER to BRONZE', () => {
expect(SubscriptionPlan.silver().canUpgradeTo(SubscriptionPlan.bronze())).toBe(false);
});
it('should not allow same plan upgrade', () => {
expect(SubscriptionPlan.pro().canUpgradeTo(SubscriptionPlan.pro())).toBe(false);
expect(SubscriptionPlan.gold().canUpgradeTo(SubscriptionPlan.gold())).toBe(false);
});
});
describe('canDowngradeTo', () => {
it('should allow downgrade from STARTER to FREE when users fit', () => {
expect(SubscriptionPlan.starter().canDowngradeTo(SubscriptionPlan.free(), 1)).toBe(true);
it('should allow downgrade from SILVER to BRONZE when users fit', () => {
expect(SubscriptionPlan.silver().canDowngradeTo(SubscriptionPlan.bronze(), 1)).toBe(true);
});
it('should not allow downgrade from STARTER to FREE when users exceed', () => {
expect(SubscriptionPlan.starter().canDowngradeTo(SubscriptionPlan.free(), 5)).toBe(false);
it('should not allow downgrade from SILVER to BRONZE when users exceed', () => {
expect(SubscriptionPlan.silver().canDowngradeTo(SubscriptionPlan.bronze(), 5)).toBe(false);
});
it('should not allow upgrade via canDowngradeTo', () => {
expect(SubscriptionPlan.free().canDowngradeTo(SubscriptionPlan.starter(), 1)).toBe(false);
expect(SubscriptionPlan.bronze().canDowngradeTo(SubscriptionPlan.silver(), 1)).toBe(false);
});
});
describe('plan details', () => {
it('should return correct name for FREE plan', () => {
expect(SubscriptionPlan.free().name).toBe('Free');
it('should return correct name for BRONZE plan', () => {
expect(SubscriptionPlan.bronze().name).toBe('Bronze');
});
it('should return correct prices for STARTER plan', () => {
const plan = SubscriptionPlan.starter();
expect(plan.monthlyPriceEur).toBe(49);
expect(plan.yearlyPriceEur).toBe(470);
it('should return correct name for SILVER plan', () => {
expect(SubscriptionPlan.silver().name).toBe('Silver');
});
it('should return features for PRO plan', () => {
const plan = SubscriptionPlan.pro();
expect(plan.features).toContain('Up to 20 users');
expect(plan.features).toContain('API access');
it('should return correct prices for SILVER plan', () => {
const plan = SubscriptionPlan.silver();
expect(plan.monthlyPriceEur).toBe(249);
expect(plan.yearlyPriceEur).toBe(2739);
});
it('should return features for GOLD plan', () => {
const plan = SubscriptionPlan.gold();
expect(plan.features).toContain("Jusqu'à 20 utilisateurs");
expect(plan.features).toContain('Intégration API');
});
});
@ -200,24 +249,24 @@ describe('SubscriptionPlan Value Object', () => {
const plans = SubscriptionPlan.getAllPlans();
expect(plans).toHaveLength(4);
expect(plans.map(p => p.value)).toEqual(['FREE', 'STARTER', 'PRO', 'ENTERPRISE']);
expect(plans.map(p => p.value)).toEqual(['BRONZE', 'SILVER', 'GOLD', 'PLATINIUM']);
});
});
describe('equals', () => {
it('should return true for same plan', () => {
expect(SubscriptionPlan.free().equals(SubscriptionPlan.free())).toBe(true);
expect(SubscriptionPlan.bronze().equals(SubscriptionPlan.bronze())).toBe(true);
});
it('should return false for different plans', () => {
expect(SubscriptionPlan.free().equals(SubscriptionPlan.starter())).toBe(false);
expect(SubscriptionPlan.bronze().equals(SubscriptionPlan.silver())).toBe(false);
});
});
describe('toString', () => {
it('should return plan value as string', () => {
expect(SubscriptionPlan.free().toString()).toBe('FREE');
expect(SubscriptionPlan.starter().toString()).toBe('STARTER');
expect(SubscriptionPlan.bronze().toString()).toBe('BRONZE');
expect(SubscriptionPlan.silver().toString()).toBe('SILVER');
});
});
});

View File

@ -55,7 +55,7 @@ const PLAN_DETAILS: Record<SubscriptionPlanType, PlanDetails> = {
name: 'Silver',
maxLicenses: 5,
monthlyPriceEur: 249,
yearlyPriceEur: 2739, // 249 * 11 months
yearlyPriceEur: 2739,
maxShipmentsPerYear: -1,
commissionRatePercent: 3,
statusBadge: 'silver',
@ -75,7 +75,7 @@ const PLAN_DETAILS: Record<SubscriptionPlanType, PlanDetails> = {
name: 'Gold',
maxLicenses: 20,
monthlyPriceEur: 899,
yearlyPriceEur: 9889, // 899 * 11 months
yearlyPriceEur: 9889,
maxShipmentsPerYear: -1,
commissionRatePercent: 2,
statusBadge: 'gold',
@ -225,59 +225,35 @@ export class SubscriptionPlan {
return PLAN_DETAILS[this.plan].planFeatures;
}
/**
* Check if this plan includes a specific feature
*/
hasFeature(feature: PlanFeature): boolean {
return this.planFeatures.includes(feature);
}
/**
* Returns true if this plan has unlimited licenses
*/
isUnlimited(): boolean {
return this.maxLicenses === -1;
}
/**
* Returns true if this plan has unlimited shipments
*/
hasUnlimitedShipments(): boolean {
return this.maxShipmentsPerYear === -1;
}
/**
* Returns true if this is a paid plan
*/
isPaid(): boolean {
return this.plan !== 'BRONZE';
}
/**
* Returns true if this is the free (Bronze) plan
*/
isFree(): boolean {
return this.plan === 'BRONZE';
}
/**
* Returns true if this plan has custom pricing (Platinium)
*/
isCustomPricing(): boolean {
return this.plan === 'PLATINIUM';
}
/**
* Check if a given number of users can be accommodated by this plan
*/
canAccommodateUsers(userCount: number): boolean {
if (this.isUnlimited()) return true;
return userCount <= this.maxLicenses;
}
/**
* Check if upgrade to target plan is allowed
*/
canUpgradeTo(targetPlan: SubscriptionPlan): boolean {
const planOrder: SubscriptionPlanType[] = ['BRONZE', 'SILVER', 'GOLD', 'PLATINIUM'];
const currentIndex = planOrder.indexOf(this.plan);
@ -285,15 +261,12 @@ export class SubscriptionPlan {
return targetIndex > currentIndex;
}
/**
* Check if downgrade to target plan is allowed given current user count
*/
canDowngradeTo(targetPlan: SubscriptionPlan, currentUserCount: number): boolean {
const planOrder: SubscriptionPlanType[] = ['BRONZE', 'SILVER', 'GOLD', 'PLATINIUM'];
const currentIndex = planOrder.indexOf(this.plan);
const targetIndex = planOrder.indexOf(targetPlan.value);
if (targetIndex >= currentIndex) return false; // Not a downgrade
if (targetIndex >= currentIndex) return false;
return targetPlan.canAccommodateUsers(currentUserCount);
}