feat(WIP): setting and upload logic

This commit is contained in:
ghost2023
2026-06-04 15:39:36 +03:00
parent ad895d695e
commit ac964bace8
14 changed files with 1059 additions and 280 deletions

View File

@@ -13,6 +13,8 @@ import { ResponseCompanyDto } from './dto/response-company.dto';
import { ResponseExternalProfileDto } from './dto/response-external-profile.dto';
import { ResponseFFClientDto } from './dto/response-ff-client.dto';
import { CompanyInfoResponseDto } from './dto/company-info-response.dto';
import { UpdateProfileDto } from './dto/update-profile.dto';
import { ProfileResponseDto } from './dto/profile-response.dto';
interface CurrentIamUser {
id: string;
@@ -36,6 +38,22 @@ export class CompaniesController {
return new CompanyInfoResponseDto(profile, company);
}
@Get('profile')
@ApiOperation({ summary: 'Get flattened profile for the settings page' })
async getProfile(@CurrentUser() user: CurrentIamUser): Promise<ProfileResponseDto> {
const { profile, company } = await this.companiesService.getCompanyInfoByUserId(user.id);
return new ProfileResponseDto(profile, company);
}
@Patch('profile')
@ApiOperation({ summary: 'Update profile (flattened settings page)' })
async updateProfile(
@CurrentUser() user: CurrentIamUser,
@Body() dto: UpdateProfileDto,
): Promise<ProfileResponseDto> {
return this.companiesService.updateProfile(user.id, dto);
}
@Post('create')
@ApiOperation({ summary: 'Create a company with its associated external profile (onboarding)' })
async createWithProfile(

View File

@@ -7,6 +7,8 @@ import { UpdateCompanyDto } from './dto/update-company.dto';
import { CreateExternalProfileDto } from './dto/create-external-profile.dto';
import { CreateFFClientDto } from './dto/create-ff-client.dto';
import { CreateCompanyWithProfileDto } from './dto/create-company-with-profile.dto';
import { UpdateProfileDto } from './dto/update-profile.dto';
import { ProfileResponseDto } from './dto/profile-response.dto';
import { Company } from './entities/company.entity';
import { ExternalProfile } from './entities/external-profile.entity';
import { FFClient } from './entities/ff-client.entity';
@@ -103,6 +105,42 @@ export class CompaniesService {
return updated;
}
async updateProfile(userId: string, dto: UpdateProfileDto): Promise<ProfileResponseDto> {
const { profile, company } = await this.getCompanyInfoByUserId(userId);
const companyUpdates: Record<string, any> = {};
const attrUpdates: Record<string, any> = { ...(company.attributes ?? {}) };
if (dto.companyName !== undefined) companyUpdates.name = dto.companyName;
if (dto.companyEmail !== undefined) companyUpdates.email = dto.companyEmail;
if (dto.companyPhone !== undefined) companyUpdates.phone = dto.companyPhone;
if (dto.companyLocation !== undefined) companyUpdates.country = dto.companyLocation;
if (dto.companyAddress !== undefined) companyUpdates.address = dto.companyAddress;
if (dto.tin !== undefined) companyUpdates.tin = dto.tin;
if (dto.vatNumber !== undefined) companyUpdates.vatNumber = dto.vatNumber;
if (dto.fanNumber !== undefined) {
companyUpdates.businessLicense = dto.fanNumber;
companyUpdates.fanNumber = dto.fanNumber;
}
if (dto.contactPersonName !== undefined) attrUpdates.contactPersonName = dto.contactPersonName;
if (dto.contactPersonPhone !== undefined) attrUpdates.contactPersonPhone = dto.contactPersonPhone;
if (dto.generalManagerName !== undefined) attrUpdates.generalManagerName = dto.generalManagerName;
if (dto.generalManagerEmail !== undefined) attrUpdates.generalManagerEmail = dto.generalManagerEmail;
if (dto.generalManagerPhone !== undefined) attrUpdates.generalManagerPhone = dto.generalManagerPhone;
if (dto.poaName !== undefined) attrUpdates.poaName = dto.poaName;
if (dto.poaPhone !== undefined) attrUpdates.poaPhone = dto.poaPhone;
if (dto.poaEmail !== undefined) attrUpdates.poaEmail = dto.poaEmail;
if (dto.poaLocation !== undefined) attrUpdates.poaLocation = dto.poaLocation;
if (dto.poaAddress !== undefined) attrUpdates.poaAddress = dto.poaAddress;
companyUpdates.attributes = attrUpdates;
const updated = await this.companiesRepo.update(company.id, companyUpdates);
if (!updated) throw new NotFoundException(`Company ${company.id} not found`);
return new ProfileResponseDto(profile, updated);
}
async deleteCompany(id: string): Promise<void> {
await this.findCompanyById(id);
await this.companiesRepo.softDelete(id);

View File

@@ -0,0 +1,53 @@
import { Company } from '../entities/company.entity';
import { ExternalProfile } from '../entities/external-profile.entity';
export class ProfileResponseDto {
companyId: string;
companyName: string;
companyEmail: string | null;
companyPhone: string | null;
companyLocation: string;
companyAddress: string | null;
tinNumber: string;
vatNumber: string | null;
fanNumber: string | null;
contactPersonName: string | null;
contactPersonPhone: string | null;
generalManagerName: string | null;
generalManagerEmail: string | null;
generalManagerPhone: string | null;
poaName: string | null;
poaPhone: string | null;
poaEmail: string | null;
poaLocation: string | null;
poaAddress: string | null;
profileId: string;
constructor(profile: ExternalProfile, company: Company) {
this.companyId = company.id;
this.companyName = company.name;
this.companyEmail = company.email ?? null;
this.companyPhone = company.phone ?? null;
this.companyLocation = company.country;
this.companyAddress = company.address ?? null;
this.tinNumber = company.tin;
this.vatNumber = company.vatNumber ?? null;
this.fanNumber = company.fanNumber ?? null;
this.profileId = profile.id;
const attrs = company.attributes ?? {};
this.contactPersonName = attrs.contactPersonName ?? null;
this.contactPersonPhone = attrs.contactPersonPhone ?? null;
this.generalManagerName = attrs.generalManagerName ?? null;
this.generalManagerEmail = attrs.generalManagerEmail ?? null;
this.generalManagerPhone = attrs.generalManagerPhone ?? null;
this.poaName = attrs.poaName ?? null;
this.poaPhone = attrs.poaPhone ?? null;
this.poaEmail = attrs.poaEmail ?? null;
this.poaLocation = attrs.poaLocation ?? null;
this.poaAddress = attrs.poaAddress ?? null;
}
}

View File

@@ -0,0 +1,83 @@
import { IsString, IsOptional, IsEmail, MaxLength, Length, Matches } from 'class-validator';
export class UpdateProfileDto {
@IsOptional()
@IsString()
@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()
@Length(10, 10)
@Matches(/^\d+$/, { message: 'TIN must contain only digits' })
tin?: string;
@IsOptional()
@IsString()
@MaxLength(50)
vatNumber?: string;
@IsOptional()
@IsString()
@MaxLength(16)
fanNumber?: string;
@IsOptional()
@IsString()
contactPersonName?: string;
@IsOptional()
@IsString()
contactPersonPhone?: string;
@IsOptional()
@IsString()
generalManagerName?: string;
@IsOptional()
@IsEmail()
generalManagerEmail?: string;
@IsOptional()
@IsString()
generalManagerPhone?: string;
@IsOptional()
@IsString()
poaName?: string;
@IsOptional()
@IsString()
poaPhone?: string;
@IsOptional()
@IsEmail()
poaEmail?: string;
@IsOptional()
@IsString()
poaLocation?: string;
@IsOptional()
@IsString()
poaAddress?: string;
}