mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
fix: gm email
This commit is contained in:
@@ -354,6 +354,93 @@ describe("Fayda identity verification binds a person to the company", () => {
|
||||
).resolves.toBeDefined();
|
||||
});
|
||||
|
||||
// Fayda's email and phone claims are optional and routinely absent. The owner
|
||||
// is who the company is reached through and the step renders no input for
|
||||
// their contact details, so the onboarding account — already OTP-proven —
|
||||
// stands in rather than leaving the company unreachable.
|
||||
describe("account contact details stand in for absent Fayda claims", () => {
|
||||
const noContactClaims = {
|
||||
purpose: "VERIFY",
|
||||
verified: true,
|
||||
sub: "new-sub",
|
||||
fullName: "Haile Gebrselassie",
|
||||
address: "Addis Ababa",
|
||||
};
|
||||
const account = {
|
||||
email: "account@example.com",
|
||||
phoneNumber: "+251911777777",
|
||||
};
|
||||
|
||||
it("falls back to the account for an owner Fayda gave no email or phone", async () => {
|
||||
const { service, ctx } = makeService({ verification: noContactClaims });
|
||||
|
||||
await service.completeIdentityVerification(
|
||||
"user-1",
|
||||
{ subject: "owner", code: "c", state: "s" },
|
||||
account,
|
||||
);
|
||||
|
||||
expect(ctx.attributes.ownerEmail).toBe("account@example.com");
|
||||
expect(ctx.attributes.ownerPhone).toBe("+251911777777");
|
||||
});
|
||||
|
||||
it("prefers the Fayda claim over the account when there is one", async () => {
|
||||
const { service, ctx } = makeService();
|
||||
|
||||
await service.completeIdentityVerification(
|
||||
"user-1",
|
||||
{ subject: "owner", code: "c", state: "s" },
|
||||
account,
|
||||
);
|
||||
|
||||
expect(ctx.attributes.ownerEmail).toBe("haile@example.com");
|
||||
expect(ctx.attributes.ownerPhone).toBe("+251922000000");
|
||||
});
|
||||
|
||||
it("leaves the PoA alone — the account is not that person", async () => {
|
||||
const { service, ctx } = makeService({ verification: noContactClaims });
|
||||
|
||||
await service.completeIdentityVerification(
|
||||
"user-1",
|
||||
{ subject: "poa", code: "c", state: "s" },
|
||||
account,
|
||||
);
|
||||
|
||||
expect(ctx.attributes.poaEmail).toBeUndefined();
|
||||
expect(ctx.attributes.poaPhone).toBeUndefined();
|
||||
});
|
||||
|
||||
// Owners verified before the fallback existed hold blank contacts. Copying
|
||||
// those blanks onto the GM makes generalManagerEmail required by onboarding
|
||||
// with no field anywhere to satisfy it.
|
||||
it("fills the GM copy from the account when the stored owner has no contacts", async () => {
|
||||
const { service, ctx } = makeService({
|
||||
attributes: { ...OWNER_VERIFIED },
|
||||
});
|
||||
|
||||
await service.setGmSameAsOwner("user-1", account);
|
||||
|
||||
expect(ctx.attributes.gmEmail).toBe("account@example.com");
|
||||
expect(ctx.attributes.generalManagerEmail).toBe("account@example.com");
|
||||
expect(ctx.attributes.generalManagerPhone).toBe("+251911777777");
|
||||
});
|
||||
|
||||
it("keeps the stored owner contacts when the GM copy has them", async () => {
|
||||
const { service, ctx } = makeService({
|
||||
attributes: {
|
||||
...OWNER_VERIFIED,
|
||||
ownerEmail: "abebe@example.com",
|
||||
ownerPhone: "+251911000111",
|
||||
},
|
||||
});
|
||||
|
||||
await service.setGmSameAsOwner("user-1", account);
|
||||
|
||||
expect(ctx.attributes.generalManagerEmail).toBe("abebe@example.com");
|
||||
expect(ctx.attributes.generalManagerPhone).toBe("+251911000111");
|
||||
});
|
||||
});
|
||||
|
||||
it("never locks or gates the general manager — it is not the verified subject", async () => {
|
||||
// GM is a plain typed role; the portal offers a "same as owner" copy, but
|
||||
// the backend must not treat it as identity-owned or require it verified.
|
||||
|
||||
@@ -139,10 +139,16 @@ export function stepPayload(
|
||||
};
|
||||
}
|
||||
case "personnel":
|
||||
// `|| undefined`, never "": the DTO's `@IsOptional()` only skips null and
|
||||
// undefined, so an empty string is validated and 400s with
|
||||
// "generalManagerEmail must be an email". An Ethiopian company never types
|
||||
// these — the GM comes from the Fayda verification (or the "same as owner"
|
||||
// declaration), so the form fields are legitimately blank and would fail a
|
||||
// step that has no input to fix.
|
||||
return {
|
||||
generalManagerName: d.generalManagerName,
|
||||
generalManagerEmail: d.generalManagerEmail,
|
||||
generalManagerPhone: d.generalManagerPhone,
|
||||
generalManagerName: d.generalManagerName || undefined,
|
||||
generalManagerEmail: d.generalManagerEmail || undefined,
|
||||
generalManagerPhone: d.generalManagerPhone || undefined,
|
||||
};
|
||||
case "contact":
|
||||
return {
|
||||
|
||||
@@ -123,6 +123,40 @@ describe("stepPayload (company)", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("stepPayload (personnel)", () => {
|
||||
// An Ethiopian company never types the GM — Fayda (or "same as owner") owns
|
||||
// those fields — so the form holds "". `@IsOptional()` on the DTO skips only
|
||||
// null/undefined, so an empty string is validated and comes back as
|
||||
// "generalManagerEmail must be an email", on a step that renders no input.
|
||||
it("omits blank GM fields instead of sending empty strings", () => {
|
||||
const payload = stepPayload(
|
||||
"personnel",
|
||||
values({
|
||||
generalManagerName: "",
|
||||
generalManagerEmail: "",
|
||||
generalManagerPhone: "",
|
||||
}),
|
||||
);
|
||||
expect(payload.generalManagerName).toBeUndefined();
|
||||
expect(payload.generalManagerEmail).toBeUndefined();
|
||||
expect(payload.generalManagerPhone).toBeUndefined();
|
||||
});
|
||||
|
||||
it("still sends typed GM details (foreign company)", () => {
|
||||
const payload = stepPayload(
|
||||
"personnel",
|
||||
values({
|
||||
generalManagerName: "Abebe Bikila",
|
||||
generalManagerEmail: "gm@example.com",
|
||||
generalManagerPhone: "+251911223344",
|
||||
}),
|
||||
);
|
||||
expect(payload.generalManagerName).toBe("Abebe Bikila");
|
||||
expect(payload.generalManagerEmail).toBe("gm@example.com");
|
||||
expect(payload.generalManagerPhone).toBe("+251911223344");
|
||||
});
|
||||
});
|
||||
|
||||
describe("firstPresent", () => {
|
||||
it("skips empty strings rather than stopping at them", () => {
|
||||
expect(firstPresent("", " ", "second@example.com")).toBe(
|
||||
|
||||
Reference in New Issue
Block a user