mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 21:15:41 +00:00
fix: make the reference generate on apporaval
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Company-profile references are now minted only when a profile is approved
|
||||||
|
* (status → Active); pending profiles carry NULL. Drop the NOT NULL constraint
|
||||||
|
* on freight.company_profiles.reference. The existing unique index is kept —
|
||||||
|
* Postgres treats NULLs as distinct, so multiple pending (NULL) profiles don't
|
||||||
|
* collide.
|
||||||
|
*/
|
||||||
|
export class MakeCompanyProfileReferenceNullable1810000000002
|
||||||
|
implements MigrationInterface
|
||||||
|
{
|
||||||
|
name = "MakeCompanyProfileReferenceNullable1810000000002";
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "freight"."company_profiles" ALTER COLUMN "reference" DROP NOT NULL`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
// Reinstating NOT NULL requires every row to have a reference; any pending
|
||||||
|
// (NULL) profiles get a placeholder so the constraint can be re-applied.
|
||||||
|
await queryRunner.query(
|
||||||
|
`UPDATE "freight"."company_profiles" SET "reference" = 'PENDING-' || left(replace("id"::text, '-', ''), 12) WHERE "reference" IS NULL`,
|
||||||
|
);
|
||||||
|
await queryRunner.query(
|
||||||
|
`ALTER TABLE "freight"."company_profiles" ALTER COLUMN "reference" SET NOT NULL`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -193,15 +193,13 @@ export class CompaniesService {
|
|||||||
input.type,
|
input.type,
|
||||||
);
|
);
|
||||||
if (existing) continue;
|
if (existing) continue;
|
||||||
const reference = await this.companyProfilesRepo.generateReference(
|
// No reference yet — these profiles await backoffice approval, which
|
||||||
input.type,
|
// is when the reference is minted (see setCompanyProfileStatus).
|
||||||
);
|
|
||||||
await this.companyProfilesRepo.create({
|
await this.companyProfilesRepo.create({
|
||||||
companyId: company.id,
|
companyId: company.id,
|
||||||
type: input.type,
|
type: input.type,
|
||||||
reference,
|
|
||||||
businessLicense: input.businessLicense ?? null,
|
businessLicense: input.businessLicense ?? null,
|
||||||
status: ProfileStatus.Active,
|
status: ProfileStatus.Pending,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
company.companyProfiles = await this.companyProfilesRepo.findByCompanyId(
|
company.companyProfiles = await this.companyProfilesRepo.findByCompanyId(
|
||||||
@@ -310,12 +308,11 @@ export class CompaniesService {
|
|||||||
type,
|
type,
|
||||||
);
|
);
|
||||||
if (existing) continue;
|
if (existing) continue;
|
||||||
const reference = await this.companyProfilesRepo.generateReference(type);
|
// No reference yet — minted on backoffice approval (setCompanyProfileStatus).
|
||||||
await this.companyProfilesRepo.create({
|
await this.companyProfilesRepo.create({
|
||||||
companyId,
|
companyId,
|
||||||
type,
|
type,
|
||||||
reference,
|
status: ProfileStatus.Pending,
|
||||||
status: ProfileStatus.Active,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -680,10 +677,20 @@ export class CompaniesService {
|
|||||||
profileId: string,
|
profileId: string,
|
||||||
status: ProfileStatus,
|
status: ProfileStatus,
|
||||||
): Promise<CompanyProfile> {
|
): Promise<CompanyProfile> {
|
||||||
const updated = await this.companyProfilesRepo.updateStatus(
|
const existing = await this.companyProfilesRepo.findById(profileId);
|
||||||
profileId,
|
if (!existing)
|
||||||
status,
|
throw new NotFoundException(`Company profile ${profileId} not found`);
|
||||||
);
|
|
||||||
|
// A reference number is only minted the first time a profile is approved
|
||||||
|
// (status → Active). Pending/unapproved profiles carry no reference.
|
||||||
|
const patch: Partial<CompanyProfile> = { status };
|
||||||
|
if (status === ProfileStatus.Active && !existing.reference) {
|
||||||
|
patch.reference = await this.companyProfilesRepo.generateReference(
|
||||||
|
existing.type,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const updated = await this.companyProfilesRepo.update(profileId, patch);
|
||||||
if (!updated)
|
if (!updated)
|
||||||
throw new NotFoundException(`Company profile ${profileId} not found`);
|
throw new NotFoundException(`Company profile ${profileId} not found`);
|
||||||
|
|
||||||
@@ -718,7 +725,7 @@ export class CompaniesService {
|
|||||||
const existing = await this.companyProfilesRepo.findByType(companyId, type);
|
const existing = await this.companyProfilesRepo.findByType(companyId, type);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
throw new ConflictException(
|
throw new ConflictException(
|
||||||
`Company already has a ${type} profile (${existing.reference})`,
|
`Company already has a ${type} profile (${existing.reference ?? "pending approval"})`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -931,7 +938,7 @@ export class CompaniesService {
|
|||||||
const licenseProfiles = (company.companyProfiles ?? []).map((p) => ({
|
const licenseProfiles = (company.companyProfiles ?? []).map((p) => ({
|
||||||
profileId: p.id,
|
profileId: p.id,
|
||||||
type: p.type,
|
type: p.type,
|
||||||
reference: p.reference,
|
reference: p.reference ?? "",
|
||||||
uploaded: (p.businessLicenseFiles?.length ?? 0) > 0,
|
uploaded: (p.businessLicenseFiles?.length ?? 0) > 0,
|
||||||
}));
|
}));
|
||||||
const missingLicenses = licenseProfiles.filter((p) => !p.uploaded);
|
const missingLicenses = licenseProfiles.filter((p) => !p.uploaded);
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export class ResponseCompanyProfileDto {
|
|||||||
this.id = profile.id;
|
this.id = profile.id;
|
||||||
this.companyId = profile.companyId;
|
this.companyId = profile.companyId;
|
||||||
this.type = profile.type;
|
this.type = profile.type;
|
||||||
this.reference = profile.reference;
|
this.reference = profile.reference ?? '';
|
||||||
this.status = profile.status;
|
this.status = profile.status;
|
||||||
this.businessLicense = profile.businessLicense;
|
this.businessLicense = profile.businessLicense;
|
||||||
this.licenseFiles = profile.businessLicenseFiles ?? [];
|
this.licenseFiles = profile.businessLicenseFiles ?? [];
|
||||||
|
|||||||
@@ -40,14 +40,19 @@ export class CompanyProfile extends BaseEntity {
|
|||||||
@Column({ name: "type", type: "varchar", length: 32, enum: ProfileType })
|
@Column({ name: "type", type: "varchar", length: 32, enum: ProfileType })
|
||||||
type!: ProfileType;
|
type!: ProfileType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Official profile reference (e.g. "EX-00001"). 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({
|
@Column({
|
||||||
name: "reference",
|
name: "reference",
|
||||||
type: "varchar",
|
type: "varchar",
|
||||||
length: 20,
|
length: 20,
|
||||||
nullable: false,
|
nullable: true,
|
||||||
unique: true,
|
|
||||||
})
|
})
|
||||||
reference!: string;
|
reference!: string | null;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
name: "status",
|
name: "status",
|
||||||
|
|||||||
Reference in New Issue
Block a user