feat(ticket): added a route to get tickets using the email of the assigned employee or the ticket status

This commit is contained in:
Matthieu Haineault 2026-02-19 08:18:43 -05:00
parent 6207784d57
commit a5fc7b1de9
62 changed files with 267 additions and 692 deletions

View File

@ -69,7 +69,7 @@ export type compta_journal_ecriture_detail_bk = Prisma.compta_journal_ecriture_d
export type compta_periode = Prisma.compta_periodeModel
/**
* Model compta_ppa_file_id
* This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
*
*/
export type compta_ppa_file_id = Prisma.compta_ppa_file_idModel
/**

View File

@ -89,7 +89,7 @@ export type compta_journal_ecriture_detail_bk = Prisma.compta_journal_ecriture_d
export type compta_periode = Prisma.compta_periodeModel
/**
* Model compta_ppa_file_id
* This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
*
*/
export type compta_ppa_file_id = Prisma.compta_ppa_file_idModel
/**

File diff suppressed because one or more lines are too long

View File

@ -14,7 +14,7 @@ import type * as Prisma from "../internal/prismaNamespace"
/**
* Model compta_ppa_file_id
* This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments
*
*/
export type compta_ppa_file_idModel = runtime.Types.Result.DefaultSelection<Prisma.$compta_ppa_file_idPayload>

View File

