251123:2300 Update T1

This commit is contained in:
2025-11-24 08:15:15 +07:00
parent 23006898d9
commit 9360d78ea6
81 changed files with 4232 additions and 347 deletions

View File

@@ -1,11 +1,18 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import {
Injectable,
NotFoundException,
BadRequestException,
ForbiddenException,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository, DataSource } from 'typeorm';
import { Repository, DataSource, Not } from 'typeorm'; // เพิ่ม Not
import { Circulation } from './entities/circulation.entity';
import { CirculationRouting } from './entities/circulation-routing.entity';
import { User } from '../user/entities/user.entity';
import { CreateCirculationDto } from './dto/create-circulation.dto'; // ต้องสร้าง DTO นี้
import { CreateCirculationDto } from './dto/create-circulation.dto';
import { UpdateCirculationRoutingDto } from './dto/update-circulation-routing.dto'; // Import ใหม่
import { SearchCirculationDto } from './dto/search-circulation.dto'; // Import ใหม่
@Injectable()
export class CirculationService {
@@ -18,13 +25,16 @@ export class CirculationService {
) {}
async create(createDto: CreateCirculationDto, user: User) {
if (!user.primaryOrganizationId) {
throw new BadRequestException('User must belong to an organization');
}
const queryRunner = this.dataSource.createQueryRunner();
await queryRunner.connect();
await queryRunner.startTransaction();
try {
// 1. Create Master Circulation
// TODO: Generate Circulation No. logic here (Simple format)
// Generate No. (Mock Logic) -> ควรใช้ NumberingService จริงในอนาคต
const circulationNo = `CIR-${Date.now()}`;
const circulation = queryRunner.manager.create(Circulation, {
@@ -37,13 +47,12 @@ export class CirculationService {
});
const savedCirculation = await queryRunner.manager.save(circulation);
// 2. Create Routings (Assignees)
if (createDto.assigneeIds && createDto.assigneeIds.length > 0) {
const routings = createDto.assigneeIds.map((userId, index) =>
queryRunner.manager.create(CirculationRouting, {
circulationId: savedCirculation.id,
stepNumber: index + 1,
organizationId: user.primaryOrganizationId, // Internal routing
organizationId: user.primaryOrganizationId,
assignedTo: userId,
status: 'PENDING',
}),
@@ -61,23 +70,84 @@ export class CirculationService {
}
}
async findAll(searchDto: SearchCirculationDto, user: User) {
const { search, status, page = 1, limit = 20 } = searchDto;
const query = this.circulationRepo
.createQueryBuilder('c')
.leftJoinAndSelect('c.creator', 'creator')
.where('c.organizationId = :orgId', {
orgId: user.primaryOrganizationId,
});
if (status) {
query.andWhere('c.statusCode = :status', { status });
}
if (search) {
query.andWhere(
'(c.circulationNo LIKE :search OR c.subject LIKE :search)',
{ search: `%${search}%` },
);
}
query
.orderBy('c.createdAt', 'DESC')
.skip((page - 1) * limit)
.take(limit);
const [data, total] = await query.getManyAndCount();
return { data, meta: { total, page, limit } };
}
async findOne(id: number) {
const circulation = await this.circulationRepo.findOne({
where: { id },
relations: ['routings', 'routings.assignee', 'correspondence'],
relations: ['routings', 'routings.assignee', 'correspondence', 'creator'],
order: { routings: { stepNumber: 'ASC' } },
});
if (!circulation) throw new NotFoundException('Circulation not found');
return circulation;
}
// Method update status (Complete task)
// ✅ Logic อัปเดตสถานะและปิดงาน
async updateRoutingStatus(
routingId: number,
status: string,
comments: string,
dto: UpdateCirculationRoutingDto,
user: User,
) {
// Logic to update routing status
// and Check if all routings are completed -> Close Circulation
const routing = await this.routingRepo.findOne({
where: { id: routingId },
relations: ['circulation'],
});
if (!routing) throw new NotFoundException('Routing task not found');
// Check Permission: คนทำต้องเป็นเจ้าของ Task
if (routing.assignedTo !== user.user_id) {
throw new ForbiddenException('You are not assigned to this task');
}
// Update Routing
routing.status = dto.status;
routing.comments = dto.comments;
routing.completedAt = new Date();
await this.routingRepo.save(routing);
// Check: ถ้าทุกคนทำเสร็จแล้ว ให้ปิดใบเวียน (Master)
const pendingCount = await this.routingRepo.count({
where: {
circulationId: routing.circulationId,
status: 'PENDING', // หรือ status ที่ยังไม่เสร็จ
},
});
if (pendingCount === 0) {
await this.circulationRepo.update(routing.circulationId, {
statusCode: 'COMPLETED',
closedAt: new Date(),
});
}
return routing;
}
}