feat(core): Introduce company and external profile management with dedicated API, services, and data schema

This commit is contained in:
ghost2023
2026-06-03 16:01:07 +03:00
parent c2145b48f5
commit dc9244d66e
22 changed files with 993 additions and 0 deletions

View File

@@ -0,0 +1,14 @@
import { Company } from '../entities/company.entity';
import { ExternalProfile } from '../entities/external-profile.entity';
import { ResponseCompanyDto } from './response-company.dto';
import { ResponseExternalProfileDto } from './response-external-profile.dto';
export class CompanyInfoResponseDto {
profile: ResponseExternalProfileDto;
company: ResponseCompanyDto;
constructor(profile: ExternalProfile, company: Company) {
this.profile = new ResponseExternalProfileDto(profile);
this.company = new ResponseCompanyDto(company);
}
}

View File

@@ -0,0 +1,58 @@
import { IsString, IsNotEmpty, IsOptional, IsEmail, MaxLength, IsBoolean, IsEnum } from 'class-validator';
import { CompanyType } from '../entities/company.entity';
export class CreateCompanyWithProfileDto {
@IsEnum(CompanyType)
companyType!: CompanyType;
@IsString()
@IsNotEmpty()
@MaxLength(200)
companyName!: string;
@IsOptional()
@IsEmail()
@MaxLength(150)
companyEmail?: string;
@IsOptional()
@IsString()
@MaxLength(20)
companyPhone?: string;
@IsOptional()
@IsString()
@MaxLength(32)
companyLocation?: string;
@IsOptional()
@IsString()
companyAddress?: string;
@IsOptional()
@IsString()
@MaxLength(10)
tin?: string;
@IsOptional()
@IsString()
@MaxLength(50)
vatNumber?: string;
@IsOptional()
@IsString()
@MaxLength(16)
fanNumber?: string;
@IsOptional()
@IsString()
@MaxLength(100)
jobTitle?: string;
@IsOptional()
@IsBoolean()
isPrimaryContact?: boolean;
@IsOptional()
attributes?: Record<string, any>;
}

View File

@@ -0,0 +1,59 @@
import { IsString, IsNotEmpty, IsOptional, IsEnum, MaxLength, Length, Matches, IsEmail } from 'class-validator';
import { CompanyType, CompanyStatus } from '../entities/company.entity';
export class CreateCompanyDto {
@IsString()
@IsNotEmpty()
@MaxLength(200)
name!: string;
@IsEnum(CompanyType)
type!: CompanyType;
@IsOptional()
@IsEnum(CompanyStatus)
status?: CompanyStatus;
@IsString()
@IsNotEmpty()
@Length(10, 10)
@Matches(/^\d+$/, { message: 'TIN must contain only digits' })
tin!: string;
@IsOptional()
@IsString()
@MaxLength(50)
vatNumber?: string;
@IsOptional()
@IsString()
@MaxLength(100)
businessLicense?: string;
@IsOptional()
@IsString()
@MaxLength(32)
country?: string;
@IsOptional()
@IsString()
address?: string;
@IsOptional()
@IsString()
@MaxLength(20)
phone?: string;
@IsOptional()
@IsEmail()
@MaxLength(150)
email?: string;
@IsOptional()
@IsString()
@MaxLength(200)
website?: string;
@IsOptional()
attributes?: Record<string, any>;
}

View File

@@ -0,0 +1,44 @@
import { IsString, IsNotEmpty, IsOptional, IsEmail, MaxLength, IsBoolean, IsUUID } from 'class-validator';
export class CreateExternalProfileDto {
@IsUUID()
@IsNotEmpty()
userId!: string;
@IsUUID()
@IsNotEmpty()
companyId!: string;
@IsString()
@IsNotEmpty()
@MaxLength(100)
firstName!: string;
@IsString()
@IsNotEmpty()
@MaxLength(100)
lastName!: string;
@IsEmail()
@IsNotEmpty()
email!: string;
@IsOptional()
@IsString()
@MaxLength(20)
phone?: string;
@IsOptional()
@IsString()
@MaxLength(50)
nationalId?: string;
@IsOptional()
@IsString()
@MaxLength(100)
jobTitle?: string;
@IsOptional()
@IsBoolean()
isPrimaryContact?: boolean;
}