@ -14,11 +14,10 @@ import { IdentityAndAccountModule } from 'src/identity-and-account/identity-and-
import { ChatbotModule } from 'src/chatbot/chatbot.module';
import { PrismaMariadbModule } from 'prisma/mariadb/prisma-mariadb.module';
import { PrismaLegacyModule } from 'prisma/prisma-legacy/prisma-legacy.module';
import { AccountModule } from 'src/customer-support/accounts/account.module';
import { CustomerSupportModule } from 'src/customer-support/customer-support.module';
@Module({
imports: [
AccountModule,
AuthenticationModule,
ConfigModule.forRoot({ isGlobal: true }),
ScheduleModule.forRoot(), //cronjobs
@ -29,6 +28,7 @@ import { AccountModule } from 'src/customer-support/accounts/account.module';
TimeAndAttendanceModule,
IdentityAndAccountModule,
ChatbotModule,
CustomerSupportModule,
],
controllers: [AppController],
providers: [

View File

@ -34,4 +34,6 @@ export class EmailToIdResolver {
if (!user) return { success: false, error: `EMPLOYEE_NOT_FOUND` };
return { success: true, data: user.id };
}
readonly findFullNameByEmail
}

View File

@ -155,4 +155,12 @@ export const addHourstoDateString = (start_time: string, hours: number): string
const hh = String(end.getUTCHours()).padStart(2, '0');
const mm = String(end.getUTCMinutes()).padStart(2, '0');
return `${hh}:${mm}:00`;
}
export const timestampToStringDate = (timestamp: number): string => {
const date = new Date(timestamp);
const dd = date.getDate().toString().padStart(2, '0');
const mm = (date.getMonth() + 1).toString().padStart(2, '0');
const yyyy = date.getFullYear();
return `${dd}-${mm}-${yyyy}`;
}

View File

@ -1,28 +0,0 @@
import { Controller, Get, Param } from "@nestjs/common";
import { AccountMemoService } from "src/customer-support/accounts/services/account-memo.service";
import { AccountService } from "src/customer-support/accounts/services/account.service";
@Controller('accounts')
export class AccountController {
constructor(
private readonly accountService: AccountService,
private readonly memoService: AccountMemoService,
) { }
@Get()
findAllAccounts() {
return this.accountService.findAllAccounts();
}
@Get('account/:id')
findAccountById(@Param('accountId') accountId: number) {
return this.accountService.findAccountById(accountId);
}
@Get(':id')
findMemosByAccountId(@Param('accountId') accountId: number) {
return this.memoService.findMemosByAccountId(accountId);
}
}

View File

@ -1,11 +0,0 @@
import { Module } from "@nestjs/common";
import { PrismaMariaDbService } from "prisma/mariadb/prisma-mariadb.service";
import { AccountController } from "src/customer-support/accounts/account.controller";
import { AccountMemoService } from "src/customer-support/accounts/services/account-memo.service";
import { AccountService } from "src/customer-support/accounts/services/account.service";
@Module({
controllers: [ AccountController ],
providers: [ AccountService, PrismaMariaDbService, AccountMemoService ],
}) export class AccountModule { };

View File

@ -1,6 +0,0 @@
import { Injectable } from "@nestjs/common";
@Injectable()
export class AccountCreateService {
}

View File

@ -1,6 +0,0 @@
import { Injectable } from "@nestjs/common";
@Injectable()
export class AccountMemoUpdateService {
}

View File

@ -1,29 +0,0 @@
import { Injectable } from "@nestjs/common";
import { PrismaMariaDbService } from "prisma/mariadb/prisma-mariadb.service";
import { Result } from "src/common/errors/result-error.factory";
import { AccountMemo } from "src/customer-support/dtos/account.dto";
@Injectable()
export class AccountMemoService {
constructor(private readonly prismaMariaDb: PrismaMariaDbService) { }
findMemosByAccountId = async (accountId: number): Promise<Result<AccountMemo[], string>> => {
const listOfMemos: AccountMemo[] = [];
const rawListOfMemos = await this.prismaMariaDb.account_memo.findMany({
where: { id: accountId },
select: { last_updated: true, staff_id: true, memo: true },
});
if (!rawListOfMemos) return { success: false, error: 'MEMOS_NOT_FOUND' };
for (const memo of rawListOfMemos) {
listOfMemos.push({
last_updated: Number(memo.last_updated),
staff_id: Number(memo.staff_id),
memo: memo.memo ? memo.memo : '',
});
}
return { success: true, data: listOfMemos }
}
}

View File

@ -1,56 +0,0 @@
// import { Injectable } from "@nestjs/common";
// import { PrismaMariaDbService } from "prisma/mariadb/prisma-mariadb.service";
// import { Result } from "src/common/errors/result-error.factory";
// import { Account } from "src/customer-support/accounts/account.dto";
// @Injectable()
// export class AccountUpdateService {
// constructor(private readonly prisma: PrismaMariaDbService) { }
// async updateAccount(account: Account): Promise<Result<boolean, string>> {
// const oldAccountInfos = await this.prisma.account.findUnique({
// where: { id: account.id },
// });
// if (!oldAccountInfos) return { success: false, error: 'ACCOUNT_NOT_FOUND' };
// await this.prisma.account.update({
// where: { id: oldAccountInfos.id },
// data: {
// customer_id: account.customerId,
// language_id: account.language,
// username: account.username,
// password: account.password,
// group_id: account.groupId,
// status: account.status,
// first_name: account.firstName,
// last_name: account.lastName,
// mandataire: account.mandataire,
// title: account.title,
// email: account.email,
// company: account.company,
// contact: account.contact,
// address1: account.address,
// address2: account.address,
// tel_home: account.telHome,
// tel_office: account.telOffice,
// tel_office_ext: account.telOffice_ext,
// cell: account.cell,
// fax: account.fax,
// land_owner: account.landOwner,
// commercial: account.commercial,
// vip: account.vip,
// notes_client: account.notes_client,
// terminate_reason: account.terminateReason,
// terminate_cie: account.terminateCie,
// terminate_date: account.terminateDate,
// terminate_note: account.terminateNote,
// mauvais_payeur: account.mauvaisPayeur,
// },
// });
// }
// }

View File

@ -1,128 +0,0 @@
import { Injectable } from "@nestjs/common";
import { PrismaMariaDbService } from "prisma/mariadb/prisma-mariadb.service";
import { Result } from "src/common/errors/result-error.factory";
import { Account } from "src/customer-support/dtos/account.dto";
@Injectable()
export class AccountService {
constructor(private readonly prismaMariaDb: PrismaMariaDbService) { }
findAllAccounts = async (): Promise<Result<Account[], string>> => {
const listOfAccounts: Account[] = [];
const rawListOfAccounts = await this.prismaMariaDb.account.findMany({});
if (!rawListOfAccounts) return { success: false, error: 'ACCOUNTS_NOT_FOUND' }
try {
for (const account of rawListOfAccounts) {
const emailList: string[] = [
account.email ? account.email : '',
account.email_autre ? account.email_autre : '',
];
const addressList: string[] = [
account.address1 ? account.address1 : '',
account.address2 ? account.address2 : '',
account.city ? account.city : '',
account.state ? account.state : '',
account.zip ? account.zip : '',
account.country_id.toString(),
];
listOfAccounts.push({
id: Number(account.id),
customerId: account.customer_id ? account.customer_id : '',
language: account.language_id,
username: account.username ? account.username : '',
password: account.password ? account.password : '',
groupId: account.group_id ? account.group_id : 0,
status: account.status ? account.status : 0,
firstName: account.first_name ? account.first_name : '',
lastName: account.last_name ? account.last_name : '',
mandataire: account.mandataire ? account.mandataire : '',
title: account.title ? account.title : '',
email: emailList,
company: account.company ? account.company : '',
contact: account.contact,
address: addressList,
telHome: account.tel_home ? account.tel_home : '',
telOffice: account.tel_office ? account.tel_office : '',
telOffice_ext: account.tel_office_ext ? account.tel_office_ext : '',
cell: account.cell ? account.cell : '',
fax: account.fax ? account.fax : '',
landOwner: account.land_owner,
commercial: account.commercial,
vip: account.vip,
notes_client: account.notes_client ? account.notes_client : '',
terminateReason: account.terminate_reason ? account.terminate_reason : '',
terminateCie: account.terminate_cie ? account.terminate_cie : '',
terminateNote: account.terminate_note ? account.terminate_note : '',
terminateDate: account.terminate_date ? account.terminate_date : '',
mauvaisPayeur: account.mauvais_payeur,
});
}
console.log(listOfAccounts);
return { success: true, data: listOfAccounts };
} catch (error) {
return { success: false, error: error + " \n An error occured during retrieving the list of accounts" }
}
}
findAccountById = async (accountId: number): Promise<Result<Account, string>> => {
const rawAccount = await this.prismaMariaDb.account.findUnique({
where: { id: accountId }
});
if (!rawAccount) return { success: false, error: 'ACCOUNT_NOT_FOUND' }
const emailList: string[] = [
rawAccount.email ? rawAccount.email : '',
rawAccount.email_autre ? rawAccount.email_autre : '',
];
const addressList: string[] = [
rawAccount.address1 ? rawAccount.address1 : '',
rawAccount.address2 ? rawAccount.address2 : '',
rawAccount.city ? rawAccount.city : '',
rawAccount.state ? rawAccount.state : '',
rawAccount.zip ? rawAccount.zip : '',
rawAccount.country_id.toString(),
];
const account: Account = {
id: Number(rawAccount.id),
customerId: rawAccount.customer_id ? rawAccount.customer_id : '',
language: rawAccount.language_id,
username: rawAccount.username ? rawAccount.username : '',
password: rawAccount.password ? rawAccount.password : '',
groupId: rawAccount.group_id ? rawAccount.group_id : 0,
status: rawAccount.status ? rawAccount.status : 0,
firstName: rawAccount.first_name ? rawAccount.first_name : '',
lastName: rawAccount.last_name ? rawAccount.last_name : '',
mandataire: rawAccount.mandataire ? rawAccount.mandataire : '',
title: rawAccount.title ? rawAccount.title : '',
email: emailList,
company: rawAccount.company ? rawAccount.company : '',
contact: rawAccount.contact,
address: addressList,
telHome: rawAccount.tel_home ? rawAccount.tel_home : '',
telOffice: rawAccount.tel_office ? rawAccount.tel_office : '',
telOffice_ext: rawAccount.tel_office_ext ? rawAccount.tel_office_ext : '',
cell: rawAccount.cell ? rawAccount.cell : '',
fax: rawAccount.fax ? rawAccount.fax : '',
landOwner: rawAccount.land_owner,
commercial: rawAccount.commercial,
vip: rawAccount.vip,
notes_client: rawAccount.notes_client ? rawAccount.notes_client : '',
terminateReason: rawAccount.terminate_reason ? rawAccount.terminate_reason : '',
terminateCie: rawAccount.terminate_cie ? rawAccount.terminate_cie : '',
terminateNote: rawAccount.terminate_note ? rawAccount.terminate_note : '',
terminateDate: rawAccount.terminate_date ? rawAccount.terminate_date : '',
mauvaisPayeur: rawAccount.mauvais_payeur,
}
return { success: true, data: account };
}
}

View File

@ -1,8 +1,10 @@
import { Module } from "@nestjs/common";
import { TicketController } from "src/customer-support/tickets/ticket.controller";
import { TicketService } from "src/customer-support/tickets/ticket.service";
@Module({
imports: [],
controllers: [],
providers: [],
controllers: [TicketController],
providers: [TicketService],
exports: [],
}) export class CustomerSupportModule {}
}) export class CustomerSupportModule { }

