From 6ba6a9cd45fc299aae2282a9c0258011ec168cb3 Mon Sep 17 00:00:00 2001 From: adonis Date: Wed, 16 Sep 2026 13:44:58 +0330 Subject: [PATCH] fix some extention bug --- src/common/iran-time.util.ts | 22 ++++------------------ src/plugins/dto/plugin.dto.ts | 12 ++++++++++++ src/plugins/plugins.service.ts | 31 +++++++++++++++++++++++++++---- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/common/iran-time.util.ts b/src/common/iran-time.util.ts index 19eb9d4..e11e5e5 100644 --- a/src/common/iran-time.util.ts +++ b/src/common/iran-time.util.ts @@ -1,6 +1,6 @@ /** Shared Iran timezone helpers for SuperAdmin API. */ -import { toGregorian, jalaaliMonthLength } from 'jalaali-js'; +import { toGregorian, jalaaliMonthLength, toJalaali } from 'jalaali-js'; export const IRAN_TZ = 'Asia/Tehran'; @@ -45,23 +45,9 @@ export type IranJalaliYmd = { year: number; month: number; day: number }; /** Jalali Y/M/D for a Date in Asia/Tehran. */ export function iranJalaliParts(date: Date): IranJalaliYmd { - const parts = new Intl.DateTimeFormat('en-u-ca-persian', { - timeZone: IRAN_TZ, - year: 'numeric', - month: 'numeric', - day: 'numeric', - }).formatToParts(date); - - const num = (type: Intl.DateTimeFormatPartTypes) => { - const raw = parts.find((p) => p.type === type)?.value ?? ''; - const n = Number(raw); - if (!Number.isFinite(n)) { - throw new Error(`Cannot read Jalali ${type} from ${date.toISOString()}`); - } - return n; - }; - - return { year: num('year'), month: num('month'), day: num('day') }; + const [gy, gm, gd] = iranYmd(date).split('-').map(Number); + const { jy, jm, jd } = toJalaali(gy, gm, gd); + return { year: jy, month: jm, day: jd }; } /** Noon Iran (+03:30) for a Jalali calendar day. */ diff --git a/src/plugins/dto/plugin.dto.ts b/src/plugins/dto/plugin.dto.ts index 04e4094..4e9b678 100644 --- a/src/plugins/dto/plugin.dto.ts +++ b/src/plugins/dto/plugin.dto.ts @@ -40,6 +40,10 @@ export class CreatePluginDto { @IsISO8601() chargedAt?: string; + @IsOptional() + @IsISO8601() + expiresAt?: string; + @IsOptional() @Type(() => Number) @IsInt() @@ -90,6 +94,10 @@ export class UpdatePluginDto { @IsISO8601() chargedAt?: string | null; + @IsOptional() + @IsISO8601() + expiresAt?: string | null; + @IsOptional() @Type(() => Number) @IsInt() @@ -122,6 +130,10 @@ export class RenewPluginDto { @IsISO8601() chargedAt?: string; + @IsOptional() + @IsISO8601() + expiresAt?: string; + @Type(() => Number) @IsInt() @IsIn(PLUGIN_PLAN_MONTHS as unknown as number[]) diff --git a/src/plugins/plugins.service.ts b/src/plugins/plugins.service.ts index 10e3e0d..a6f49a6 100644 --- a/src/plugins/plugins.service.ts +++ b/src/plugins/plugins.service.ts @@ -248,11 +248,20 @@ export class PluginsService implements OnModuleInit, OnModuleDestroy { let planMonths = dto.planMonths ?? null; let expiresAt: Date | null = null; + if (dto.expiresAt) { + expiresAt = new Date(dto.expiresAt); + if (Number.isNaN(expiresAt.getTime())) { + throw new BadRequestException('تاریخ انقضا نامعتبر است'); + } + } + if (chargedAt && planMonths) { if (!PLUGIN_PLAN_MONTHS.includes(planMonths as any)) { throw new BadRequestException('مدت اشتراک نامعتبر است'); } - expiresAt = addIranPlanExpiry(chargedAt, planMonths); + if (!expiresAt) { + expiresAt = addIranPlanExpiry(chargedAt, planMonths); + } } const settingKey = @@ -330,7 +339,16 @@ export class PluginsService implements OnModuleInit, OnModuleDestroy { if (dto.planMonths !== undefined) { planMonths = dto.planMonths; } - if ( + if (dto.expiresAt !== undefined) { + if (dto.expiresAt) { + expiresAt = new Date(dto.expiresAt); + if (Number.isNaN(expiresAt.getTime())) { + throw new BadRequestException('تاریخ انقضا نامعتبر است'); + } + } else { + expiresAt = null; + } + } else if ( (dto.chargedAt !== undefined || dto.planMonths !== undefined) && chargedAt && planMonths @@ -358,7 +376,9 @@ export class PluginsService implements OnModuleInit, OnModuleDestroy { ...(dto.priceRials !== undefined && { priceRials: dto.priceRials }), ...(dto.chargedAt !== undefined && { chargedAt }), ...(dto.planMonths !== undefined && { planMonths }), - ...(dto.chargedAt !== undefined || dto.planMonths !== undefined + ...(dto.chargedAt !== undefined || + dto.planMonths !== undefined || + dto.expiresAt !== undefined ? { expiresAt } : {}), ...(dto.alertDaysBefore !== undefined && { @@ -406,7 +426,10 @@ export class PluginsService implements OnModuleInit, OnModuleDestroy { if (Number.isNaN(chargedAt.getTime())) { throw new BadRequestException('تاریخ شارژ نامعتبر است'); } - const expiresAt = addIranPlanExpiry(chargedAt, dto.planMonths); + let expiresAt = dto.expiresAt ? new Date(dto.expiresAt) : addIranPlanExpiry(chargedAt, dto.planMonths); + if (Number.isNaN(expiresAt.getTime())) { + throw new BadRequestException('تاریخ انقضا نامعتبر است'); + } await this.prisma.$transaction([ this.prisma.pluginSubscription.update({