251119:1700 Backend Phase 1

This commit is contained in:
admin
2025-11-19 16:58:44 +07:00
parent 2b36e5554b
commit 4c961aa4ee
42 changed files with 1701 additions and 45 deletions
@@ -0,0 +1,25 @@
import { Entity, Column, PrimaryColumn, ManyToOne, JoinColumn } from 'typeorm';
import { Contract } from './contract.entity.js';
import { Organization } from './organization.entity.js';
@Entity('contract_organizations')
export class ContractOrganization {
@PrimaryColumn({ name: 'contract_id' })
contractId!: number;
@PrimaryColumn({ name: 'organization_id' })
organizationId!: number;
@Column({ name: 'role_in_contract', nullable: true, length: 100 })
roleInContract?: string;
// Relation ไปยัง Contract
@ManyToOne(() => Contract, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'contract_id' })
contract?: Contract;
// Relation ไปยัง Organization
@ManyToOne(() => Organization, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'organization_id' })
organization?: Organization;
}
@@ -0,0 +1,41 @@
import {
Entity,
Column,
PrimaryGeneratedColumn,
ManyToOne,
JoinColumn,
} from 'typeorm';
import { BaseEntity } from '../../../common/entities/base.entity.js';
import { Project } from './project.entity.js';
@Entity('contracts')
export class Contract extends BaseEntity {
@PrimaryGeneratedColumn()
id!: number;
@Column({ name: 'project_id' })
projectId!: number;
@Column({ name: 'contract_code', unique: true, length: 50 })
contractCode!: string;
@Column({ name: 'contract_name', length: 255 })
contractName!: string;
@Column({ type: 'text', nullable: true })
description?: string;
@Column({ name: 'start_date', type: 'date', nullable: true })
startDate?: Date;
@Column({ name: 'end_date', type: 'date', nullable: true })
endDate?: Date;
@Column({ name: 'is_active', default: true })
isActive!: boolean;
// Relation
@ManyToOne(() => Project)
@JoinColumn({ name: 'project_id' })
project?: Project;
}
@@ -0,0 +1,17 @@
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
import { BaseEntity } from '../../../common/entities/base.entity.js';
@Entity('organizations')
export class Organization extends BaseEntity {
@PrimaryGeneratedColumn()
id!: number;
@Column({ name: 'organization_code', unique: true, length: 20 })
organizationCode!: string;
@Column({ name: 'organization_name', length: 255 })
organizationName!: string;
@Column({ name: 'is_active', default: true })
isActive!: boolean;
}
@@ -0,0 +1,23 @@
import { Entity, PrimaryColumn, ManyToOne, JoinColumn } from 'typeorm';
import { Project } from './project.entity.js';
import { Organization } from './organization.entity.js';
@Entity('project_organizations')
export class ProjectOrganization {
// Composite Primary Key (ใช้ 2 คอลัมน์รวมกันเป็น PK)
@PrimaryColumn({ name: 'project_id' })
projectId!: number;
@PrimaryColumn({ name: 'organization_id' })
organizationId!: number;
// Relation ไปยัง Project
@ManyToOne(() => Project, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'project_id' })
project?: Project;
// Relation ไปยัง Organization
@ManyToOne(() => Organization, { onDelete: 'CASCADE' })
@JoinColumn({ name: 'organization_id' })
organization?: Organization;
}
@@ -0,0 +1,17 @@
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
import { BaseEntity } from '../../../common/entities/base.entity.js';
@Entity('projects')
export class Project extends BaseEntity {
@PrimaryGeneratedColumn()
id!: number;
@Column({ name: 'project_code', unique: true, length: 50 })
projectCode!: string;
@Column({ name: 'project_name', length: 255 })
projectName!: string;
@Column({ name: 'is_active', default: 1, type: 'tinyint' })
isActive!: boolean;
}
@@ -0,0 +1,19 @@
import { Controller, Get, UseGuards } from '@nestjs/common';
import { ProjectService } from './project.service.js';
import { JwtAuthGuard } from '../../common/auth/jwt-auth.guard.js';
@Controller('projects')
@UseGuards(JwtAuthGuard)
export class ProjectController {
constructor(private readonly projectService: ProjectService) {}
@Get()
findAll() {
return this.projectService.findAllProjects();
}
@Get('organizations')
findAllOrgs() {
return this.projectService.findAllOrganizations();
}
}
@@ -0,0 +1,4 @@
import { Controller } from '@nestjs/common';
@Controller('project')
export class ProjectController {}
@@ -0,0 +1,25 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ProjectService } from './project.service.js';
import { ProjectController } from './project.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'; // เพิ่ม
@Module({
imports: [
TypeOrmModule.forFeature([
Project,
Organization,
Contract,
ProjectOrganization, // ลงทะเบียน
ContractOrganization, // ลงทะเบียน
]),
],
controllers: [ProjectController],
providers: [ProjectService],
exports: [ProjectService], // Export เผื่อ Module อื่นใช้
})
export class ProjectModule {}
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ProjectService } from './project.service';
describe('ProjectService', () => {
let service: ProjectService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [ProjectService],
}).compile();
service = module.get<ProjectService>(ProjectService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
@@ -0,0 +1,25 @@
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Project } from './entities/project.entity.js';
import { Organization } from './entities/organization.entity.js';
@Injectable()
export class ProjectService {
constructor(
@InjectRepository(Project)
private projectRepository: Repository<Project>,
@InjectRepository(Organization)
private organizationRepository: Repository<Organization>,
) {}
// ดึงรายการ Project ทั้งหมด
async findAllProjects() {
return this.projectRepository.find();
}
// ดึงรายการ Organization ทั้งหมด
async findAllOrganizations() {
return this.organizationRepository.find();
}
}