View File

@ -1,6 +0,0 @@
import { Controller } from "@nestjs/common";
@Controller()
export class CustomerController {
}

View File

@ -1,8 +0,0 @@
import { Module } from "@nestjs/common";
import { CustomerController } from "src/customer-support/customers/customer.controller";
import { CustomerService } from "src/customer-support/customers/customer.service";
@Module({
imports: [CustomerService],
providers: [CustomerController],
}) export class CustomerModule { }

View File

@ -1,6 +0,0 @@
import { Injectable } from "@nestjs/common";
@Injectable()
export class CustomerService {
}

View File

@ -1,6 +0,0 @@
import { Controller } from "@nestjs/common";
@Controller()
export class DeliveryController {
}

View File

@ -1,8 +0,0 @@
import { Module } from "@nestjs/common";
import { DeliveryController } from "src/customer-support/deliveries/delivery.controller";
import { DeliveryService } from "src/customer-support/deliveries/delivery.service";
@Module({
imports: [DeliveryService],
providers: [DeliveryController],
}) export class DeliveryModule { }

View File

@ -1,6 +0,0 @@
import { Injectable } from "@nestjs/common";
@Injectable()
export class DeliveryService {
}

View File

@ -1,6 +0,0 @@
import { Controller } from "@nestjs/common";
@Controller()
export class DeviceController {
}

