feat: Add validation and improve error messaging for CSV import

This commit is contained in:
2026-01-02 16:21:51 +05:30
parent e06172c000
commit 79a65547e1

View File

@@ -566,7 +566,7 @@ export async function searchPermitByAddress(address: string) {
.limit(1);
}
export async function bulkImport(csvData: Object[], user: AuthenticatedUser) {
export async function bulkImport(csvData: any[], user: AuthenticatedUser) {
const allowedFields = [
"Permit Number",
"County",
@@ -584,22 +584,26 @@ export async function bulkImport(csvData: Object[], user: AuthenticatedUser) {
const failed = [];
const created = [];
const clientCache = {};
const countyCache = {};
// Validation run
for (const [index, record] of csvData.entries()) {
try {
const errors = [];
if (!record["Permit Number"]) {
failed.push(index);
continue;
errors.push("Permit Number is empty");
} else if (!record["County"]) {
errors.push("County is empty");
} else if (!record["Client"]) {
errors.push("Client is empty");
} else if (!record["Address"]) {
errors.push("Address is empty");
}
const permitInDb = await permitModel.findOne({
permitNumber: record["Permit Number"],
});
if (!permitInDb) {
let clientData = null;
let countyData = null;
if (record["Client"]) {
if (record["County"] && record["Client"]) {
let clientData = clientCache[record["Client"]];
if (!clientData) {
const clientInDb = await orgModel.findOne({ name: record["Client"] });
if (clientInDb) {
clientData = {
@@ -609,10 +613,17 @@ export async function bulkImport(csvData: Object[], user: AuthenticatedUser) {
name: clientInDb.name,
avatar: clientInDb.avatar,
};
clientCache[record["Client"]] = clientData;
} else {
errors.push("Client not found");
}
}
if (record["County"]) {
csvData[index].clientData = clientData;
let countyData = countyCache[record["County"]];
if (!countyData) {
const countyInDb = await orgModel.findOne({ name: record["County"] });
if (countyInDb) {
countyData = {
@@ -621,16 +632,36 @@ export async function bulkImport(csvData: Object[], user: AuthenticatedUser) {
name: countyInDb.name,
avatar: countyInDb.avatar,
};
countyCache[record["County"]] = countyData;
} else {
errors.push("County not found");
}
}
csvData[index].countyData = countyData;
}
if (errors.length > 0) failed.push({ rowId: index + 2, errors });
}
if (failed.length > 0) return { created, failed, allowedFields };
// Main run
for (const [index, record] of csvData.entries()) {
try {
const permitInDb = await permitModel.findOne({
permitNumber: record["Permit Number"],
});
if (!permitInDb) {
const newPermit = await permitModel.create({
tenantId: user.tenantId,
pid: generateId(),
permitNumber: record["Permit Number"],
county: countyData,
client: clientData?.id,
clientData: clientData,
county: record.countyData,
client: record.clientData?.id,
clientData: record.clientData,
cleanStatus: record["County Status"],
address: record["Address"],
recordType: record["Record Type"],
@@ -649,10 +680,17 @@ export async function bulkImport(csvData: Object[], user: AuthenticatedUser) {
});
created.push(populatedPermit);
} else {
failed.push({
rowId: index + 2,
errors: [
`Permit with this number: ${record["Permit Number"]} already exists`,
],
});
}
} catch (err) {
console.log(err);
failed.push(index + 2);
failed.push({ rowId: index + 2, errors: ["Internal Error"] });
}
}