mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 17:45:42 +00:00
130 lines
3.9 KiB
TypeScript
130 lines
3.9 KiB
TypeScript
import { BaseEntity } from "@edr/api-common";
|
|
import { Column, Entity, Index, JoinColumn, ManyToOne } from "typeorm";
|
|
import { Company } from "./company.entity";
|
|
|
|
export enum ProfileType {
|
|
importer = "importer",
|
|
exporter = "exporter",
|
|
freightForwarder = "freight_forwarder",
|
|
djFreightForwarder = "dj_freight_forwarder",
|
|
transporter = "transporter",
|
|
}
|
|
|
|
export enum ProfileStatus {
|
|
Active = "active",
|
|
Pending = "pending",
|
|
/** Reviewer declined the role; carries a note. Customer can reapply → Pending. */
|
|
Rejected = "rejected",
|
|
Suspended = "suspended",
|
|
Blacklisted = "blacklisted",
|
|
}
|
|
|
|
/**
|
|
* @deprecated Legacy inline shape. Business-license files now live in the
|
|
* FileRecord model (`freight.files`, resource `company_profiles`). Kept only for
|
|
* the by-reference reuse shape consumed by bookings/contracts snapshots.
|
|
*/
|
|
export interface BusinessLicenseFile {
|
|
name: string;
|
|
url: string;
|
|
size: number;
|
|
mimeType?: string;
|
|
}
|
|
|
|
/**
|
|
* `live` — approved & in effect; `pending_add` — uploaded, awaiting approval;
|
|
* `pending_remove` — live but flagged for deletion on approval.
|
|
*/
|
|
export type StagedFileStatus = "live" | "pending_add" | "pending_remove";
|
|
|
|
/** A business-license file plus its change-review state, surfaced to clients. */
|
|
export interface ProfileLicenseFileView {
|
|
id: string;
|
|
name: string;
|
|
size: number;
|
|
mimeType: string;
|
|
status: StagedFileStatus;
|
|
}
|
|
|
|
/** A company-level document (e.g. the PoA letter) with its change-review state. */
|
|
export interface CompanyDocumentFileView {
|
|
id: string;
|
|
name: string;
|
|
size: number;
|
|
mimeType: string;
|
|
status: StagedFileStatus;
|
|
}
|
|
|
|
@Entity({ schema: "freight", name: "company_profiles" })
|
|
@Index(["reference"], { unique: true })
|
|
@Index(["type"])
|
|
@Index(["companyId"])
|
|
export class CompanyProfile extends BaseEntity {
|
|
@Column({ name: "company_id", type: "uuid" })
|
|
companyId!: string;
|
|
|
|
@ManyToOne(() => Company, (company) => company.companyProfiles)
|
|
@JoinColumn({ name: "company_id" })
|
|
company!: Company;
|
|
|
|
@Column({ name: "type", type: "varchar", length: 32, enum: ProfileType })
|
|
type!: ProfileType;
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
@Column({
|
|
name: "reference",
|
|
type: "varchar",
|
|
length: 20,
|
|
nullable: true,
|
|
})
|
|
reference!: string | null;
|
|
|
|
/**
|
|
* A newly requested operational role is unreviewed, so it defaults to Pending.
|
|
* Only {@link CompaniesService.setCompanyProfileStatus} may promote it to
|
|
* Active — an approved-by-default role would let a customer self-grant a
|
|
* service (e.g. importer) without any documentation review.
|
|
*/
|
|
@Column({
|
|
name: "status",
|
|
type: "varchar",
|
|
length: 32,
|
|
default: ProfileStatus.Pending,
|
|
})
|
|
status!: ProfileStatus;
|
|
|
|
@Column({
|
|
name: "business_license",
|
|
type: "varchar",
|
|
length: 100,
|
|
nullable: true,
|
|
})
|
|
businessLicense?: string | null;
|
|
|
|
/**
|
|
* Business-license documents for this profile, stored directly on the profile
|
|
* (multi-file). The bytes live in object storage; only the metadata/URLs are
|
|
* persisted here — this is intentionally NOT modelled via the FileRecord table.
|
|
*/
|
|
@Column({ name: "business_license_files", type: "jsonb", nullable: true })
|
|
businessLicenseFiles?: BusinessLicenseFile[] | null;
|
|
|
|
@Column({ name: "attributes", type: "jsonb", nullable: true })
|
|
attributes?: Record<string, any> | null;
|
|
|
|
/** Reviewer's note when the role is Rejected (cleared on reapply). */
|
|
@Column({ name: "review_note", type: "text", nullable: true })
|
|
reviewNote?: string | null;
|
|
|
|
@Column({ name: "reviewed_by", type: "uuid", nullable: true })
|
|
reviewedBy?: string | null;
|
|
|
|
@Column({ name: "reviewed_at", type: "timestamptz", nullable: true })
|
|
reviewedAt?: Date | null;
|
|
}
|