View File

@ -1,8 +0,0 @@
import { Module } from "@nestjs/common";
import { DeviceController } from "src/customer-support/devices/device.controller";
import { DeviceService } from "src/customer-support/devices/device.service";
@Module({
imports: [DeviceService],
providers: [DeviceController]
}) export class DeviceModule { }

View File

@ -1,6 +0,0 @@
import { Injectable } from "@nestjs/common";
@Injectable()
export class DeviceService {
}

View File

@ -1,13 +0,0 @@
export class Account {
id: string;
account_number: string;
primary_contact_id: string;
secondary_contacts_id: string[];
addresses: string[];
primary_address: string;
billingRecurrence: string;
billingDayOfMonth: number;
nextBillingDate: string;
created_date: Date;
status: string;
}

View File

@ -1,16 +0,0 @@
export class Address {
id: string;
account_id: string;
civic_number: string;
street: string;
suite: string;
city: string;
province: string;
country: string;
postal_code: string;
constacts: string[];
devices: string[];
services: string[];
technicalTickets: number[];
is_primary: boolean;
}

View File

@ -1,8 +0,0 @@
export class Customer {
id:string;
first_name:string;
last_name:string;
email:string;
phone:string;
primary_contact:boolean;
}

View File

@ -1,22 +0,0 @@
import { Address } from "cluster";
import { Account } from "src/customer-support/dtos/account.dto";
import { Product } from "src/customer-support/dtos/product.dto";
import { Tickets } from "src/customer-support/dtos/ticket.dto";
//A delivery represent an Address where product can be delivered.
//A delivery can be linked to a single Account and a single address
//A delivery can have 1 or more Product
export class Delivery {
address: Address;
account: Account[];
ticket: Tickets[];
product: Product[];
}
export class AccountDeliveryJunction {
accountId: Account;
deliveryId:Delivery;
ticket:Tickets[];
}

View File

@ -1,17 +0,0 @@
// A Device is linked to a Service
// A Device can be used as a "parent" or be a "child" of an other device
export class Device {
id: string;
name:string;
status:string;
address_id: string;
category:string;
model:string;
sn:string;
speed:string;
price:string;
description:string;
tag:string;
photo:string;
}

View File

@ -1,3 +0,0 @@
export class Fibre {
}

View File

