feat(freight): record when a company is approved

Ticket #420 — add approved_at to companies (migration), stamped at
both promotion sites (first-profile auto-approve and manual staff
status change). Surfaced as Submitted on/Approved on in the backoffice
customer list and detail views.
This commit is contained in:
Nathnael
2026-07-31 11:43:36 +00:00
parent 83d3fc3b78
commit d67297a601
7 changed files with 85 additions and 1 deletions

View File

@@ -682,7 +682,16 @@ export class CompaniesService {
async updateCompany(id: string, dto: UpdateCompanyDto): Promise<Company> {
const before = await this.findCompanyById(id);
const updated = await this.companiesRepo.update(id, dto);
const patch: UpdateCompanyDto & { approvedAt?: Date } = { ...dto };
// Staff can also promote Pending -> Active directly through this generic
// endpoint (not just via the first-profile-approval path), so stamp it here too.
if (
dto.status === CompanyStatus.Active &&
before.status !== CompanyStatus.Active
) {
patch.approvedAt = new Date();
}
const updated = await this.companiesRepo.update(id, patch);
if (!updated) throw new NotFoundException(`Company ${id} not found`);
// Suspending or blacklisting locks the customer out, so they must be told.
@@ -1472,6 +1481,7 @@ export class CompaniesService {
) {
await companyRepo.update(updated.companyId, {
status: CompanyStatus.Active,
approvedAt: new Date(),
});
this.companyNotifier.companyApproved(company);
}

View File

@@ -97,6 +97,7 @@ export class ResponseCompanyDto {
createdAt: Date;
updatedAt: Date;
approvedAt: Date | null;
constructor(company: Company) {
this.id = company.id;
@@ -135,5 +136,6 @@ export class ResponseCompanyDto {
this.identity = buildCompanyIdentityState(company);
this.createdAt = company.createdAt;
this.updatedAt = company.updatedAt;
this.approvedAt = company.approvedAt ?? null;
}
}

View File

@@ -61,6 +61,10 @@ export class Company extends BaseEntity {
})
status!: CompanyStatus;
/** Set when the company is first promoted Pending → Active. Null for companies approved before this column existed. */
@Column({ name: "approved_at", type: "timestamptz", nullable: true })
approvedAt?: Date | null;
@Column({ name: "tin", type: "varchar", length: 10, unique: true })
tin!: string;