feat: add eTrade fields to company entity and onboarding process

- Added new fields to the Company entity: licenceNumber, statusDescription, dateRegistered, renewedFrom, renewalDate, renewedTo, region, zone, woreda, kebele, houseNo, and etradePhone.
- Updated onboarding wizard to include a new contact step and fetch company information from eTrade using TIN.
- Created ETradeInfo component to handle fetching and displaying eTrade data.
- Implemented ETradeService to interact with eTrade API and extract relevant company registration data.
- Added new DTOs for fetching eTrade data and handling responses.
- Updated CompanyProfileForm to integrate new fields and handle eTrade data.
- Created hooks for managing eTrade data fetching and error handling.
This commit is contained in:
Marshal
2026-06-20 10:27:41 +00:00
parent 4a0085ef57
commit 1f92a04ecf
19 changed files with 1088 additions and 75 deletions

View File

@@ -0,0 +1,96 @@
import {
Alert,
Button,
Group,
Loader,
SimpleGrid,
Stack,
Text,
TextInput,
} from "@mantine/core";
import { AlertCircle, CheckCircle2, RefreshCw } from "lucide-react";
import { useETradeData } from "@/hooks/useETradeData";
import type { CompanyRegistrationData } from "@edr/types";
interface ETradeInfoProps {
tin: string;
onDataLoaded: (data: CompanyRegistrationData) => void;
}
export default function ETradeInfo({ tin, onDataLoaded }: ETradeInfoProps) {
const mutation = useETradeData();
const isLoading = mutation.isPending;
const hasError = mutation.isError;
const hasData = mutation.data;
const handleFetch = async () => {
if (!tin || tin.length !== 10) return;
const result = await mutation.mutateAsync(tin);
if (result) {
onDataLoaded(result);
}
};
const errorMessage =
hasError && mutation.error
? (mutation.error as any).message ||
"Failed to fetch company information. Please try again."
: null;
return (
<Stack gap="md">
<Group grow>
<TextInput
label="TIN Number"
placeholder="1234567890"
value={tin}
disabled
readOnly
/>
<Button
variant="filled"
color="edr-green"
onClick={handleFetch}
disabled={!tin || tin.length !== 10 || isLoading}
leftSection={isLoading ? <Loader size={16} /> : <RefreshCw size={16} />}
mt="24px"
>
{isLoading ? "Fetching..." : "Fetch Info from eTrade"}
</Button>
</Group>
{hasError && errorMessage && (
<Alert
icon={<AlertCircle size={16} />}
color="red"
title="Failed to fetch data"
>
{errorMessage}
</Alert>
)}
{hasData && (
<Alert
icon={<CheckCircle2 size={16} />}
color="green"
title="Company information loaded"
>
<Stack gap={0}>
<Text size="sm">
<strong>License:</strong> {hasData.licenceNumber}
</Text>
<Text size="sm">
<strong>Status:</strong> {hasData.statusDescription}
</Text>
{hasData.region && (
<Text size="sm">
<strong>Location:</strong> {hasData.kebele}, {hasData.woreda},{" "}
{hasData.zone}, {hasData.region}
</Text>
)}
</Stack>
</Alert>
)}
</Stack>
);
}

View File

