diff --git a/prisma/migrations/20241114072657_employment_office/migration.sql b/prisma/migrations/20241114072657_employment_office/migration.sql new file mode 100644 index 0000000..bf46f4c --- /dev/null +++ b/prisma/migrations/20241114072657_employment_office/migration.sql @@ -0,0 +1,26 @@ +-- CreateTable +CREATE TABLE "EmploymentOffice" ( + "id" TEXT NOT NULL, + "name" TEXT NOT NULL, + "nameEN" TEXT NOT NULL, + "provinceId" TEXT NOT NULL, + + CONSTRAINT "EmploymentOffice_pkey" PRIMARY KEY ("id") +); + +-- CreateTable +CREATE TABLE "EmploymentOfficeDistrict" ( + "areaId" TEXT NOT NULL, + "districtId" TEXT NOT NULL, + + CONSTRAINT "EmploymentOfficeDistrict_pkey" PRIMARY KEY ("areaId","districtId") +); + +-- AddForeignKey +ALTER TABLE "EmploymentOffice" ADD CONSTRAINT "EmploymentOffice_provinceId_fkey" FOREIGN KEY ("provinceId") REFERENCES "Province"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "EmploymentOfficeDistrict" ADD CONSTRAINT "EmploymentOfficeDistrict_areaId_fkey" FOREIGN KEY ("areaId") REFERENCES "EmploymentOffice"("id") ON DELETE RESTRICT ON UPDATE CASCADE; + +-- AddForeignKey +ALTER TABLE "EmploymentOfficeDistrict" ADD CONSTRAINT "EmploymentOfficeDistrict_districtId_fkey" FOREIGN KEY ("districtId") REFERENCES "District"("id") ON DELETE RESTRICT ON UPDATE CASCADE; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 62901e2..511e233 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -164,6 +164,7 @@ model Province { customerBranchCitizen CustomerBranchCitizen[] customerBranchHouseRegis CustomerBranchHouseRegis[] institution Institution[] + employmentOffice EmploymentOffice[] } model District { @@ -187,6 +188,7 @@ model District { customerBranchCitizen CustomerBranchCitizen[] customerBranchHouseRegis CustomerBranchHouseRegis[] institution Institution[] + employmentOffice EmploymentOfficeDistrict[] } model SubDistrict { @@ -212,6 +214,28 @@ model SubDistrict { institution Institution[] } +model EmploymentOffice { + id String @id @default(cuid()) + + name String + nameEN String + + provinceId String + province Province @relation(fields: [provinceId], references: [id]) + + district EmploymentOfficeDistrict[] +} + +model EmploymentOfficeDistrict { + areaId String + area EmploymentOffice @relation(fields: [areaId], references: [id]) + + districtId String + district District @relation(fields: [districtId], references: [id]) + + @@id([areaId, districtId]) +} + enum Status { CREATED ACTIVE diff --git a/src/app.ts b/src/app.ts index bf4756a..7fd3543 100644 --- a/src/app.ts +++ b/src/app.ts @@ -4,7 +4,7 @@ import express, { json, urlencoded } from "express"; import error from "./middlewares/error"; import morgan from "./middlewares/morgan"; import { RegisterRoutes } from "./routes"; -import { initThailandAreaDatabase } from "./utils/thailand-area"; +import { initEmploymentOffice, initThailandAreaDatabase } from "./utils/thailand-area"; import { initFirstAdmin } from "./utils/database"; import { apiReference } from "@scalar/express-api-reference"; import { initSchedule } from "./services/schedule"; @@ -17,6 +17,7 @@ const APP_PORT = +(process.env.APP_PORT || 3000); await initThailandAreaDatabase(); await initFirstAdmin(); + await initEmploymentOffice(); initSchedule(); diff --git a/src/controllers/00-employment-office-controller.ts b/src/controllers/00-employment-office-controller.ts new file mode 100644 index 0000000..6e54199 --- /dev/null +++ b/src/controllers/00-employment-office-controller.ts @@ -0,0 +1,28 @@ +import { Controller, Get, Query, Route, Tags } from "tsoa"; +import prisma from "../db"; + +@Route("/api/v1/employment-office") +@Tags("Employment Office") +export class EmploymentOfficeController extends Controller { + @Get() + async getEmploymentOfficeList(@Query() districtId?: string) { + return await prisma.employmentOffice.findMany({ + where: { + OR: [ + { + province: { + district: { some: { id: districtId } }, + }, + district: { none: {} }, + }, + { + district: { + some: { districtId }, + }, + }, + ], + }, + orderBy: [{ provinceId: "asc" }, { id: "asc" }], + }); + } +} diff --git a/src/utils/thailand-area.ts b/src/utils/thailand-area.ts index 24d72c1..799505f 100644 --- a/src/utils/thailand-area.ts +++ b/src/utils/thailand-area.ts @@ -141,4 +141,94 @@ export async function initThailandAreaDatabase() { }), ); }); + + console.log("[INFO]: Sync thailand province, district and subdistrict, OK."); +} + +export async function initEmploymentOffice() { + const name = (provinceName: string) => `สำนักงานจัดหางานจังหวัด${provinceName}`; + const nameEN = (provinceNameEN: string) => `${provinceNameEN} Employment Office`; + const nameSpecial = (provinceName: string, areaNo: number) => + `สำนักงานจัดหางาน${provinceName} พื้นที่ ${areaNo}`; + const nameSpecialEN = (provinceNameEN: string, areaNo: number) => + `${provinceNameEN} Employment Office Area ${areaNo}`; + + const special: Record = { + "10": { + "1": ["1004", "1007", "1012", "1028", "1031"], + "2": ["1021", "1024", "1035", "1049", "1050"], + "3": ["1009", "1032", "1033", "1034", "1039", "1047"], + "4": ["1006", "1038", "1043", "1027", "1045"], + "5": ["1003", "1010", "1011", "1042", "1044", "1046"], + "6": ["1015", "1016", "1018", "1020", "1025"], + "7": ["1019", "1022", "1023", "1040", "1048"], + "8": ["1001", "1002", "1008", "1013"], + "9": ["1005", "1029", "1030", "1041"], + "10": ["1014", "1017", "1026", "1036", "1037"], + }, + }; + + const list = await prisma.province.findMany(); + + await prisma.$transaction(async (tx) => { + await Promise.all( + list + .map(async (province) => { + if (special[province.id]) { + await tx.employmentOffice.deleteMany({ + where: { provinceId: province.id, district: { none: {} } }, + }); + return Object.entries(special[province.id]).map(([key, val]) => { + const id = province.id + "-" + key.padStart(2, "0"); + return tx.employmentOffice.upsert({ + where: { id }, + create: { + id, + name: nameSpecial(province.name, +key), + nameEN: nameSpecialEN(province.nameEN, +key), + provinceId: province.id, + district: { + createMany: { + data: val.map((districtId) => ({ districtId })), + skipDuplicates: true, + }, + }, + }, + update: { + id, + name: nameSpecial(province.name, +key), + nameEN: nameSpecialEN(province.nameEN, +key), + provinceId: province.id, + district: { + deleteMany: { districtId: { notIn: val } }, + createMany: { + data: val.map((districtId) => ({ districtId })), + skipDuplicates: true, + }, + }, + }, + }); + }); + } + + return tx.employmentOffice.upsert({ + where: { id: province.id }, + create: { + id: province.id, + name: name(province.name), + nameEN: nameEN(province.nameEN), + provinceId: province.id, + }, + update: { + name: name(province.name), + nameEN: nameEN(province.nameEN), + provinceId: province.id, + }, + }); + }) + .flat(), + ); + }); + + console.log("[INFO]: Sync employment office, OK."); } diff --git a/tsoa.json b/tsoa.json index 4ea98ff..715964a 100644 --- a/tsoa.json +++ b/tsoa.json @@ -21,6 +21,7 @@ { "name": "Notification" }, { "name": "Permission" }, { "name": "Address" }, + { "name": "Employment Office" }, { "name": "Branch" }, { "name": "User" }, { "name": "Branch User" },