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:
@@ -1,4 +1,8 @@
|
|||||||
/** کلیدهای deploy_settings_const — داخل باندل کامپایل میشود تا ایمپورت به فایل prisma وابسته نباشد. */
|
/**
|
||||||
|
* کلیدهای INSERT در khaneghi_server/database/sql/deploy_settings_const.sql
|
||||||
|
* منبع قالب ایمپورت سوپرادمین — داخل باندل تا به فایل prisma وابسته نباشد.
|
||||||
|
* این ۱۹۵ کلید با SQL فعلی همتراز است؛ کلید داخل این مجموعه در مودال «تصمیم برای هر کلید» نمیآید.
|
||||||
|
*/
|
||||||
export const DEPLOY_SETTING_CATALOG_KEYS = new Set<string>([
|
export const DEPLOY_SETTING_CATALOG_KEYS = new Set<string>([
|
||||||
"accounting_provider",
|
"accounting_provider",
|
||||||
"admin_url",
|
"admin_url",
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ export class ProgramSettingsService implements OnModuleInit {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** پیشنمایش ایمپورت — برای هر کلید تصمیمگیری لازم است */
|
/** پیشنمایش ایمپورت — تصمیم فقط برای کلید خارج از قالب deploy_settings_const */
|
||||||
async previewImport(tenantId: string, mobile: string, password: string) {
|
async previewImport(tenantId: string, mobile: string, password: string) {
|
||||||
const tenant = await this.requireKhanegiTenant(tenantId);
|
const tenant = await this.requireKhanegiTenant(tenantId);
|
||||||
const mobileNorm = this.normalizeAdminMobile(mobile);
|
const mobileNorm = this.normalizeAdminMobile(mobile);
|
||||||
@@ -194,7 +194,8 @@ export class ProgramSettingsService implements OnModuleInit {
|
|||||||
await this.ensureTemplatesSeeded();
|
await this.ensureTemplatesSeeded();
|
||||||
const remote = await this.fetchSystemSettings(apiBase, token);
|
const remote = await this.fetchSystemSettings(apiBase, token);
|
||||||
const local = await this.listTenantRows(tenantId);
|
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 localByKey = new Map(local.map((row) => [String(row.key), row]));
|
||||||
const remoteByKey = new Map(
|
const remoteByKey = new Map(
|
||||||
remote
|
remote
|
||||||
@@ -212,6 +213,7 @@ export class ProgramSettingsService implements OnModuleInit {
|
|||||||
}> = [];
|
}> = [];
|
||||||
|
|
||||||
for (const [key, row] of remoteByKey) {
|
for (const [key, row] of remoteByKey) {
|
||||||
|
if (catalogKeys.has(key)) continue;
|
||||||
const localRow = localByKey.get(key);
|
const localRow = localByKey.get(key);
|
||||||
const khanegiValue = String(row.value ?? '');
|
const khanegiValue = String(row.value ?? '');
|
||||||
const superadminValue = localRow ? String(localRow.value ?? '') : null;
|
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 {
|
return {
|
||||||
tenant: this.tenantMeta(tenant),
|
tenant: this.tenantMeta(tenant),
|
||||||
@@ -234,7 +242,7 @@ export class ProgramSettingsService implements OnModuleInit {
|
|||||||
onlySuperAdminKeys: onlySuperAdmin,
|
onlySuperAdminKeys: onlySuperAdmin,
|
||||||
importableCount: remoteByKey.size,
|
importableCount: remoteByKey.size,
|
||||||
note:
|
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);
|
const { apiBase, token } = await this.loginKhanegiAdmin(tenant, mobileNorm, password);
|
||||||
await this.ensureTemplatesSeeded();
|
await this.ensureTemplatesSeeded();
|
||||||
const remote = await this.fetchSystemSettings(apiBase, token);
|
const remote = await this.fetchSystemSettings(apiBase, token);
|
||||||
|
const catalogKeys = this.deployCatalogKeySet();
|
||||||
const remoteByKey = new Map(
|
const remoteByKey = new Map(
|
||||||
remote
|
remote
|
||||||
.map((row) => this.normalizeIncoming(row))
|
.map((row) => this.normalizeIncoming(row))
|
||||||
@@ -283,7 +292,8 @@ export class ProgramSettingsService implements OnModuleInit {
|
|||||||
await this.ensureTemplateDefaultsForTenant(tx, tenantId);
|
await this.ensureTemplateDefaultsForTenant(tx, tenantId);
|
||||||
|
|
||||||
for (const [key, row] of remoteByKey) {
|
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;
|
if (scope === 'none') continue;
|
||||||
|
|
||||||
const targetIds = scope === 'all' ? khanegiTenantIds : [tenantId];
|
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 } });
|
const tpl = await tx.settingTemplate.findUnique({ where: { key } });
|
||||||
if (!tpl) {
|
if (!tpl) {
|
||||||
await tx.settingTemplate.create({
|
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);
|
const keys = new Set<string>(DEPLOY_SETTING_CATALOG_KEYS);
|
||||||
for (const row of this.readSeedRows()) {
|
for (const row of this.readSeedRows()) {
|
||||||
const key = String(row.key || '').trim();
|
const key = String(row.key || '').trim();
|
||||||
if (key) keys.add(key);
|
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;
|
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() {
|
private async seedEmptyKhanegiTenants() {
|
||||||
const tenants = await this.prisma.tenant.findMany({
|
const tenants = await this.prisma.tenant.findMany({
|
||||||
where: { product: ProductType.khanegi },
|
where: { product: ProductType.khanegi },
|
||||||
|
|||||||
Reference in New Issue
Block a user