Files
dsc-api/src/modules/subscriptions/providers/subscriptions.service.ts
T
morteza bd1d8685a7
Build and Deploy Docker Images / build_and_deploy (push) Has been cancelled
add: get dpage plans
2026-06-17 16:35:51 +03:30

717 lines
27 KiB
TypeScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { InjectQueue } from "@nestjs/bullmq";
import { BadRequestException, ForbiddenException, Injectable, Logger } from "@nestjs/common";
import { ModuleRef } from "@nestjs/core";
import { Queue } from "bullmq";
import dayjs from "dayjs";
import Decimal from "decimal.js";
import slugify from "slugify";
import { DataSource, In, Not, QueryRunner } from "typeorm";
import { ServiceMessage, SubscriptionMessage } from "../../../common/enums/message.enum";
import { DanakServicesService } from "../../danak-services/providers/danak-services.service";
import { RestaurantService } from "../../dmenu/providers/restaurant.service";
import { INVOICE } from "../../invoices/constants";
import { InvoicesService } from "../../invoices/providers/invoices.service";
import { User } from "../../users/entities/user.entity";
import { UsersService } from "../../users/providers/users.service";
import { PaginationUtils } from "../../utils/providers/pagination.utils";
import { SUBSCRIPTIONS } from "../constants";
import { AddSubscriptionsToServiceDto } from "../DTO/create-subscription.dto";
import { AdminUserSubscriptionsQueryDto } from "../DTO/admin-user-subscriptions-query.dto";
import { SearchUserSubsQueryDto } from "../DTO/search-user-subs-query.dto";
import { ServiceSubsQueryDto } from "../DTO/service-subs-query.dto";
import { ExtendUSerSubscribeServiceDto, SubscribeServiceDto } from "../DTO/subscribe-service.dto";
import { SubscriptionAccessDto } from "../DTO/subscription-access-dto";
import { UpdateSubscriptionPlanDto } from "../DTO/update-subscription.dto";
import { SubscriptionPlan } from "../entities/subscription.entity";
import { UserSubscription } from "../entities/user-subscription.entity";
import { SubscriptionStatus } from "../enums/subscription-status.enum";
import { IBusinessProvisioningJob } from "../interfaces/IProvisioning-job-data";
import { SubscriptionsPlanRepository } from "../repositories/subscriptions.repository";
import { UserSubscriptionsRepository } from "../repositories/user-subscriptions.repository";
import { InvoicePurpose } from "../../invoices/interfaces/external-invoice.interface";
@Injectable()
export class SubscriptionsService {
private readonly logger: Logger = new Logger(SubscriptionsService.name);
constructor(
@InjectQueue(SUBSCRIPTIONS.PROVISIONING_QUEUE_NAME) private readonly provisioningQueue: Queue,
private readonly subscriptionsPlanRepository: SubscriptionsPlanRepository,
private readonly userSubscriptionsRepository: UserSubscriptionsRepository,
private readonly moduleRef: ModuleRef,
private readonly usersService: UsersService,
private readonly danakServices: DanakServicesService,
private readonly dataSource: DataSource,
) { }
private get invoicesService(): InvoicesService {
return this.moduleRef.get(InvoicesService, { strict: false });
}
private get restaurantService(): RestaurantService {
return this.moduleRef.get(RestaurantService, { strict: false });
}
//************************************ */
async createSubscriptionsPlan(createDto: AddSubscriptionsToServiceDto) {
const danakService = await this.danakServices.findServiceById(createDto.serviceId);
if (!danakService) throw new BadRequestException(ServiceMessage.SERVICE_NOT_FOUND_BY_ID);
const subscriptions = createDto.subs.map((sub) => {
const adjustedPrice = sub.price < 100_000 ? new Decimal(0) : new Decimal(sub.price);
const isFree = sub.price < 100_000;
if (isFree) {
console.log(`🎁 Plan "${sub.name}" marked as FREE (price ${sub.price} < 100,000 IRR)`);
} else {
console.log(`💰 Plan "${sub.name}" price: ${adjustedPrice.toNumber()} IRR`);
}
return {
...sub,
service: { id: createDto.serviceId },
price: adjustedPrice,
originalPrice: adjustedPrice,
isFree,
};
});
const subscriptionNames = createDto.subs.map((sub) => sub.name);
const existingSubscriptions = await this.subscriptionsPlanRepository.find({
where: {
name: In(subscriptionNames),
service: { id: createDto.serviceId },
},
});
if (existingSubscriptions.length > 0)
throw new BadRequestException({ message: [SubscriptionMessage.NAME_EXIST, existingSubscriptions] });
const createdSubscriptions = this.subscriptionsPlanRepository.create(subscriptions);
await this.subscriptionsPlanRepository.save(createdSubscriptions);
return {
message: SubscriptionMessage.CREATED,
subscriptions: createdSubscriptions,
};
}
//************************************ */
async getUserSubscriptions(userId: string, queryDto: SearchUserSubsQueryDto) {
const queryBuilder = this.userSubscriptionsRepository
.createQueryBuilder("userSubscription")
.leftJoinAndSelect("userSubscription.plan", "plan")
.leftJoinAndSelect("plan.service", "service")
.where("userSubscription.user.id = :userId", { userId });
if (queryDto.q) {
queryBuilder.andWhere("(service.name ILIKE :query OR service.title ILIKE :query OR service.description ILIKE :query)", {
query: `%${queryDto.q}%`,
});
}
const subscriptions = await queryBuilder.getMany();
return {
subscriptions,
};
}
//************************************ */
async getUserSubscriptionById(userSubId: string, userId: string) {
const userSubscription = await this.userSubscriptionsRepository.findOne({
where: { id: userSubId, user: { id: userId } },
relations: {
plan: {
service: {
images: true,
subscriptionPlans: true,
},
},
},
});
if (!userSubscription) throw new BadRequestException(SubscriptionMessage.USER_SUBS_NOT_FOUND);
return {
userSubscription,
};
}
//************************************ */
async updateSubscriptionPlan(id: string, updateDto: UpdateSubscriptionPlanDto) {
const subscription = await this.subscriptionsPlanRepository.findOne({ where: { id }, relations: { service: true } });
if (!subscription) throw new BadRequestException(SubscriptionMessage.NOT_FOUND);
if (updateDto.serviceId) {
const danakService = await this.danakServices.findServiceById(updateDto.serviceId);
if (!danakService) throw new BadRequestException(ServiceMessage.SERVICE_NOT_FOUND_BY_ID);
subscription.service = danakService;
}
if (updateDto.name) {
const existSubscription = await this.subscriptionsPlanRepository.findOneBy({
name: updateDto.name,
id: Not(id),
service: { id: subscription.service.id },
});
if (existSubscription) throw new BadRequestException(SubscriptionMessage.NAME_EXIST);
subscription.name = updateDto.name;
}
if (updateDto.duration) subscription.duration = updateDto.duration;
if (updateDto.price) {
const adjustedPrice = updateDto.price < 100_000 ? new Decimal(0) : new Decimal(updateDto.price);
const isFree = updateDto.price < 100_000;
if (isFree) {
console.log(`🎁 Plan "${subscription.name}" updated to FREE (price ${updateDto.price} < 100,000 IRR)`);
} else {
console.log(`💰 Plan "${subscription.name}" price updated to: ${adjustedPrice.toNumber()} IRR`);
}
subscription.price = adjustedPrice;
subscription.originalPrice = adjustedPrice;
}
await this.subscriptionsPlanRepository.save({
...subscription,
isFree: updateDto.price ? updateDto.price < 100_000 : false,
});
return {
message: SubscriptionMessage.UPDATED,
subscription,
};
}
//************************************ */
async getSubscriptionPlanById(subscriptionId: string) {
const subscription = await this.subscriptionsPlanRepository.findOneBy({ id: subscriptionId });
if (!subscription) throw new BadRequestException(SubscriptionMessage.NOT_FOUND);
return {
subscription,
};
}
//************************************ */
async All(serviceId: string, queryDto: ServiceSubsQueryDto) {
const service = await this.danakServices.findServiceById(serviceId);
const { limit, skip } = PaginationUtils(queryDto);
const queryBuilder = this.subscriptionsPlanRepository
.createQueryBuilder("subscription")
.leftJoin("subscription.service", "service")
.addSelect(["service.id"])
// .leftJoin("subscription.discounts", "discount")
// .addSelect(["discount.calculationType", "discount.amount", "discount.startDate", "discount.endDate", "discount.isActive"])
.where("service.id = :serviceId", { serviceId });
if (queryDto.q) {
queryBuilder.andWhere("subscription.name ILIKE :query", { query: `%${queryDto.q}%` });
}
if (queryDto.isActive !== undefined) {
queryBuilder.andWhere("subscription.isActive = :isActive", { isActive: queryDto.isActive === 1 });
}
const [subscriptions, count] = await queryBuilder.skip(skip).take(limit).getManyAndCount();
return {
service,
subscriptions,
count,
pagination: true,
};
}
//************************************ */
async toggleSubStatus(subId: string) {
const subscription = await this.subscriptionsPlanRepository.findOneBy({ id: subId });
if (!subscription) throw new BadRequestException(SubscriptionMessage.NOT_FOUND);
subscription.isActive = !subscription.isActive;
await this.subscriptionsPlanRepository.save(subscription);
return {
message: SubscriptionMessage.STATUS_UPDATED,
isActive: subscription.isActive,
};
}
//************************************ */
async subscribeToPlan(serviceId: string, subscribeDto: SubscribeServiceDto, userId: string) {
const queryRunner = this.dataSource.createQueryRunner();
let isFree = false;
try {
await queryRunner.connect();
await queryRunner.startTransaction();
const user = await this.usersService.findOneByIdWithQueryRunner(userId, queryRunner);
const plan = await queryRunner.manager.findOne(SubscriptionPlan, {
where: { id: subscribeDto.planId, service: { id: serviceId } },
relations: {
service: true,
directDiscount: true,
},
});
if (!plan) throw new BadRequestException(SubscriptionMessage.NOT_FOUND);
if (plan.isFree) {
isFree = true;
// const oneMonthAgo = dayjs().subtract(1, "month").toDate();
const existingFreePlanSubscription = await queryRunner.manager.findOne(UserSubscription, {
where: {
user: { id: userId },
plan: {
isFree: true,
service: {
id: serviceId,
},
},
// startDate: MoreThan(oneMonthAgo),
},
relations: {
plan: true,
},
});
if (existingFreePlanSubscription) {
throw new BadRequestException(SubscriptionMessage.FREE_PLAN_LIMIT_EXCEEDED);
}
}
const startDate = dayjs().toDate();
const endDate = dayjs().add(plan.duration, "day").toDate();
let slug = subscribeDto.slug;
if (!slug) {
slug = slugify(subscribeDto.businessName, { lower: true, strict: true });
}
const existingSlug = await queryRunner.manager.findOne(UserSubscription, { where: { slug, deletedAt: undefined } });
if (existingSlug) throw new BadRequestException(SubscriptionMessage.SLUG_EXISTS);
let staff: User[] = [];
if (subscribeDto.staff && subscribeDto.staff.length > 0) {
staff = await this.usersService.findUsersByIds(subscribeDto.staff);
}
const userSubscription = queryRunner.manager.create(UserSubscription, {
...subscribeDto,
user,
plan,
startDate,
endDate,
slug,
staff,
});
await queryRunner.manager.save(UserSubscription, userSubscription);
const invoiceDueDate = dayjs(userSubscription.startDate).add(INVOICE.DUEDATE, "day").toDate();
const invoice = await this.invoicesService.createInvoiceForSubscription(user, plan, userSubscription, invoiceDueDate, queryRunner, InvoicePurpose.NEW);
userSubscription.status = SubscriptionStatus.INACTIVE;
await queryRunner.manager.save(UserSubscription, userSubscription);
await this.addProvisioningJob(userSubscription, plan, user);
if (isFree) {
await this.invoicesService.payInvoice(invoice.id, user.id, undefined, queryRunner);
}
await queryRunner.commitTransaction();
return {
message: SubscriptionMessage.SUBSCRIBED,
userSubscription,
invoice,
};
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
//************************************ */
async renewUserSubscription(userSubscriptionId: string, dto: ExtendUSerSubscribeServiceDto, userId: string) {
const queryRunner = this.dataSource.createQueryRunner();
try {
await queryRunner.connect();
await queryRunner.startTransaction();
const userSubscription = await queryRunner.manager.findOne(UserSubscription, {
where: { id: userSubscriptionId },
relations: {
user: true,
plan: true,
},
});
if (!userSubscription) throw new BadRequestException(SubscriptionMessage.NOT_FOUND);
const user = await this.usersService.findOneByIdWithQueryRunner(userId, queryRunner);
const plan = await queryRunner.manager.findOne(SubscriptionPlan, {
where: { id: dto.planId, service: { id: dto.serviceId } },
relations: { service: true, directDiscount: true },
});
if (!plan) throw new BadRequestException(SubscriptionMessage.PLAN_NOT_FOUND);
if (plan.isFree) {
throw new BadRequestException(SubscriptionMessage.FREE_PLAN_NOT_ALLOWED);
}
const invoiceDueDate = dayjs().add(INVOICE.DUEDATE, "day").toDate();
const invoice = await this.invoicesService.createInvoiceForSubscription(user, plan, userSubscription, invoiceDueDate, queryRunner, InvoicePurpose.RENEW);
// userSubscription.plan = plan;
// await queryRunner.manager.save(userSubscription);
await this.addProvisioningJob(userSubscription, plan, user);
await queryRunner.commitTransaction();
return {
message: SubscriptionMessage.INVOICE_CREATED_SUCCESSFULLY,
userSubscription,
invoice,
};
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
//************************************ */
async upgradeSubscription(userSubscriptionId: string, planId: string, userId: string) {
const queryRunner = this.dataSource.createQueryRunner();
try {
await queryRunner.connect();
await queryRunner.startTransaction();
const userSubscription = await queryRunner.manager.findOne(UserSubscription, {
where: { id: userSubscriptionId, user: { id: userId } },
relations: { plan: { service: true }, user: true }
});
if (!userSubscription) throw new BadRequestException(SubscriptionMessage.USER_SUBS_NOT_FOUND);
// Check if restaurant exists for dmenu service
if (userSubscription.plan.service.name.includes('دی منو')) {
try {
const rest = await this.restaurantService.getRestaurantSubscription(userSubscriptionId);
console.log('rest', rest)
} catch (error) {
throw new BadRequestException('Restaurant* not found for this subscription');
}
}
const newPlan = await this.subscriptionsPlanRepository.findById(planId);
if (!newPlan) throw new BadRequestException(SubscriptionMessage.PLAN_NOT_FOUND);
if (userSubscription.plan.service.id !== newPlan.service.id) {
throw new BadRequestException(SubscriptionMessage.SERVICE_MISMATCH);
}
// Validate that new plan is more expensive than current plan
if (new Decimal(newPlan.price).lessThan(userSubscription.plan.price)) {
throw new BadRequestException(SubscriptionMessage.UPGRADE_TO_LOWER_OR_EQUAL_PLAN_NOT_ALLOWED);
}
// Calculate remaining days in current subscription
const today = dayjs();
const endDate = dayjs(userSubscription.endDate);
const currentPlanRemainingDays = Math.max(0, endDate.diff(today, 'day'));
console.log('🔢 CALCULATION LOGS:');
console.log(`📅 Remaining days: ${currentPlanRemainingDays} (endDate: ${endDate.format('YYYY-MM-DD')}, today: ${today.format('YYYY-MM-DD')})`);
if (currentPlanRemainingDays <= 0) {
throw new BadRequestException(SubscriptionMessage.SUBSCRIPTION_EXPIRED_CANNOT_UPGRADE);
}
const remainingDays = newPlan.duration - currentPlanRemainingDays
// Calculate daily rates
const currentPlanDuration = userSubscription.plan.duration;
const newPlanDuration = newPlan.duration;
const currentDailyRate = new Decimal(userSubscription.plan.price).div(currentPlanDuration);
const newDailyRate = new Decimal(newPlan.price).div(newPlanDuration);
console.log(`💰 Current plan: ${userSubscription.plan.price} IRR for ${currentPlanDuration} days = ${currentDailyRate.toNumber()} IRR/day`);
console.log(`💰 New plan: ${newPlan.price} IRR for ${newPlanDuration} days = ${newDailyRate.toNumber()} IRR/day`);
// Calculate price difference per day
const dailyPriceDifference = newDailyRate.sub(currentDailyRate);
console.log(`📈 Daily price difference: ${dailyPriceDifference.toNumber()} IRR/day`);
// Calculate prorated upgrade cost for remaining days
const proratedUpgradeCost = dailyPriceDifference.mul(currentPlanRemainingDays).add(newDailyRate.mul(remainingDays))
console.log(`🧮 Prorated upgrade cost: ${dailyPriceDifference.toNumber()} IRR/day × ${currentPlanRemainingDays} days = ${proratedUpgradeCost.toNumber()} IRR`);
// Ensure minimum charge amount
const minimumCharge = new Decimal(1000); // 1000 IRR minimum
const finalUpgradeCost = + Decimal.max(proratedUpgradeCost, minimumCharge).toNumber().toFixed(0)
console.log(`✅ Final upgrade cost: max(${proratedUpgradeCost.toNumber()} IRR, ${minimumCharge.toNumber()} IRR minimum) = ${finalUpgradeCost} IRR`);
const user = await this.usersService.findOneByIdWithQueryRunner(userSubscription.user.id, queryRunner);
const invoiceDueDate = dayjs().add(INVOICE.DUEDATE, "day").toDate();
const invoice = await this.invoicesService.createInvoiceForSubscriptionUpgrade(
user,
newPlan,
userSubscription,
invoiceDueDate,
queryRunner,
finalUpgradeCost
);
// Update the subscription to the new plan
// userSubscription.plan = newPlan;
// await queryRunner.manager.save(UserSubscription, userSubscription);
// Add provisioning job for the new plan
await this.addProvisioningJob(userSubscription, newPlan, user);
await queryRunner.commitTransaction();
return {
message: SubscriptionMessage.INVOICE_CREATED_SUCCESSFULLY,
userSubscription,
invoice,
upgradeDetails: {
remainingDays: currentPlanRemainingDays,
currentPlanPrice: userSubscription.plan.price,
newPlanPrice: newPlan.price,
proratedUpgradeCost: finalUpgradeCost,
},
};
} catch (error) {
await queryRunner.rollbackTransaction();
throw error;
} finally {
await queryRunner.release();
}
}
//************************************ */
async getServiceSubscriptions(serviceId: string, queryDto: ServiceSubsQueryDto) {
const service = await this.danakServices.findServiceById(serviceId);
const { limit, skip } = PaginationUtils(queryDto);
const queryBuilder = this.subscriptionsPlanRepository
.createQueryBuilder("subscription")
.leftJoin("subscription.service", "service")
.addSelect(["service.id"])
// .leftJoin("subscription.discounts", "discount")
// .addSelect(["discount.calculationType", "discount.amount", "discount.startDate", "discount.endDate", "discount.isActive"])
.where("service.id = :serviceId", { serviceId });
if (queryDto.q) {
queryBuilder.andWhere("subscription.name ILIKE :query", { query: `%${queryDto.q}%` });
}
if (queryDto.isActive !== undefined) {
queryBuilder.andWhere("subscription.isActive = :isActive", { isActive: queryDto.isActive === 1 });
}
const [subscriptions, count] = await queryBuilder.skip(skip).take(limit).getManyAndCount();
return {
service,
subscriptions,
count,
pagination: true,
};
}
//************************************ */
async getAllServiceSubscriptions(serviceIds: string[], queryRunner: QueryRunner) {
const subscriptions = await queryRunner.manager.find(this.subscriptionsPlanRepository.target, {
where: { service: { id: In(serviceIds) }, isActive: true },
relations: { directDiscount: true, service: true },
});
return subscriptions;
}
//************************************ */
async countUserSubscriptions(userId: string) {
const subscriptionCount = await this.userSubscriptionsRepository.count({
where: { user: { id: userId }, status: SubscriptionStatus.ACTIVE },
});
return subscriptionCount;
}
//************************************ */
async getUserSubscriptionsForService(userId: string, serviceId: string) {
const userSubscriptions = await this.userSubscriptionsRepository.find({
where: [
{ user: { id: userId }, plan: { service: { id: serviceId } }, status: SubscriptionStatus.ACTIVE },
{ staff: { id: userId }, plan: { service: { id: serviceId } }, status: SubscriptionStatus.ACTIVE },
],
relations: {
plan: { service: true },
staff: true,
},
order: { endDate: "DESC" },
select: {
id: true,
businessName: true,
businessPhone: true,
description: true,
slug: true,
status: true,
endDate: true,
startDate: true,
plan: { id: true, name: true, duration: true, service: { id: true, name: true, slug: true, title: true } },
staff: { id: true, firstName: true, lastName: true, email: true, phone: true },
},
});
if (!userSubscriptions.length) throw new ForbiddenException(SubscriptionMessage.USER_DOES_NOT_HAVE_ACCESS);
return { workspaces: userSubscriptions };
}
//************************************ */
async checkUserAccessToService(serviceId: string, accessDto: SubscriptionAccessDto) {
const userSubscriptions = await this.userSubscriptionsRepository.findOne({
where: [
{
id: accessDto.danakSubscriptionId,
user: { id: accessDto.userId },
plan: { service: { id: serviceId } },
status: SubscriptionStatus.ACTIVE,
},
{
id: accessDto.danakSubscriptionId,
staff: { id: accessDto.userId },
plan: { service: { id: serviceId } },
status: SubscriptionStatus.ACTIVE,
},
],
relations: {
plan: { service: true },
staff: true,
},
});
return { hasAccess: !!userSubscriptions && userSubscriptions.status === SubscriptionStatus.ACTIVE };
}
//************************************ */
async addProvisioningJob(userSubscription: UserSubscription, plan: SubscriptionPlan, user: User) {
this.logger.debug(`Adding provisioning job for user ${user.id} and subscription ${userSubscription.id}`);
await this.provisioningQueue.add(
SUBSCRIPTIONS.PROVISIONING_JOB_NAME,
{
subscriptionId: userSubscription.id,
serviceId: plan.service.id,
serviceName: plan.service.name,
businessName: userSubscription.businessName,
userId: user.id,
slug: userSubscription.slug,
phone: user.phone,
email: user.email,
fullName: `${user.firstName} ${user.lastName}`,
} as IBusinessProvisioningJob,
{
priority: SUBSCRIPTIONS.PROVISIONING_JOB_PRIORITY,
delay: SUBSCRIPTIONS.PROVISIONING_JOB_DELAY,
attempts: SUBSCRIPTIONS.PROVISIONING_JOB_ATTEMPTS,
backoff: { type: "exponential", delay: SUBSCRIPTIONS.PROVISIONING_JOB_BACKOFF },
},
);
}
//************************************ */
async getAllUserSubscriptions(queryDto: AdminUserSubscriptionsQueryDto) {
const { limit, skip } = PaginationUtils(queryDto);
const queryBuilder = this.userSubscriptionsRepository
.createQueryBuilder("userSubscription")
.leftJoinAndSelect("userSubscription.user", "user")
.leftJoinAndSelect("userSubscription.plan", "plan")
.leftJoin("plan.service", "service")
.addSelect(["service.name", "service.title"]);
if (queryDto.q) {
queryBuilder.andWhere(
"(userSubscription.businessName ILIKE :query OR userSubscription.description ILIKE :query OR user.email ILIKE :query OR user.phone ILIKE :query OR user.firstName ILIKE :query OR user.lastName ILIKE :query OR service.name ILIKE :query OR service.title ILIKE :query)",
{ query: `%${queryDto.q}%` }
);
}
if (queryDto.userId) {
queryBuilder.andWhere("user.id = :userId", { userId: queryDto.userId });
}
if (queryDto.serviceId) {
queryBuilder.andWhere("service.id = :serviceId", { serviceId: queryDto.serviceId });
}
if (queryDto.status) {
queryBuilder.andWhere("userSubscription.status = :status", { status: queryDto.status });
}
if (queryDto.startDateFrom) {
queryBuilder.andWhere("userSubscription.startDate >= :startDateFrom", { startDateFrom: queryDto.startDateFrom });
}
if (queryDto.startDateTo) {
queryBuilder.andWhere("userSubscription.startDate <= :startDateTo", { startDateTo: queryDto.startDateTo });
}
if (queryDto.endDateFrom) {
queryBuilder.andWhere("userSubscription.endDate >= :endDateFrom", { endDateFrom: queryDto.endDateFrom });
}
if (queryDto.endDateTo) {
queryBuilder.andWhere("userSubscription.endDate <= :endDateTo", { endDateTo: queryDto.endDateTo });
}
queryBuilder.orderBy("userSubscription.createdAt", "DESC");
const [userSubscriptions, count] = await queryBuilder.skip(skip).take(limit).getManyAndCount();
return {
userSubscriptions,
count,
pagination: true,
};
}
//************************************ */
async getDpagePlans() {
const plans = await this.subscriptionsPlanRepository.find({ where: { service:{slug:'Dpage'} } });
return plans;
}
//************************************ */
async softDeleteUSerSubscription(userSubscriptionId: string) {
const usersubscription = await this.userSubscriptionsRepository.findOne({ where: { id: userSubscriptionId } })
if (!usersubscription) {
throw new BadRequestException(SubscriptionMessage.NOT_FOUND)
}
await this.userSubscriptionsRepository.softDelete(userSubscriptionId)
return {
message: SubscriptionMessage.SUBSCRIPTION_DELETED
}
}
// ******************************** //
async findOneOrFail(userSubscriptionId: string){
const usersubscription = await this.userSubscriptionsRepository.findOne({ where: { id: userSubscriptionId },relations:['user'] })
if (!usersubscription) {
throw new BadRequestException(SubscriptionMessage.NOT_FOUND)
}
return usersubscription
}
}