diff --git a/src/customer-support/customer-support.module.ts b/src/customer-support/customer-support.module.ts index ca8da4c..ed44336 100644 --- a/src/customer-support/customer-support.module.ts +++ b/src/customer-support/customer-support.module.ts @@ -1,13 +1,17 @@ import { Module } from "@nestjs/common"; +import { CreateTicketService } from "src/customer-support/tickets/services/create-ticket.service"; +import { GetTicketListService } from "src/customer-support/tickets/services/get-ticket-list.service"; +import { UpdateTicketService } from "src/customer-support/tickets/services/update-ticket.service"; import { TicketController } from "src/customer-support/tickets/ticket.controller"; -import { TicketService } from "src/customer-support/tickets/ticket.service"; @Module({ controllers: [ TicketController ], providers: [ - TicketService + GetTicketListService, + CreateTicketService, + UpdateTicketService, ], }) export class CustomerSupportModule { } \ No newline at end of file diff --git a/src/customer-support/http-test-files/ticket.test.http b/src/customer-support/http-test-files/ticket-with-filter.test.http similarity index 51% rename from src/customer-support/http-test-files/ticket.test.http rename to src/customer-support/http-test-files/ticket-with-filter.test.http index cc409ac..2796e4a 100644 --- a/src/customer-support/http-test-files/ticket.test.http +++ b/src/customer-support/http-test-files/ticket-with-filter.test.http @@ -1 +1 @@ -GET http://localhost:3000/tickets/OPEN?sortOrder=last_update&sortTypes=DESC&offset=0&limit=10&email=gilles@targointernet.com \ No newline at end of file +GET http://localhost:3000/tickets/OPEN?sortOrder=last_update&sortTypes=DESC&offset=0&limit=30&email=gilles@targointernet.com \ No newline at end of file diff --git a/src/customer-support/tickets/services/create-ticket.service.ts b/src/customer-support/tickets/services/create-ticket.service.ts new file mode 100644 index 0000000..7fdd3e3 --- /dev/null +++ b/src/customer-support/tickets/services/create-ticket.service.ts @@ -0,0 +1,11 @@ +import { Injectable } from "@nestjs/common"; +import { PrismaMariaDbService } from "prisma/mariadb/prisma-mariadb.service"; + +@Injectable() +export class CreateTicketService { + constructor(private readonly prisma: PrismaMariaDbService) { } + + createTicket = async () => { + + } +} \ No newline at end of file diff --git a/src/customer-support/tickets/services/get-ticket-list.service.ts b/src/customer-support/tickets/services/get-ticket-list.service.ts new file mode 100644 index 0000000..730eac6 --- /dev/null +++ b/src/customer-support/tickets/services/get-ticket-list.service.ts @@ -0,0 +1,132 @@ +import { Injectable } from "@nestjs/common"; +import { Result } from "src/common/errors/result-error.factory"; +import { PrismaMariaDbService } from "prisma/mariadb/prisma-mariadb.service"; +import { TicketList } from "src/customer-support/tickets/dtos/ticket-list.dto"; +import { sortOrders, sortTypes } from "src/customer-support/tickets/dtos/ticket.dto"; +import { Prisma } from "prisma/mariadb/generated/prisma/client/mariadb/client"; + +export const TIMESTAMP_MINIMUM = 1672531200; // 1er janvier 2023 + +@Injectable() +export class GetTicketListService { + constructor(private readonly prisma: PrismaMariaDbService) { } + + getListOfAllTicketByFilters = async ( + status: string[], + offset: number = 0, + limit: number = 25, + sortOrder: string = 'last_update', + sortType: 'DESC' | 'ASC' = 'DESC', + email?: string + ): Promise> => { + + try { + const staff = await this.prisma.staff.findFirst({ + where: { email }, + }); + if (!staff) return { success: false, error: 'EMPLOYEE_NOT_FOUND' } + if (!sortOrders.includes(sortOrder) || !sortTypes.includes(sortType)) return { success: false, error: 'INVALID_FILTER' } + + const statusList = Prisma.join(status); + + const rawTicketList = await this.prisma.$queryRaw( + Prisma.sql` + SELECT + t.id AS id, + t.status AS status, + CONCAT(s.first_name,' ',s.last_name) AS assignTo, + a.address1 AS deliveryAddress, + t.subject AS subject, + d.name AS department, + t.parent AS parentTicketId, + + CASE + WHEN t.due_date > 1672531200 + THEN FROM_UNIXTIME(t.due_date, '%d/%m/%y') + ELSE NULL + END AS dueDate, + + FROM_UNIXTIME(t.last_update, '%d/%m/%y') AS lastUpdate, + + CASE + WHEN CAST(t.date_closed AS UNSIGNED) > 1672531200 + THEN FROM_UNIXTIME(CAST(t.date_closed AS UNSIGNED), '%d/%m/%y') + ELSE NULL + END AS completedAt + + FROM staff s + LEFT JOIN ticket t ON t.assign_to = s.id + LEFT JOIN account a ON t.account_id = a.id + LEFT JOIN ticket_dept d ON t.dept_id = d.id + WHERE s.id = ${staff.id} + AND t.status IN (${statusList}) + ORDER BY ${Prisma.raw(sortOrder)} ${Prisma.raw(sortType)} + LIMIT ${limit} OFFSET ${offset} + `); + + return { success: true, data: rawTicketList } + } catch (error) { + return { success: false, error: 'TICKET_LIST_NOT_FOUND, ' + error }; + } + } + + getListOfTickets = async ( + email: string, + offset: number = 0, + limit: number = 25, + ): Promise> => { + + try { + const staff = await this.prisma.staff.findFirst({ + where: { email }, + }); + if (!staff) return { success: false, error: 'EMPLOYEE_NOT_FOUND' } + + const rawTicketList = await this.prisma.$queryRaw( + Prisma.sql` + SELECT + t.id AS id, + t.status AS status, + CONCAT(s.first_name,' ',s.last_name) AS assignTo, + a.address1 AS deliveryAddress, + t.subject AS subject, + d.name AS department, + t.parent AS parentTicketId, + + CASE + WHEN t.due_date > 1672531200 + THEN FROM_UNIXTIME(t.due_date, '%d/%m/%y') + ELSE NULL + END AS dueDate, + + FROM_UNIXTIME(t.last_update, '%d/%m/%y') AS lastUpdate, + + CASE + WHEN CAST(t.date_closed AS UNSIGNED) > 1672531200 + THEN FROM_UNIXTIME(CAST(t.date_closed AS UNSIGNED), '%d/%m/%y') + ELSE NULL + END AS completedAt + + FROM staff s + LEFT JOIN ticket t ON t.assign_to = s.id + LEFT JOIN account a ON t.account_id = a.id + LEFT JOIN ticket_dept d ON t.dept_id = d.id + WHERE s.id = ${staff.id} + ORDER BY + CASE + WHEN t.status = 'open' AND t.assign_to = 0 THEN 0 + WHEN t.status = 'open' AND t.assign_to = s.id THEN 1 + WHEN t.status = 'pending' AND t.assign_to = s.id THEN 2 + WHEN t.status = 'open' AND t.assign_to != s.id THEN 3 + WHEN t.status = 'pending' AND t.assign_to != s.id THEN 4 + ELSE 5 + END + LIMIT ${limit} OFFSET ${offset}; + `); + + return { success: true, data: rawTicketList } + } catch (error) { + return { success: false, error: 'TICKET_LIST_NOT_FOUND, ' + error }; + } + } +} \ No newline at end of file diff --git a/src/customer-support/tickets/services/update-ticket.service.ts b/src/customer-support/tickets/services/update-ticket.service.ts new file mode 100644 index 0000000..3d6c75e --- /dev/null +++ b/src/customer-support/tickets/services/update-ticket.service.ts @@ -0,0 +1,24 @@ +import { Injectable } from "@nestjs/common"; +import { PrismaMariaDbService } from "prisma/mariadb/prisma-mariadb.service"; +import { Result } from "src/common/errors/result-error.factory"; + +@Injectable() +export class UpdateTicketService { + constructor(private readonly prisma: PrismaMariaDbService) { } + + updateTicketById = async ( + ticketId: number + ): Promise> => { + try { + await this.prisma.ticket.update({ + where: { id: ticketId }, + data: {} + }) + + return { success: true, data: true } + } catch (error) { + console.error(error) + return { success: false, error: 'INVALID_TICKET_ID' } + } + } +} \ No newline at end of file diff --git a/src/customer-support/tickets/ticket.controller.ts b/src/customer-support/tickets/ticket.controller.ts index ec24471..332bdb8 100644 --- a/src/customer-support/tickets/ticket.controller.ts +++ b/src/customer-support/tickets/ticket.controller.ts @@ -2,12 +2,12 @@ import { Controller, Get, Param, ParseIntPipe, Query } from "@nestjs/common"; import { Access } from "src/common/decorators/module-access.decorators"; import { Result } from "src/common/errors/result-error.factory"; import { TicketList } from "src/customer-support/tickets/dtos/ticket-list.dto"; -import { TicketService } from "src/customer-support/tickets/ticket.service"; +import { GetTicketListService } from "src/customer-support/tickets/services/get-ticket-list.service"; @Controller('tickets') export class TicketController { - constructor(private readonly getService: TicketService) { } + constructor(private readonly getService: GetTicketListService) { } @Get(':status') async findTicketByFilters( @@ -31,4 +31,17 @@ export class TicketController { queryEmail, ); } + + @Get('list') + async findTicketList( + @Access('email') email:string, + @Query('offset', ParseIntPipe) offset: number, + @Query('limit', ParseIntPipe) limit: number, + ) { + return await this.getService.getListOfTickets( + email, + offset, + limit + ); + } } \ No newline at end of file diff --git a/src/customer-support/tickets/ticket.module.ts b/src/customer-support/tickets/ticket.module.ts index 805680b..ff23e91 100644 --- a/src/customer-support/tickets/ticket.module.ts +++ b/src/customer-support/tickets/ticket.module.ts @@ -1,10 +1,10 @@ import { Module } from "@nestjs/common"; +import { GetTicketListService } from "src/customer-support/tickets/services/get-ticket-list.service"; import { TicketController } from "src/customer-support/tickets/ticket.controller"; -import { TicketService } from "src/customer-support/tickets/ticket.service"; @Module({ imports: [ - TicketService + GetTicketListService ], providers: [ TicketController diff --git a/src/customer-support/tickets/ticket.service.ts b/src/customer-support/tickets/ticket.service.ts deleted file mode 100644 index f9dd5c4..0000000 --- a/src/customer-support/tickets/ticket.service.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { Injectable } from "@nestjs/common"; -import { Result } from "src/common/errors/result-error.factory"; -import { PrismaMariaDbService } from "prisma/mariadb/prisma-mariadb.service"; -import { TicketList } from "src/customer-support/tickets/dtos/ticket-list.dto"; -import { sortOrders, sortTypes } from "src/customer-support/tickets/dtos/ticket.dto"; -import { Prisma } from "prisma/mariadb/generated/prisma/client/mariadb/client"; - -@Injectable() -export class TicketService { - constructor(private readonly prisma: PrismaMariaDbService) { } - - getListOfAllTicketByFilters = async ( - status: string[], - offset: number = 0, - limit: number = 25, - sortOrder: string = 'last_update', - sortType: 'DESC' | 'ASC' = 'DESC', - email?: string - ): Promise> => { - - try { - const staff = await this.prisma.staff.findFirst({ - where: { email }, - }); - if (!staff) return { success: false, error: 'EMPLOYEE_NOT_FOUND' } - if (!sortOrders.includes(sortOrder) || !sortTypes.includes(sortType)) return { success: false, error: 'INVALID_FILTER' } - - const statusList = Prisma.join(status); - - const rawticketList = await this.prisma.$queryRaw( - Prisma.sql` - SELECT - t.id AS id, - t.status AS status, - CONCAT(s.first_name,' ',s.last_name) AS assignTo, - a.address1 AS deliveryAddress, - t.subject AS subject, - d.name AS department, - t.parent AS parentTicketId, - DATE_FORMAT(FROM_UNIXTIME(t.due_date / 1000), '%d/%m/%y') AS dueDate, - DATE_FORMAT(FROM_UNIXTIME(t.last_update / 1000), '%d/%m/%y') AS updatedAt, - CASE - WHEN t.date_closed IS NOT NULL - THEN DATE_FORMAT(FROM_UNIXTIME(t.date_closed / 1000), '%d/%m/%y') - ELSE NULL - END AS completedAt - FROM staff s - LEFT JOIN ticket t ON t.assign_to = s.id - LEFT JOIN account a ON t.account_id = a.id - LEFT JOIN ticket_dept d ON t.dept_id = d.id - WHERE s.email = ${email} - AND t.status IN (${statusList}) - ORDER BY ${Prisma.raw(sortOrder)} ${Prisma.raw(sortType)} - LIMIT ${limit} OFFSET ${offset}; - `); - - return { success: true, data: rawticketList } - } catch (error) { - return { success: false, error: 'TICKET_LIST_NOT_FOUND, ' + error }; - } - } -} \ No newline at end of file