Fix plugin purchase 500 when subscription catalog columns are missing.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -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");
|
||||||
@@ -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;
|
||||||
where: { tenantId, settingKey: item.settingKey, isActive: true },
|
try {
|
||||||
orderBy: { expiresAt: 'desc' },
|
sub = await this.prisma.pluginSubscription.findFirst({
|
||||||
});
|
where: { tenantId, settingKey: item.settingKey, isActive: true },
|
||||||
|
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,35 +743,50 @@ export class PluginStoreService implements OnModuleInit, OnModuleDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const created = await this.prisma.pluginPurchaseRequest.create({
|
try {
|
||||||
data: {
|
const created = await this.prisma.pluginPurchaseRequest.create({
|
||||||
tenantId,
|
data: {
|
||||||
catalogItemId: item.id,
|
tenantId,
|
||||||
durationDays: dto.durationDays,
|
catalogItemId: item.id,
|
||||||
originalPriceRials: price.originalPriceRials,
|
durationDays: dto.durationDays,
|
||||||
finalPriceRials: price.finalPriceRials,
|
originalPriceRials: price.originalPriceRials,
|
||||||
status: 'pending',
|
finalPriceRials: price.finalPriceRials,
|
||||||
},
|
status: 'pending',
|
||||||
include: {
|
},
|
||||||
catalogItem: { select: { titleFa: true, settingKey: true } },
|
include: {
|
||||||
tenant: { select: { nameFa: true, domain: true } },
|
catalogItem: { select: { titleFa: true, settingKey: true } },
|
||||||
},
|
tenant: { select: { nameFa: true, domain: true } },
|
||||||
});
|
},
|
||||||
|
});
|
||||||
|
|
||||||
this.notify.notifyAdmins(
|
this.notify.notifyAdmins(
|
||||||
`درخواست افزونه: «${created.catalogItem.titleFa}» ${pluginStoreDurationLabel(dto.durationDays)} برای «${created.tenant.nameFa}» (${created.tenant.domain}) — ${price.finalPriceRials.toLocaleString('fa-IR')} ریال`,
|
`درخواست افزونه: «${created.catalogItem.titleFa}» ${pluginStoreDurationLabel(dto.durationDays)} برای «${created.tenant.nameFa}» (${created.tenant.domain}) — ${price.finalPriceRials.toLocaleString('fa-IR')} ریال`,
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.toRequestRow({
|
return this.toRequestRow({
|
||||||
...created,
|
...created,
|
||||||
tenant: {
|
tenant: {
|
||||||
id: tenantId,
|
id: tenantId,
|
||||||
nameFa: created.tenant.nameFa,
|
nameFa: created.tenant.nameFa,
|
||||||
domain: created.tenant.domain,
|
domain: created.tenant.domain,
|
||||||
slug: '',
|
slug: '',
|
||||||
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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user