company detail api and frontend

This commit is contained in:
hagiye
2026-05-26 01:06:06 +03:00
parent ab1dfe0c16
commit f90e5e0e1c
22 changed files with 2740 additions and 415 deletions

View File

@@ -1,5 +1,6 @@
// src/modules/customers/customers.controller.ts
import {
Body,
Controller,
Delete,
Get,
@@ -9,33 +10,54 @@ import {
ParseUUIDPipe,
Patch,
Post,
Body,
Query,
} from "@nestjs/common";
import { ApiOperation, ApiTags } from "@nestjs/swagger";
import { ApiOperation } from "@nestjs/swagger";
import { CustomersService } from "./customers.service";
import { CreateCustomerDto } from "./dto/create-customer.dto";
import { UpdateCustomerDto } from "./dto/update-customer.dto";
import { Customer } from "./entities/customer.entity";
@ApiTags("customers")
@Controller("customers")
export class CustomersController {
constructor(private readonly customersService: CustomersService) {}
@Post()
@ApiOperation({ summary: "Create a new customer" })
create(@Body() dto: CreateCustomerDto) {
return this.customersService.create(dto);
create(@Body() createCustomerDto: CreateCustomerDto): Promise<Customer> {
return this.customersService.create(createCustomerDto);
}
@Get()
@ApiOperation({ summary: "List all customers" })
findAll() {
findAll(): Promise<Customer[]> {
return this.customersService.findAll();
}
@Get("stats")
@ApiOperation({ summary: "Get customer statistics" })
getStats(): Promise<{ total: number; withVatNumber: number }> {
return this.customersService.getStats();
}
@Get("search")
searchByName(@Query("name") name: string): Promise<Customer[]> {
return this.customersService.searchByName(name);
}
@Get("email/:email")
findByEmail(@Param("email") email: string): Promise<Customer> {
return this.customersService.findByEmail(email);
}
@Get("vat/:vatNumber")
findByVatNumber(@Param("vatNumber") vatNumber: string): Promise<Customer> {
return this.customersService.findByVatNumber(vatNumber);
}
@Get(":id")
@ApiOperation({ summary: "Get a customer by ID" })
findOne(@Param("id", ParseUUIDPipe) id: string) {
findById(@Param("id", ParseUUIDPipe) id: string): Promise<Customer> {
return this.customersService.findById(id);
}
@@ -44,14 +66,14 @@ export class CustomersController {
update(
@Param("id", ParseUUIDPipe) id: string,
@Body() dto: UpdateCustomerDto,
) {
): Promise<Customer> {
return this.customersService.update(id, dto);
}
@Delete(":id")
@ApiOperation({ summary: "Soft-delete a customer" })
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param("id", ParseUUIDPipe) id: string) {
return this.customersService.remove(id);
remove(@Param("id", ParseUUIDPipe) id: string): Promise<void> {
return this.customersService.delete(id);
}
}
}

View File

@@ -1,21 +1,110 @@
import { BaseRepository } from "@edr/api-common";
// import { BaseRepository } from "@edr/api-common";
// import { EntityRepository } from "typeorm";
// src/modules/customers/customers.repository.ts
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { Repository, FindManyOptions, FindOptionsWhere } from "typeorm";
import { Customer } from "./entities/customer.entity";
import { CreateCustomerDto } from "./dto/create-customer.dto";
// import { UpdateCustomerDto } from "./dto/update-customer.dto";
@Injectable()
export class CustomersRepository extends BaseRepository<Customer> {
export class CustomersRepository {
constructor(
@InjectRepository(Customer)
repository: Repository<Customer>,
) {
super(repository);
private readonly repository: Repository<Customer>,
) {}
async create(dto: CreateCustomerDto): Promise<Customer> {
const customer = this.repository.create(dto);
return await this.repository.save(customer);
}
/** Find a customer by their unique email. */
findByEmail(email: string): Promise<Customer | null> {
return this.repository.findOne({ where: { email } });
async findAll(options?: FindManyOptions<Customer>): Promise<Customer[]> {
return await this.repository.find(options);
}
}
async findById(id: string): Promise<Customer | null> {
return await this.repository.findOne({ where: { id } as FindOptionsWhere<Customer> });
}
async findByEmail(email: string): Promise<Customer | null> {
return await this.repository.findOne({ where: { email } as FindOptionsWhere<Customer> });
}
async findByVatNumber(vatNumber: string): Promise<Customer | null> {
return await this.repository.findOne({ where: { vatNumber } as FindOptionsWhere<Customer> });
}
async findByName(name: string): Promise<Customer[]> {
return await this.repository
.createQueryBuilder("customer")
.where("customer.name ILIKE :name", { name: `%${name}%` })
.getMany();
}
async findOneByEmailOrVat(email?: string, vatNumber?: string): Promise<Customer | null> {
if (!email && !vatNumber) return null;
const queryBuilder = this.repository.createQueryBuilder('customer');
if (email && vatNumber) {
queryBuilder.where('customer.email = :email', { email })
.orWhere('customer.vatNumber = :vatNumber', { vatNumber });
} else if (email) {
queryBuilder.where('customer.email = :email', { email });
} else if (vatNumber) {
queryBuilder.where('customer.vatNumber = :vatNumber', { vatNumber });
}
return await queryBuilder.getOne();
}
async update(id: string, updates: Partial<Customer>): Promise<Customer | null> {
await this.repository.update(id, updates);
return this.findById(id);
}
async delete(id: string): Promise<boolean> {
const result = await this.repository.delete(id);
return (result.affected ?? 0) > 0;
}
async count(where?: any): Promise<number> {
if (where?.createdAt) {
const result = await this.repository
.createQueryBuilder('customer')
.where('customer.createdAt >= :date', { date: where.createdAt })
.getCount();
return result;
}
return await this.repository.count();
}
async existsByUniqueFields(email: string, vatNumber?: string): Promise<boolean> {
const queryBuilder = this.repository.createQueryBuilder('customer')
.where('customer.email = :email', { email });
if (vatNumber) {
queryBuilder.orWhere('customer.vatNumber = :vatNumber', { vatNumber });
}
const count = await queryBuilder.getCount();
return count > 0;
}
async countWithVatNumber(): Promise<number> {
const count = await this.repository
.createQueryBuilder('customer')
.where('customer.vatNumber IS NOT NULL')
.andWhere("customer.vatNumber != ''")
.getCount();
return count;
}
getRepository(): Repository<Customer> {
return this.repository;
}
}

View File

@@ -1,7 +1,8 @@
import {
ConflictException,
Injectable,
NotFoundException,
ConflictException,
BadRequestException,
} from "@nestjs/common";
import { CustomersRepository } from "./customers.repository";
@@ -13,34 +14,87 @@ import { Customer } from "./entities/customer.entity";
export class CustomersService {
constructor(private readonly customersRepository: CustomersRepository) {}
/** Create a new customer */
async create(dto: CreateCustomerDto): Promise<Customer> {
const existing = await this.customersRepository.findByEmail(dto.email);
if (existing) {
const exists = await this.customersRepository.existsByUniqueFields(
dto.email,
dto.vatNumber,
);
if (exists) {
throw new ConflictException(
`Customer with email "${dto.email}" already exists`,
"Customer with same email or VAT number already exists",
);
}
if (dto.vatNumber && dto.vatNumber.length !== 10) {
throw new BadRequestException("VAT number must be exactly 10 digits");
}
return this.customersRepository.create(dto);
}
/** Get all customers */
findAll(): Promise<Customer[]> {
return this.customersRepository.findAll({ order: { name: "ASC" } });
return this.customersRepository.findAll({
order: { companyName: "ASC" },
});
}
/** Get customer by ID */
async findById(id: string): Promise<Customer> {
const customer = await this.customersRepository.findById(id);
if (!customer) {
throw new NotFoundException(`Customer ${id} not found`);
throw new NotFoundException(`Customer with ID ${id} not found`);
}
return customer;
}
/** Get customer by email */
async findByEmail(email: string): Promise<Customer> {
const customer = await this.customersRepository.findByEmail(email);
if (!customer) {
throw new NotFoundException(`Customer with email ${email} not found`);
}
return customer;
}
/** Get customer by VAT number */
async findByVatNumber(vatNumber: string): Promise<Customer> {
const customer = await this.customersRepository.findByVatNumber(vatNumber);
if (!customer) {
throw new NotFoundException(
`Customer with VAT number ${vatNumber} not found`,
);
}
return customer;
}
/** Search customers by name */
searchByName(name: string): Promise<Customer[]> {
return this.customersRepository.findByName(name);
}
/** Update customer */
async update(id: string, dto: UpdateCustomerDto): Promise<Customer> {
await this.findById(id);
// Validate VAT number if provided
if (dto.vatNumber && dto.vatNumber.length !== 10) {
throw new BadRequestException("VAT number must be exactly 10 digits");
}
// Check email conflict
if (dto.email) {
const conflict = await this.customersRepository.findByEmail(dto.email);
if (conflict && conflict.id !== id) {
const existing = await this.customersRepository.findByEmail(dto.email);
if (existing && existing.userId !== id) {
throw new ConflictException(
`Customer with email "${dto.email}" already exists`,
);
@@ -48,14 +102,25 @@ export class CustomersService {
}
const updated = await this.customersRepository.update(id, dto);
if (!updated) {
throw new NotFoundException(`Customer ${id} not found`);
}
return updated;
}
/** Delete customer (soft delete) */
async remove(id: string): Promise<void> {
await this.findById(id);
await this.customersRepository.softDelete(id);
}
}
/** Get customer statistics */
async getStats(): Promise<{ total: number; withVatNumber: number }> {
const total = await this.customersRepository.count();
const withVatNumber = await this.customersRepository.countWithVatNumber();
return { total, withVatNumber };
}
}

View File

@@ -4,8 +4,12 @@ import {
IsOptional,
IsString,
MaxLength,
IsNotEmpty,
Length,
Matches,
} from "class-validator";
// Enums
export enum CustomerStatusDto {
Active = "Active",
Pending = "Pending",
@@ -18,23 +22,53 @@ export enum CustomerTypeDto {
Supplier = "Supplier",
}
// DTO
export class CreateCustomerDto {
// Basic identity
@IsString()
@MaxLength(256)
name!: string;
@IsNotEmpty()
@MaxLength(100)
firstName!: string;
@IsString()
@IsNotEmpty()
@MaxLength(100)
lastName!: string;
@IsEmail()
@IsNotEmpty()
email!: string;
@IsString()
@MaxLength(32)
@IsNotEmpty()
@MaxLength(20)
phone!: string;
@IsOptional()
// Company info
@IsString()
@MaxLength(256)
company?: string;
@IsNotEmpty()
@MaxLength(200)
companyName!: string;
@IsEmail()
@IsNotEmpty()
companyEmail!: string;
@IsString()
@IsNotEmpty()
@MaxLength(20)
companyPhone!: string;
@IsString()
@IsNotEmpty()
@MaxLength(100)
companyLocation!: string;
@IsString()
@IsNotEmpty()
companyAddress!: string;
// Classification
@IsOptional()
@IsEnum(CustomerTypeDto)
customerType?: CustomerTypeDto;
@@ -43,31 +77,76 @@ export class CreateCustomerDto {
@IsEnum(CustomerStatusDto)
status?: CustomerStatusDto;
// Legal identifiers
@IsString()
@IsNotEmpty()
@Length(10, 10)
@Matches(/^\d+$/, { message: "TIN must contain only digits" })
tinNumber!: string;
@IsString()
@IsNotEmpty()
@Length(16, 16)
@Matches(/^\d+$/, { message: "FAN must contain only digits" })
fanNumber!: string;
@IsString()
@IsNotEmpty()
@MaxLength(50)
vatNumber!: string;
// Contact person
@IsString()
@IsNotEmpty()
@MaxLength(100)
contactPersonName!: string;
@IsString()
@IsNotEmpty()
@MaxLength(20)
contactPersonPhone!: string;
// Management
@IsString()
@IsNotEmpty()
@MaxLength(100)
generalManagerName!: string;
@IsEmail()
@IsNotEmpty()
generalManagerEmail!: string;
@IsString()
@IsNotEmpty()
@MaxLength(20)
generalManagerPhone!: string;
// POA (Power of Attorney)
@IsOptional()
@IsString()
@MaxLength(64)
tinNumber?: string;
@MaxLength(100)
poaName?: string;
@IsOptional()
@IsString()
@MaxLength(128)
city?: string;
@MaxLength(20)
poaPhone?: string;
@IsOptional()
@IsString()
@MaxLength(128)
country?: string;
poaAddress?: string;
@IsOptional()
@IsEmail()
poaEmail?: string;
@IsOptional()
@IsString()
address?: string;
@IsOptional()
@IsString()
@MaxLength(64)
taxId?: string;
@MaxLength(100)
poaLocation?: string;
// Extra
@IsOptional()
@IsString()
notes?: string;
}
}

View File

@@ -0,0 +1,60 @@
// src/modules/customers/dto/response-customer.dto.ts
import { Customer } from '../entities/customer.entity';
export class ResponseCustomerDto {
UserId: string;
firstName: string;
lastName: string;
email: string;
phone: string;
companyName: string;
companyEmail: string;
companyPhone: string;
companyLocation: string;
companyAddress: string;
contactPersonName: string;
contactPersonPhone: string;
tinNumber: string;
vatNumber: string;
fanNumber: string;
generalManagerName: string;
generalManagerEmail: string;
generalManagerPhone: string;
poaName?: string;
poaPhone?: string;
poaAddress?: string;
poaEmail?: string;
poaLocation?: string;
notes?: string;
createdAt: Date;
updatedAt: Date;
constructor(customer: Customer) {
this.UserId = customer.userId;
this.firstName = customer.firstName;
this.lastName = customer.lastName;
this.email = customer.email;
this.phone = customer.phone;
this.companyName = customer.companyName;
this.companyEmail = customer.companyEmail;
this.companyPhone = customer.companyPhone;
this.companyLocation = customer.companyLocation;
this.companyAddress = customer.companyAddress;
this.contactPersonName = customer.contactPersonName;
this.contactPersonPhone = customer.contactPersonPhone;
this.tinNumber = customer.tinNumber;
this.vatNumber = customer.vatNumber;
this.fanNumber = customer.fanNumber;
this.generalManagerName = customer.generalManagerName;
this.generalManagerEmail = customer.generalManagerEmail;
this.generalManagerPhone = customer.generalManagerPhone;
this.poaName = customer.poaName ?? '';
this.poaPhone = customer.poaPhone ?? '';
this.poaAddress = customer.poaAddress ?? '';
this.poaEmail = customer.poaEmail ?? '';
this.poaLocation = customer.poaLocation ?? '';
this.notes = customer.notes ?? '';
this.createdAt = customer.createdAt;
this.updatedAt = customer.updatedAt;
}
}

View File

@@ -1,5 +1,9 @@
import { PartialType } from "@nestjs/swagger";
// src/modules/customers/dto/update-customer.dto.ts
import { PartialType } from '@nestjs/swagger';
import { CreateCustomerDto } from './create-customer.dto';
import { CreateCustomerDto } from "./create-customer.dto";
export class UpdateCustomerDto extends PartialType(CreateCustomerDto) {}
export class UpdateCustomerDto extends PartialType(CreateCustomerDto) {
email?: string;
vatNumber?: string;
// Add any other properties you need to access directly
}

View File

@@ -1,54 +1,94 @@
import { BaseEntity } from "@edr/api-common";
import { Column, Entity } from "typeorm";
export type CustomerStatus = "Active" | "Pending" | "Inactive";
export type CustomerType = "Importer" | "Exporter" | "Supplier";
import { Column, Entity ,
PrimaryGeneratedColumn,
CreateDateColumn,
UpdateDateColumn,
Index,
} from "typeorm";
@Entity({schema:"freight", name: "customers" })
export class Customer extends BaseEntity {
@Column({ name: "name", type: "varchar", length: 256 })
name!: string;
@Entity("customers")
export class Customer {
@PrimaryGeneratedColumn("uuid")
userId!: string;
@Column({ name: "email", type: "varchar", length: 256, unique: true })
@Column({ name: "firstName", length: 100 })
@Index()
firstName!: string;
@Column({ name: "lastName", length: 100 })
@Index()
lastName!: string;
@Column({ unique: true })
@Index()
email!: string;
@Column({ name: "phone", type: "varchar", length: 32 })
@Column({ length: 20 })
phone!: string;
@Column({ name: "company", type: "varchar", length: 256, nullable: true })
company?: string | null;
@Column({ name: "companyName", length: 200 })
@Index()
companyName!: string;
@Column({
name: "customer_type",
type: "varchar",
length: 32,
default: "Importer",
})
customerType!: CustomerType;
@Column({ name: "companyEmail" })
companyEmail!: string;
@Column({
name: "status",
type: "varchar",
length: 32,
default: "Active",
})
status!: CustomerStatus;
@Column({ name: "companyPhone", length: 20 })
companyPhone!: string;
@Column({ name: "tin_number", type: "varchar", length: 64, nullable: true })
tinNumber?: string | null;
@Column({ name: "companyLocation", length: 100 })
companyLocation!: string;
@Column({ name: "city", type: "varchar", length: 128, nullable: true })
city?: string | null;
@Column({ name: "companyAddress", type: "text" })
companyAddress!: string;
@Column({ name: "country", type: "varchar", length: 128, nullable: true })
country?: string | null;
@Column({ name: "contactPersonName", length: 100 })
contactPersonName!: string;
@Column({ name: "address", type: "text", nullable: true })
address?: string | null;
@Column({ name: "contactPersonPhone", length: 20 })
contactPersonPhone!: string;
@Column({ name: "tax_id", type: "varchar", length: 64, nullable: true })
taxId?: string | null;
@Column({ name: "tinNumber", length: 10, unique: true })
@Index()
tinNumber!: string;
@Column({ name: "notes", type: "text", nullable: true })
notes?: string | null;
@Column({ name: "vatNumber", length: 50 })
vatNumber!: string;
@Column({ name: "fanNumber", length: 16, unique: true })
@Index()
fanNumber!: string;
@Column({ name: "generalManagerName", length: 100 })
generalManagerName!: string;
@Column({ name: "generalManagerEmail" })
generalManagerEmail!: string;
@Column({ name: "generalManagerPhone", length: 20 })
generalManagerPhone!: string;
@Column({ name: "poaName", length: 100, nullable: true })
poaName?: string;
@Column({ name: "poaPhone", length: 20, nullable: true })
poaPhone?: string;
@Column({ name: "poaAddress", type: "text", nullable: true })
poaAddress?: string;
@Column({ name: "poaEmail", nullable: true })
poaEmail?: string;
@Column({ name: "poaLocation", length: 100, nullable: true })
poaLocation?: string;
@Column({ type: "text", nullable: true })
notes?: string;
@CreateDateColumn({ name: "createdAt" })
createdAt!: Date;
@UpdateDateColumn({ name: "updatedAt" })
updatedAt!: Date;
}

View File

@@ -0,0 +1,57 @@
import {
Body,
Controller,
Delete,
Get,
HttpCode,
HttpStatus,
Param,
ParseUUIDPipe,
Patch,
Post,
} from "@nestjs/common";
import { ApiOperation, ApiTags } from "@nestjs/swagger";
import { CustomersService } from "./customers.service";
import { CreateCustomerDto } from "./dto/create-customer.dto";
import { UpdateCustomerDto } from "./dto/update-customer.dto";
@ApiTags("customers")
@Controller("customers")
export class CustomersController {
constructor(private readonly customersService: CustomersService) {}
@Post()
@ApiOperation({ summary: "Create a new customer" })
create(@Body() dto: CreateCustomerDto) {
return this.customersService.create(dto);
}
@Get()
@ApiOperation({ summary: "List all customers" })
findAll() {
return this.customersService.findAll();
}
@Get(":id")
@ApiOperation({ summary: "Get a customer by ID" })
findOne(@Param("id", ParseUUIDPipe) id: string) {
return this.customersService.findById(id);
}
@Patch(":id")
@ApiOperation({ summary: "Update a customer" })
update(
@Param("id", ParseUUIDPipe) id: string,
@Body() dto: UpdateCustomerDto,
) {
return this.customersService.update(id, dto);
}
@Delete(":id")
@ApiOperation({ summary: "Soft-delete a customer" })
@HttpCode(HttpStatus.NO_CONTENT)
remove(@Param("id", ParseUUIDPipe) id: string) {
return this.customersService.remove(id);
}
}

View File

@@ -0,0 +1,15 @@
import { Module } from "@nestjs/common";
import { TypeOrmModule } from "@nestjs/typeorm";
import { CustomersController } from "./customers.controller";
import { CustomersRepository } from "./customers.repository";
import { CustomersService } from "./customers.service";
import { Customer } from "./entities/customer.entity";
@Module({
imports: [TypeOrmModule.forFeature([Customer])],
controllers: [CustomersController],
providers: [CustomersService, CustomersRepository],
exports: [CustomersService],
})
export class CustomersModule {}

View File

@@ -0,0 +1,21 @@
import { BaseRepository } from "@edr/api-common";
import { Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Repository } from "typeorm";
import { Customer } from "./entities/customer.entity";
@Injectable()
export class CustomersRepository extends BaseRepository<Customer> {
constructor(
@InjectRepository(Customer)
repository: Repository<Customer>,
) {
super(repository);
}
/** Find a customer by their unique email. */
findByEmail(email: string): Promise<Customer | null> {
return this.repository.findOne({ where: { email } });
}
}

View File

@@ -0,0 +1,61 @@
import {
ConflictException,
Injectable,
NotFoundException,
} from "@nestjs/common";
import { CustomersRepository } from "./customers.repository";
import { CreateCustomerDto } from "./dto/create-customer.dto";
import { UpdateCustomerDto } from "./dto/update-customer.dto";
import { Customer } from "./entities/customer.entity";
@Injectable()
export class CustomersService {
constructor(private readonly customersRepository: CustomersRepository) {}
async create(dto: CreateCustomerDto): Promise<Customer> {
const existing = await this.customersRepository.findByEmail(dto.email);
if (existing) {
throw new ConflictException(
`Customer with email "${dto.email}" already exists`,
);
}
return this.customersRepository.create(dto);
}
findAll(): Promise<Customer[]> {
return this.customersRepository.findAll({ order: { name: "ASC" } });
}
async findById(id: string): Promise<Customer> {
const customer = await this.customersRepository.findById(id);
if (!customer) {
throw new NotFoundException(`Customer ${id} not found`);
}
return customer;
}
async update(id: string, dto: UpdateCustomerDto): Promise<Customer> {
await this.findById(id);
if (dto.email) {
const conflict = await this.customersRepository.findByEmail(dto.email);
if (conflict && conflict.id !== id) {
throw new ConflictException(
`Customer with email "${dto.email}" already exists`,
);
}
}
const updated = await this.customersRepository.update(id, dto);
if (!updated) {
throw new NotFoundException(`Customer ${id} not found`);
}
return updated;
}
async remove(id: string): Promise<void> {
await this.findById(id);
await this.customersRepository.softDelete(id);
}
}

View File

@@ -0,0 +1,73 @@
import {
IsEmail,
IsEnum,
IsOptional,
IsString,
MaxLength,
} from "class-validator";
export enum CustomerStatusDto {
Active = "Active",
Pending = "Pending",
Inactive = "Inactive",
}
export enum CustomerTypeDto {
Importer = "Importer",
Exporter = "Exporter",
Supplier = "Supplier",
}
export class CreateCustomerDto {
@IsString()
@MaxLength(256)
name!: string;
@IsEmail()
email!: string;
@IsString()
@MaxLength(32)
phone!: string;
@IsOptional()
@IsString()
@MaxLength(256)
company?: string;
@IsOptional()
@IsEnum(CustomerTypeDto)
customerType?: CustomerTypeDto;
@IsOptional()
@IsEnum(CustomerStatusDto)
status?: CustomerStatusDto;
@IsOptional()
@IsString()
@MaxLength(64)
tinNumber?: string;
@IsOptional()
@IsString()
@MaxLength(128)
city?: string;
@IsOptional()
@IsString()
@MaxLength(128)
country?: string;
@IsOptional()
@IsString()
address?: string;
@IsOptional()
@IsString()
@MaxLength(64)
taxId?: string;
@IsOptional()
@IsString()
notes?: string;
}

View File

@@ -0,0 +1,5 @@
import { PartialType } from "@nestjs/swagger";
import { CreateCustomerDto } from "./create-customer.dto";
export class UpdateCustomerDto extends PartialType(CreateCustomerDto) {}

View File

@@ -0,0 +1,54 @@
import { BaseEntity } from "@edr/api-common";
import { Column, Entity } from "typeorm";
export type CustomerStatus = "Active" | "Pending" | "Inactive";
export type CustomerType = "Importer" | "Exporter" | "Supplier";
@Entity({schema:"freight", name: "customers" })
export class Customer extends BaseEntity {
@Column({ name: "name", type: "varchar", length: 256 })
name!: string;
@Column({ name: "email", type: "varchar", length: 256, unique: true })
email!: string;
@Column({ name: "phone", type: "varchar", length: 32 })
phone!: string;
@Column({ name: "company", type: "varchar", length: 256, nullable: true })
company?: string | null;
@Column({
name: "customer_type",
type: "varchar",
length: 32,
default: "Importer",
})
customerType!: CustomerType;
@Column({
name: "status",
type: "varchar",
length: 32,
default: "Active",
})
status!: CustomerStatus;
@Column({ name: "tin_number", type: "varchar", length: 64, nullable: true })
tinNumber?: string | null;
@Column({ name: "city", type: "varchar", length: 128, nullable: true })
city?: string | null;
@Column({ name: "country", type: "varchar", length: 128, nullable: true })
country?: string | null;
@Column({ name: "address", type: "text", nullable: true })
address?: string | null;
@Column({ name: "tax_id", type: "varchar", length: 64, nullable: true })
taxId?: string | null;
@Column({ name: "notes", type: "text", nullable: true })
notes?: string | null;
}