mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 00:10:57 +00:00
BuyerDetails Country/Region/City/Wereda now resolve from the Ministry's own EIMS_COUNTRY_REGION_VW master instead of the EIMS_BUYER_*_CODES env maps and the ethiopia-geo-codes table. Both invented their codes and looked names up globally, so KERSA/GORO/BABILE/BURE — each present in several zones with different LOCALITY_NOs — could be filed against the wrong jurisdiction. Resolution is hierarchical and refuses to guess: an unknown or ambiguous address raises a local validation error naming the level that failed, and never selects the first matching row. Spelling differences between EDR and MoR live in a reviewed, parent-scoped alias layer; the dataset itself stays verbatim so it remains traceable to the Ministry sheet. Resolution now runs before the counter reservation in both the single and bulk paths, so a bad company address no longer burns an EIMS sequence number. Adds eims:import-locations to regenerate the dataset from a future workbook, reporting duplicate rows and same-hierarchy code conflicts.
73 lines
2.1 KiB
TypeScript
73 lines
2.1 KiB
TypeScript
import eimsConfigFactory from "./eims.config";
|
|
|
|
const REQUIRED = {
|
|
EIMS_ENABLED: "true",
|
|
EIMS_CLIENT_ID: "cid",
|
|
EIMS_CLIENT_SECRET: "secret",
|
|
EIMS_API_KEY: "apikey",
|
|
EIMS_TIN: "0000000000",
|
|
};
|
|
|
|
const withEnv = (vars: Record<string, string | undefined>, fn: () => void) => {
|
|
const prior: Record<string, string | undefined> = {};
|
|
for (const [key, value] of Object.entries(vars)) {
|
|
prior[key] = process.env[key];
|
|
if (value === undefined) delete process.env[key];
|
|
else process.env[key] = value;
|
|
}
|
|
try {
|
|
fn();
|
|
} finally {
|
|
for (const [key, value] of Object.entries(prior)) {
|
|
if (value === undefined) delete process.env[key];
|
|
else process.env[key] = value;
|
|
}
|
|
}
|
|
};
|
|
|
|
describe("eims.config — private key / certificate resolution", () => {
|
|
it("unescapes a literal \\n when the PEM was pasted without real newlines", () => {
|
|
withEnv(
|
|
{ ...REQUIRED, EIMS_PRIVATE_KEY: "line1\\nline2", EIMS_CERTIFICATE_PATH: "/dev/null" },
|
|
() => {
|
|
expect(eimsConfigFactory().privateKeyPem).toBe("line1\nline2");
|
|
},
|
|
);
|
|
});
|
|
|
|
it("leaves a PEM with real newlines untouched", () => {
|
|
withEnv(
|
|
{ ...REQUIRED, EIMS_PRIVATE_KEY: "line1\nline2", EIMS_CERTIFICATE_PATH: "/dev/null" },
|
|
() => {
|
|
expect(eimsConfigFactory().privateKeyPem).toBe("line1\nline2");
|
|
},
|
|
);
|
|
});
|
|
|
|
it("throws naming all three key/cert options when none are set", () => {
|
|
withEnv(
|
|
{
|
|
...REQUIRED,
|
|
EIMS_PRIVATE_KEY_PATH: undefined,
|
|
EIMS_PRIVATE_KEY_BASE64: undefined,
|
|
EIMS_PRIVATE_KEY: undefined,
|
|
EIMS_CERTIFICATE_PATH: "/dev/null",
|
|
},
|
|
() => {
|
|
expect(() => eimsConfigFactory()).toThrow(
|
|
/EIMS_PRIVATE_KEY_PATH or EIMS_PRIVATE_KEY_BASE64 or EIMS_PRIVATE_KEY/,
|
|
);
|
|
},
|
|
);
|
|
});
|
|
|
|
it("is satisfied by any single one of the three key options", () => {
|
|
withEnv(
|
|
{ ...REQUIRED, EIMS_PRIVATE_KEY: "x", EIMS_CERTIFICATE_PATH: "/dev/null" },
|
|
() => {
|
|
expect(() => eimsConfigFactory()).not.toThrow();
|
|
},
|
|
);
|
|
});
|
|
});
|