refactor: employee

This commit is contained in:
Methapon Metanipat 2024-09-13 17:39:12 +07:00
parent 77739da154
commit c51a403f2a
7 changed files with 637 additions and 277 deletions

View file

@ -0,0 +1,99 @@
/*
Warnings:
- You are about to drop the column `entryDate` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `passportExpiryDate` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `passportIssueDate` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `passportIssuingCountry` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `passportIssuingPlace` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `passportNumber` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `passportType` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `previousPassportReference` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `tm6Number` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `visaExpiryDate` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `visaIssueDate` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `visaIssuingPlace` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `visaNumber` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `visaStayUntilDate` on the `Employee` table. All the data in the column will be lost.
- You are about to drop the column `visaType` on the `Employee` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE "Employee" DROP COLUMN "entryDate",
DROP COLUMN "passportExpiryDate",
DROP COLUMN "passportIssueDate",
DROP COLUMN "passportIssuingCountry",
DROP COLUMN "passportIssuingPlace",
DROP COLUMN "passportNumber",
DROP COLUMN "passportType",
DROP COLUMN "previousPassportReference",
DROP COLUMN "tm6Number",
DROP COLUMN "visaExpiryDate",
DROP COLUMN "visaIssueDate",
DROP COLUMN "visaIssuingPlace",
DROP COLUMN "visaNumber",
DROP COLUMN "visaStayUntilDate",
DROP COLUMN "visaType",
ADD COLUMN "workerType" TEXT;
-- CreateTable
CREATE TABLE "EmployeePassport" (
"id" TEXT NOT NULL,
"number" TEXT NOT NULL,
"type" TEXT NOT NULL,
"issueDate" DATE NOT NULL,
"expireDate" DATE NOT NULL,
"issueCountry" TEXT NOT NULL,
"issuePlace" TEXT NOT NULL,
"previousPassportRef" TEXT,
"employeeId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "EmployeePassport_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "EmployeeVisa" (
"id" TEXT NOT NULL,
"number" TEXT NOT NULL,
"type" TEXT NOT NULL,
"entryCount" INTEGER NOT NULL,
"issueCountry" TEXT NOT NULL,
"issuePlace" TEXT NOT NULL,
"issueDate" DATE NOT NULL,
"expireDate" DATE NOT NULL,
"mrz" TEXT,
"remark" TEXT,
"employeeId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "EmployeeVisa_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "EmployeeInCountryNotice" (
"id" TEXT NOT NULL,
"noticeNumber" TEXT NOT NULL,
"noticeDate" TEXT NOT NULL,
"nextNoticeDate" DATE NOT NULL,
"tmNumber" TEXT NOT NULL,
"entryDate" DATE NOT NULL,
"travelBy" TEXT NOT NULL,
"travelFrom" TEXT NOT NULL,
"employeeId" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
CONSTRAINT "EmployeeInCountryNotice_pkey" PRIMARY KEY ("id")
);
-- AddForeignKey
ALTER TABLE "EmployeePassport" ADD CONSTRAINT "EmployeePassport_employeeId_fkey" FOREIGN KEY ("employeeId") REFERENCES "Employee"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "EmployeeVisa" ADD CONSTRAINT "EmployeeVisa_employeeId_fkey" FOREIGN KEY ("employeeId") REFERENCES "Employee"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "EmployeeInCountryNotice" ADD CONSTRAINT "EmployeeInCountryNotice_employeeId_fkey" FOREIGN KEY ("employeeId") REFERENCES "Employee"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View file

@ -552,23 +552,8 @@ model Employee {
subDistrict SubDistrict? @relation(fields: [subDistrictId], references: [id], onDelete: SetNull) subDistrict SubDistrict? @relation(fields: [subDistrictId], references: [id], onDelete: SetNull)
subDistrictId String? subDistrictId String?
passportType String workerType String?
passportNumber String workerStatus String?
passportIssueDate DateTime @db.Date
passportExpiryDate DateTime @db.Date
passportIssuingCountry String
passportIssuingPlace String
previousPassportReference String?
visaType String?
visaNumber String?
visaIssueDate DateTime? @db.Date
visaExpiryDate DateTime? @db.Date
visaIssuingPlace String?
visaStayUntilDate DateTime? @db.Date
tm6Number String?
entryDate DateTime? @db.Date
workerStatus String?
customerBranch CustomerBranch @relation(fields: [customerBranchId], references: [id], onDelete: Cascade) customerBranch CustomerBranch @relation(fields: [customerBranchId], references: [id], onDelete: Cascade)
customerBranchId String customerBranchId String
@ -584,9 +569,12 @@ model Employee {
updatedBy User? @relation(name: "EmployeeUpdatedByUser", fields: [updatedByUserId], references: [id], onDelete: SetNull) updatedBy User? @relation(name: "EmployeeUpdatedByUser", fields: [updatedByUserId], references: [id], onDelete: SetNull)
updatedByUserId String? updatedByUserId String?
employeeCheckup EmployeeCheckup[] employeePassport EmployeePassport[]
employeeWork EmployeeWork[] employeeVisa EmployeeVisa[]
employeeOtherInfo EmployeeOtherInfo? employeeInCountryNotice EmployeeInCountryNotice[]
employeeCheckup EmployeeCheckup[]
employeeWork EmployeeWork[]
employeeOtherInfo EmployeeOtherInfo?
editHistory EmployeeHistory[] editHistory EmployeeHistory[]
quotationWorker QuotationWorker[] quotationWorker QuotationWorker[]
@ -606,6 +594,63 @@ model EmployeeHistory {
master Employee @relation(fields: [masterId], references: [id], onDelete: Cascade) master Employee @relation(fields: [masterId], references: [id], onDelete: Cascade)
} }
model EmployeePassport {
id String @id @default(cuid())
number String
type String
issueDate DateTime @db.Date
expireDate DateTime @db.Date
issueCountry String
issuePlace String
previousPassportRef String?
employee Employee @relation(fields: [employeeId], references: [id])
employeeId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model EmployeeVisa {
id String @id @default(cuid())
number String
type String
entryCount Int
issueCountry String
issuePlace String
issueDate DateTime @db.Date
expireDate DateTime @db.Date
mrz String?
remark String?
employee Employee @relation(fields: [employeeId], references: [id])
employeeId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model EmployeeInCountryNotice {
id String @id @default(cuid())
noticeNumber String
noticeDate String
nextNoticeDate DateTime @db.Date
tmNumber String
entryDate DateTime @db.Date
travelBy String
travelFrom String
employee Employee @relation(fields: [employeeId], references: [id])
employeeId String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model EmployeeCheckup { model EmployeeCheckup {
id String @id @default(cuid()) id String @id @default(cuid())

View file

@ -26,7 +26,7 @@ import {
} from "../services/permission"; } from "../services/permission";
import { connectOrDisconnect, connectOrNot, whereAddressQuery } from "../utils/relation"; import { connectOrDisconnect, connectOrNot, whereAddressQuery } from "../utils/relation";
import { notFoundError, relationError } from "../utils/error"; import { notFoundError, relationError } from "../utils/error";
import { deleteFile, fileLocation, getFile, listFile, setFile } from "../utils/minio"; import { deleteFile, deleteFolder, fileLocation, getFile, listFile, setFile } from "../utils/minio";
if (!process.env.MINIO_BUCKET) { if (!process.env.MINIO_BUCKET) {
throw Error("Require MinIO bucket."); throw Error("Require MinIO bucket.");
@ -77,69 +77,13 @@ type EmployeeCreate = {
street?: string | null; street?: string | null;
streetEN?: string | null; streetEN?: string | null;
passportType: string;
passportNumber: string;
passportIssueDate: Date;
passportExpiryDate: Date;
passportIssuingCountry: string;
passportIssuingPlace: string;
previousPassportReference?: string;
visaType?: string | null;
visaNumber?: string | null;
visaIssueDate?: Date | null;
visaExpiryDate?: Date | null;
visaIssuingPlace?: string | null;
visaStayUntilDate?: Date | null;
tm6Number?: string | null;
entryDate?: Date | null;
workerStatus?: string | null;
subDistrictId?: string | null; subDistrictId?: string | null;
districtId?: string | null; districtId?: string | null;
provinceId?: string | null; provinceId?: string | null;
workerType?: string | null;
workerStatus?: string | null;
selectedImage?: string | null; selectedImage?: string | null;
employeeWork?: {
ownerName?: string | null;
positionName?: string | null;
jobType?: string | null;
workplace?: string | null;
workPermitNo?: string | null;
workPermitIssuDate?: Date | null;
workPermitExpireDate?: Date | null;
workEndDate?: Date | null;
remark?: string | null;
}[];
employeeCheckup?: {
checkupType?: string | null;
checkupResult?: string | null;
provinceId?: string | null;
hospitalName?: string | null;
remark?: string | null;
medicalBenefitScheme?: string | null;
insuranceCompany?: string | null;
coverageStartDate?: Date | null;
coverageExpireDate?: Date | null;
}[];
employeeOtherInfo?: {
citizenId?: string | null;
fatherFirstName?: string | null;
fatherLastName?: string | null;
fatherBirthPlace?: string | null;
motherFirstName?: string | null;
motherLastName?: string | null;
motherBirthPlace?: string | null;
fatherFirstNameEN?: string | null;
fatherLastNameEN?: string | null;
motherFirstNameEN?: string | null;
motherLastNameEN?: string | null;
};
}; };
type EmployeeUpdate = { type EmployeeUpdate = {
@ -169,71 +113,13 @@ type EmployeeUpdate = {
street?: string | null; street?: string | null;
streetEN?: string | null; streetEN?: string | null;
passportType?: string; workerType?: string | null;
passportNumber?: string;
passportIssueDate?: Date;
passportExpiryDate?: Date;
passportIssuingCountry?: string;
passportIssuingPlace?: string;
previousPassportReference?: string;
visaType?: string | null;
visaNumber?: string | null;
visaIssueDate?: Date | null;
visaExpiryDate?: Date | null;
visaIssuingPlace?: string | null;
visaStayUntilDate?: Date | null;
tm6Number?: string | null;
entryDate?: Date | null;
workerStatus?: string | null; workerStatus?: string | null;
selectedImage?: string | null; selectedImage?: string | null;
subDistrictId?: string | null; subDistrictId?: string | null;
districtId?: string | null; districtId?: string | null;
provinceId?: string | null; provinceId?: string | null;
employeeWork?: {
id?: string;
ownerName?: string | null;
positionName?: string | null;
jobType?: string | null;
workplace?: string | null;
workPermitNo?: string | null;
workPermitIssuDate?: Date | null;
workPermitExpireDate?: Date | null;
workEndDate?: Date | null;
remark?: string | null;
}[];
employeeCheckup?: {
id?: string;
checkupType?: string | null;
checkupResult?: string | null;
provinceId?: string | null;
hospitalName?: string | null;
remark?: string | null;
medicalBenefitScheme?: string | null;
insuranceCompany?: string | null;
coverageStartDate?: Date | null;
coverageExpireDate?: Date | null;
}[];
employeeOtherInfo?: {
citizenId?: string | null;
fatherFirstName?: string | null;
fatherLastName?: string | null;
fatherBirthPlace?: string | null;
motherFirstName?: string | null;
motherLastName?: string | null;
motherBirthPlace?: string | null;
fatherFirstNameEN?: string | null;
fatherLastNameEN?: string | null;
motherFirstNameEN?: string | null;
motherLastNameEN?: string | null;
};
}; };
@Route("api/v1/employee") @Route("api/v1/employee")
@ -306,7 +192,6 @@ export class EmployeeController extends Controller {
{ firstNameEN: { contains: query } }, { firstNameEN: { contains: query } },
{ lastName: { contains: query } }, { lastName: { contains: query } },
{ lastNameEN: { contains: query } }, { lastNameEN: { contains: query } },
{ passportNumber: { contains: query } },
...whereAddressQuery(query), ...whereAddressQuery(query),
], ],
AND: { AND: {
@ -403,35 +288,7 @@ export class EmployeeController extends Controller {
await permissionCheck(req.user, customerBranch.customer.registeredBranch); await permissionCheck(req.user, customerBranch.customer.registeredBranch);
const { const { provinceId, districtId, subDistrictId, customerBranchId, ...rest } = body;
provinceId,
districtId,
subDistrictId,
customerBranchId,
employeeWork,
employeeCheckup,
employeeOtherInfo,
...rest
} = body;
const listProvinceId = employeeCheckup?.reduce<string[]>((acc, cur) => {
if (cur.provinceId && !acc.includes(cur.provinceId)) return acc.concat(cur.provinceId);
if (!cur.provinceId) cur.provinceId = null;
return acc;
}, []);
if (listProvinceId) {
const [listProvince] = await prisma.$transaction([
prisma.province.findMany({ where: { id: { in: listProvinceId } } }),
]);
if (listProvince.length !== listProvinceId.length) {
throw new HttpError(
HttpStatus.BAD_REQUEST,
"Some province cannot be found.",
"someProvinceNotFound",
);
}
}
const record = await prisma.$transaction( const record = await prisma.$transaction(
async (tx) => { async (tx) => {
@ -465,23 +322,6 @@ export class EmployeeController extends Controller {
...rest, ...rest,
statusOrder: +(rest.status === "INACTIVE"), statusOrder: +(rest.status === "INACTIVE"),
code: `${customerBranch.code}-${`${new Date().getFullYear()}`.slice(-2).padStart(2, "0")}${`${last.value}`.padStart(7, "0")}`, code: `${customerBranch.code}-${`${new Date().getFullYear()}`.slice(-2).padStart(2, "0")}${`${last.value}`.padStart(7, "0")}`,
employeeWork: {
createMany: {
data: employeeWork || [],
},
},
employeeCheckup: {
createMany: {
data:
employeeCheckup?.map((v) => ({
...v,
provinceId: !!v.provinceId ? null : v.provinceId,
})) || [],
},
},
employeeOtherInfo: {
create: employeeOtherInfo,
},
province: connectOrNot(provinceId), province: connectOrNot(provinceId),
district: connectOrNot(districtId), district: connectOrNot(districtId),
subDistrict: connectOrNot(subDistrictId), subDistrict: connectOrNot(subDistrictId),
@ -568,35 +408,7 @@ export class EmployeeController extends Controller {
await permissionCheck(req.user, customerBranch.customer.registeredBranch); await permissionCheck(req.user, customerBranch.customer.registeredBranch);
} }
const { const { provinceId, districtId, subDistrictId, customerBranchId, ...rest } = body;
provinceId,
districtId,
subDistrictId,
customerBranchId,
employeeWork,
employeeCheckup,
employeeOtherInfo,
...rest
} = body;
const listProvinceId = employeeCheckup?.reduce<string[]>((acc, cur) => {
if (cur.provinceId && !acc.includes(cur.provinceId)) return acc.concat(cur.provinceId);
if (!cur.provinceId) cur.provinceId = null;
return acc;
}, []);
if (listProvinceId) {
const [listProvince] = await prisma.$transaction([
prisma.province.findMany({ where: { id: { in: listProvinceId } } }),
]);
if (listProvince.length !== listProvinceId.length) {
throw new HttpError(
HttpStatus.BAD_REQUEST,
"Some province cannot be found.",
"someProvinceNotFound",
);
}
}
const record = await prisma.$transaction(async (tx) => { const record = await prisma.$transaction(async (tx) => {
let code: string | undefined; let code: string | undefined;
@ -640,53 +452,6 @@ export class EmployeeController extends Controller {
statusOrder: +(rest.status === "INACTIVE"), statusOrder: +(rest.status === "INACTIVE"),
code, code,
customerBranch: connectOrNot(customerBranchId), customerBranch: connectOrNot(customerBranchId),
employeeWork: employeeWork
? {
deleteMany: {
id: {
notIn: employeeWork.map((v) => v.id).filter((v): v is string => !!v) || [],
},
},
upsert: employeeWork.map((v) => ({
where: { id: v.id || "" },
create: {
...v,
createdByUserId: req.user.sub,
updatedByUserId: req.user.sub,
id: undefined,
},
update: {
...v,
updatedByUserId: req.user.sub,
},
})),
}
: undefined,
employeeCheckup: employeeCheckup
? {
deleteMany: {
id: {
notIn: employeeCheckup.map((v) => v.id).filter((v): v is string => !!v) || [],
},
},
upsert: employeeCheckup.map((v) => ({
where: { id: v.id || "" },
create: {
...v,
provinceId: !v.provinceId ? undefined : v.provinceId,
createdByUserId: req.user.sub,
updatedByUserId: req.user.sub,
id: undefined,
},
update: {
...v,
updatedByUserId: req.user.sub,
},
})),
}
: undefined,
employeeOtherInfo: employeeOtherInfo ? { update: employeeOtherInfo } : undefined,
province: connectOrDisconnect(provinceId), province: connectOrDisconnect(provinceId),
district: connectOrDisconnect(districtId), district: connectOrDisconnect(districtId),
subDistrict: connectOrDisconnect(subDistrictId), subDistrict: connectOrDisconnect(subDistrictId),
@ -698,13 +463,7 @@ export class EmployeeController extends Controller {
const historyEntries: { field: string; valueBefore: string; valueAfter: string }[] = []; const historyEntries: { field: string; valueBefore: string; valueAfter: string }[] = [];
for (const k of Object.keys(body)) { for (const field of Object.keys(body) as (keyof typeof body)[]) {
const field = k as keyof typeof body;
if (field === "employeeCheckup") continue;
if (field === "employeeOtherInfo") continue;
if (field === "employeeWork") continue;
let valueBefore = employee[field]; let valueBefore = employee[field];
let valueAfter = body[field]; let valueAfter = body[field];
@ -757,6 +516,14 @@ export class EmployeeController extends Controller {
throw new HttpError(HttpStatus.FORBIDDEN, "Employee is in used.", "employeeInUsed"); throw new HttpError(HttpStatus.FORBIDDEN, "Employee is in used.", "employeeInUsed");
} }
await Promise.all([
deleteFolder(fileLocation.employee.img(employeeId)),
deleteFolder(fileLocation.employee.attachment(employeeId)),
deleteFolder(fileLocation.employee.passport(employeeId)),
deleteFolder(fileLocation.employee.visa(employeeId)),
deleteFolder(fileLocation.employee.inCountryNotice(employeeId)),
]);
return await prisma.employee.delete({ return await prisma.employee.delete({
include: { include: {
createdBy: true, createdBy: true,
@ -876,4 +643,111 @@ export class EmployeeFileController extends Controller {
await this.checkPermission(req.user, employeeId); await this.checkPermission(req.user, employeeId);
return await deleteFile(fileLocation.employee.attachment(employeeId, name)); return await deleteFile(fileLocation.employee.attachment(employeeId, name));
} }
@Get("file-passport")
@Security("keycloak")
async listPassport(@Request() req: RequestWithUser, @Path() employeeId: string) {
await this.checkPermission(req.user, employeeId);
return await listFile(fileLocation.employee.passport(employeeId));
}
@Get("file-passport/{passportId}")
@Security("keycloak")
async getPassport(@Path() employeeId: string, @Path() passportId: string) {
return await getFile(fileLocation.employee.passport(employeeId, passportId));
}
@Put("file-passport/{passportId}")
@Security("keycloak")
async putPassport(
@Request() req: RequestWithUser,
@Path() employeeId: string,
@Path() passportId: string,
) {
await this.checkPermission(req.user, employeeId);
return req.res?.redirect(await setFile(fileLocation.employee.passport(employeeId, passportId)));
}
@Delete("file-passport/{passportId}")
@Security("keycloak")
async delPassport(
@Request() req: RequestWithUser,
@Path() employeeId: string,
@Path() passportId: string,
) {
await this.checkPermission(req.user, employeeId);
return await deleteFile(fileLocation.employee.passport(employeeId, passportId));
}
@Get("file-visa")
@Security("keycloak")
async listVisa(@Request() req: RequestWithUser, @Path() employeeId: string) {
await this.checkPermission(req.user, employeeId);
return await listFile(fileLocation.employee.visa(employeeId));
}
@Get("file-visa/{visaId}")
@Security("keycloak")
async getVisa(@Path() employeeId: string, @Path() visaId: string) {
return await getFile(fileLocation.employee.visa(employeeId, visaId));
}
@Put("file-visa/{visaId}")
@Security("keycloak")
async putVisa(
@Request() req: RequestWithUser,
@Path() employeeId: string,
@Path() visaId: string,
) {
await this.checkPermission(req.user, employeeId);
return req.res?.redirect(await setFile(fileLocation.employee.visa(employeeId, visaId)));
}
@Delete("file-visa/{visaId}")
@Security("keycloak")
async delVisa(
@Request() req: RequestWithUser,
@Path() employeeId: string,
@Path() visaId: string,
) {
await this.checkPermission(req.user, employeeId);
return await deleteFile(fileLocation.employee.visa(employeeId, visaId));
}
@Get("file-in-country-notice")
@Security("keycloak")
async listNotice(@Request() req: RequestWithUser, @Path() employeeId: string) {
await this.checkPermission(req.user, employeeId);
return await listFile(fileLocation.employee.inCountryNotice(employeeId));
}
@Get("file-in-country-notice/{noticeId}")
@Security("keycloak")
async getNotice(@Path() employeeId: string, @Path() noticeId: string) {
return await getFile(fileLocation.employee.inCountryNotice(employeeId, noticeId));
}
@Put("file-in-country-notice/{noticeId}")
@Security("keycloak")
async putNotice(
@Request() req: RequestWithUser,
@Path() employeeId: string,
@Path() noticeId: string,
) {
await this.checkPermission(req.user, employeeId);
return req.res?.redirect(
await setFile(fileLocation.employee.inCountryNotice(employeeId, noticeId)),
);
}
@Delete("file-in-country-notice/{noticeId}")
@Security("keycloak")
async delNotice(
@Request() req: RequestWithUser,
@Path() employeeId: string,
@Path() noticeId: string,
) {
await this.checkPermission(req.user, employeeId);
return await deleteFile(fileLocation.employee.inCountryNotice(employeeId, noticeId));
}
} }

View file

@ -0,0 +1,116 @@
import {
Body,
Controller,
Delete,
Get,
Middlewares,
Path,
Post,
Put,
Route,
Security,
Tags,
} from "tsoa";
import { RequestWithUser } from "../interfaces/user";
import prisma from "../db";
import HttpStatus from "../interfaces/http-status";
import { permissionCheck } from "../middlewares/employee";
import { notFoundError } from "../utils/error";
const MANAGE_ROLES = [
"system",
"head_of_admin",
"admin",
"head_of_account",
"account",
"head_of_sale",
];
function globalAllow(user: RequestWithUser["user"]) {
const allowList = ["system", "head_of_admin", "admin", "head_of_account", "head_of_sale"];
return allowList.some((v) => user.roles?.includes(v));
}
type EmployeeInCountryNoticePayload = {
noticeNumber: string;
noticeDate: string;
nextNoticeDate: Date;
tmNumber: string;
entryDate: Date;
travelBy: string;
travelFrom: string;
};
@Route("api/v1/employee/{employeeId}/work")
@Tags("Employee Work")
@Middlewares(permissionCheck(globalAllow))
export class EmployeeInCountryNoticeController extends Controller {
@Get()
@Security("keycloak")
async list(@Path() employeeId: string) {
return prisma.employeeInCountryNotice.findMany({
orderBy: { createdAt: "asc" },
where: { employeeId },
});
}
@Get("{passportId}")
@Security("keycloak")
async getById(@Path() employeeId: string, @Path() passportId: string) {
const record = await prisma.employeeInCountryNotice.findFirst({
where: { id: passportId, employeeId },
});
if (!record) throw notFoundError("Employee Work");
return record;
}
@Post()
@Security("keycloak", MANAGE_ROLES)
async create(@Path() employeeId: string, @Body() body: EmployeeInCountryNoticePayload) {
const record = await prisma.employeeInCountryNotice.create({
data: {
...body,
employee: { connect: { id: employeeId } },
},
});
this.setStatus(HttpStatus.CREATED);
return record;
}
@Put("{passportId}")
@Security("keycloak", MANAGE_ROLES)
async editById(
@Path() employeeId: string,
@Path() passportId: string,
@Body() body: EmployeeInCountryNoticePayload,
) {
const work = await prisma.employeeInCountryNotice.findUnique({
where: { id: passportId, employeeId },
});
if (!work) throw notFoundError("Employee Work");
const record = await prisma.employeeInCountryNotice.update({
where: { id: passportId, employeeId },
data: { ...body },
});
this.setStatus(HttpStatus.CREATED);
return record;
}
@Delete("{passportId}")
@Security("keycloak", MANAGE_ROLES)
async deleteById(@Path() employeeId: string, @Path() passportId: string) {
const record = await prisma.employeeInCountryNotice.findFirst({
where: { id: passportId, employeeId },
});
if (!record) throw notFoundError("Employee Work");
return await prisma.employeeInCountryNotice.delete({ where: { id: passportId, employeeId } });
}
}

View file

@ -0,0 +1,116 @@
import {
Body,
Controller,
Delete,
Get,
Middlewares,
Path,
Post,
Put,
Route,
Security,
Tags,
} from "tsoa";
import { RequestWithUser } from "../interfaces/user";
import prisma from "../db";
import HttpStatus from "../interfaces/http-status";
import { permissionCheck } from "../middlewares/employee";
import { notFoundError } from "../utils/error";
const MANAGE_ROLES = [
"system",
"head_of_admin",
"admin",
"head_of_account",
"account",
"head_of_sale",
];
function globalAllow(user: RequestWithUser["user"]) {
const allowList = ["system", "head_of_admin", "admin", "head_of_account", "head_of_sale"];
return allowList.some((v) => user.roles?.includes(v));
}
type EmployeePassportPayload = {
number: string;
type: string;
issueDate: Date;
expireDate: Date;
issueCountry: string;
issuePlace: string;
previousPassportRef?: string | null;
};
@Route("api/v1/employee/{employeeId}/work")
@Tags("Employee Work")
@Middlewares(permissionCheck(globalAllow))
export class EmployeePassportController extends Controller {
@Get()
@Security("keycloak")
async list(@Path() employeeId: string) {
return prisma.employeePassport.findMany({
orderBy: { createdAt: "asc" },
where: { employeeId },
});
}
@Get("{passportId}")
@Security("keycloak")
async getById(@Path() employeeId: string, @Path() passportId: string) {
const record = await prisma.employeePassport.findFirst({
where: { id: passportId, employeeId },
});
if (!record) throw notFoundError("Employee Work");
return record;
}
@Post()
@Security("keycloak", MANAGE_ROLES)
async create(@Path() employeeId: string, @Body() body: EmployeePassportPayload) {
const record = await prisma.employeePassport.create({
data: {
...body,
employee: { connect: { id: employeeId } },
},
});
this.setStatus(HttpStatus.CREATED);
return record;
}
@Put("{passportId}")
@Security("keycloak", MANAGE_ROLES)
async editById(
@Path() employeeId: string,
@Path() passportId: string,
@Body() body: EmployeePassportPayload,
) {
const work = await prisma.employeePassport.findUnique({
where: { id: passportId, employeeId },
});
if (!work) throw notFoundError("Employee Work");
const record = await prisma.employeePassport.update({
where: { id: passportId, employeeId },
data: { ...body },
});
this.setStatus(HttpStatus.CREATED);
return record;
}
@Delete("{passportId}")
@Security("keycloak", MANAGE_ROLES)
async deleteById(@Path() employeeId: string, @Path() passportId: string) {
const record = await prisma.employeePassport.findFirst({
where: { id: passportId, employeeId },
});
if (!record) throw notFoundError("Employee Work");
return await prisma.employeePassport.delete({ where: { id: passportId, employeeId } });
}
}

View file

@ -0,0 +1,118 @@
import {
Body,
Controller,
Delete,
Get,
Middlewares,
Path,
Post,
Put,
Route,
Security,
Tags,
} from "tsoa";
import { RequestWithUser } from "../interfaces/user";
import prisma from "../db";
import HttpStatus from "../interfaces/http-status";
import { permissionCheck } from "../middlewares/employee";
import { notFoundError } from "../utils/error";
const MANAGE_ROLES = [
"system",
"head_of_admin",
"admin",
"head_of_account",
"account",
"head_of_sale",
];
function globalAllow(user: RequestWithUser["user"]) {
const allowList = ["system", "head_of_admin", "admin", "head_of_account", "head_of_sale"];
return allowList.some((v) => user.roles?.includes(v));
}
type EmployeeVisaPayload = {
number: string;
type: string;
entryCount: number;
issueCountry: string;
issuePlace: string;
issueDate: Date;
expireDate: Date;
mrz?: string;
remark?: string;
};
@Route("api/v1/employee/{employeeId}/work")
@Tags("Employee Work")
@Middlewares(permissionCheck(globalAllow))
export class EmployeeVisaController extends Controller {
@Get()
@Security("keycloak")
async list(@Path() employeeId: string) {
return prisma.employeeVisa.findMany({
orderBy: { createdAt: "asc" },
where: { employeeId },
});
}
@Get("{passportId}")
@Security("keycloak")
async getById(@Path() employeeId: string, @Path() passportId: string) {
const record = await prisma.employeeVisa.findFirst({
where: { id: passportId, employeeId },
});
if (!record) throw notFoundError("Employee Work");
return record;
}
@Post()
@Security("keycloak", MANAGE_ROLES)
async create(@Path() employeeId: string, @Body() body: EmployeeVisaPayload) {
const record = await prisma.employeeVisa.create({
data: {
...body,
employee: { connect: { id: employeeId } },
},
});
this.setStatus(HttpStatus.CREATED);
return record;
}
@Put("{passportId}")
@Security("keycloak", MANAGE_ROLES)
async editById(
@Path() employeeId: string,
@Path() passportId: string,
@Body() body: EmployeeVisaPayload,
) {
const work = await prisma.employeeVisa.findUnique({
where: { id: passportId, employeeId },
});
if (!work) throw notFoundError("Employee Work");
const record = await prisma.employeeVisa.update({
where: { id: passportId, employeeId },
data: { ...body },
});
this.setStatus(HttpStatus.CREATED);
return record;
}
@Delete("{passportId}")
@Security("keycloak", MANAGE_ROLES)
async deleteById(@Path() employeeId: string, @Path() passportId: string) {
const record = await prisma.employeeVisa.findFirst({
where: { id: passportId, employeeId },
});
if (!record) throw notFoundError("Employee Work");
return await prisma.employeeVisa.delete({ where: { id: passportId, employeeId } });
}
}

View file

@ -113,14 +113,6 @@ type QuotationUpdate = {
addressEN: string; addressEN: string;
address: string; address: string;
zipCode: string; zipCode: string;
passportType: string;
passportNumber: string;
passportIssueDate: Date;
passportExpiryDate: Date;
passportIssuingCountry: string;
passportIssuingPlace: string;
previousPassportReference?: string;
} }
)[]; )[];