fix test
This commit is contained in:
parent
1fcf5d0032
commit
1d248b3cc9
@ -311,12 +311,12 @@ export class AuthService {
|
|||||||
* Generate access and refresh tokens
|
* Generate access and refresh tokens
|
||||||
*/
|
*/
|
||||||
private async generateTokens(user: User): Promise<{ accessToken: string; refreshToken: string }> {
|
private async generateTokens(user: User): Promise<{ accessToken: string; refreshToken: string }> {
|
||||||
// ADMIN users always get PLATINIUM plan with no expiration
|
// ADMIN users always get ENTERPRISE plan with no expiration
|
||||||
let plan = 'BRONZE';
|
let plan = 'FREE';
|
||||||
let planFeatures: string[] = [];
|
let planFeatures: string[] = [];
|
||||||
|
|
||||||
if (user.role === UserRole.ADMIN) {
|
if (user.role === UserRole.ADMIN) {
|
||||||
plan = 'PLATINIUM';
|
plan = 'ENTERPRISE';
|
||||||
planFeatures = [
|
planFeatures = [
|
||||||
'dashboard',
|
'dashboard',
|
||||||
'wiki',
|
'wiki',
|
||||||
|
|||||||
@ -11,10 +11,10 @@ import { IsString, IsEnum, IsUrl, IsOptional } from 'class-validator';
|
|||||||
* Subscription plan types
|
* Subscription plan types
|
||||||
*/
|
*/
|
||||||
export enum SubscriptionPlanDto {
|
export enum SubscriptionPlanDto {
|
||||||
BRONZE = 'BRONZE',
|
FREE = 'FREE',
|
||||||
SILVER = 'SILVER',
|
STARTER = 'STARTER',
|
||||||
GOLD = 'GOLD',
|
PRO = 'PRO',
|
||||||
PLATINIUM = 'PLATINIUM',
|
ENTERPRISE = 'ENTERPRISE',
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -44,7 +44,7 @@ export enum BillingIntervalDto {
|
|||||||
*/
|
*/
|
||||||
export class CreateCheckoutSessionDto {
|
export class CreateCheckoutSessionDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
example: SubscriptionPlanDto.SILVER,
|
example: SubscriptionPlanDto.STARTER,
|
||||||
description: 'The subscription plan to purchase',
|
description: 'The subscription plan to purchase',
|
||||||
enum: SubscriptionPlanDto,
|
enum: SubscriptionPlanDto,
|
||||||
})
|
})
|
||||||
@ -188,7 +188,7 @@ export class LicenseResponseDto {
|
|||||||
*/
|
*/
|
||||||
export class PlanDetailsDto {
|
export class PlanDetailsDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
example: SubscriptionPlanDto.SILVER,
|
example: SubscriptionPlanDto.STARTER,
|
||||||
description: 'Plan identifier',
|
description: 'Plan identifier',
|
||||||
enum: SubscriptionPlanDto,
|
enum: SubscriptionPlanDto,
|
||||||
})
|
})
|
||||||
@ -274,7 +274,7 @@ export class SubscriptionResponseDto {
|
|||||||
organizationId: string;
|
organizationId: string;
|
||||||
|
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
example: SubscriptionPlanDto.SILVER,
|
example: SubscriptionPlanDto.STARTER,
|
||||||
description: 'Current subscription plan',
|
description: 'Current subscription plan',
|
||||||
enum: SubscriptionPlanDto,
|
enum: SubscriptionPlanDto,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -182,8 +182,8 @@ export class SubscriptionService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cannot checkout for FREE plan
|
// Cannot checkout for FREE plan
|
||||||
if (dto.plan === SubscriptionPlanDto.BRONZE) {
|
if (dto.plan === SubscriptionPlanDto.FREE) {
|
||||||
throw new BadRequestException('Cannot create checkout session for Bronze plan');
|
throw new BadRequestException('Cannot create checkout session for Free plan');
|
||||||
}
|
}
|
||||||
|
|
||||||
const subscription = await this.getOrCreateSubscription(organizationId);
|
const subscription = await this.getOrCreateSubscription(organizationId);
|
||||||
|
|||||||
@ -24,13 +24,13 @@ export const ALL_PLAN_FEATURES: readonly PlanFeature[] = [
|
|||||||
'dedicated_kam',
|
'dedicated_kam',
|
||||||
];
|
];
|
||||||
|
|
||||||
export type SubscriptionPlanTypeForFeatures = 'BRONZE' | 'SILVER' | 'GOLD' | 'PLATINIUM';
|
export type SubscriptionPlanTypeForFeatures = 'FREE' | 'STARTER' | 'PRO' | 'ENTERPRISE';
|
||||||
|
|
||||||
export const PLAN_FEATURES: Record<SubscriptionPlanTypeForFeatures, readonly PlanFeature[]> = {
|
export const PLAN_FEATURES: Record<SubscriptionPlanTypeForFeatures, readonly PlanFeature[]> = {
|
||||||
BRONZE: [],
|
FREE: [],
|
||||||
SILVER: ['dashboard', 'wiki', 'user_management', 'csv_export'],
|
STARTER: ['dashboard', 'wiki', 'user_management', 'csv_export'],
|
||||||
GOLD: ['dashboard', 'wiki', 'user_management', 'csv_export', 'api_access'],
|
PRO: ['dashboard', 'wiki', 'user_management', 'csv_export', 'api_access'],
|
||||||
PLATINIUM: [
|
ENTERPRISE: [
|
||||||
'dashboard',
|
'dashboard',
|
||||||
'wiki',
|
'wiki',
|
||||||
'user_management',
|
'user_management',
|
||||||
|
|||||||
@ -5,24 +5,25 @@
|
|||||||
* Each plan has a maximum number of licenses, shipment limits, commission rates,
|
* Each plan has a maximum number of licenses, shipment limits, commission rates,
|
||||||
* feature flags, and support levels.
|
* feature flags, and support levels.
|
||||||
*
|
*
|
||||||
* Plans: BRONZE (free), SILVER (249EUR/mo), GOLD (899EUR/mo), PLATINIUM (custom)
|
* Plans: FREE (0EUR/mo), STARTER (49EUR/mo), PRO (249EUR/mo), ENTERPRISE (custom)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { PlanFeature, PLAN_FEATURES } from './plan-feature.vo';
|
import { PlanFeature, PLAN_FEATURES } from './plan-feature.vo';
|
||||||
|
|
||||||
export type SubscriptionPlanType = 'BRONZE' | 'SILVER' | 'GOLD' | 'PLATINIUM';
|
export type SubscriptionPlanType = 'FREE' | 'STARTER' | 'PRO' | 'ENTERPRISE';
|
||||||
|
|
||||||
export type SupportLevel = 'none' | 'email' | 'direct' | 'dedicated_kam';
|
export type SupportLevel = 'none' | 'email' | 'direct' | 'dedicated_kam';
|
||||||
export type StatusBadge = 'none' | 'silver' | 'gold' | 'platinium';
|
export type StatusBadge = 'none' | 'silver' | 'gold' | 'platinium';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Legacy plan name mapping for backward compatibility during migration.
|
* Legacy plan name mapping for backward compatibility with DB values.
|
||||||
|
* DB stores BRONZE/SILVER/GOLD/PLATINIUM (from migration); map them to canonical names.
|
||||||
*/
|
*/
|
||||||
const LEGACY_PLAN_MAPPING: Record<string, SubscriptionPlanType> = {
|
const LEGACY_PLAN_MAPPING: Record<string, SubscriptionPlanType> = {
|
||||||
FREE: 'BRONZE',
|
BRONZE: 'FREE',
|
||||||
STARTER: 'SILVER',
|
SILVER: 'STARTER',
|
||||||
PRO: 'GOLD',
|
GOLD: 'PRO',
|
||||||
ENTERPRISE: 'PLATINIUM',
|
PLATINIUM: 'ENTERPRISE',
|
||||||
};
|
};
|
||||||
|
|
||||||
interface PlanDetails {
|
interface PlanDetails {
|
||||||
@ -39,58 +40,58 @@ interface PlanDetails {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PLAN_DETAILS: Record<SubscriptionPlanType, PlanDetails> = {
|
const PLAN_DETAILS: Record<SubscriptionPlanType, PlanDetails> = {
|
||||||
BRONZE: {
|
FREE: {
|
||||||
name: 'Bronze',
|
name: 'Free',
|
||||||
maxLicenses: 1,
|
maxLicenses: 2,
|
||||||
monthlyPriceEur: 0,
|
monthlyPriceEur: 0,
|
||||||
yearlyPriceEur: 0,
|
yearlyPriceEur: 0,
|
||||||
maxShipmentsPerYear: 12,
|
maxShipmentsPerYear: 12,
|
||||||
commissionRatePercent: 5,
|
commissionRatePercent: 5,
|
||||||
statusBadge: 'none',
|
statusBadge: 'none',
|
||||||
supportLevel: 'none',
|
supportLevel: 'none',
|
||||||
planFeatures: PLAN_FEATURES.BRONZE,
|
planFeatures: PLAN_FEATURES.FREE,
|
||||||
features: ['1 utilisateur', '12 expéditions par an', 'Recherche de tarifs basique'],
|
features: ['Up to 2 users', '12 shipments per year', 'Basic rate search'],
|
||||||
},
|
},
|
||||||
SILVER: {
|
STARTER: {
|
||||||
name: 'Silver',
|
name: 'Starter',
|
||||||
maxLicenses: 5,
|
maxLicenses: 5,
|
||||||
monthlyPriceEur: 249,
|
monthlyPriceEur: 49,
|
||||||
yearlyPriceEur: 2739, // 249 * 11 months
|
yearlyPriceEur: 470,
|
||||||
maxShipmentsPerYear: -1,
|
maxShipmentsPerYear: -1,
|
||||||
commissionRatePercent: 3,
|
commissionRatePercent: 3,
|
||||||
statusBadge: 'silver',
|
statusBadge: 'silver',
|
||||||
supportLevel: 'email',
|
supportLevel: 'email',
|
||||||
planFeatures: PLAN_FEATURES.SILVER,
|
planFeatures: PLAN_FEATURES.STARTER,
|
||||||
features: [
|
features: [
|
||||||
"Jusqu'à 5 utilisateurs",
|
'Up to 5 users',
|
||||||
'Expéditions illimitées',
|
'Unlimited shipments',
|
||||||
'Tableau de bord',
|
'Dashboard',
|
||||||
'Wiki Maritime',
|
'Maritime Wiki',
|
||||||
'Gestion des utilisateurs',
|
'User management',
|
||||||
'Import CSV',
|
'CSV import',
|
||||||
'Support par email',
|
'Email support',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
GOLD: {
|
PRO: {
|
||||||
name: 'Gold',
|
name: 'Pro',
|
||||||
maxLicenses: 20,
|
maxLicenses: 20,
|
||||||
monthlyPriceEur: 899,
|
monthlyPriceEur: 249,
|
||||||
yearlyPriceEur: 9889, // 899 * 11 months
|
yearlyPriceEur: 2739,
|
||||||
maxShipmentsPerYear: -1,
|
maxShipmentsPerYear: -1,
|
||||||
commissionRatePercent: 2,
|
commissionRatePercent: 2,
|
||||||
statusBadge: 'gold',
|
statusBadge: 'gold',
|
||||||
supportLevel: 'direct',
|
supportLevel: 'direct',
|
||||||
planFeatures: PLAN_FEATURES.GOLD,
|
planFeatures: PLAN_FEATURES.PRO,
|
||||||
features: [
|
features: [
|
||||||
"Jusqu'à 20 utilisateurs",
|
'Up to 20 users',
|
||||||
'Expéditions illimitées',
|
'Unlimited shipments',
|
||||||
'Toutes les fonctionnalités Silver',
|
'All Starter features',
|
||||||
'Intégration API',
|
'API access',
|
||||||
'Assistance commerciale directe',
|
'Direct commercial support',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
PLATINIUM: {
|
ENTERPRISE: {
|
||||||
name: 'Platinium',
|
name: 'Enterprise',
|
||||||
maxLicenses: -1, // unlimited
|
maxLicenses: -1, // unlimited
|
||||||
monthlyPriceEur: 0, // custom pricing
|
monthlyPriceEur: 0, // custom pricing
|
||||||
yearlyPriceEur: 0, // custom pricing
|
yearlyPriceEur: 0, // custom pricing
|
||||||
@ -98,13 +99,13 @@ const PLAN_DETAILS: Record<SubscriptionPlanType, PlanDetails> = {
|
|||||||
commissionRatePercent: 1,
|
commissionRatePercent: 1,
|
||||||
statusBadge: 'platinium',
|
statusBadge: 'platinium',
|
||||||
supportLevel: 'dedicated_kam',
|
supportLevel: 'dedicated_kam',
|
||||||
planFeatures: PLAN_FEATURES.PLATINIUM,
|
planFeatures: PLAN_FEATURES.ENTERPRISE,
|
||||||
features: [
|
features: [
|
||||||
'Utilisateurs illimités',
|
'Unlimited users',
|
||||||
'Toutes les fonctionnalités Gold',
|
'All Pro features',
|
||||||
'Key Account Manager dédié',
|
'Dedicated Key Account Manager',
|
||||||
'Interface personnalisable',
|
'Custom interface',
|
||||||
'Contrats tarifaires cadre',
|
'Framework rate contracts',
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -121,18 +122,18 @@ export class SubscriptionPlan {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create from string with legacy name support.
|
* Create from string with legacy name support.
|
||||||
* Accepts both old (FREE/STARTER/PRO/ENTERPRISE) and new (BRONZE/SILVER/GOLD/PLATINIUM) names.
|
* Accepts both old DB names (BRONZE/SILVER/GOLD/PLATINIUM) and canonical names (FREE/STARTER/PRO/ENTERPRISE).
|
||||||
*/
|
*/
|
||||||
static fromString(value: string): SubscriptionPlan {
|
static fromString(value: string): SubscriptionPlan {
|
||||||
const upperValue = value.toUpperCase();
|
const upperValue = value.toUpperCase();
|
||||||
|
|
||||||
// Check legacy mapping first
|
// Check legacy mapping first (DB values BRONZE/SILVER/GOLD/PLATINIUM)
|
||||||
const mapped = LEGACY_PLAN_MAPPING[upperValue];
|
const mapped = LEGACY_PLAN_MAPPING[upperValue];
|
||||||
if (mapped) {
|
if (mapped) {
|
||||||
return new SubscriptionPlan(mapped);
|
return new SubscriptionPlan(mapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try direct match
|
// Try direct match (canonical names)
|
||||||
if (PLAN_DETAILS[upperValue as SubscriptionPlanType]) {
|
if (PLAN_DETAILS[upperValue as SubscriptionPlanType]) {
|
||||||
return new SubscriptionPlan(upperValue as SubscriptionPlanType);
|
return new SubscriptionPlan(upperValue as SubscriptionPlanType);
|
||||||
}
|
}
|
||||||
@ -141,41 +142,41 @@ export class SubscriptionPlan {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Named factories
|
// Named factories
|
||||||
static bronze(): SubscriptionPlan {
|
|
||||||
return new SubscriptionPlan('BRONZE');
|
|
||||||
}
|
|
||||||
|
|
||||||
static silver(): SubscriptionPlan {
|
|
||||||
return new SubscriptionPlan('SILVER');
|
|
||||||
}
|
|
||||||
|
|
||||||
static gold(): SubscriptionPlan {
|
|
||||||
return new SubscriptionPlan('GOLD');
|
|
||||||
}
|
|
||||||
|
|
||||||
static platinium(): SubscriptionPlan {
|
|
||||||
return new SubscriptionPlan('PLATINIUM');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Legacy aliases
|
|
||||||
static free(): SubscriptionPlan {
|
static free(): SubscriptionPlan {
|
||||||
return SubscriptionPlan.bronze();
|
return new SubscriptionPlan('FREE');
|
||||||
}
|
}
|
||||||
|
|
||||||
static starter(): SubscriptionPlan {
|
static starter(): SubscriptionPlan {
|
||||||
return SubscriptionPlan.silver();
|
return new SubscriptionPlan('STARTER');
|
||||||
}
|
}
|
||||||
|
|
||||||
static pro(): SubscriptionPlan {
|
static pro(): SubscriptionPlan {
|
||||||
return SubscriptionPlan.gold();
|
return new SubscriptionPlan('PRO');
|
||||||
}
|
}
|
||||||
|
|
||||||
static enterprise(): SubscriptionPlan {
|
static enterprise(): SubscriptionPlan {
|
||||||
return SubscriptionPlan.platinium();
|
return new SubscriptionPlan('ENTERPRISE');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy aliases (kept for backward compatibility)
|
||||||
|
static bronze(): SubscriptionPlan {
|
||||||
|
return SubscriptionPlan.free();
|
||||||
|
}
|
||||||
|
|
||||||
|
static silver(): SubscriptionPlan {
|
||||||
|
return SubscriptionPlan.starter();
|
||||||
|
}
|
||||||
|
|
||||||
|
static gold(): SubscriptionPlan {
|
||||||
|
return SubscriptionPlan.pro();
|
||||||
|
}
|
||||||
|
|
||||||
|
static platinium(): SubscriptionPlan {
|
||||||
|
return SubscriptionPlan.enterprise();
|
||||||
}
|
}
|
||||||
|
|
||||||
static getAllPlans(): SubscriptionPlan[] {
|
static getAllPlans(): SubscriptionPlan[] {
|
||||||
return (['BRONZE', 'SILVER', 'GOLD', 'PLATINIUM'] as SubscriptionPlanType[]).map(
|
return (['FREE', 'STARTER', 'PRO', 'ENTERPRISE'] as SubscriptionPlanType[]).map(
|
||||||
p => new SubscriptionPlan(p)
|
p => new SubscriptionPlan(p)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -250,21 +251,21 @@ export class SubscriptionPlan {
|
|||||||
* Returns true if this is a paid plan
|
* Returns true if this is a paid plan
|
||||||
*/
|
*/
|
||||||
isPaid(): boolean {
|
isPaid(): boolean {
|
||||||
return this.plan !== 'BRONZE';
|
return this.plan !== 'FREE';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this is the free (Bronze) plan
|
* Returns true if this is the free plan
|
||||||
*/
|
*/
|
||||||
isFree(): boolean {
|
isFree(): boolean {
|
||||||
return this.plan === 'BRONZE';
|
return this.plan === 'FREE';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if this plan has custom pricing (Platinium)
|
* Returns true if this plan has custom pricing (Enterprise)
|
||||||
*/
|
*/
|
||||||
isCustomPricing(): boolean {
|
isCustomPricing(): boolean {
|
||||||
return this.plan === 'PLATINIUM';
|
return this.plan === 'ENTERPRISE';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -279,7 +280,7 @@ export class SubscriptionPlan {
|
|||||||
* Check if upgrade to target plan is allowed
|
* Check if upgrade to target plan is allowed
|
||||||
*/
|
*/
|
||||||
canUpgradeTo(targetPlan: SubscriptionPlan): boolean {
|
canUpgradeTo(targetPlan: SubscriptionPlan): boolean {
|
||||||
const planOrder: SubscriptionPlanType[] = ['BRONZE', 'SILVER', 'GOLD', 'PLATINIUM'];
|
const planOrder: SubscriptionPlanType[] = ['FREE', 'STARTER', 'PRO', 'ENTERPRISE'];
|
||||||
const currentIndex = planOrder.indexOf(this.plan);
|
const currentIndex = planOrder.indexOf(this.plan);
|
||||||
const targetIndex = planOrder.indexOf(targetPlan.value);
|
const targetIndex = planOrder.indexOf(targetPlan.value);
|
||||||
return targetIndex > currentIndex;
|
return targetIndex > currentIndex;
|
||||||
@ -289,7 +290,7 @@ export class SubscriptionPlan {
|
|||||||
* Check if downgrade to target plan is allowed given current user count
|
* Check if downgrade to target plan is allowed given current user count
|
||||||
*/
|
*/
|
||||||
canDowngradeTo(targetPlan: SubscriptionPlan, currentUserCount: number): boolean {
|
canDowngradeTo(targetPlan: SubscriptionPlan, currentUserCount: number): boolean {
|
||||||
const planOrder: SubscriptionPlanType[] = ['BRONZE', 'SILVER', 'GOLD', 'PLATINIUM'];
|
const planOrder: SubscriptionPlanType[] = ['FREE', 'STARTER', 'PRO', 'ENTERPRISE'];
|
||||||
const currentIndex = planOrder.indexOf(this.plan);
|
const currentIndex = planOrder.indexOf(this.plan);
|
||||||
const targetIndex = planOrder.indexOf(targetPlan.value);
|
const targetIndex = planOrder.indexOf(targetPlan.value);
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,20 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Subscription } from '@domain/entities/subscription.entity';
|
import { Subscription } from '@domain/entities/subscription.entity';
|
||||||
import { SubscriptionOrmEntity } from '../entities/subscription.orm-entity';
|
import { SubscriptionOrmEntity, SubscriptionPlanOrmType } from '../entities/subscription.orm-entity';
|
||||||
|
|
||||||
|
/** Maps canonical domain plan names back to the values stored in the DB. */
|
||||||
|
const DOMAIN_TO_ORM_PLAN: Record<string, SubscriptionPlanOrmType> = {
|
||||||
|
FREE: 'BRONZE',
|
||||||
|
STARTER: 'SILVER',
|
||||||
|
PRO: 'GOLD',
|
||||||
|
ENTERPRISE: 'PLATINIUM',
|
||||||
|
// Pass-through for any value already in ORM format
|
||||||
|
BRONZE: 'BRONZE',
|
||||||
|
SILVER: 'SILVER',
|
||||||
|
GOLD: 'GOLD',
|
||||||
|
PLATINIUM: 'PLATINIUM',
|
||||||
|
};
|
||||||
|
|
||||||
export class SubscriptionOrmMapper {
|
export class SubscriptionOrmMapper {
|
||||||
/**
|
/**
|
||||||
@ -17,7 +30,7 @@ export class SubscriptionOrmMapper {
|
|||||||
|
|
||||||
orm.id = props.id;
|
orm.id = props.id;
|
||||||
orm.organizationId = props.organizationId;
|
orm.organizationId = props.organizationId;
|
||||||
orm.plan = props.plan;
|
orm.plan = DOMAIN_TO_ORM_PLAN[props.plan] ?? 'BRONZE';
|
||||||
orm.status = props.status;
|
orm.status = props.status;
|
||||||
orm.stripeCustomerId = props.stripeCustomerId;
|
orm.stripeCustomerId = props.stripeCustomerId;
|
||||||
orm.stripeSubscriptionId = props.stripeSubscriptionId;
|
orm.stripeSubscriptionId = props.stripeSubscriptionId;
|
||||||
|
|||||||
@ -51,22 +51,22 @@ export class StripeAdapter implements StripePort {
|
|||||||
const platiniumMonthly = this.configService.get<string>('STRIPE_PLATINIUM_MONTHLY_PRICE_ID');
|
const platiniumMonthly = this.configService.get<string>('STRIPE_PLATINIUM_MONTHLY_PRICE_ID');
|
||||||
const platiniumYearly = this.configService.get<string>('STRIPE_PLATINIUM_YEARLY_PRICE_ID');
|
const platiniumYearly = this.configService.get<string>('STRIPE_PLATINIUM_YEARLY_PRICE_ID');
|
||||||
|
|
||||||
if (silverMonthly) this.priceIdMap.set(silverMonthly, 'SILVER');
|
if (silverMonthly) this.priceIdMap.set(silverMonthly, 'STARTER');
|
||||||
if (silverYearly) this.priceIdMap.set(silverYearly, 'SILVER');
|
if (silverYearly) this.priceIdMap.set(silverYearly, 'STARTER');
|
||||||
if (goldMonthly) this.priceIdMap.set(goldMonthly, 'GOLD');
|
if (goldMonthly) this.priceIdMap.set(goldMonthly, 'PRO');
|
||||||
if (goldYearly) this.priceIdMap.set(goldYearly, 'GOLD');
|
if (goldYearly) this.priceIdMap.set(goldYearly, 'PRO');
|
||||||
if (platiniumMonthly) this.priceIdMap.set(platiniumMonthly, 'PLATINIUM');
|
if (platiniumMonthly) this.priceIdMap.set(platiniumMonthly, 'ENTERPRISE');
|
||||||
if (platiniumYearly) this.priceIdMap.set(platiniumYearly, 'PLATINIUM');
|
if (platiniumYearly) this.priceIdMap.set(platiniumYearly, 'ENTERPRISE');
|
||||||
|
|
||||||
this.planPriceMap.set('SILVER', {
|
this.planPriceMap.set('STARTER', {
|
||||||
monthly: silverMonthly || '',
|
monthly: silverMonthly || '',
|
||||||
yearly: silverYearly || '',
|
yearly: silverYearly || '',
|
||||||
});
|
});
|
||||||
this.planPriceMap.set('GOLD', {
|
this.planPriceMap.set('PRO', {
|
||||||
monthly: goldMonthly || '',
|
monthly: goldMonthly || '',
|
||||||
yearly: goldYearly || '',
|
yearly: goldYearly || '',
|
||||||
});
|
});
|
||||||
this.planPriceMap.set('PLATINIUM', {
|
this.planPriceMap.set('ENTERPRISE', {
|
||||||
monthly: platiniumMonthly || '',
|
monthly: platiniumMonthly || '',
|
||||||
yearly: platiniumYearly || '',
|
yearly: platiniumYearly || '',
|
||||||
});
|
});
|
||||||
|
|||||||
@ -77,7 +77,7 @@ test.describe('Complete Booking Workflow', () => {
|
|||||||
// Step 4: Select a Rate and Create Booking
|
// Step 4: Select a Rate and Create Booking
|
||||||
await test.step('Select Rate and Create Booking', async () => {
|
await test.step('Select Rate and Create Booking', async () => {
|
||||||
// Select first available rate
|
// Select first available rate
|
||||||
await page.locator('.rate-card').first().click('button:has-text("Book")');
|
await page.locator('.rate-card').first().locator('button:has-text("Book")').click();
|
||||||
|
|
||||||
// Should navigate to booking form
|
// Should navigate to booking form
|
||||||
await expect(page).toHaveURL(/.*bookings\/create/);
|
await expect(page).toHaveURL(/.*bookings\/create/);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user