@ -1,7 +0,0 @@
//I question the need for a phone dto. Could be an enum since most columns repeat themselves in the product table.
//A phone is a type of product, not sure what would need to be in this class.
export class Phone {
}

View File

@ -1,36 +0,0 @@
import { Device } from "src/customer-support/dtos/device.dto";
import { Service } from "src/customer-support/dtos/services.dto";
import { Comments } from "src/customer-support/shared/shared-class.dto";
import { Television } from "src/customer-support/dtos/television.dto";
export class Product {
description: string;
downloadSpeed?: number;
uploadSpeed?: number;
dayQuota: number;
nightQuota: number;
phoneNumber: string;
inventory: Inventory;
isPortalAvailable: boolean;
isCommercial: boolean;
isComboDiscountEligible: boolean;
categoryName: string;
note: Comments;
status: boolean;
stockKeepingUnit: string; // **sku**
name: string;
price: number;
soldUnit: number;
isAvailable: boolean;
televiesion?: Television;
service?: Service;
device?: Device;
}
export class Inventory {
followUp: boolean;
tag: string;
localisation: string;
alert: number;
listedTicketTech: boolean; //what is this for?
}

View File

@ -1,24 +0,0 @@
//A Service is a product
export class Service {
id: string;
accountId: string;
address_id: string;
serviceFromCatalogId: string;
name: string;
type: string;
activatedAt: string;
date_of_suspension: any[];
date_of_reactivation: any[];
}
export class OfferedService {
id: string;
code: string;
name: string;
description: string;
standardPrice: number;
category:string;
status:string;
effectiveDate:string;
}

View File

@ -1,27 +0,0 @@
import { Customer } from "src/customer-support/dtos/customer.dto";
import { Service } from "src/customer-support/dtos/services.dto";
import { Comments } from "src/customer-support/shared/shared-class.dto";
//Television is a product, can be "A la carte" or by package
export class Television {
service: Service;
channel?: Channels[];
package?: ChannelPackages;
}
export class Channels {
number: number;
name: string;
owner: string;
unitPrice: number;
unitSoldPrice: number;
bundlePrice: number;
bundleSoldPrice: number;
note: Comments;
}
export class ChannelPackages {
price: number;
isActive: boolean;
}

View File

@ -1,21 +0,0 @@
//matches frontend needs
export class Tickets {
id: number;
address_id: string;
customer_id: string;
status: string;
type: string;
short_description: string;
employee_assigned: string;
full_description: string;
assistant: string;
departement: string;
created_by: string;
creation_date: Date;
last_update: Date;
assigned_date: Date;
ticketSuperType: string;
attached: string[];
}

View File

@ -1,6 +0,0 @@
import { Controller } from "@nestjs/common";
@Controller()
export class FibreController {
}

View File

@ -1,8 +0,0 @@
import { Module } from "@nestjs/common";
import { FibreController } from "src/customer-support/fibre/fibre.controller";
import { FibreService } from "src/customer-support/fibre/fibre.service";
@Module({
imports: [FibreService],
providers: [FibreController],
}) export class FibreModule { }

View File

@ -1,6 +0,0 @@
import { Injectable } from "@nestjs/common";
@Injectable()
export class FibreService {
}

View File

@ -1,6 +0,0 @@
# GET http://localhost:3000/accounts
# GET http://localhost:3000/accounts/6912
GET http://localhost:3000/accounts/account/6912

View File

@ -1,6 +0,0 @@
import { Controller } from "@nestjs/common";
@Controller()
export class PhoneController {
}

View File

@ -1,8 +0,0 @@
import { Module } from "@nestjs/common";
import { PhoneController } from "src/customer-support/phones/phone.controller";
import { PhoneService } from "src/customer-support/phones/phone.service";
@Module({
imports: [PhoneService],
providers: [PhoneController],
}) export class PhoneModule { }

View File

@ -1,6 +0,0 @@
import { Injectable } from "@nestjs/common";
@Injectable()
export class PhoneService {
}

View File

@ -1,6 +0,0 @@
import { Controller } from "@nestjs/common";
@Controller()
export class ProductController {
}

View File

