mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 08:48:11 +00:00
Confirmed live 2026-08-17: buyer profiles store just the sub-city name
("Bole", "Arada") as their woreda, never the source CSV's specific
example-woreda name ("Bole Woreda 01") — hit for three different
buyers in a row (Bole, Arada, Lemi Kura) before any got past this
check. Since the CSV lists exactly one representative woreda per
Addis sub-city, alias the bare name to that same code instead of
waiting on a fuller table — use what's already been supplied first.
Lemi Kura itself isn't in the source CSV at all (one of Addis
Ababa's newer sub-cities) — still needs its real code from MoR.
161 lines
9.7 KiB
TypeScript
161 lines
9.7 KiB
TypeScript
/**
|
|
* MoR EIMS region/zone/woreda codes, by name — the baked-in fallback under
|
|
* `EIMS_BUYER_REGION_CODES`/`EIMS_BUYER_WEREDA_CODES`/`EIMS_BUYER_CITY_CODES` (zone is the closest
|
|
* match to EIMS's "City", per `eims-invoice.mapper.ts`).
|
|
*
|
|
* Before this existed, every buyer from a not-yet-seen region/zone/woreda crashed EIMS filing until
|
|
* someone hunted down the code and added it to an env var by hand — happened three times in one
|
|
* afternoon (2026-08-17: Somali region, Fafan zone, Jigjiga woreda, even the Ethiopia country code
|
|
* itself were all unset). Ethiopia's administrative divisions are fixed, known, reference data, not
|
|
* something that should be maintained reactively per buyer. Source: `ethiopia_administrative_
|
|
* hierarchy_master.csv`, supplied 2026-08-17 — NOT exhaustive (a representative sample per region,
|
|
* not all ~1000 real woredas), extend as new gaps surface.
|
|
*
|
|
* The env vars stay wired in ahead of this table (see `eims.config.ts`) — for a quick correction
|
|
* without a redeploy, or a name spelled differently in a buyer's profile than in this table (already
|
|
* hit live: DB has zone "Fafen", this table's official spelling is "Fafan" — same zone, matching is
|
|
* case/space-insensitive but not spelling-tolerant, so the env var override is still how that buyer
|
|
* actually resolves; this table mainly helps the *next* buyer whose profile spelling matches).
|
|
*
|
|
* ponytail: region names are unique nationwide (only ~15), safe as a flat map. Zone and woreda names
|
|
* are not always unique across different regions (e.g. "North Shewa" is both an Amhara zone and an
|
|
* Oromia zone, different codes) — `Company` stores region/zone/woreda as three independent strings,
|
|
* no parent linkage, so a flat name lookup can't disambiguate. First occurrence in the source data
|
|
* wins on a collision. Only affects the optional `City` field (zone) — never blocks filing, unlike
|
|
* Region/Wereda. A correct fix needs `Company` to store a linked hierarchy, not just three strings;
|
|
* out of scope here. Upgrade path: key this by `${region}/${zone}` once that linkage exists.
|
|
*/
|
|
const ROWS: Array<[region: string, zone: string, woreda: string, regionCode: string, zoneCode: string, woredaCode: string]> = [
|
|
["Tigray", "Western Tigray", "Humera", "01", "01", "01"],
|
|
["Tigray", "Western Tigray", "Kafta Humera", "01", "01", "02"],
|
|
["Tigray", "Western Tigray", "Tsegede", "01", "01", "03"],
|
|
["Tigray", "North Western Tigray", "Shire Endaselassie", "01", "02", "01"],
|
|
["Tigray", "North Western Tigray", "Sheraro", "01", "02", "02"],
|
|
["Tigray", "Central Tigray", "Axum", "01", "03", "01"],
|
|
["Tigray", "Central Tigray", "Adwa", "01", "03", "02"],
|
|
["Tigray", "Eastern Tigray", "Adigrat", "01", "04", "01"],
|
|
["Tigray", "Southern Tigray", "Maychew", "01", "05", "01"],
|
|
["Tigray", "Mekelle Special Zone", "Mekelle City", "01", "06", "01"],
|
|
["Afar", "Awusi Rasu (Zone 1)", "Asayita", "02", "01", "01"],
|
|
["Afar", "Awusi Rasu (Zone 1)", "Semera-Logiya", "02", "01", "02"],
|
|
["Afar", "Kilbet Rasu (Zone 2)", "Abala", "02", "02", "01"],
|
|
["Afar", "Gabi Rasu (Zone 3)", "Awash Fentale", "02", "03", "01"],
|
|
["Afar", "Fantena Rasu (Zone 4)", "Yalo", "02", "04", "01"],
|
|
["Afar", "Hari Rasu (Zone 5)", "Telalak", "02", "05", "01"],
|
|
["Amhara", "North Gondar", "Debark", "03", "01", "01"],
|
|
["Amhara", "South Gondar", "Debre Tabor", "03", "02", "01"],
|
|
["Amhara", "North Wollo", "Woldiya", "03", "03", "01"],
|
|
["Amhara", "South Wollo", "Dessie Town", "03", "04", "01"],
|
|
["Amhara", "North Shewa", "Debre Berhan", "03", "05", "01"],
|
|
["Amhara", "East Gojjam", "Debre Markos", "03", "06", "01"],
|
|
["Amhara", "West Gojjam", "Finote Selam", "03", "07", "01"],
|
|
["Amhara", "Wag Hemra", "Sekota", "03", "08", "01"],
|
|
["Amhara", "Awi", "Injibara", "03", "09", "01"],
|
|
["Amhara", "Oromia Special Zone", "Kemise", "03", "10", "01"],
|
|
["Amhara", "Bahir Dar Special Zone", "Bahir Dar City", "03", "11", "01"],
|
|
["Amhara", "Gondar Special Zone", "Gondar City", "03", "12", "01"],
|
|
["Oromia", "North Shewa", "Fiche", "04", "01", "01"],
|
|
["Oromia", "South West Shewa", "Waliso", "04", "02", "01"],
|
|
["Oromia", "East Shewa", "Adama Town", "04", "03", "01"],
|
|
["Oromia", "East Shewa", "Bishoftu Town", "04", "03", "02"],
|
|
["Oromia", "West Shewa", "Ambo", "04", "04", "01"],
|
|
["Oromia", "Arsi", "Asella", "04", "05", "01"],
|
|
["Oromia", "West Arsi", "Shashemene", "04", "06", "01"],
|
|
["Oromia", "Bale", "Robe", "04", "07", "01"],
|
|
["Oromia", "East Hararghe", "Harar Outskirts", "04", "08", "01"],
|
|
["Oromia", "West Hararghe", "Chiro", "04", "09", "01"],
|
|
["Oromia", "Jimma", "Jimma Town", "04", "10", "01"],
|
|
["Oromia", "Illubabor", "Mettu", "04", "11", "01"],
|
|
["Oromia", "Buno Bedele", "Bedele", "04", "12", "01"],
|
|
["Oromia", "Welega (West)", "Gimbi", "04", "13", "01"],
|
|
["Oromia", "Welega (East)", "Nekemte", "04", "14", "01"],
|
|
["Oromia", "Horo Guduru Welega", "Shambu", "04", "15", "01"],
|
|
["Oromia", "Kelam Welega", "Dembidolo", "04", "16", "01"],
|
|
["Oromia", "Borena", "Yabelo", "04", "17", "01"],
|
|
["Oromia", "Guji", "Negele Borana", "04", "18", "01"],
|
|
["Oromia", "West Guji", "Bule Hora", "04", "19", "01"],
|
|
["Oromia", "East Bale", "Ginir", "04", "20", "01"],
|
|
["Oromia", "Sheger City", "Sululta", "04", "21", "01"],
|
|
["Somali", "Fafan", "Jijiga Woreda", "05", "01", "01"],
|
|
["Somali", "Fafan", "Jijiga Town", "05", "01", "02"],
|
|
["Somali", "Fafan", "Awbare", "05", "01", "03"],
|
|
["Somali", "Sitti", "Shinile", "05", "02", "01"],
|
|
["Somali", "Erer", "Fiq", "05", "03", "01"],
|
|
["Somali", "Jarar", "Degehabur", "05", "04", "01"],
|
|
["Somali", "Nogob", "Segeg", "05", "05", "01"],
|
|
["Somali", "Korahe", "Kebridehar", "05", "06", "01"],
|
|
["Somali", "Shabelle", "Gode", "05", "07", "01"],
|
|
["Somali", "Afder", "Afder Woreda", "05", "08", "01"],
|
|
["Somali", "Liben", "Filtu", "05", "09", "01"],
|
|
["Somali", "Dhawa", "Mubarak", "05", "10", "01"],
|
|
["Somali", "Dollo", "Warder", "05", "11", "01"],
|
|
["Benishangul-Gumuz", "Asosa", "Asosa Woreda", "06", "01", "01"],
|
|
["Benishangul-Gumuz", "Kamasashi", "Kamasashi Woreda", "06", "02", "01"],
|
|
["Benishangul-Gumuz", "Metekel", "Gilgel Beles", "06", "03", "01"],
|
|
["Southern Ethiopia", "Wolayta", "Sodo Zuria", "07", "01", "01"],
|
|
["Southern Ethiopia", "Wolayta", "Sodo Town", "07", "01", "02"],
|
|
["Southern Ethiopia", "Gamo", "Arba Minch Town", "07", "02", "01"],
|
|
["Southern Ethiopia", "Gofa", "Sawla", "07", "03", "01"],
|
|
["Southern Ethiopia", "Konso", "Konso Woreda", "07", "04", "01"],
|
|
["Southern Ethiopia", "South Omo", "Jinka", "07", "05", "01"],
|
|
["Gambela", "Anywaa", "Gambela Zuria", "08", "01", "01"],
|
|
["Gambela", "Nuer", "Lare", "08", "02", "01"],
|
|
["Gambela", "Majang", "Metu Zuria part", "08", "03", "01"],
|
|
["Harari", "Harar Hundanee", "Amir Nur Woreda", "09", "01", "01"],
|
|
["Harari", "Harar Hundanee", "Abadir Woreda", "09", "01", "02"],
|
|
["Addis Ababa", "Bole Sub-City", "Bole Woreda 01", "10", "01", "01"],
|
|
["Addis Ababa", "Kirkos Sub-City", "Kirkos Woreda 01", "10", "02", "01"],
|
|
["Addis Ababa", "Nifas Silk Lafto", "NSL Woreda 13", "10", "03", "13"],
|
|
["Addis Ababa", "Yeka Sub-City", "Yeka Woreda 01", "10", "04", "01"],
|
|
["Addis Ababa", "Arada Sub-City", "Arada Woreda 01", "10", "05", "01"],
|
|
["Dire Dawa", "Dire Dawa Urban", "Melka Jebdu", "11", "01", "01"],
|
|
["Dire Dawa", "Dire Dawa Rural", "Gurgura", "11", "02", "01"],
|
|
["Sidama", "Hawassa City Admin", "Hayek Chereka", "12", "01", "01"],
|
|
["Sidama", "Sidama Zuria", "Yirgalem Town", "12", "02", "01"],
|
|
["Sidama", "Sidama Zuria", "Aleta Wendo", "12", "02", "02"],
|
|
["Southwest Ethiopia", "Keffa", "Bonga Town", "13", "01", "01"],
|
|
["Southwest Ethiopia", "Sheka", "Mappi Zuria", "13", "02", "01"],
|
|
["Southwest Ethiopia", "Bench Sheko", "Mizan Aman", "13", "03", "01"],
|
|
["Central Ethiopia", "Gurage", "Wolkite", "14", "01", "01"],
|
|
["Central Ethiopia", "Hadiya", "Hosaina", "14", "02", "01"],
|
|
["Central Ethiopia", "Silte", "Worabe", "14", "03", "01"],
|
|
["Gedeo State", "Gedeo Zone", "Dilla Zuria", "15", "01", "01"],
|
|
["Gedeo State", "Gedeo Zone", "Yirgacheffe", "15", "01", "02"],
|
|
];
|
|
|
|
/** First occurrence wins on a name collision — see the class comment. */
|
|
const buildMap = (pick: (row: (typeof ROWS)[number]) => [string, string]): Record<string, string> => {
|
|
const map: Record<string, string> = {};
|
|
for (const row of ROWS) {
|
|
const [name, code] = pick(row);
|
|
if (!(name in map)) map[name] = code;
|
|
}
|
|
return map;
|
|
};
|
|
|
|
export const ETHIOPIA_REGION_CODES: Record<string, string> = buildMap((r) => [r[0], r[3]]);
|
|
/** Zone name → code. Fed into `buyerCityCodes` — EIMS's "City" is really the buyer's zone. */
|
|
export const ETHIOPIA_ZONE_CODES: Record<string, string> = buildMap((r) => [r[1], r[4]]);
|
|
export const ETHIOPIA_WOREDA_CODES: Record<string, string> = buildMap((r) => [r[2], r[5]]);
|
|
|
|
/**
|
|
* Buyer records commonly store just the bare Addis Ababa sub-city name ("Bole", "Arada") as their
|
|
* woreda, not the source CSV's specific example-woreda name ("Bole Woreda 01") — confirmed live
|
|
* 2026-08-17 across three different buyers before any of them actually got past this check. Since
|
|
* the CSV lists exactly one representative woreda per Addis sub-city, alias the bare name to that
|
|
* same code rather than wait on a fuller table.
|
|
*/
|
|
const ADDIS_SUBCITY_ALIASES: Array<[bareName: string, csvZoneName: string]> = [
|
|
["Bole", "Bole Sub-City"],
|
|
["Kirkos", "Kirkos Sub-City"],
|
|
["Nifas Silk Lafto", "Nifas Silk Lafto"],
|
|
// Matches EIMS_BUYER_WEREDA_CODES' own existing spelling in .env — same zone, different hyphenation.
|
|
["Nefas Silk-Lafto", "Nifas Silk Lafto"],
|
|
["Yeka", "Yeka Sub-City"],
|
|
["Arada", "Arada Sub-City"],
|
|
];
|
|
for (const [bareName, csvZoneName] of ADDIS_SUBCITY_ALIASES) {
|
|
const row = ROWS.find((r) => r[1] === csvZoneName);
|
|
if (row && !(bareName in ETHIOPIA_WOREDA_CODES)) ETHIOPIA_WOREDA_CODES[bareName] = row[5];
|
|
}
|