mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 07:22:53 +00:00
fix: profile id and licence to registration
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { Injectable, InternalServerErrorException } from "@nestjs/common";
|
||||
import { InjectRepository } from "@nestjs/typeorm";
|
||||
import { Repository } from "typeorm";
|
||||
import { BaseRepository } from "@edr/api-common";
|
||||
@@ -20,6 +20,11 @@ const PREFIX_MAP: Record<ProfileType, string> = {
|
||||
[ProfileType.transporter]: "TR",
|
||||
};
|
||||
|
||||
const SERIES_LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
/** Numbers per series letter: A00001..A99999, then B00001. */
|
||||
const SERIES_SIZE = 99_999;
|
||||
|
||||
@Injectable()
|
||||
export class CompanyProfileRepository extends BaseRepository<CompanyProfile> {
|
||||
constructor(
|
||||
@@ -38,9 +43,20 @@ export class CompanyProfileRepository extends BaseRepository<CompanyProfile> {
|
||||
const result = await this.repository.query(
|
||||
`SELECT nextval('${seqName}') AS next_id`,
|
||||
);
|
||||
const nextId = result[0].next_id as number;
|
||||
const nextId = Number(result[0].next_id);
|
||||
const offset = nextId - 1;
|
||||
const seriesIndex = Math.floor(offset / SERIES_SIZE);
|
||||
|
||||
if (seriesIndex >= SERIES_LETTERS.length) {
|
||||
throw new InternalServerErrorException(
|
||||
`Company profile reference series exhausted for type "${type}"`,
|
||||
);
|
||||
}
|
||||
|
||||
const letter = SERIES_LETTERS[seriesIndex];
|
||||
const number = (offset % SERIES_SIZE) + 1;
|
||||
const prefix = PREFIX_MAP[type];
|
||||
return `${prefix}-${String(nextId).padStart(5, "0")}`;
|
||||
return `${prefix}-${letter}${String(number).padStart(5, "0")}`;
|
||||
}
|
||||
|
||||
async findByCompanyId(companyId: string): Promise<CompanyProfile[]> {
|
||||
|
||||
@@ -60,7 +60,7 @@ export class CompanyProfile extends BaseEntity {
|
||||
type!: ProfileType;
|
||||
|
||||
/**
|
||||
* Official profile reference (e.g. "EX-00001"). Minted only when the profile
|
||||
* Official profile reference (e.g. "EX-A00001"). Minted only when the profile
|
||||
* is approved (status → Active); pending/unapproved profiles carry NULL.
|
||||
* The unique index tolerates this because Postgres treats NULLs as distinct.
|
||||
* API responses surface it as "" when absent — see ResponseCompanyProfileDto.
|
||||
|
||||
@@ -33,8 +33,9 @@ const ETHIOPIAN_ONBOARDING_FIELDS: OnboardingField[] = [
|
||||
},
|
||||
{
|
||||
fileKey: "commercial_license",
|
||||
fileLabel: "Commercial License",
|
||||
helpText: "Verified against the government trade system during registration.",
|
||||
fileLabel: "Commercial Registration",
|
||||
helpText:
|
||||
"Verified against the government trade system during registration.",
|
||||
isRequired: true,
|
||||
isMultiple: false,
|
||||
maxFiles: 1,
|
||||
@@ -108,7 +109,8 @@ const LEGACY_ONBOARDING_FIELDS: OnboardingField[] = [
|
||||
{
|
||||
fileKey: "business_license",
|
||||
fileLabel: "Business License / Trade License",
|
||||
helpText: "Verified against the government trade system during registration.",
|
||||
helpText:
|
||||
"Verified against the government trade system during registration.",
|
||||
isRequired: true,
|
||||
isMultiple: false,
|
||||
maxFiles: 1,
|
||||
@@ -489,9 +491,14 @@ const SELF_CLEARANCE_SETTINGS: OnboardingDocumentSetting[] = [
|
||||
const CONTRACT_INTAKE_ENTITY = "contract_intake";
|
||||
|
||||
const CONTRACT_INTAKE_FIELDS: OnboardingField[] = [
|
||||
clearanceField("commercial_framework", "Commercial Framework / Agreement", 1, {
|
||||
required: false,
|
||||
}),
|
||||
clearanceField(
|
||||
"commercial_framework",
|
||||
"Commercial Framework / Agreement",
|
||||
1,
|
||||
{
|
||||
required: false,
|
||||
},
|
||||
),
|
||||
clearanceField("onboarding_attachment", "Onboarding Attachment", 2, {
|
||||
required: false,
|
||||
}),
|
||||
@@ -542,7 +549,7 @@ const DRIVER_DOCUMENT_SETTINGS: OnboardingDocumentSetting[] = [
|
||||
export class FileUploadSettingsSeeder {
|
||||
private readonly logger = new Logger(FileUploadSettingsSeeder.name);
|
||||
|
||||
constructor(private readonly dataSource: DataSource) {}
|
||||
constructor(private readonly dataSource: DataSource) { }
|
||||
|
||||
async run() {
|
||||
await this.dataSource.transaction(async (manager) => {
|
||||
@@ -552,35 +559,35 @@ export class FileUploadSettingsSeeder {
|
||||
const allSettings: Array<
|
||||
OnboardingDocumentSetting & { description: string }
|
||||
> = [
|
||||
...COMPANY_ONBOARDING_DOCUMENTS.map((s) => ({
|
||||
...s,
|
||||
description: COMPANY_ONBOARDING_DESCRIPTION,
|
||||
})),
|
||||
...CLEARANCE_DOCUMENT_SETTINGS.map((s) => ({
|
||||
...s,
|
||||
description: CLEARANCE_DESCRIPTION,
|
||||
})),
|
||||
...CONTRACT_CLEARANCE_SETTINGS.map((s) => ({
|
||||
...s,
|
||||
description:
|
||||
"Pre-booking clearance documents collected on the contract (Path B), by operation and freight type.",
|
||||
})),
|
||||
...SELF_CLEARANCE_SETTINGS.map((s) => ({
|
||||
...s,
|
||||
description:
|
||||
"Customer self-clearance documents (Path A, no EDR customs service), reviewed by Operations.",
|
||||
})),
|
||||
...CONTRACT_INTAKE_SETTINGS.map((s) => ({
|
||||
...s,
|
||||
description:
|
||||
"Commercial/framework documents attached at contract submission.",
|
||||
})),
|
||||
...DRIVER_DOCUMENT_SETTINGS.map((s) => ({
|
||||
...s,
|
||||
description:
|
||||
"Documents uploaded against a driver profile (license, ID, contracts, etc.).",
|
||||
})),
|
||||
];
|
||||
...COMPANY_ONBOARDING_DOCUMENTS.map((s) => ({
|
||||
...s,
|
||||
description: COMPANY_ONBOARDING_DESCRIPTION,
|
||||
})),
|
||||
...CLEARANCE_DOCUMENT_SETTINGS.map((s) => ({
|
||||
...s,
|
||||
description: CLEARANCE_DESCRIPTION,
|
||||
})),
|
||||
...CONTRACT_CLEARANCE_SETTINGS.map((s) => ({
|
||||
...s,
|
||||
description:
|
||||
"Pre-booking clearance documents collected on the contract (Path B), by operation and freight type.",
|
||||
})),
|
||||
...SELF_CLEARANCE_SETTINGS.map((s) => ({
|
||||
...s,
|
||||
description:
|
||||
"Customer self-clearance documents (Path A, no EDR customs service), reviewed by Operations.",
|
||||
})),
|
||||
...CONTRACT_INTAKE_SETTINGS.map((s) => ({
|
||||
...s,
|
||||
description:
|
||||
"Commercial/framework documents attached at contract submission.",
|
||||
})),
|
||||
...DRIVER_DOCUMENT_SETTINGS.map((s) => ({
|
||||
...s,
|
||||
description:
|
||||
"Documents uploaded against a driver profile (license, ID, contracts, etc.).",
|
||||
})),
|
||||
];
|
||||
|
||||
for (const documentSetting of allSettings) {
|
||||
await settingRepository.upsert(
|
||||
@@ -601,7 +608,9 @@ export class FileUploadSettingsSeeder {
|
||||
});
|
||||
|
||||
if (!setting) {
|
||||
throw new Error(`file_upload_setting_seed_failed:${documentSetting.code}`);
|
||||
throw new Error(
|
||||
`file_upload_setting_seed_failed:${documentSetting.code}`,
|
||||
);
|
||||
}
|
||||
|
||||
await fieldRepository.delete({ settingId: setting.id });
|
||||
|
||||
@@ -10,7 +10,7 @@ const LABEL_BY_CODE = new Map<string, string>([
|
||||
...REQUIRED_DOC_FIELDS.map((d) => [d.key, d.label] as const),
|
||||
// Company onboarding document codes (see file-upload-settings seeder).
|
||||
["tin_certificate", "TIN Certificate"],
|
||||
["commercial_license", "Commercial License"],
|
||||
["commercial_license", "Commercial Registration"],
|
||||
["business_license", "Business License / Trade License"],
|
||||
["investment_license", "Investment License"],
|
||||
["national_id", "National ID"],
|
||||
|
||||
@@ -26,7 +26,7 @@ export default function NationalitySelect({
|
||||
<SimpleGrid cols={{ base: 1, sm: 2 }} spacing="md">
|
||||
<RoleCard
|
||||
label="Ethiopian Company"
|
||||
description="Registered in Ethiopia. You'll provide a TIN certificate, commercial license and national ID."
|
||||
description="Registered in Ethiopia. You'll provide a TIN certificate, commercial registration and national ID."
|
||||
icon={<MapPin size={22} />}
|
||||
selected={value === "ethiopian"}
|
||||
onClick={() => onChange("ethiopian")}
|
||||
|
||||
Reference in New Issue
Block a user