fix: file upload seeder

This commit is contained in:
Nathnael
2026-08-12 08:39:54 +00:00
parent 2a3a231665
commit abeb296157

View File

@@ -1,6 +1,7 @@
import { Injectable, Logger } from "@nestjs/common";
import { DataSource } from "typeorm";
import { FileUploadField } from "../modules/file-upload-settings/entities/file-upload-field.entity";
import { FileUploadSetting } from "../modules/file-upload-settings/entities/file-upload-setting.entity";
import { poaDelegationField } from "../modules/file-upload-settings/poa-delegation.constants";
@@ -165,10 +166,13 @@ const FOREIGN_ONBOARDING_FIELDS: OnboardingField[] = [
* actually produce is a backoffice decision, edited in the file-settings editor.
*/
const COOPERATIVE_ONBOARDING_FIELDS: OnboardingField[] = [
// First on purpose: only the first field of a new set is seeded, and this is
// the paper that distinguishes a co-operative from every other company.
{
fileKey: "tin_certificate",
fileLabel: "TIN Certificate",
helpText: "Verified against the TIN registry during registration.",
fileKey: "cooperative_registration_certificate",
fileLabel: "Co-operative Union / Farm Registration Certificate",
helpText:
"Certificate issued by the co-operative promotion agency that registered the union or farm.",
isRequired: true,
isMultiple: false,
maxFiles: 1,
@@ -177,10 +181,9 @@ const COOPERATIVE_ONBOARDING_FIELDS: OnboardingField[] = [
displayOrder: 1,
},
{
fileKey: "cooperative_registration_certificate",
fileLabel: "Co-operative Union / Farm Registration Certificate",
helpText:
"Certificate issued by the co-operative promotion agency that registered the union or farm.",
fileKey: "tin_certificate",
fileLabel: "TIN Certificate",
helpText: "Verified against the TIN registry during registration.",
isRequired: true,
isMultiple: false,
maxFiles: 1,
@@ -662,16 +665,15 @@ export class FileUploadSettingsSeeder {
async run() {
const settingRepository = this.dataSource.getRepository(FileUploadSetting);
// Seed only into an empty table: any existing rows (including
// soft-deleted ones, which would still conflict on the unique `code`)
// mean the data is admin-managed, so leave it untouched.
const existing = await settingRepository.count({ withDeleted: true });
if (existing > 0) {
this.logger.log(
`file_upload_settings already has ${existing} rows — skipping seed`,
);
return;
}
// Seed per CODE, not "only into an empty table". An existing row is
// admin-managed and never touched — including a soft-deleted one, which
// means the set was removed on purpose (and would still conflict on the
// unique `code`). What the table-wide check got wrong is the other half: a
// set added to this file after the first boot could never reach a database
// that already held the others, so it existed in code and nowhere else.
const existingCodes = new Set(
(await settingRepository.find({ withDeleted: true })).map((s) => s.code),
);
const allSettings: Array<
OnboardingDocumentSetting & { description: string }
@@ -701,20 +703,41 @@ export class FileUploadSettingsSeeder {
})),
];
// Insert setting rows only — no FileUploadField rows. Fields start empty
// and are configured from the backoffice file-settings editor; the field
// definitions above are kept as reference defaults.
await settingRepository.insert(
allSettings.map((documentSetting) => ({
code: documentSetting.code,
label: documentSetting.label,
description: documentSetting.description,
entity: documentSetting.entity,
})),
const missing = allSettings.filter((s) => !existingCodes.has(s.code));
if (missing.length === 0) {
this.logger.log("file upload settings up to date — nothing to seed");
return;
}
const inserted = await settingRepository.save(
missing.map((documentSetting) =>
settingRepository.create({
code: documentSetting.code,
label: documentSetting.label,
description: documentSetting.description,
entity: documentSetting.entity,
}),
),
);
// A brand-new set gets exactly ONE field: its first reference default. The
// rest of the list above stays documentation — what a set actually asks for
// is a backoffice decision, edited in the file-settings editor. Seeding one
// means a set is never born empty (an empty set silently requires nothing),
// while leaving the admin a single row to extend rather than a list to prune.
const fieldRepository = this.dataSource.getRepository(FileUploadField);
const firstFields = inserted.flatMap((setting) => {
const reference = missing.find((s) => s.code === setting.code)?.fields[0];
return reference
? [fieldRepository.create({ ...reference, settingId: setting.id })]
: [];
});
if (firstFields.length > 0) await fieldRepository.save(firstFields);
this.logger.log(
`Seeded ${allSettings.length} file upload settings with empty fields`,
`Seeded ${missing.length} file upload settings (${firstFields.length} with a default field): ${missing
.map((s) => s.code)
.join(", ")}`,
);
}
}