Fix plugin purchase 500 when subscription catalog columns are missing.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-10 10:33:48 +03:30
co-authored by Cursor
parent 6cc10e3333
commit cf92635c0e
2 changed files with 66 additions and 31 deletions
@@ -0,0 +1,13 @@
-- Catalog linkage on plugin_subscriptions was in schema.prisma without a
-- CREATE COLUMN migration. Remote store GET swallows the missing column;
-- POST create did not, so purchase requests returned HTTP 500.
ALTER TABLE "plugin_subscriptions"
ADD COLUMN IF NOT EXISTS "setting_key" VARCHAR(50);
ALTER TABLE "plugin_subscriptions"
ADD COLUMN IF NOT EXISTS "auto_cut_on_expiry" BOOLEAN NOT NULL DEFAULT false;
ALTER TABLE "plugin_subscriptions"
ADD COLUMN IF NOT EXISTS "alert_marks" JSONB;
CREATE INDEX IF NOT EXISTS "plugin_subscriptions_setting_key_idx"
ON "plugin_subscriptions"("setting_key");
+23 -1
View File
@@ -3,6 +3,7 @@ import {
ConflictException, ConflictException,
ForbiddenException, ForbiddenException,
Injectable, Injectable,
InternalServerErrorException,
Logger, Logger,
NotFoundException, NotFoundException,
OnModuleDestroy, OnModuleDestroy,
@@ -722,10 +723,16 @@ export class PluginStoreService implements OnModuleInit, OnModuleDestroy {
throw new ConflictException('درخواست در انتظار برای این افزونه وجود دارد'); throw new ConflictException('درخواست در انتظار برای این افزونه وجود دارد');
} }
const sub = await this.prisma.pluginSubscription.findFirst({ let sub: { isActive: boolean; expiresAt: Date | null } | null = null;
try {
sub = await this.prisma.pluginSubscription.findFirst({
where: { tenantId, settingKey: item.settingKey, isActive: true }, where: { tenantId, settingKey: item.settingKey, isActive: true },
orderBy: { expiresAt: 'desc' }, orderBy: { expiresAt: 'desc' },
select: { isActive: true, expiresAt: true },
}); });
} catch (error: any) {
this.logger.warn(`remoteCreateRequest sub skipped: ${error?.message || error}`);
}
if (sub?.isActive && !sub.expiresAt) { if (sub?.isActive && !sub.expiresAt) {
throw new ConflictException('این افزونه یکبار پرداخت شده و فعال است'); throw new ConflictException('این افزونه یکبار پرداخت شده و فعال است');
} }
@@ -736,6 +743,7 @@ export class PluginStoreService implements OnModuleInit, OnModuleDestroy {
} }
} }
try {
const created = await this.prisma.pluginPurchaseRequest.create({ const created = await this.prisma.pluginPurchaseRequest.create({
data: { data: {
tenantId, tenantId,
@@ -765,6 +773,20 @@ export class PluginStoreService implements OnModuleInit, OnModuleDestroy {
product: ProductType.khanegi, product: ProductType.khanegi,
}, },
} as any); } as any);
} catch (error: any) {
if (
error instanceof BadRequestException ||
error instanceof ConflictException ||
error instanceof ForbiddenException ||
error instanceof NotFoundException
) {
throw error;
}
this.logger.error(`remoteCreateRequest failed: ${error?.message || error}`);
throw new InternalServerErrorException(
error?.message || 'ثبت درخواست افزونه ناموفق بود',
);
}
} }
async remoteCancelRequest(tenantId: string, product: string, requestId: string) { async remoteCancelRequest(tenantId: string, product: string, requestId: string) {