@@ -20,10 +20,17 @@ import NationalitySelect from "@/pages/settings/NationalitySelect";
import OnboardingRoleSelect from "@/pages/settings/OnboardingRoleSelect";
/** Form steps shared by CompanyProfileForm and ForwarderForm. */
type FormStep = "company" | "personnel" | "poa" | "documents" | "additional";
type FormStep =
| "company"
| "personnel"
| "contact"
| "poa"
| "documents"
| "additional";
const FORM_STEPS: FormStep[] = [
"company",
"personnel",
"contact",
"poa",
"documents",
"additional",

View File

@@ -90,6 +90,7 @@ export const URL_CONSTANTS = {
ONBOARDING_STEP: "/api/companies/onboarding-step",
ONBOARDING_COMPLETE: "/api/companies/onboarding/complete",
DASHBOARD: "/api/companies/dashboard",
FETCH_ETRADE_INFO: "/api/companies/fetch-etrade-info",
DOCUMENTS: (id: string) => `/api/companies/${id}/documents`,
PROFILE_LICENSE: (profileId: string) =>
`/api/companies/company-profiles/${profileId}/license`,

View File

@@ -0,0 +1,16 @@
import { useMutation } from "@tanstack/react-query";
import { companiesService } from "@/services/companies.service";
import { extractApiError } from "@/utils/result";
import type { CompanyRegistrationData } from "@edr/types";
export function useETradeData() {
return useMutation({
mutationFn: async (tin: string): Promise<CompanyRegistrationData> => {
return companiesService.fetchETradeInfo({ tin });
},
onError: (error) => {
const { message } = extractApiError(error);
console.error("eTrade fetch error:", message);
},
});
}

View File

@@ -2,6 +2,7 @@ import {
Alert,
Box,
Button,
Checkbox,
Divider,
Group,
Loader,
@@ -23,6 +24,7 @@ import {
FileText,
UploadCloud,
User,
UserCheck,
} from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { useForm } from "react-hook-form";
@@ -31,6 +33,7 @@ import { z } from "zod";
import type { AuthUser } from "@/types/auth";
import type { CreateCompanyPayload } from "@/services/companies.service";
import type { ProfileResponse, UpdateProfilePayload } from "@/types/profile";
import type { CompanyRegistrationData } from "@edr/types";
import PhoneInput from "@/components/auth/PhoneInput";
import { SmartFileInput } from "@edr/ui-common";
import { api } from "@/services/api";
@@ -38,8 +41,15 @@ import { splitPhone } from "@/utils/phone";
import RoleLicenseStep, {
type RoleLicenseProfile,
} from "@/components/onboarding/RoleLicenseStep";
import ETradeInfo from "@/components/onboarding/ETradeInfo";
type CompanyStep = "company" | "personnel" | "poa" | "documents" | "additional";
type CompanyStep =
| "company"
| "personnel"
| "contact"
| "poa"
| "documents"
| "additional";
const onboardingSchema = z.object({
companyName: z.string().min(1, "Company name is required"),
@@ -54,7 +64,25 @@ const onboardingSchema = z.object({
.min(1, "VAT number is required")
.length(10, "VAT number must be exactly 10 digits"),
fanNumber: z.string().length(16, "FAN must be exactly 16 digits"),
licenceNumber: z.string().optional(),
statusDescription: z.string().optional(),
dateRegistered: z.string().optional(),
renewedFrom: z.string().optional(),
renewalDate: z.string().optional(),
renewedTo: z.string().optional(),
region: z.string().optional(),
zone: z.string().optional(),
woreda: z.string().optional(),
kebele: z.string().optional(),
houseNo: z.string().optional(),
etradePhone: z.string().optional(),
contactPersonName: z.string().min(1, "Contact person name is required"),
contactPersonPosition: z.string().optional(),
contactPersonEmail: z
.string()
.email("Invalid email address")
.optional()
.or(z.literal("")),
contactPersonPhone: z.string().min(1, "Contact person phone is required"),
contactPersonPhoneCountryCode: z.string().min(1, "Country code is required"),
generalManagerName: z.string().min(1, "GM name is required"),
@@ -82,16 +110,32 @@ const stepFields: Record<CompanyStep, (keyof FormData)[]> = {
"tinNumber",
"vatNumber",
"fanNumber",
"licenceNumber",
"statusDescription",
"dateRegistered",
"renewedFrom",
"renewalDate",
"renewedTo",
"region",
"zone",
"woreda",
"kebele",
"houseNo",
"etradePhone",
],
personnel: [
"contactPersonName",
"contactPersonPhone",
"contactPersonPhoneCountryCode",
"generalManagerName",
"generalManagerEmail",
"generalManagerPhone",
"generalManagerPhoneCountryCode",
],
contact: [
"contactPersonName",
"contactPersonPosition",
"contactPersonEmail",
"contactPersonPhone",
"contactPersonPhoneCountryCode",
],
poa: [],
documents: [],
additional: [],
@@ -109,6 +153,8 @@ function buildPayload(data: FormData, _user: AuthUser): CreateCompanyPayload {
fanNumber: data.fanNumber,
attributes: {
contactPersonName: data.contactPersonName,
contactPersonPosition: data.contactPersonPosition || undefined,
contactPersonEmail: data.contactPersonEmail || undefined,
contactPersonPhone: `${data.contactPersonPhoneCountryCode}${data.contactPersonPhone}`,
generalManagerName: data.generalManagerName,
generalManagerEmail: data.generalManagerEmail,
@@ -138,15 +184,32 @@ function stepPayload(step: CompanyStep, d: FormData): Partial<UpdateProfilePaylo
tin: d.tinNumber,
vatNumber: d.vatNumber,
fanNumber: d.fanNumber,
licenceNumber: d.licenceNumber,
statusDescription: d.statusDescription,
dateRegistered: d.dateRegistered,
renewedFrom: d.renewedFrom,
renewalDate: d.renewalDate,
renewedTo: d.renewedTo,
region: d.region,
zone: d.zone,
woreda: d.woreda,
kebele: d.kebele,
houseNo: d.houseNo,
etradePhone: d.etradePhone,
};
case "personnel":
return {
contactPersonName: d.contactPersonName,
contactPersonPhone: `${d.contactPersonPhoneCountryCode}${d.contactPersonPhone}`,
generalManagerName: d.generalManagerName,
generalManagerEmail: d.generalManagerEmail,
generalManagerPhone: `${d.generalManagerPhoneCountryCode}${d.generalManagerPhone}`,
};
case "contact":
return {
contactPersonName: d.contactPersonName,
contactPersonPosition: d.contactPersonPosition || undefined,
contactPersonEmail: d.contactPersonEmail || undefined,
contactPersonPhone: `${d.contactPersonPhoneCountryCode}${d.contactPersonPhone}`,
};
case "poa":
return {
poaName: d.poaName || undefined,
@@ -181,7 +244,21 @@ function toFormValues(p: ProfileResponse): FormData {
tinNumber: tin,
vatNumber: p.vatNumber ?? "",
fanNumber: p.fanNumber ?? "",
licenceNumber: p.licenceNumber ?? "",
statusDescription: p.statusDescription ?? "",
dateRegistered: p.dateRegistered ?? "",
renewedFrom: p.renewedFrom ?? "",
renewalDate: p.renewalDate ?? "",
renewedTo: p.renewedTo ?? "",
region: p.region ?? "",
zone: p.zone ?? "",
woreda: p.woreda ?? "",
kebele: p.kebele ?? "",
houseNo: p.houseNo ?? "",
etradePhone: p.etradePhone ?? "",
contactPersonName: p.contactPersonName ?? "",
contactPersonPosition: p.contactPersonPosition ?? "",
contactPersonEmail: p.contactPersonEmail ?? "",
contactPersonPhone: contactPhone.number,
contactPersonPhoneCountryCode: contactPhone.countryCode,
generalManagerName: p.generalManagerName ?? "",
@@ -281,6 +358,7 @@ export default function CompanyProfileForm({
handleSubmit,
trigger,
watch,
setValue,
formState: { errors },
} = useForm<FormData>({
resolver: zodResolver(onboardingSchema),
@@ -294,7 +372,21 @@ export default function CompanyProfileForm({
tinNumber: "",
vatNumber: "",
fanNumber: "",
licenceNumber: "",
statusDescription: "",
dateRegistered: "",
renewedFrom: "",
renewalDate: "",
renewedTo: "",
region: "",
zone: "",
woreda: "",
kebele: "",
houseNo: "",
etradePhone: "",
contactPersonName: "",
contactPersonPosition: "",
contactPersonEmail: "",
contactPersonPhone: "",
contactPersonPhoneCountryCode: "+251",
generalManagerName: "",
@@ -312,8 +404,83 @@ export default function CompanyProfileForm({
values: rehydrate ? toFormValues(rehydrate) : undefined,
});
// The business owner/manager pulled from eTrade — powers "Use owner as
// manager" on the General Manager step. Null until a TIN lookup succeeds.
const [etradeOwner, setEtradeOwner] = useState<{
name: string;
phone: string;
} | null>(null);
// Mirror the two "copy from previous person" checkboxes so they can be
// re-toggled (re-checking re-pulls the latest values).
const [gmIsContact, setGmIsContact] = useState(false);
const [contactIsPoa, setContactIsPoa] = useState(false);
const handleETradeDataLoaded = (data: CompanyRegistrationData) => {
setValue("licenceNumber", data.licenceNumber);
setValue("statusDescription", data.statusDescription);
setValue("dateRegistered", data.dateRegistered);
setValue("renewedFrom", data.renewedFrom);
setValue("renewalDate", data.renewalDate);
setValue("renewedTo", data.renewedTo);
setValue("region", data.region);
setValue("zone", data.zone);
setValue("woreda", data.woreda);
setValue("kebele", data.kebele);
setValue("houseNo", data.houseNo);
setValue("etradePhone", data.regularPhone || data.mobilePhone);
setEtradeOwner({
name: data.managerName,
phone: data.managerPhone || data.regularPhone || data.mobilePhone,
});
};
/** Fill the General Manager from the eTrade business owner. */
const useOwnerAsManager = () => {
if (!etradeOwner) return;
setValue("generalManagerName", etradeOwner.name);
const { number, countryCode } = splitPhone(etradeOwner.phone);
setValue("generalManagerPhone", number);
setValue("generalManagerPhoneCountryCode", countryCode);
};
/** Copy the General Manager into the Contact Person fields (toggleable). */
const toggleGmAsContact = (checked: boolean) => {
setGmIsContact(checked);
if (!checked) return;
setValue("contactPersonName", watch("generalManagerName"));
setValue("contactPersonEmail", watch("generalManagerEmail"));
setValue("contactPersonPhone", watch("generalManagerPhone"));
setValue(
"contactPersonPhoneCountryCode",
watch("generalManagerPhoneCountryCode"),
);
};
/** Copy the Contact Person into the PoA fields (toggleable, still editable). */
const toggleContactAsPoa = (checked: boolean) => {
setContactIsPoa(checked);
if (!checked) return;
setValue("poaName", watch("contactPersonName"));
setValue("poaEmail", watch("contactPersonEmail"));
setValue("poaPhone", watch("contactPersonPhone"));
setValue("poaPhoneCountryCode", watch("contactPersonPhoneCountryCode"));
};
const hasDocuments = Boolean(uploadSetting?.fields?.length);
const totalSteps = 5;
// Single source of truth for step sequence — navigation, labels and the
// progress bar all derive from this so adding/removing a step is one edit.
const stepOrder: CompanyStep[] = [
"company",
"personnel",
"contact",
"poa",
"documents",
"additional",
];
const totalSteps = stepOrder.length;
const currentIdx = stepOrder.indexOf(step);
/** Validate + persist the current step, returning whether we may advance. */
const saveCurrentStep = async (): Promise<boolean> => {
@@ -351,55 +518,44 @@ export default function CompanyProfileForm({
handleSubmit((data) => onSubmit(buildPayload(data, user)))();
return;
}
if (step === "documents") {
setStep("additional");
return;
// The documents step has nothing to persist; field steps validate + save
// before advancing.
if (step !== "documents") {
const ok = await saveCurrentStep();
if (!ok) return;
}
// company / personnel / poa: validate + save before advancing.
const ok = await saveCurrentStep();
if (!ok) return;
setStep(
step === "company" ? "personnel" : step === "personnel" ? "poa" : "documents",
);
setStep(stepOrder[currentIdx + 1]);
};
const prevStep = () => {
setSaveError(null);
if (step === "company") onBack();
else if (step === "personnel") setStep("company");
else if (step === "poa") setStep("personnel");
else if (step === "documents") setStep("poa");
else setStep("documents");
if (currentIdx === 0) onBack();
else setStep(stepOrder[currentIdx - 1]);
};
// Back is hidden on the first step during onboarding (can't return to role
// selection); otherwise always available.
const showBack = !(hideFirstStepBack && step === "company");
const STEPS: { key: CompanyStep; icon: React.ReactNode }[] = [
{ key: "company", icon: <Building2 size={18} /> },
{ key: "personnel", icon: <User size={18} /> },
{ key: "poa", icon: <FileText size={18} /> },
{ key: "documents", icon: <UploadCloud size={18} /> },
{ key: "additional", icon: <CheckCircle2 size={18} /> },
];
const STEP_LABELS: Record<CompanyStep, string> = {
company: `Step 1 of ${totalSteps} — Company Information`,
personnel: `Step 2 of ${totalSteps} — Personnel Details`,
poa: `Step 3 of ${totalSteps} — Power of Attorney (Optional)`,
documents: `Step 4 of ${totalSteps} — Upload Documents`,
additional: `Step 5 of ${totalSteps} — Business License`,
const STEP_ICONS: Record<CompanyStep, React.ReactNode> = {
company: <Building2 size={18} />,
personnel: <User size={18} />,
contact: <UserCheck size={18} />,
poa: <FileText size={18} />,
documents: <UploadCloud size={18} />,
additional: <CheckCircle2 size={18} />,
};
const stepOrder: CompanyStep[] = [
"company",
"personnel",
"poa",
"documents",
"additional",
];
const currentIdx = stepOrder.indexOf(step);
const STEP_TITLES: Record<CompanyStep, string> = {
company: "Company Information",
personnel: "General Manager",
contact: "Contact Person",
poa: "Power of Attorney (Optional)",
documents: "Upload Documents",
additional: "Business License",
};
const stepLabel = `Step ${currentIdx + 1} of ${totalSteps}${STEP_TITLES[step]}`;
return (
<>
@@ -421,7 +577,7 @@ export default function CompanyProfileForm({
className="relative max-w-lg mx-auto px-2"
>
<Box className="absolute top-1/2 left-2 right-2 h-0.5 bg-edr-border -translate-y-1/2 z-0" />
{STEPS.map(({ key, icon }, i) => {
{stepOrder.map((key, i) => {
const done = i < currentIdx;
const active = i === currentIdx;
return done || active ? (
@@ -433,7 +589,7 @@ export default function CompanyProfileForm({
color="edr-green"
className="relative z-10"
>
{done ? <CheckCircle2 size={18} /> : icon}
{done ? <CheckCircle2 size={18} /> : STEP_ICONS[key]}
</ThemeIcon>
) : (
<Box
@@ -443,14 +599,14 @@ export default function CompanyProfileForm({
c="edr-slate"
className="relative z-10 flex items-center justify-center rounded-full border-2 border-edr-border bg-edr-card"
>
{icon}
{STEP_ICONS[key]}
</Box>
);
})}
</Group>
<Text size="sm" c="edr-muted" ta="center" mt="sm">
{STEP_LABELS[step]}
{stepLabel}
</Text>
</Box>
@@ -520,38 +676,133 @@ export default function CompanyProfileForm({
error={errors.fanNumber?.message}
{...register("fanNumber")}
/>
<Divider my="sm" />
<Text fw={600} size="sm" c="edr-text">
Fetch Company Information from eTrade
</Text>
<ETradeInfo
tin={watch("tinNumber")}
onDataLoaded={handleETradeDataLoaded}
/>
{watch("licenceNumber") && (
<>
<Divider my="sm" />
<Text fw={600} size="sm" c="edr-text">
Registration Details from eTrade
</Text>
<SimpleGrid cols={2} spacing="md">
<TextInput
label="License Number"
placeholder="01/23/01/19786/2006"
error={errors.licenceNumber?.message}
{...register("licenceNumber")}
/>
<TextInput
label="Status"
placeholder="Not renewed for 2 years"
error={errors.statusDescription?.message}
{...register("statusDescription")}
/>
</SimpleGrid>
<SimpleGrid cols={2} spacing="md">
<TextInput
label="Date Registered"
placeholder="12/17/2013"
error={errors.dateRegistered?.message}
{...register("dateRegistered")}
/>
<TextInput
label="Renewal Date"
placeholder="3/17/2016"
error={errors.renewalDate?.message}
{...register("renewalDate")}
/>
</SimpleGrid>
<SimpleGrid cols={2} spacing="md">
<TextInput
label="Renewed From"
placeholder="3/17/2016"
error={errors.renewedFrom?.message}
{...register("renewedFrom")}
/>
<TextInput
label="Renewed To"
placeholder="7/7/2016"
error={errors.renewedTo?.message}
{...register("renewedTo")}
/>
</SimpleGrid>
<Text fw={600} size="sm" c="edr-text" mt="md">
Address Information
</Text>
<SimpleGrid cols={2} spacing="md">
<TextInput
label="Region"
placeholder="Tigray"
error={errors.region?.message}
{...register("region")}
/>
<TextInput
label="Zone"
placeholder="EASTERN TIGRAY"
error={errors.zone?.message}
{...register("zone")}
/>
</SimpleGrid>
<SimpleGrid cols={2} spacing="md">
<TextInput
label="Woreda"
placeholder="EROB"
error={errors.woreda?.message}
{...register("woreda")}
/>
<TextInput
label="Kebele"
placeholder="ARAS"
error={errors.kebele?.message}
{...register("kebele")}
/>
</SimpleGrid>
<SimpleGrid cols={2} spacing="md">
<TextInput
label="House No"
placeholder="House Number"
error={errors.houseNo?.message}
{...register("houseNo")}
/>
<TextInput
label="Phone"
placeholder="0355235416"
error={errors.etradePhone?.message}
{...register("etradePhone")}
/>
</SimpleGrid>
</>
)}
</>
)}
{step === "personnel" && (
<>
<Text fw={600} size="sm" c="edr-text">
Contact Person
</Text>
<SimpleGrid cols={2} spacing="md">
<TextInput
label="Name"
placeholder="Jane Smith"
error={errors.contactPersonName?.message}
{...register("contactPersonName")}
/>
<PhoneInput
countryCode={{ ...register("contactPersonPhoneCountryCode") }}
phone={{
...register("contactPersonPhone"),
placeholder: "912345678",
}}
countryCodeError={errors.contactPersonPhoneCountryCode}
phoneError={errors.contactPersonPhone}
label="Phone"
/>
</SimpleGrid>
<Divider color="edr-border" />
<Text fw={600} size="sm" c="edr-text">
General Manager
</Text>
<Group justify="space-between" align="center">
<Text fw={600} size="sm" c="edr-text">
General Manager
</Text>
{etradeOwner && (
<Button
variant="light"
color="edr-green"
size="xs"
leftSection={<UserCheck size={14} />}
onClick={useOwnerAsManager}
>
Use owner as manager
</Button>
)}
</Group>
<TextInput
label="Name"
placeholder="Abebe Bikila"
@@ -582,12 +833,65 @@ export default function CompanyProfileForm({
</>
)}
{step === "contact" && (
<>
<Text fw={600} size="sm" c="edr-text">
Contact Person
</Text>
<Checkbox
color="edr-green"
label="Use General Manager as contact person"
checked={gmIsContact}
onChange={(e) => toggleGmAsContact(e.currentTarget.checked)}
/>
<SimpleGrid cols={2} spacing="md">
<TextInput
label="Name"
placeholder="Jane Smith"
error={errors.contactPersonName?.message}
{...register("contactPersonName")}
/>
<TextInput
label="Position (Optional)"
placeholder="Operations Lead"
error={errors.contactPersonPosition?.message}
{...register("contactPersonPosition")}
/>
</SimpleGrid>
<SimpleGrid cols={2} spacing="md">
<TextInput
label="Email (Optional)"
type="email"
placeholder="contact@company.com"
error={errors.contactPersonEmail?.message}
{...register("contactPersonEmail")}
/>
<PhoneInput
countryCode={{ ...register("contactPersonPhoneCountryCode") }}
phone={{
...register("contactPersonPhone"),
placeholder: "912345678",
}}
countryCodeError={errors.contactPersonPhoneCountryCode}
phoneError={errors.contactPersonPhone}
label="Phone"
/>
</SimpleGrid>
</>
)}
{step === "poa" && (
<>
<Text size="sm" c="edr-muted">
Power of Attorney details are optional. Fill them in if you have
them, or skip to continue.
</Text>
<Checkbox
color="edr-green"
label="Use contact person as Power of Attorney"
checked={contactIsPoa}
onChange={(e) => toggleContactAsPoa(e.currentTarget.checked)}
/>
<TextInput
label="PoA Name"
placeholder="Authorized Representative Name"

View File

@@ -266,4 +266,13 @@ export const companiesService = {
);
return unwrap(response.data);
},
/** Fetch company registration data from eTrade by TIN. */
fetchETradeInfo: async (payload: { tin: string }): Promise<any> => {
const response = await client.post<ApiResponse<any>>(
URL_CONSTANTS.COMPANIES_API.FETCH_ETRADE_INFO,
payload,
);
return unwrap(response.data);
},
};

View File

@@ -13,7 +13,21 @@ export interface ProfileResponse {
tinNumber: string;
vatNumber: string | null;
fanNumber: string | null;
licenceNumber?: string | null;
statusDescription?: string | null;
dateRegistered?: string | null;
renewedFrom?: string | null;
renewalDate?: string | null;
renewedTo?: string | null;
region?: string | null;
zone?: string | null;
woreda?: string | null;
kebele?: string | null;
houseNo?: string | null;
etradePhone?: string | null;
contactPersonName: string | null;
contactPersonPosition: string | null;
contactPersonEmail: string | null;
contactPersonPhone: string | null;
generalManagerName: string | null;
generalManagerEmail: string | null;
@@ -36,7 +50,21 @@ export interface UpdateProfilePayload {
tin?: string;
vatNumber?: string;
fanNumber?: string;
licenceNumber?: string;
statusDescription?: string;
dateRegistered?: string;
renewedFrom?: string;
renewalDate?: string;
renewedTo?: string;
region?: string;
zone?: string;
woreda?: string;
kebele?: string;
houseNo?: string;
etradePhone?: string;
contactPersonName?: string;
contactPersonPosition?: string;
contactPersonEmail?: string;
contactPersonPhone?: string;
generalManagerName?: string;
generalManagerEmail?: string;