@ -1,8 +0,0 @@
import { Module } from "@nestjs/common";
import { ProductController } from "src/customer-support/product/product.controller";
import { ProductService } from "src/customer-support/product/product.service";
@Module({
imports: [ProductService],
providers: [ProductController],
}) export class ProductModule { }

View File

@ -1,6 +0,0 @@
import { Injectable } from "@nestjs/common";
@Injectable()
export class ProductService {
}

View File

@ -1,6 +0,0 @@
import { Controller } from "@nestjs/common";
@Controller()
export class ServiceController{
}

View File

@ -1,8 +0,0 @@
import { Module } from "@nestjs/common";
import { ServiceController } from "src/customer-support/services/services.controller";
import { ServiceService } from "src/customer-support/services/services.service";
@Module({
imports: [ServiceService],
providers: [ServiceController],
}) export class ServiceModule { }

View File

@ -1,6 +0,0 @@
import { Injectable } from "@nestjs/common";
@Injectable()
export class ServiceService {
}

View File

@ -1,38 +1,38 @@
//This file is used to store function that help translate MariaDB data to Typescript manipulation requirements for the type "boolean".
// //This file is used to store function that help translate MariaDB data to Typescript manipulation requirements for the type "boolean".
import { PhoneAddrEnhancedCapable } from "src/customer-support/dtos/phone.dto";
// import { PhoneAddrEnhancedCapable } from "src/customer-support/dtos/phone.dto";
//From MariaDB to Frontend
export const fromTinyIntToBoolean = async (tinyInt: number): Promise<boolean> => {
let booleanValue = true;
if ((tinyInt = 0) || (tinyInt = -1)) return booleanValue = false;
return booleanValue;
}
// //From MariaDB to Frontend
// export const fromTinyIntToBoolean = async (tinyInt: number): Promise<boolean> => {
// let booleanValue = true;
// if ((tinyInt = 0) || (tinyInt = -1)) return booleanValue = false;
// return booleanValue;
// }
//From Frontend to MariaDB TinyInt boolean 1 - 0
export const fromBooleanToTinyInt = async (boolean: boolean): Promise<number> => {
return boolean ? 1 : 0;
}
// //From Frontend to MariaDB TinyInt boolean 1 - 0
// export const fromBooleanToTinyInt = async (boolean: boolean): Promise<number> => {
// return boolean ? 1 : 0;
// }
//From Frontend to MariaDB TinyInt boolean -1 - 1
export const fromBooleanToTinyIntNegative = async (boolean: boolean): Promise<number> => {
return boolean ? 1 : -1;
}
// //From Frontend to MariaDB TinyInt boolean -1 - 1
// export const fromBooleanToTinyIntNegative = async (boolean: boolean): Promise<number> => {
// return boolean ? 1 : -1;
// }
//From MariaDB to Frontend String boolean yes - no / Y - N / etc...
export const fromStringToBoolean = async (string: string): Promise<boolean> => {
let booleanValue = true;
let stringValue = string.toLowerCase();
if ((stringValue = "n") || (stringValue = "no") || (stringValue = "non")) {
return booleanValue = false;
}
return booleanValue;
}
// //From MariaDB to Frontend String boolean yes - no / Y - N / etc...
// export const fromStringToBoolean = async (string: string): Promise<boolean> => {
// let booleanValue = true;
// let stringValue = string.toLowerCase();
// if ((stringValue = "n") || (stringValue = "no") || (stringValue = "non")) {
// return booleanValue = false;
// }
// return booleanValue;
// }
export const fromBooleanToEnum = async (boolean: boolean): Promise<PhoneAddrEnhancedCapable> => {
return boolean ? PhoneAddrEnhancedCapable.Y : PhoneAddrEnhancedCapable.N;
}
// export const fromBooleanToEnum = async (boolean: boolean): Promise<PhoneAddrEnhancedCapable> => {
// return boolean ? PhoneAddrEnhancedCapable.Y : PhoneAddrEnhancedCapable.N;
// }
export const fromEnumToBoolean = async (enumValue: PhoneAddrEnhancedCapable): Promise<boolean> => {
return enumValue ? true : false;
}
// export const fromEnumToBoolean = async (enumValue: PhoneAddrEnhancedCapable): Promise<boolean> => {
// return enumValue ? true : false;
// }

View File

