fix: resolve TypeORM cascade bug in ticket reply/close/updateStatus

- Replace ticketsRepo.save(ticket) with ticketsRepo.update() to avoid
  cascade orphaning existing messages (SET ticketId=null violates NOT NULL)
- Fix reply(), close() in tickets.service.ts
- Fix updateStatus() in tickets.controller.ts using new updateTicketFields() method
- Add updateTicketFields() helper to TicketsService for safe partial updates
This commit is contained in:
keyhan
2026-04-06 13:34:48 +03:30
parent 3ab647be2e
commit a1dbd0a85f
2 changed files with 23 additions and 18 deletions
+17 -14
View File
@@ -85,24 +85,20 @@ export class TicketsService {
// ─── Reply to ticket ───
async reply(ticketId: string, userId: string, userRole: UserRole, dto: ReplyTicketDto): Promise<TicketMessage> {
const ticket = await this.findOne(ticketId, userId, userRole);
// Verify access first
await this.findOne(ticketId, userId, userRole);
const msg = this.messagesRepo.create({
ticketId: ticket.id,
ticketId,
senderId: userId,
senderRole: userRole,
message: dto.message,
});
const saved = await this.messagesRepo.save(msg);
// Update ticket status based on who replied
if (userRole === UserRole.USER) {
ticket.status = TicketStatus.WAITING;
} else {
// Staff or admin replied
ticket.status = TicketStatus.ANSWERED;
}
await this.ticketsRepo.save(ticket);
// Update ticket status directly (avoid cascade issues with loaded relations)
const newStatus = userRole === UserRole.USER ? TicketStatus.WAITING : TicketStatus.ANSWERED;
await this.ticketsRepo.update(ticketId, { status: newStatus });
this.logger.log(`Reply on ticket ${ticketId} by ${userRole} user ${userId}`);
return saved;
@@ -110,10 +106,17 @@ export class TicketsService {
// ─── Close ticket ───
async close(ticketId: string, userId: string, userRole: UserRole): Promise<Ticket> {
const ticket = await this.findOne(ticketId, userId, userRole);
ticket.status = TicketStatus.CLOSED;
ticket.closedAt = new Date();
return this.ticketsRepo.save(ticket);
await this.findOne(ticketId, userId, userRole);
await this.ticketsRepo.update(ticketId, {
status: TicketStatus.CLOSED,
closedAt: new Date(),
});
return this.findOne(ticketId, userId, userRole);
}
// ─── Update ticket fields (safe, no cascade) ───
async updateTicketFields(ticketId: string, data: Partial<Ticket>): Promise<void> {
await this.ticketsRepo.update(ticketId, data);
}
// ─── Staff: List department tickets ───