mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 17:38:12 +00:00
feat(freight-api): gate poa paper, fayda identity, foreign passport
- dars delegation paper mandatory wherever poa state changes (named, removed, forwarder role applied for/approved), not just onboarding - ethiopian companies verify owner (and poa, once named) via fayda; identity, not general manager, is the verified subject - foreign companies require a typed owner passport number instead, independent of an optional fayda verification - fanNumber removed from client-writable dtos; server-derived only Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,11 @@ import {
|
||||
FILE_UPLOAD_SETTINGS_REPOSITORY,
|
||||
IFileUploadSettingsRepository,
|
||||
} from "./interfaces/file-upload-settings.repository.interface";
|
||||
import {
|
||||
COMPANY_ONBOARDING_CODE_PREFIX,
|
||||
POA_DELEGATION_FILE_KEY,
|
||||
poaDelegationField,
|
||||
} from "./poa-delegation.constants";
|
||||
|
||||
@Injectable()
|
||||
export class FileUploadSettingsService {
|
||||
@@ -40,6 +45,22 @@ export class FileUploadSettingsService {
|
||||
async getByCode(code: string): Promise<FileUploadSetting> {
|
||||
const setting = await this.repository.findByCode(code);
|
||||
if (!setting) throw new NotFoundException(`Setting "${code}" not found`);
|
||||
return this.withPoaDelegationField(setting);
|
||||
}
|
||||
|
||||
/**
|
||||
* Company onboarding sets always carry the DARS delegation paper, whether or
|
||||
* not anyone configured a row for it — see poa-delegation.constants.ts. Every
|
||||
* consumer (the portal's PoA step, the onboarding gate) reads the set through
|
||||
* here, so this is the single place the field can be guaranteed.
|
||||
*/
|
||||
private withPoaDelegationField(setting: FileUploadSetting): FileUploadSetting {
|
||||
if (!setting.code.startsWith(COMPANY_ONBOARDING_CODE_PREFIX)) return setting;
|
||||
const fields = setting.fields ?? [];
|
||||
if (fields.some((f) => f.fileKey === POA_DELEGATION_FILE_KEY)) return setting;
|
||||
|
||||
const lastOrder = fields.reduce((max, f) => Math.max(max, f.displayOrder), 0);
|
||||
setting.fields = [...fields, poaDelegationField(lastOrder + 1)];
|
||||
return setting;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import { FileUploadField } from "./entities/file-upload-field.entity";
|
||||
|
||||
/**
|
||||
* The DARS delegation paper — the document that evidences a company's Power of
|
||||
* Attorney (EDRFREIGHT-358).
|
||||
*
|
||||
* Every other onboarding document is admin-managed: the rows in
|
||||
* `file_upload_fields` are edited from the backoffice file-settings editor and
|
||||
* the seeder deliberately inserts none. This one is different — a company that
|
||||
* names a PoA must produce a delegation paper authenticated by the Documents
|
||||
* Authentication and Registration Service, and that is a legal requirement
|
||||
* rather than a configuration choice. So the field is defined here in code and
|
||||
* injected into the company onboarding sets on read: no row to forget to seed,
|
||||
* and deleting one in the editor cannot silently switch the requirement off.
|
||||
*/
|
||||
|
||||
/** FileRecord `code` (and upload field key) of the live delegation paper. */
|
||||
export const POA_DELEGATION_FILE_KEY = "poa_delegation_letter";
|
||||
|
||||
/** Code for a delegation paper staged in an open change request (not yet live). */
|
||||
export const POA_DELEGATION_PENDING_CODE = "poa_delegation_letter_pending";
|
||||
|
||||
/** Customer-facing name of the document, used by the API and both web apps. */
|
||||
export const POA_DELEGATION_LABEL = "DARS Delegation Paper";
|
||||
|
||||
/** Prefix of the setting codes the field is injected into. */
|
||||
export const COMPANY_ONBOARDING_CODE_PREFIX = "company_onboarding_documents_";
|
||||
|
||||
const POA_DELEGATION_HELP =
|
||||
"Delegation paper issued by the Documents Authentication and Registration " +
|
||||
"Service (DARS) delegating the representative named above. Upload the " +
|
||||
"authenticated copy — a plain letter is not accepted.";
|
||||
|
||||
/**
|
||||
* The field descriptor. `isRequired` stays false because the paper is only due
|
||||
* once a PoA has actually been named (or the company operates as a freight
|
||||
* forwarder) — a rule that spans form fields as well as files, so it is
|
||||
* enforced in CompaniesService rather than by this flag.
|
||||
*/
|
||||
export function poaDelegationField(displayOrder: number): FileUploadField {
|
||||
return {
|
||||
fileKey: POA_DELEGATION_FILE_KEY,
|
||||
fileLabel: POA_DELEGATION_LABEL,
|
||||
helpText: POA_DELEGATION_HELP,
|
||||
isRequired: false,
|
||||
isMultiple: false,
|
||||
maxFiles: 1,
|
||||
allowedExtensions: ["pdf", "jpg", "jpeg", "png"],
|
||||
maxSizeMb: 10,
|
||||
displayOrder,
|
||||
} as FileUploadField;
|
||||
}
|
||||
Reference in New Issue
Block a user