View File

@@ -0,0 +1,24 @@
import { IsUUID, IsNotEmpty, IsOptional, IsBoolean, IsEnum } from 'class-validator';
import { FFClientRelationship } from '../entities/ff-client.entity';
export class CreateFFClientDto {
@IsUUID()
@IsNotEmpty()
forwarderCompanyId!: string;
@IsUUID()
@IsNotEmpty()
clientCompanyId!: string;
@IsOptional()
@IsEnum(FFClientRelationship)
relationshipType?: FFClientRelationship;
@IsOptional()
@IsBoolean()
canBookOnBehalf?: boolean;
@IsOptional()
@IsBoolean()
canViewDocuments?: boolean;
}

View File

@@ -0,0 +1,42 @@
import { Company, CompanyType, CompanyStatus } from '../entities/company.entity';
import { ResponseExternalProfileDto } from './response-external-profile.dto';
export class ResponseCompanyDto {
id: string;
name: string;
type: CompanyType;
status: CompanyStatus;
tin: string;
vatNumber?: string | null;
businessLicense?: string | null;
fanNumber?: string | null;
country: string;
address?: string | null;
phone?: string | null;
email?: string | null;
website?: string | null;
attributes?: Record<string, any> | null;
profiles?: ResponseExternalProfileDto[];
createdAt: Date;
updatedAt: Date;
constructor(company: Company) {
this.id = company.id;
this.name = company.name;
this.type = company.type;
this.status = company.status;
this.tin = company.tin;
this.vatNumber = company.vatNumber;
this.businessLicense = company.businessLicense;
this.fanNumber = company.fanNumber;
this.country = company.country;
this.address = company.address;
this.phone = company.phone;
this.email = company.email;
this.website = company.website;
this.attributes = company.attributes;
this.profiles = company.profiles?.map((p) => new ResponseExternalProfileDto(p));
this.createdAt = company.createdAt;
this.updatedAt = company.updatedAt;
}
}

View File

@@ -0,0 +1,31 @@
import { ExternalProfile } from '../entities/external-profile.entity';
export class ResponseExternalProfileDto {
id: string;
userId: string;
companyId: string;
firstName: string;
lastName: string;
email: string;
phone?: string | null;
nationalId?: string | null;
jobTitle?: string | null;
isPrimaryContact: boolean;
createdAt: Date;
updatedAt: Date;
constructor(profile: ExternalProfile) {
this.id = profile.id;
this.userId = profile.userId;
this.companyId = profile.companyId;
this.firstName = profile.firstName;
this.lastName = profile.lastName;
this.email = profile.email;
this.phone = profile.phone;
this.nationalId = profile.nationalId;
this.jobTitle = profile.jobTitle;
this.isPrimaryContact = profile.isPrimaryContact;
this.createdAt = profile.createdAt;
this.updatedAt = profile.updatedAt;
}
}

View File

@@ -0,0 +1,23 @@
import { FFClient, FFClientRelationship } from '../entities/ff-client.entity';
export class ResponseFFClientDto {
id: string;
forwarderCompanyId: string;
clientCompanyId: string;
relationshipType: FFClientRelationship;
canBookOnBehalf: boolean;
canViewDocuments: boolean;
createdAt: Date;
updatedAt: Date;
constructor(client: FFClient) {
this.id = client.id;
this.forwarderCompanyId = client.forwarderCompanyId;
this.clientCompanyId = client.clientCompanyId;
this.relationshipType = client.relationshipType;
this.canBookOnBehalf = client.canBookOnBehalf;
this.canViewDocuments = client.canViewDocuments;
this.createdAt = client.createdAt;
this.updatedAt = client.updatedAt;
}
}

View File

@@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateCompanyDto } from './create-company.dto';
export class UpdateCompanyDto extends PartialType(CreateCompanyDto) {}

View File

@@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateExternalProfileDto } from './create-external-profile.dto';
export class UpdateExternalProfileDto extends PartialType(CreateExternalProfileDto) {}

View File

@@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateFFClientDto } from './create-ff-client.dto';
export class UpdateFFClientDto extends PartialType(CreateFFClientDto) {}