fix: normalized the region and logged the otp properly

This commit is contained in:
Nathnael
2026-07-20 08:19:59 +00:00
parent c7195f077a
commit a45e1008fa
18 changed files with 812 additions and 63 deletions

View File

@@ -1,4 +1,5 @@
import { IsString, IsOptional, IsEmail, MaxLength, IsEnum } from 'class-validator';
import { IsString, IsOptional, IsEmail, MaxLength, IsEnum, IsIn } from 'class-validator';
import { ETHIOPIAN_REGIONS, type EthiopianRegion } from '@edr/types';
import { CompanyNationality } from '../entities/company.entity';
import { IsValidPhone } from '../../../common/validators/is-phone-number.validator';
import { IsTin } from '../../../common/validators/is-tin.validator';
@@ -138,10 +139,14 @@ export class UpdateProfileDto {
@MaxLength(50)
renewedTo?: string;
// Zone/woreda/kebele below stay free text: there is no authoritative dataset
// of Ethiopian zones/woredas/kebeles in the platform yet, and eTrade returns
// them uncoded. Only region is a closed set today.
@IsOptional()
@IsString()
@MaxLength(100)
region?: string;
@IsIn(ETHIOPIAN_REGIONS as unknown as string[], {
message: "region must be a recognised Ethiopian region",
})
region?: EthiopianRegion;
@IsOptional()
@IsString()

View File

@@ -6,6 +6,7 @@ import {
ETradeCompanyInfo,
ETradeBusinessInfo,
CompanyRegistrationData,
normalizeRegion,
} from "@edr/types";
@Injectable()
@@ -108,7 +109,11 @@ export class ETradeService {
renewedFrom: businessInfo.RenewedFrom,
renewalDate: businessInfo.RenewalDate,
renewedTo: businessInfo.RenewedTo,
region: businessInfo.AddressInfo?.Region || "",
// eTrade returns uncoded uppercase text and sometimes a zone name in the
// Region slot. Map it onto the canonical list; an unresolved value yields
// "" so the form asks the user to pick rather than failing validation on
// save with a value they never typed.
region: normalizeRegion(businessInfo.AddressInfo?.Region) ?? "",
zone: businessInfo.AddressInfo?.Zone || "",
woreda: businessInfo.AddressInfo?.Woreda || "",
kebele: businessInfo.AddressInfo?.Kebele || "",

View File

@@ -0,0 +1,54 @@
import { ETHIOPIAN_REGIONS, normalizeRegion } from '@edr/types';
/**
* normalizeRegion lives in @edr/types (no jest there), but it exists to keep
* eTrade autofill from feeding UpdateProfileDto a region its @IsIn will reject.
* That contract is an API concern, so it is guarded here.
*/
describe('normalizeRegion', () => {
it('passes through every canonical region unchanged', () => {
for (const region of ETHIOPIAN_REGIONS) {
expect(normalizeRegion(region)).toBe(region);
}
});
it.each([
['ADDIS ABABA', 'Addis Ababa'],
['Addis ababa', 'Addis Ababa'],
[' addis ababa ', 'Addis Ababa'],
['oromoia', 'Oromia'],
['OROMIYA', 'Oromia'],
['gambella', 'Gambela'],
['TIGRAI', 'Tigray'],
['benishangul gumuz', 'Benishangul-Gumuz'],
])('resolves the variant %s', (input, expected) => {
expect(normalizeRegion(input)).toBe(expected);
});
it('maps a zone name in the region slot back to its parent region', () => {
// eTrade's own placeholder data does this — "EASTERN TIGRAY" is a zone.
expect(normalizeRegion('EASTERN TIGRAY')).toBe('Tigray');
expect(normalizeRegion('North Wollo')).toBe('Amhara');
});
it.each([
['a city, not a region', 'Arba Minch'],
['unknown text', 'Nowhere Land'],
['empty', ''],
['whitespace only', ' '],
['null', null],
['undefined', undefined],
])('returns null for %s rather than guessing', (_label, input) => {
expect(normalizeRegion(input as string | null | undefined)).toBeNull();
});
it('never returns a value outside the canonical set', () => {
const samples = ['ADDIS ABABA', 'oromoia', 'EASTERN TIGRAY', 'garbage', ''];
for (const s of samples) {
const out = normalizeRegion(s);
if (out !== null) {
expect(ETHIOPIAN_REGIONS).toContain(out);
}
}
});
});