feat: routines module; super admin subscription badge, 7-day trial and lifetime plan

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-06 19:54:38 +03:30
co-authored by Cursor
parent 3de2d0fa67
commit b3784818fc
58 changed files with 13018 additions and 18 deletions
+2 -2
View File
@@ -124,8 +124,8 @@ export class ResetPlatformUserPasswordDto {
}
export class ApplyBillingPlanDto {
@IsIn(['trial', 'monthly', 'quarterly', 'semiannual', 'yearly', 'custom'])
planCode!: 'trial' | 'monthly' | 'quarterly' | 'semiannual' | 'yearly' | 'custom';
@IsIn(['trial', 'monthly', 'quarterly', 'semiannual', 'yearly', 'lifetime', 'custom'])
planCode!: 'trial' | 'monthly' | 'quarterly' | 'semiannual' | 'yearly' | 'lifetime' | 'custom';
@IsOptional()
@IsInt()
+18 -2
View File
@@ -18,7 +18,7 @@ import { normalizeMobile } from '../auth/auth.service';
import { MembershipsService } from '../memberships/memberships.service';
import { OrgRolesService } from '../org-roles/org-roles.service';
import { PipelinesService } from '../pipelines/pipelines.service';
import { BillingService } from '../billing/billing.service';
import { BillingService, toSummary } from '../billing/billing.service';
import { PrismaService } from '../prisma/prisma.service';
import { buildSearchWhere, ci } from '../common/search';
import type {
@@ -103,9 +103,21 @@ export class PlatformService {
deals: true,
},
},
memberships: {
where: { role: 'owner', isActive: true },
orderBy: { createdAt: 'asc' },
take: 1,
select: { user: { select: { billingAccount: true } } },
},
},
});
return rows.map((row) => this.orgToDto(row));
return rows.map((row) => {
const account = row.memberships[0]?.user.billingAccount;
return {
...this.orgToDto(row),
subscription: account ? toSummary(account) : null,
};
});
}
async getOrganization(id: string): Promise<PlatformOrganizationDto> {
@@ -144,8 +156,12 @@ export class PlatformService {
},
});
if (!row) throw new NotFoundException('محیط پیدا نشد');
const ownerAccount = row.memberships.find(
(m) => m.role === 'owner' && m.isActive,
)?.user.billingAccount;
return {
...this.orgToDto(row),
subscription: ownerAccount ? toSummary(ownerAccount) : null,
members: row.memberships.map((m) => {
const isBillingOwner = m.role === 'owner';
return {