fix(settings): skip deploy_settings_const keys in import decision modal

Catalog keys from the SQL template write onto this tenant automatically; only extra keys need a per-key decision.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-18 19:06:32 +03:30
co-authored by Cursor
parent 71f1fa1092
commit 0b2e4b05f9
2 changed files with 37 additions and 14 deletions
@@ -183,7 +183,7 @@ export class ProgramSettingsService implements OnModuleInit {
};
}
/** پیش‌نمایش ایمپورت — برای هر کلید تصمیم‌گیری لازم است */
/** پیش‌نمایش ایمپورت — تصمیم فقط برای کلید خارج از قالب deploy_settings_const */
async previewImport(tenantId: string, mobile: string, password: string) {
const tenant = await this.requireKhanegiTenant(tenantId);
const mobileNorm = this.normalizeAdminMobile(mobile);
@@ -194,7 +194,8 @@ export class ProgramSettingsService implements OnModuleInit {
await this.ensureTemplatesSeeded();
const remote = await this.fetchSystemSettings(apiBase, token);
const local = await this.listTenantRows(tenantId);
const catalogKeys = await this.catalogKeySet();
const catalogKeys = this.deployCatalogKeySet();
const seedCanEdit = this.deployCatalogCanEditMap();
const localByKey = new Map(local.map((row) => [String(row.key), row]));
const remoteByKey = new Map(
remote
@@ -212,6 +213,7 @@ export class ProgramSettingsService implements OnModuleInit {
}> = [];
for (const [key, row] of remoteByKey) {
if (catalogKeys.has(key)) continue;
const localRow = localByKey.get(key);
const khanegiValue = String(row.value ?? '');
const superadminValue = localRow ? String(localRow.value ?? '') : null;
@@ -225,7 +227,13 @@ export class ProgramSettingsService implements OnModuleInit {
});
}
const onlySuperAdmin = [...catalogKeys].filter((key) => !remoteByKey.has(key));
const onlySuperAdmin = [...catalogKeys].filter((key) => {
if (isRuntimeProgramSettingKey(key)) return false;
if (remoteByKey.has(key)) return false;
const canEdit = seedCanEdit.get(key);
if (canEdit === 1) return false;
return true;
});
return {
tenant: this.tenantMeta(tenant),
@@ -234,7 +242,7 @@ export class ProgramSettingsService implements OnModuleInit {
onlySuperAdminKeys: onlySuperAdmin,
importableCount: remoteByKey.size,
note:
'مقدار کلیدهای can_edit=0 خانگی روی همین پروژه نوشته می‌شود. اگر تصمیم نفرستی، پیش‌فرض «فقط این پروژه» است.',
'کلیدهای قالب deploy_settings_const بدون سؤال روی همین پروژه نوشته می‌شوند. فقط کلید خارج از قالب اینجا می‌آید.',
};
}
@@ -253,6 +261,7 @@ export class ProgramSettingsService implements OnModuleInit {
const { apiBase, token } = await this.loginKhanegiAdmin(tenant, mobileNorm, password);
await this.ensureTemplatesSeeded();
const remote = await this.fetchSystemSettings(apiBase, token);
const catalogKeys = this.deployCatalogKeySet();
const remoteByKey = new Map(
remote
.map((row) => this.normalizeIncoming(row))
@@ -283,7 +292,8 @@ export class ProgramSettingsService implements OnModuleInit {
await this.ensureTemplateDefaultsForTenant(tx, tenantId);
for (const [key, row] of remoteByKey) {
const scope = decisionMap.get(key) ?? 'this';
const inCatalog = catalogKeys.has(key);
const scope = inCatalog ? 'this' : (decisionMap.get(key) ?? 'this');
if (scope === 'none') continue;
const targetIds = scope === 'all' ? khanegiTenantIds : [tenantId];
@@ -295,7 +305,8 @@ export class ProgramSettingsService implements OnModuleInit {
});
}
// کلید جدید از خانگی → وارد قالب هم بشود اگر نبود
if (inCatalog) continue;
const tpl = await tx.settingTemplate.findUnique({ where: { key } });
if (!tpl) {
await tx.settingTemplate.create({
@@ -510,21 +521,29 @@ export class ProgramSettingsService implements OnModuleInit {
}
}
/** کلیدهای deploy const (داخل باندل) + فایل seed + جدول قالب. */
private async catalogKeySet() {
/**
* قالب ایمپورت = کلیدهای INSERT در deploy_settings_const.sql
* (باندل + JSON هم‌تراز همان فایل). جدول setting_templates منبع قالب نیست.
*/
private deployCatalogKeySet() {
const keys = new Set<string>(DEPLOY_SETTING_CATALOG_KEYS);
for (const row of this.readSeedRows()) {
const key = String(row.key || '').trim();
if (key) keys.add(key);
}
const rows = await this.prisma.settingTemplate.findMany({
where: { deletedAt: null },
select: { key: true },
});
for (const row of rows as Array<{ key: string }>) keys.add(row.key);
return keys;
}
private deployCatalogCanEditMap() {
const map = new Map<string, number>();
for (const row of this.readSeedRows()) {
const key = String(row.key || '').trim();
if (!key) continue;
map.set(key, this.toSmallInt(row.can_edit, 0));
}
return map;
}
private async seedEmptyKhanegiTenants() {
const tenants = await this.prisma.tenant.findMany({
where: { product: ProductType.khanegi },