251204:1700 Prepare to version 1.5.1
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
UseGuards,
|
||||
ParseIntPipe,
|
||||
Query,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiTags,
|
||||
ApiOperation,
|
||||
ApiBearerAuth,
|
||||
ApiQuery,
|
||||
} from '@nestjs/swagger';
|
||||
import { ContractService } from './contract.service.js';
|
||||
import { CreateContractDto } from './dto/create-contract.dto.js';
|
||||
import { UpdateContractDto } from './dto/update-contract.dto.js';
|
||||
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard.js';
|
||||
import { RequirePermission } from '../../common/decorators/require-permission.decorator.js';
|
||||
|
||||
@ApiTags('Contracts')
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('contracts')
|
||||
export class ContractController {
|
||||
constructor(private readonly contractService: ContractService) {}
|
||||
|
||||
@Post()
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Create Contract' })
|
||||
create(@Body() dto: CreateContractDto) {
|
||||
return this.contractService.create(dto);
|
||||
}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({
|
||||
summary: 'Get All Contracts (Optional: filter by projectId)',
|
||||
})
|
||||
@ApiQuery({ name: 'projectId', required: false, type: Number })
|
||||
findAll(@Query('projectId') projectId?: number) {
|
||||
return this.contractService.findAll(projectId);
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Get Contract by ID' })
|
||||
findOne(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.contractService.findOne(id);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Update Contract' })
|
||||
update(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() dto: UpdateContractDto
|
||||
) {
|
||||
return this.contractService.update(id, dto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Delete Contract' })
|
||||
remove(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.contractService.remove(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
import {
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
ConflictException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Contract } from './entities/contract.entity.js';
|
||||
import { CreateContractDto } from './dto/create-contract.dto.js';
|
||||
import { UpdateContractDto } from './dto/update-contract.dto.js';
|
||||
|
||||
@Injectable()
|
||||
export class ContractService {
|
||||
constructor(
|
||||
@InjectRepository(Contract)
|
||||
private readonly contractRepo: Repository<Contract>
|
||||
) {}
|
||||
|
||||
async create(dto: CreateContractDto) {
|
||||
const existing = await this.contractRepo.findOne({
|
||||
where: { contractCode: dto.contractCode },
|
||||
});
|
||||
if (existing) {
|
||||
throw new ConflictException(
|
||||
`Contract Code "${dto.contractCode}" already exists`
|
||||
);
|
||||
}
|
||||
const contract = this.contractRepo.create(dto);
|
||||
return this.contractRepo.save(contract);
|
||||
}
|
||||
|
||||
async findAll(projectId?: number) {
|
||||
const query = this.contractRepo
|
||||
.createQueryBuilder('c')
|
||||
.leftJoinAndSelect('c.project', 'p')
|
||||
.orderBy('c.contractCode', 'ASC');
|
||||
|
||||
if (projectId) {
|
||||
query.where('c.projectId = :projectId', { projectId });
|
||||
}
|
||||
|
||||
return query.getMany();
|
||||
}
|
||||
|
||||
async findOne(id: number) {
|
||||
const contract = await this.contractRepo.findOne({
|
||||
where: { id },
|
||||
relations: ['project'],
|
||||
});
|
||||
if (!contract) throw new NotFoundException(`Contract ID ${id} not found`);
|
||||
return contract;
|
||||
}
|
||||
|
||||
async update(id: number, dto: UpdateContractDto) {
|
||||
const contract = await this.findOne(id);
|
||||
Object.assign(contract, dto);
|
||||
return this.contractRepo.save(contract);
|
||||
}
|
||||
|
||||
async remove(id: number) {
|
||||
const contract = await this.findOne(id);
|
||||
// Schema doesn't have deleted_at for Contract either.
|
||||
return this.contractRepo.remove(contract);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
import {
|
||||
IsString,
|
||||
IsNotEmpty,
|
||||
IsBoolean,
|
||||
IsOptional,
|
||||
Length,
|
||||
IsInt,
|
||||
IsDateString,
|
||||
} from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class CreateContractDto {
|
||||
@ApiProperty({ example: 1 })
|
||||
@IsInt()
|
||||
@IsNotEmpty()
|
||||
projectId!: number;
|
||||
|
||||
@ApiProperty({ example: 'C-001' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Length(1, 50)
|
||||
contractCode!: string;
|
||||
|
||||
@ApiProperty({ example: 'Main Construction Contract' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Length(1, 255)
|
||||
contractName!: string;
|
||||
|
||||
@ApiProperty({ example: 'Description of the contract', required: false })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
description?: string;
|
||||
|
||||
@ApiProperty({ example: '2024-01-01', required: false })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
startDate?: string; // Receive as string, TypeORM handles date
|
||||
|
||||
@ApiProperty({ example: '2025-12-31', required: false })
|
||||
@IsOptional()
|
||||
@IsDateString()
|
||||
endDate?: string;
|
||||
|
||||
@ApiProperty({ example: true, required: false })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
isActive?: boolean;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import {
|
||||
IsString,
|
||||
IsNotEmpty,
|
||||
IsBoolean,
|
||||
IsOptional,
|
||||
Length,
|
||||
} from 'class-validator';
|
||||
import { ApiProperty } from '@nestjs/swagger';
|
||||
|
||||
export class CreateOrganizationDto {
|
||||
@ApiProperty({ example: 'ITD' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Length(1, 20)
|
||||
organizationCode!: string;
|
||||
|
||||
@ApiProperty({ example: 'Italian-Thai Development' })
|
||||
@IsString()
|
||||
@IsNotEmpty()
|
||||
@Length(1, 255)
|
||||
organizationName!: string;
|
||||
|
||||
@ApiProperty({ example: true, required: false })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
isActive?: boolean;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { PartialType } from '@nestjs/swagger';
|
||||
import { CreateContractDto } from './create-contract.dto.js';
|
||||
|
||||
export class UpdateContractDto extends PartialType(CreateContractDto) {}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { PartialType } from '@nestjs/swagger';
|
||||
import { CreateOrganizationDto } from './create-organization.dto.js';
|
||||
|
||||
export class UpdateOrganizationDto extends PartialType(CreateOrganizationDto) {}
|
||||
@@ -0,0 +1,61 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Post,
|
||||
Body,
|
||||
Patch,
|
||||
Param,
|
||||
Delete,
|
||||
UseGuards,
|
||||
ParseIntPipe,
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { OrganizationService } from './organization.service.js';
|
||||
import { CreateOrganizationDto } from './dto/create-organization.dto.js';
|
||||
import { UpdateOrganizationDto } from './dto/update-organization.dto.js';
|
||||
import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard.js';
|
||||
import { RequirePermission } from '../../common/decorators/require-permission.decorator.js';
|
||||
|
||||
@ApiTags('Organizations')
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('organizations')
|
||||
export class OrganizationController {
|
||||
constructor(private readonly orgService: OrganizationService) {}
|
||||
|
||||
@Post()
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Create Organization' })
|
||||
create(@Body() dto: CreateOrganizationDto) {
|
||||
return this.orgService.create(dto);
|
||||
}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: 'Get All Organizations' })
|
||||
findAll() {
|
||||
return this.orgService.findAll();
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@ApiOperation({ summary: 'Get Organization by ID' })
|
||||
findOne(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.orgService.findOne(id);
|
||||
}
|
||||
|
||||
@Patch(':id')
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Update Organization' })
|
||||
update(
|
||||
@Param('id', ParseIntPipe) id: number,
|
||||
@Body() dto: UpdateOrganizationDto
|
||||
) {
|
||||
return this.orgService.update(id, dto);
|
||||
}
|
||||
|
||||
@Delete(':id')
|
||||
@RequirePermission('master_data.manage')
|
||||
@ApiOperation({ summary: 'Delete Organization' })
|
||||
remove(@Param('id', ParseIntPipe) id: number) {
|
||||
return this.orgService.remove(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import {
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
ConflictException,
|
||||
} from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { Organization } from './entities/organization.entity.js';
|
||||
import { CreateOrganizationDto } from './dto/create-organization.dto.js';
|
||||
import { UpdateOrganizationDto } from './dto/update-organization.dto.js';
|
||||
|
||||
@Injectable()
|
||||
export class OrganizationService {
|
||||
constructor(
|
||||
@InjectRepository(Organization)
|
||||
private readonly orgRepo: Repository<Organization>
|
||||
) {}
|
||||
|
||||
async create(dto: CreateOrganizationDto) {
|
||||
const existing = await this.orgRepo.findOne({
|
||||
where: { organizationCode: dto.organizationCode },
|
||||
});
|
||||
if (existing) {
|
||||
throw new ConflictException(
|
||||
`Organization Code "${dto.organizationCode}" already exists`
|
||||
);
|
||||
}
|
||||
const org = this.orgRepo.create(dto);
|
||||
return this.orgRepo.save(org);
|
||||
}
|
||||
|
||||
async findAll() {
|
||||
return this.orgRepo.find({
|
||||
order: { organizationCode: 'ASC' },
|
||||
});
|
||||
}
|
||||
|
||||
async findOne(id: number) {
|
||||
const org = await this.orgRepo.findOne({ where: { id } });
|
||||
if (!org) throw new NotFoundException(`Organization ID ${id} not found`);
|
||||
return org;
|
||||
}
|
||||
|
||||
async update(id: number, dto: UpdateOrganizationDto) {
|
||||
const org = await this.findOne(id);
|
||||
Object.assign(org, dto);
|
||||
return this.orgRepo.save(org);
|
||||
}
|
||||
|
||||
async remove(id: number) {
|
||||
const org = await this.findOne(id);
|
||||
// Hard delete or Soft delete? Schema doesn't have deleted_at for Organization, but let's check.
|
||||
// Schema says: created_at, updated_at. No deleted_at.
|
||||
// So hard delete.
|
||||
return this.orgRepo.remove(org);
|
||||
}
|
||||
}
|
||||
@@ -2,26 +2,32 @@ import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { ProjectService } from './project.service.js';
|
||||
import { ProjectController } from './project.controller.js';
|
||||
import { OrganizationService } from './organization.service.js';
|
||||
import { OrganizationController } from './organization.controller.js';
|
||||
import { ContractService } from './contract.service.js';
|
||||
import { ContractController } from './contract.controller.js';
|
||||
|
||||
import { Project } from './entities/project.entity.js';
|
||||
import { Organization } from './entities/organization.entity.js';
|
||||
import { Contract } from './entities/contract.entity.js';
|
||||
import { ProjectOrganization } from './entities/project-organization.entity.js'; // เพิ่ม
|
||||
import { ContractOrganization } from './entities/contract-organization.entity.js'; // เพิ่ม
|
||||
import { ProjectOrganization } from './entities/project-organization.entity.js';
|
||||
import { ContractOrganization } from './entities/contract-organization.entity.js';
|
||||
// Modules
|
||||
import { UserModule } from '../user/user.module'; // ✅ 1. Import UserModule
|
||||
import { UserModule } from '../user/user.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
TypeOrmModule.forFeature([
|
||||
Project,
|
||||
Organization,
|
||||
Contract,
|
||||
ProjectOrganization, // ลงทะเบียน
|
||||
ContractOrganization, // ลงทะเบียน
|
||||
ProjectOrganization,
|
||||
ContractOrganization,
|
||||
]),
|
||||
UserModule, // ✅ 2. เพิ่ม UserModule เข้าไปใน imports
|
||||
UserModule,
|
||||
],
|
||||
controllers: [ProjectController],
|
||||
providers: [ProjectService],
|
||||
exports: [ProjectService], // Export เผื่อ Module อื่นใช้
|
||||
controllers: [ProjectController, OrganizationController, ContractController],
|
||||
providers: [ProjectService, OrganizationService, ContractService],
|
||||
exports: [ProjectService, OrganizationService, ContractService],
|
||||
})
|
||||
export class ProjectModule {}
|
||||
|
||||
Reference in New Issue
Block a user