feat: add support plan but not tested

This commit is contained in:
mahyargdz
2025-05-05 14:44:53 +03:30
parent 06272b5afe
commit 61513d5059
21 changed files with 434 additions and 8 deletions
+5 -4
View File
@@ -7,13 +7,13 @@ import { ConfigModule } from "@nestjs/config";
import { ThrottlerModule } from "@nestjs/throttler";
import { TypeOrmModule } from "@nestjs/typeorm";
import { MailerModule } from "@nestjs-modules/mailer";
import { TelegrafModule } from "nestjs-telegraf";
// import { TelegrafModule } from "nestjs-telegraf";
import { bullMqConfig } from "./configs/bullmq.config";
import { cacheConfig } from "./configs/cache.config";
import { mailerConfig } from "./configs/mailer.config";
import { rateLimitConfig } from "./configs/rateLimit.config";
import { telegrafConfig } from "./configs/telegraf.config";
// import { telegrafConfig } from "./configs/telegraf.config";
import { databaseConfigs } from "./configs/typeorm.config";
import { HTTPLogger } from "./core/middlewares/logger.middleware";
import { AddressModule } from "./modules/address/address.module";
@@ -35,15 +35,15 @@ import { PaymentsModule } from "./modules/payments/payments.module";
import { ReferralsModule } from "./modules/referrals/referrals.module";
import { SettingModule } from "./modules/settings/settings.module";
import { SubscriptionsModule } from "./modules/subscriptions/subscriptions.module";
import { SupportPlansModule } from "./modules/support-plans/support-plans.module";
import { TicketsModule } from "./modules/tickets/tickets.module";
import { UploaderModule } from "./modules/uploader/uploader.module";
import { UsersModule } from "./modules/users/users.module";
import { WalletsModule } from "./modules/wallets/wallets.module";
import { MonitoringModule } from "./monitoring/monitoring.module";
@Module({
imports: [
TelegrafModule.forRootAsync(telegrafConfig()),
// TelegrafModule.forRootAsync(telegrafConfig()),
MailerModule.forRootAsync(mailerConfig()),
BullModule.forRootAsync(bullMqConfig()),
ThrottlerModule.forRootAsync(rateLimitConfig()),
@@ -84,6 +84,7 @@ import { MonitoringModule } from "./monitoring/monitoring.module";
LandingModule,
ReferralsModule,
DiscountsModule,
SupportPlansModule,
],
controllers: [],
})
+30
View File
@@ -120,6 +120,7 @@ export const enum CommonMessage {
PaymentTypeQueryNotEmpty = "نوع پرداخت نمی‌تواند خالی باشد",
SEARCH_QUERY_STRING = "رشته جستجو باید یک رشته باشد",
UPDATED = "با موفقیت آپدیت شد",
IS_ACTIVE_SHOULD_BE_1_0 = "وضعیت باید یکی از مقادیر ۰ و ۱ باشد",
}
export const enum CategoryMessage {
@@ -776,3 +777,32 @@ export const enum ReferralMessage {
INVALID_OR_INACTIVE_REFERRAL_CODE = "کد ارجاع نامعتبر یا غیرفعال است",
USER_ALREADY_REFERRED = "کاربر قبلاً ارجاع داده شده است",
}
export const enum SupportPlanMessage {
NAME_REQUIRED = "نام الزامی است",
NAME_STRING = "نام باید یک رشته باشد",
NAME_MAX_LENGTH = "حداکثر طول نام باید ۱۵۰ کاراکتر باشد",
DESCRIPTION_REQUIRED = "توضیحات الزامی است",
DESCRIPTION_STRING = "توضیحات باید یک رشته باشد",
DESCRIPTION_MAX_LENGTH = "حداکثر طول توضیحات باید ۱۰۰۰ کاراکتر باشد",
PRICE_REQUIRED = "قیمت الزامی است",
PRICE_NUMBER = "قیمت باید یک عدد باشد",
PRICE_MIN = "قیمت باید بیشتر از ۱۰۰۰۰ باشد",
DURATION_REQUIRED = "مدت الزامی است",
DURATION_NUMBER = "مدت باید یک عدد باشد",
DURATION_MIN = "مدت باید بیشتر از ۰ باشد",
IS_ACTIVE_REQUIRED = "وضعیت فعال بودن الزامی است",
IS_ACTIVE_BOOLEAN = "وضعیت فعال بودن باید یک بولین باشد",
SUPPORT_PLAN_CREATED = "پلن پشتیبانی با موفقیت ایجاد شد",
FEATURE_KEY_REQUIRED = "کلید ویژگی الزامی است",
FEATURE_VALUE_REQUIRED = "مقدار ویژگی الزامی است",
FEATURE_VALUE_STRING = "مقدار ویژگی باید یک رشته باشد",
FEATURE_TYPE_REQUIRED = "نوع ویژگی الزامی است",
FEATURE_ICON_URL = "آدرس آیکون ویژگی باید یک URL معتبر باشد",
FEATURE_ICON_REQUIRED = "آیکون ویژگی الزامی است",
FEATURES_ARRAY = "ویژگی‌ها باید یک آرایه باشد",
FEATURES_VALIDATE_NESTED = "ویژگی‌ها باید یک آرایه از ویژگی‌ها باشد",
SUPPORT_PLAN_NOT_FOUND = "پلن پشتیبانی مورد نظر یافت نشد",
SUPPORT_PLAN_DELETED = "پلن پشتیبانی با موفقیت حذف شد",
SUPPORT_PLAN_UPDATED = "پلن پشتیبانی با موفقیت به روز رسانی شد",
}
+1 -1
View File
@@ -13,7 +13,7 @@ export function databaseConfigs(): TypeOrmModuleAsyncOptions {
username: configService.getOrThrow<string>("DB_USER"),
password: configService.getOrThrow<string>("DB_PASS"),
autoLoadEntities: true,
synchronize: configService.getOrThrow<string>("NODE_ENV") == "production" ? false : true,
synchronize: configService.getOrThrow<string>("NODE_ENV") == "production" ? false : false,
logging: configService.getOrThrow<string>("NODE_ENV") == "production" ? false : true,
migrationsTableName: "typeorm_migrations",
migrationsRun: false,
+1 -1
View File
@@ -36,7 +36,7 @@ export class CreateAdsDto {
isActive: boolean;
@IsNotEmpty({ message: AdsMessage.IMAGE_URL_REQUIRED })
@IsUrl({ protocols: ["http", "https"], require_protocol: true }, { message: AdsMessage.IMAGE_SHOULD_BE_URL })
@IsUrl({ protocols: ["https"], require_protocol: true }, { message: AdsMessage.IMAGE_SHOULD_BE_URL })
@ApiProperty({ description: "The URL of the image to be displayed", example: "https://test.com/pic.png" })
imageUrl: string;
@@ -105,10 +105,10 @@ export class DanakServicesService {
async updateCategory(categoryId: string, updateDto: UpdateDanakServiceCategoryDto) {
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
await queryRunner.connect();
await queryRunner.startTransaction();
const category = await queryRunner.manager.findOne(DanakServiceCategory, { where: { id: categoryId } });
if (!category) throw new BadRequestException(CategoryMessage.CATEGORY_NOT_EXIST);
@@ -386,6 +386,7 @@ export class DanakServicesService {
description: true,
createDate: true,
icon: true,
slug: true,
createdAt: true,
isActive: true,
isDanakSuggest: true,
@@ -0,0 +1,29 @@
import { ApiProperty } from "@nestjs/swagger";
import { IsEnum, IsNotEmpty, IsOptional, IsString, IsUrl } from "class-validator";
import { SupportPlanMessage } from "../../../common/enums/message.enum";
import { SupportPlanFeatureKey } from "../enums/support-plan-feature-key.enum";
import { SupportPlanFeatureType } from "../enums/support-plan-feature-type.enum";
export class CreateSupportPlanFeatureDto {
@IsNotEmpty({ message: SupportPlanMessage.FEATURE_KEY_REQUIRED })
@IsEnum(SupportPlanFeatureKey)
@ApiProperty({ description: "The key of the feature", enum: SupportPlanFeatureKey, example: SupportPlanFeatureKey.LEARNING_DOCS })
featureKey: SupportPlanFeatureKey;
@IsNotEmpty({ message: SupportPlanMessage.FEATURE_VALUE_REQUIRED })
@IsString({ message: SupportPlanMessage.FEATURE_VALUE_STRING })
@ApiProperty({ description: "The value of the feature", example: "true" })
featureValue: string;
@IsNotEmpty({ message: SupportPlanMessage.FEATURE_TYPE_REQUIRED })
@IsEnum(SupportPlanFeatureType)
@ApiProperty({ description: "The type of the feature", enum: SupportPlanFeatureType, example: SupportPlanFeatureType.BOOLEAN })
featureType: SupportPlanFeatureType;
@IsOptional()
@IsNotEmpty({ message: SupportPlanMessage.FEATURE_ICON_REQUIRED })
@IsUrl({ protocols: ["https"] }, { message: SupportPlanMessage.FEATURE_ICON_URL })
@ApiProperty({ description: "The icon of the feature", example: "https://example.com/icon.png" })
icon?: string;
}
@@ -0,0 +1,58 @@
import { ApiProperty } from "@nestjs/swagger";
import { Type } from "class-transformer";
import {
ArrayMinSize,
IsArray,
IsBoolean,
IsNotEmpty,
IsNumber,
IsOptional,
IsString,
MaxLength,
Min,
ValidateNested,
} from "class-validator";
import { CreateSupportPlanFeatureDto } from "./create-support-plan-feature.dto";
import { SupportPlanMessage } from "../../../common/enums/message.enum";
export class CreateSupportPlanDto {
@IsNotEmpty({ message: SupportPlanMessage.NAME_REQUIRED })
@IsString({ message: SupportPlanMessage.NAME_STRING })
@MaxLength(150, { message: SupportPlanMessage.NAME_MAX_LENGTH })
@ApiProperty({ description: "The name of the support plan" })
name: string;
@IsOptional()
@IsNotEmpty({ message: SupportPlanMessage.DESCRIPTION_REQUIRED })
@IsString({ message: SupportPlanMessage.DESCRIPTION_STRING })
@MaxLength(1000, { message: SupportPlanMessage.DESCRIPTION_MAX_LENGTH })
@ApiProperty({ description: "The description of the support plan" })
description: string;
@IsNotEmpty({ message: SupportPlanMessage.PRICE_REQUIRED })
@IsNumber({}, { message: SupportPlanMessage.PRICE_NUMBER })
@Min(10000, { message: SupportPlanMessage.PRICE_MIN })
@ApiProperty({ description: "The price of the support plan" })
price: number;
@IsNotEmpty({ message: SupportPlanMessage.DURATION_REQUIRED })
@IsNumber({}, { message: SupportPlanMessage.DURATION_NUMBER })
@Min(1, { message: SupportPlanMessage.DURATION_MIN })
@ApiProperty({ description: "The duration of the support plan" })
duration: number;
@IsOptional()
@IsNotEmpty({ message: SupportPlanMessage.IS_ACTIVE_REQUIRED })
@IsBoolean({ message: SupportPlanMessage.IS_ACTIVE_BOOLEAN })
@ApiProperty({ description: "The status of the support plan" })
isActive: boolean;
@IsNotEmpty({ message: SupportPlanMessage.FEATURES_VALIDATE_NESTED })
@IsArray({ message: SupportPlanMessage.FEATURES_VALIDATE_NESTED })
@ArrayMinSize(9, { message: SupportPlanMessage.FEATURES_VALIDATE_NESTED })
@ValidateNested({ each: true })
@Type(() => CreateSupportPlanFeatureDto)
@ApiProperty({ description: "The features of the support plan", type: [CreateSupportPlanFeatureDto] })
features: CreateSupportPlanFeatureDto[];
}
@@ -0,0 +1,19 @@
import { ApiPropertyOptional } from "@nestjs/swagger";
import { Type } from "class-transformer";
import { IsIn, IsOptional, IsString } from "class-validator";
import { PaginationDto } from "../../../common/DTO/pagination.dto";
import { CommonMessage } from "../../../common/enums/message.enum";
export class GetSupportPlanListQueryDto extends PaginationDto {
@IsOptional()
@Type(() => Number)
@IsIn([1, 0], { message: CommonMessage.IS_ACTIVE_SHOULD_BE_1_0 })
@ApiPropertyOptional({ description: "status", example: 1 })
isActive?: number;
@IsOptional()
@IsString({ message: CommonMessage.SEARCH_QUERY_STRING })
@ApiPropertyOptional({ description: "Search query", example: "search query" })
q?: string;
}
@@ -0,0 +1,5 @@
import { PartialType } from "@nestjs/swagger";
import { CreateSupportPlanDto } from "./create-support-plan.dto";
export class UpdateSupportPlanDto extends PartialType(CreateSupportPlanDto) {}
@@ -0,0 +1,24 @@
import { Column, Entity, ManyToOne } from "typeorm";
import { SupportPlan } from "./support-plan.entity";
import { BaseEntity } from "../../../common/entities/base.entity";
import { SupportPlanFeatureKey } from "../enums/support-plan-feature-key.enum";
import { SupportPlanFeatureType } from "../enums/support-plan-feature-type.enum";
@Entity()
export class SupportPlanFeature extends BaseEntity {
@ManyToOne(() => SupportPlan, (plan) => plan.features, { nullable: false, onDelete: "CASCADE" })
supportPlan: SupportPlan;
@Column({ type: "enum", enum: SupportPlanFeatureKey, nullable: false })
featureKey: SupportPlanFeatureKey;
@Column({ type: "varchar", length: 255, nullable: false })
featureValue: string;
@Column({ type: "enum", enum: SupportPlanFeatureType, nullable: false })
featureType: SupportPlanFeatureType;
@Column({ type: "varchar", length: 255, nullable: true })
icon: string | null;
}
@@ -0,0 +1,29 @@
import { Decimal } from "decimal.js";
import { Column, DeleteDateColumn, Entity, OneToMany } from "typeorm";
import { SupportPlanFeature } from "./support-plan-feature.entity";
import { BaseEntity } from "../../../common/entities/base.entity";
import { DecimalTransformer } from "../../../common/transformers/decimal.transformer";
@Entity()
export class SupportPlan extends BaseEntity {
@Column({ type: "varchar", length: 150, nullable: false })
name: string;
@Column({ type: "text", nullable: true })
description: string | null;
@Column({ type: "decimal", precision: 16, scale: 2, nullable: false, transformer: new DecimalTransformer() })
price: Decimal;
@Column({ type: "int", nullable: false })
duration: number; //days
@Column({ type: "boolean", default: true })
isActive: boolean;
@OneToMany(() => SupportPlanFeature, (feature) => feature.supportPlan, { cascade: true })
features: SupportPlanFeature[];
@DeleteDateColumn({ nullable: true })
deletedAt?: Date;
}
@@ -0,0 +1,24 @@
import { Column, Entity, ManyToOne } from "typeorm";
import { SupportPlan } from "./support-plan.entity";
import { BaseEntity } from "../../../common/entities/base.entity";
import { User } from "../../users/entities/user.entity";
import { UserSupportPlanStatus } from "../enums/user-support-plan-status.enum";
@Entity()
export class UserSupportPlan extends BaseEntity {
@ManyToOne(() => User, { nullable: false, onDelete: "CASCADE" })
user: User;
@ManyToOne(() => SupportPlan, { nullable: false, onDelete: "CASCADE" })
supportPlan: SupportPlan;
@Column({ type: "timestamptz", nullable: false })
startDate: Date;
@Column({ type: "timestamptz", nullable: false })
endDate: Date;
@Column({ type: "enum", enum: UserSupportPlanStatus, default: UserSupportPlanStatus.INACTIVE })
status: UserSupportPlanStatus;
}
@@ -0,0 +1,11 @@
export enum SupportPlanFeatureKey {
LEARNING_DOCS = "learning_docs", // راهنما و مستندات آموزشی
TICKET_SUPPORT = "ticket_support", // ارسال تیکت
RESPONSE_TIME = "response_time", // زمان پاسخگویی به تیکت
PHONE_SUPPORT = "phone_support", // پاسخگویی تلفنی
BACKUP_VERSION = "backup_version", // نسخه بکاپ
TECHNICAL_EXPERT_ACCESS = "technical_expert_access", // دسترسی به متخصصین فنی
ON_SITE_SUPPORT = "on_site_support", // پشتیبانی در محل
ON_SITE_TRAINING = "on_site_training", // آموزش در محل
TICKET_LIMIT = "ticket_limit", // ظرفیت ارسال تیکت
}
@@ -0,0 +1,7 @@
export enum SupportPlanFeatureType {
TEXT = "text",
BOOLEAN = "boolean",
// NUMBER = "number",
// DATE = "date",
// TIME = "time",
}
@@ -0,0 +1,5 @@
export enum UserSupportPlanStatus {
ACTIVE = "ACTIVE",
INACTIVE = "INACTIVE",
CANCELLED = "CANCELLED",
}
@@ -0,0 +1,62 @@
import { BadRequestException, Injectable } from "@nestjs/common";
import { SupportPlanMessage } from "../../../common/enums/message.enum";
import { CreateSupportPlanDto } from "../DTO/create-support-plan.dto";
import { GetSupportPlanListQueryDto } from "../DTO/get-support-plan-list-query.dto";
import { UpdateSupportPlanDto } from "../DTO/update-support-plan-feature.dto";
import { SupportPlanRepository } from "../repositories/support-plan.repository";
@Injectable()
export class SupportPlansService {
constructor(
private readonly supportPlanRepo: SupportPlanRepository,
// private readonly userSupportPlanRepo: UserSupportPlanRepository,
) {}
async createSupportPlan(createSupportPlanDto: CreateSupportPlanDto) {
const supportPlan = this.supportPlanRepo.create(createSupportPlanDto);
await this.supportPlanRepo.save(supportPlan);
return {
message: SupportPlanMessage.SUPPORT_PLAN_CREATED,
supportPlan,
};
}
//***************************************** */
async getSupportPlansList(queryDto: GetSupportPlanListQueryDto) {
const [supportPlans, count] = await this.supportPlanRepo.getSupportPlansListAdmin(queryDto);
return {
supportPlans,
count,
paginate: true,
};
}
//***************************************** */
async getSupportPlanById(id: string) {
const supportPlan = await this.supportPlanRepo.getSupportPlanById(id);
if (!supportPlan) throw new BadRequestException(SupportPlanMessage.SUPPORT_PLAN_NOT_FOUND);
return {
supportPlan,
};
}
//***************************************** */
async deleteSupportPlanById(id: string) {
const supportPlan = await this.supportPlanRepo.getSupportPlanById(id);
if (!supportPlan) throw new BadRequestException(SupportPlanMessage.SUPPORT_PLAN_NOT_FOUND);
await this.supportPlanRepo.softDelete(id);
return {
message: SupportPlanMessage.SUPPORT_PLAN_DELETED,
};
}
//***************************************** */
async updateSupportPlanById(id: string, updateSupportPlanDto: UpdateSupportPlanDto) {
const supportPlan = await this.supportPlanRepo.getSupportPlanById(id);
if (!supportPlan) throw new BadRequestException(SupportPlanMessage.SUPPORT_PLAN_NOT_FOUND);
await this.supportPlanRepo.save({ ...supportPlan, ...updateSupportPlanDto });
return {
message: SupportPlanMessage.SUPPORT_PLAN_UPDATED,
};
}
}
@@ -0,0 +1,35 @@
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { IsNull, Repository } from "typeorm";
import { PaginationUtils } from "../../utils/providers/pagination.utils";
import { GetSupportPlanListQueryDto } from "../DTO/get-support-plan-list-query.dto";
import { SupportPlan } from "../entities/support-plan.entity";
@Injectable()
export class SupportPlanRepository extends Repository<SupportPlan> {
constructor(@InjectRepository(SupportPlan) supportPlanRepo: Repository<SupportPlan>) {
super(supportPlanRepo.target, supportPlanRepo.manager, supportPlanRepo.queryRunner);
}
//***************************************** */
async getSupportPlansListAdmin(queryDto: GetSupportPlanListQueryDto) {
const { limit, skip } = PaginationUtils(queryDto);
const query = this.createQueryBuilder("supportPlan").where("supportPlan.deletedAt IS NULL");
if (queryDto.q) {
query.andWhere("supportPlan.name ILIKE :q OR supportPlan.description ILIKE :q", { q: `%${queryDto.q}%` });
}
if (queryDto.isActive !== undefined) {
query.andWhere("supportPlan.isActive = :isActive", { isActive: queryDto.isActive === 1 });
}
query.skip(skip).take(limit).orderBy("supportPlan.createdAt", "DESC");
return query.getManyAndCount();
}
//***************************************** */
async getSupportPlanById(id: string) {
return this.findOne({ where: { id, deletedAt: IsNull() }, relations: { features: true } });
}
}
@@ -0,0 +1,12 @@
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { UserSupportPlan } from "../entities/user-support-plan.entity";
@Injectable()
export class UserSupportPlanRepository extends Repository<UserSupportPlan> {
constructor(@InjectRepository(UserSupportPlan) userSupportPlanRepo: Repository<UserSupportPlan>) {
super(userSupportPlanRepo.target, userSupportPlanRepo.manager, userSupportPlanRepo.queryRunner);
}
}
@@ -0,0 +1,55 @@
import { Body, Controller, Delete, Get, Param, Post, Query } from "@nestjs/common";
import { ApiOperation } from "@nestjs/swagger";
import { CreateSupportPlanDto } from "./DTO/create-support-plan.dto";
import { GetSupportPlanListQueryDto } from "./DTO/get-support-plan-list-query.dto";
import { SupportPlansService } from "./providers/support-plans.service";
import { AdminRoute } from "../../common/decorators/admin.decorator";
import { AuthGuards } from "../../common/decorators/auth-guard.decorator";
import { ParamDto } from "../../common/DTO/param.dto";
@Controller("support-plans")
@AuthGuards()
export class SupportPlansController {
constructor(private readonly supportPlansService: SupportPlansService) {}
@AdminRoute()
// @PermissionsDec(PermissionEnum.SUPPORT_PLAN)
@ApiOperation({ summary: "Create a new support plan (admin)" })
@Post()
createSupportPlan(@Body() createSupportPlanDto: CreateSupportPlanDto) {
return this.supportPlansService.createSupportPlan(createSupportPlanDto);
}
@AdminRoute()
// @PermissionsDec(PermissionEnum.SUPPORT_PLAN)
@ApiOperation({ summary: "Get all support plans (admin)" })
@Get("list")
getSupportPlansList(@Query() queryDto: GetSupportPlanListQueryDto) {
return this.supportPlansService.getSupportPlansList(queryDto);
}
@AdminRoute()
// @PermissionsDec(PermissionEnum.SUPPORT_PLAN)
@ApiOperation({ summary: "Get a support plan by id (admin)" })
@Get(":id")
getSupportPlanById(@Param() paramDto: ParamDto) {
return this.supportPlansService.getSupportPlanById(paramDto.id);
}
@AdminRoute()
// @PermissionsDec(PermissionEnum.SUPPORT_PLAN)
@ApiOperation({ summary: "Delete a support plan by id (admin)" })
@Delete(":id")
deleteSupportPlanById(@Param() paramDto: ParamDto) {
return this.supportPlansService.deleteSupportPlanById(paramDto.id);
}
// @AdminRoute()
// @PermissionsDec(PermissionEnum.SUPPORT_PLAN)
// @ApiOperation({ summary: "Update a support plan by id (admin)" })
// @Patch(":id")
// updateSupportPlanById(@Param() paramDto: ParamDto, @Body() updateSupportPlanDto: UpdateSupportPlanDto) {
// return this.supportPlansService.updateSupportPlanById(paramDto.id, updateSupportPlanDto);
// }
}
@@ -0,0 +1,18 @@
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { SupportPlanFeature } from "./entities/support-plan-feature.entity";
import { SupportPlan } from "./entities/support-plan.entity";
import { UserSupportPlan } from "./entities/user-support-plan.entity";
import { SupportPlansService } from "./providers/support-plans.service";
import { SupportPlanRepository } from "./repositories/support-plan.repository";
import { UserSupportPlanRepository } from "./repositories/user-support-plan.repository";
import { SupportPlansController } from "./support-plans.controller";
@Module({
imports: [TypeOrmModule.forFeature([SupportPlan, SupportPlanFeature, UserSupportPlan])],
controllers: [SupportPlansController],
providers: [SupportPlansService, SupportPlanRepository, UserSupportPlanRepository],
exports: [SupportPlansService],
})
export class SupportPlansModule {}
@@ -19,4 +19,5 @@ export enum PermissionEnum {
BANK_ACCOUNTS = "bank_accounts",
PAYMENTS = "payments",
MANAGE_SSO_CLIENTS = "manage_sso_clients",
SUPPORT_PLAN = "support_plan",
}