@ -1,20 +0,0 @@
export class Comments {
comment: string;
isPublic: boolean;
createdAt: Date;
createdBy: string;
updatedAt: Date;
updatedBy: string;
}
export class Address {
door_number: number;
street: string;
city: string;
province: string;
postal_code: string;
latitude: string;
longitude: string;
createdAt: Date;
comment: Comments;
}

View File

@ -1,8 +0,0 @@
import { Controller } from "@nestjs/common";
@Controller()
export class TelevisionController {
}

View File

@ -1,8 +0,0 @@
import { Module } from "@nestjs/common";
import { TelevisionController } from "src/customer-support/television/television.controller";
import { TelevisionService } from "src/customer-support/television/television.service";
@Module({
imports: [TelevisionService],
providers: [TelevisionController],
}) export class TelevisionModule { }

View File

@ -1,7 +0,0 @@
import { Injectable } from "@nestjs/common";
@Injectable()
export class TelevisionService {
}

View File

@ -0,0 +1,45 @@
/*
To allow me to get all infos needed to display in the ticket list page i need to access these informations and how to get it :
-> ticket_id:
- ticket table:
using the account ids and delivery ids, i can :
i need first name and last name for contacts, i will use the account_ids to query the account table
i need to find the service_id, i need the product_id to query the service table.
-> status:
-ticket table : the status is here.
-> assign_to:
- ticket table :
displays a staff_id:
I need to query the staff table, using the email to get the id of the employee, its email, its first and last name,
-> deliveryAddress:
- ticket table: the account_id is here.
- delivery table: i can get the address here, using the account_id.
-> product_type:
- ticket table : using the account_id :
i can query the delivery table:
-delivery table:
get delivery id linked to the account id
i can query the service table
- service table:
delivery_id to get the product_id and device_id
- product table:
using the product_id, i can get the type here
-> department:
- ticket table:
i can get the dept_id here
- ticket_dept :
using the dept_id from the ticket table, i can get the name here.
-> parentTicketId:
- ticket table:
i can get the parent here.
-> dueDate, updatedAt, completedAt:
- ticket table:
i can get the due_date, last_update, Date_closed here.
*/

View File

@ -0,0 +1,14 @@
import { IsInt, IsOptional, IsString } from "class-validator";
export class TicketListItem {
@IsInt() id: number;
@IsString() status: string;
@IsString() @IsOptional() assignedTo: string;
@IsString() deliveryAddress: string;
@IsString() subject: string;
@IsString() department: string;
@IsInt() @IsOptional() parentTicketId: number;
@IsString() dueDate: string;;
@IsString() updatedAt: string;
@IsString() completedAt: string;
}

View File

@ -0,0 +1,65 @@
import { Type } from "class-transformer";
import { IsBoolean, IsInt, IsOptional, IsString } from "class-validator";
export class Ticket {
@IsInt() id: number;
@IsString() createdAt: string;
@Type(() => DeliveryAddress) deliveryAddress: DeliveryAddress;
@Type(() => Message) message: Message[];
@Type(() => Service) service: Service[];
@Type(() => Device) device: Device[];
@Type(() => Contact) contact: Contact[];
@Type(() => TicketHistory) TicketHistory: TicketHistory;
}
export class DeliveryAddress {
@IsString() address: string;
@IsString() department: string;
@IsString() shortDescription: string;
@IsString() description: string;
}
export class Message {
@IsString() attachment: string;
@IsString() comment: string;
@IsString() createdBy: string;
@IsString() createdAt: string;
}
export class Service {
@IsString() serviceType: string;
@IsString() shortDescription: string;
@Type(() => Number) price: number;
@IsBoolean() status: boolean;
}
export class Device {
@IsString() name: string;
@IsString() model: string;
@IsString() category: string;
@IsString() sku: string;
@IsString() sn: string;
@IsString() gponSn: string;
@IsString() @IsOptional() mac?: string;
@IsString() @IsOptional() wifiPass?: string;
@IsString() @IsOptional() tag?: string;
@IsString() room: string;
@Type(() => Number) price: number;
@IsString() @IsOptional() speed?: string;
@IsString() description: string;
}
export class Contact {
@IsString() FirstName: string;
@IsString() LastName: string;
@IsString() @IsOptional() telHome?: string;
@IsString() @IsOptional() telOffice?: string;
@IsString() @IsOptional() telOfficeExt?: string;
@IsString() @IsOptional() cell?: string;
@IsString() @IsOptional() fax?: string;
@IsString() email: string;
}
export class TicketHistory {
@Type(() => Ticket) ticket: Ticket[];
}

