Initial commit: Hedena Gold monorepo.
First commit of the Hedena Gold product (separate from gold-bank): branding, package names, and deploy defaults aligned to the new brand; legacy Henza trees stay local-only via .gitignore.
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* D0 requirement 3 — review report for names that cannot be split safely.
|
||||
*
|
||||
* The migration backfills firstName = first token, lastName = the rest. That is
|
||||
* correct for two-token names and a guess for anything longer: "سید محمد
|
||||
* حسینی" should almost certainly be firstName="سید محمد", and the migration
|
||||
* writes firstName="سید" instead. Those rows need a human.
|
||||
*
|
||||
* READ-ONLY. It changes nothing; it prints what a person has to check.
|
||||
*
|
||||
* node scripts/report-name-split.cjs # print to stdout
|
||||
* node scripts/report-name-split.cjs --csv out.csv
|
||||
*
|
||||
* Run it AFTER the 20260922120000_customer_name_parts migration.
|
||||
*/
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
const fs = require('fs');
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
/** Same normalisation the migration's SQL uses. */
|
||||
const tokens = (s) => String(s ?? '').trim().replace(/\s+/g, ' ').split(' ').filter(Boolean);
|
||||
|
||||
(async () => {
|
||||
const customers = await prisma.$queryRawUnsafe(`
|
||||
SELECT id, "fullName", "firstName", "lastName", mobile, "memberCode"
|
||||
FROM "Customer"
|
||||
ORDER BY "createdAt"
|
||||
`);
|
||||
|
||||
const multi = [];
|
||||
const empty = [];
|
||||
const single = [];
|
||||
|
||||
for (const c of customers) {
|
||||
const t = tokens(c.fullName);
|
||||
if (t.length === 0) empty.push(c);
|
||||
else if (t.length === 1) single.push(c);
|
||||
else if (t.length > 2) multi.push({ ...c, tokenCount: t.length });
|
||||
}
|
||||
|
||||
console.log(`Customers scanned: ${customers.length}`);
|
||||
console.log(` two tokens (split is reliable): ${customers.length - multi.length - empty.length - single.length}`);
|
||||
console.log(` one token (lastName is NULL): ${single.length}`);
|
||||
console.log(` empty name (nothing to split): ${empty.length}`);
|
||||
console.log(` MORE THAN TWO TOKENS — NEEDS REVIEW: ${multi.length}`);
|
||||
|
||||
if (single.length) {
|
||||
console.log('\n--- single-token names (no surname recorded) ---');
|
||||
for (const c of single) console.log(` ${c.id} ${c.mobile} "${c.fullName}"`);
|
||||
}
|
||||
if (empty.length) {
|
||||
console.log('\n--- empty names ---');
|
||||
for (const c of empty) console.log(` ${c.id} ${c.mobile}`);
|
||||
}
|
||||
|
||||
if (multi.length) {
|
||||
console.log('\n--- NEEDS REVIEW: more than two tokens ---');
|
||||
console.log('The migration guessed first-token / rest. Verify each one.\n');
|
||||
for (const c of multi) {
|
||||
console.log(` ${c.id} ${c.mobile} (${c.tokenCount} tokens)`);
|
||||
console.log(` fullName : "${c.fullName}"`);
|
||||
console.log(` guessed : firstName="${c.firstName}" lastName="${c.lastName}"`);
|
||||
}
|
||||
}
|
||||
|
||||
const csvArg = process.argv.indexOf('--csv');
|
||||
if (csvArg !== -1 && process.argv[csvArg + 1]) {
|
||||
const esc = (v) => `"${String(v ?? '').replace(/"/g, '""')}"`;
|
||||
const rows = [
|
||||
['id', 'mobile', 'memberCode', 'fullName', 'guessedFirstName', 'guessedLastName', 'tokenCount'].join(','),
|
||||
...multi.map((c) =>
|
||||
[c.id, c.mobile, c.memberCode, c.fullName, c.firstName, c.lastName, c.tokenCount].map(esc).join(','),
|
||||
),
|
||||
];
|
||||
// BOM so Excel opens the Persian text in the right encoding.
|
||||
fs.writeFileSync(process.argv[csvArg + 1], '' + rows.join('\n'), 'utf8');
|
||||
console.log(`\nCSV written: ${process.argv[csvArg + 1]} (${multi.length} rows)`);
|
||||
}
|
||||
|
||||
await prisma.$disconnect();
|
||||
})().catch(async (e) => {
|
||||
console.error(e);
|
||||
await prisma.$disconnect();
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user