View File

@ -1,11 +1,21 @@
import { Controller } from "@nestjs/common";
import { Controller, Get, Param } from "@nestjs/common";
import { ModuleAccessAllowed } from "src/common/decorators/modules-guard.decorators";
import { Result } from "src/common/errors/result-error.factory";
import { TicketListItem } from "src/customer-support/tickets/dtos/ticket-list.dto";
import { TicketService } from "src/customer-support/tickets/ticket.service";
@Controller()
@Controller('tickets')
export class TicketController {
constructor(private readonly getService: TicketService) { }
@Get(':email/:status')
@ModuleAccessAllowed()
async findTicketByFilters(
@Param('status') status: string,
@Param('email') email?: string,
): Promise<Result<TicketListItem[], string>> {
return await this.getService.getListOfAllTicketByFilters(status, email);
}
}

View File

@ -1,9 +1,85 @@
import { Injectable } from "@nestjs/common";
import { Result } from "src/common/errors/result-error.factory";
import { PrismaMariaDbService } from "prisma/mariadb/prisma-mariadb.service";
import { TicketListItem } from "src/customer-support/tickets/dtos/ticket-list.dto";
import { timestampToStringDate } from "src/common/utils/date-utils";
@Injectable()
export class TicketService {
constructor(private readonly prisma: PrismaMariaDbService) { }
constructor(
private readonly prisma: PrismaMariaDbService,
) { }
getListOfAllTicketByFilters = async (status: string, email?: string): Promise<Result<TicketListItem[], string>> => {
//fetch
const staffId = await this.prisma.staff.findFirst({
where: { email },
select: {
id: true,
first_name: true,
last_name: true,
email: true,
}
});
if (!staffId) return { success: false, error: 'EMPLOYEE_NOT_FOUND' }
}
//fetch the data for the following columns : ID, SUBJECT, STATUS, DÉPEND DU TICKET, DATE ASSIGNÉE, DERNIÈRE MISE À JOUR, DATE COMPLÉTÉE
const assignedTickets = await this.prisma.ticket.findMany({
where: { assign_to: staffId.id, status },
select: {
id: true,
delivery_id: true, // to fetch the address in the delivery table
status: true, // status column
dept_id: true, // to fetch the name of the department in the ticket_dept table
parent: true, // dépend du ticket column
due_date: true, // date assignée column
last_update: true, // dernière mise à jour column
date_closed: true, // date complétée column
subject: true, // type column
},
});
if (!assignedTickets) return { success: false, error: 'TICKETS_NOT_FOUND' };
let ticketListItem: TicketListItem[] = [];
//fetch the data for the remaining columns: ADRESSE, DEPARTMENT
for (const ticket of assignedTickets) {
//Address column
const delivery = await this.prisma.delivery.findUnique({
where: { id: ticket.delivery_id },
select: { address1: true, id: true, },
});
if (!delivery) return { success: false, error: 'ADDRESS_NOT_FOUND' };
//department column
const department = await this.prisma.ticket_dept.findUnique({
where: { id: ticket.dept_id! },
select: { name: true },
});
if (!department) return { success: false, error: 'DEPARTMENT_NOT_FOUND' };
//translate timestamp to Date string format
const dueDate = timestampToStringDate(Number(ticket.due_date));
const updatedAt = timestampToStringDate(Number(ticket.last_update))
const completedAt = timestampToStringDate(Number(ticket.date_closed));
//build a ticket for the ticket list
ticketListItem.push({
id: Number(ticket.id),
subject: ticket.subject ? ticket.subject : '',
status: ticket.status,
assignedTo: '',
deliveryAddress: delivery.address1!,
department: department.name,
parentTicketId: Number(ticket.parent) ? Number(ticket.parent) : 0,
dueDate: dueDate,
updatedAt: updatedAt,
completedAt: completedAt,
});
}
return { success: true, data: ticketListItem }
}
}