import { Prisma, Status } from "@prisma/client"; import { Body, Controller, Delete, Get, Patch, Path, Post, Query, Request, Route, Security, Tags, } from "tsoa"; import prisma from "../../db"; import HttpError from "../../interfaces/http-error"; import HttpStatus from "../../interfaces/http-status"; import { RequestWithUser } from "../../interfaces/user"; type BranchCreate = { code: string; taxNo: string; nameEN: string; nameTH: string; addressEN: string; addressTH: string; zipCode: string; email: string; telephoneNo: string; longitude: string; latitude: string; subDistrictId?: string | null; districtId?: string | null; provinceId?: string | null; headOfficeId?: string | null; }; type BranchUpdate = { code?: string; taxNo?: string; nameEN?: string; nameTH?: string; addressEN?: string; addressTH?: string; zipCode?: string; email?: string; telephoneNo?: string; longitude?: string; latitude?: string; subDistrictId?: string | null; districtId?: string | null; provinceId?: string | null; headOfficeId?: string | null; }; @Route("api/branch") @Tags("Branch") @Security("keycloak") export class BranchController extends Controller { @Get() async getBranch( @Query() zipCode?: string, @Query() query: string = "", @Query() page: number = 1, @Query() pageSize: number = 30, ) { const where = { OR: [ { nameEN: { contains: query }, zipCode }, { nameTH: { contains: query }, zipCode }, { email: { contains: query }, zipCode }, ], } satisfies Prisma.BranchWhereInput; const [result, total] = await prisma.$transaction([ prisma.branch.findMany({ include: { province: true, district: true, subDistrict: true, }, where, take: pageSize, skip: (page - 1) * pageSize, }), prisma.branch.count({ where }), ]); return { result, page, pageSize, total }; } @Get("{branchId}") async getBranchById(@Path() branchId: string) { return await prisma.branch.findFirst({ include: { province: true, district: true, subDistrict: true, }, where: { id: branchId }, }); } @Post() async createBranch(@Request() req: RequestWithUser, @Body() body: BranchCreate) { if (body.provinceId || body.districtId || body.subDistrictId || body.headOfficeId) { const [province, district, subDistrict, branch] = await prisma.$transaction([ prisma.province.findFirst({ where: { id: body.provinceId || undefined } }), prisma.district.findFirst({ where: { id: body.districtId || undefined } }), prisma.subDistrict.findFirst({ where: { id: body.subDistrictId || undefined } }), prisma.branch.findFirst({ where: { id: body.headOfficeId || undefined } }), ]); if (body.provinceId && !province) throw new HttpError(HttpStatus.BAD_REQUEST, "Province cannot be found."); if (body.districtId && !district) throw new HttpError(HttpStatus.BAD_REQUEST, "District cannot be found."); if (body.subDistrictId && !subDistrict) throw new HttpError(HttpStatus.BAD_REQUEST, "Sub-district cannot be found."); if (body.headOfficeId && !branch) throw new HttpError(HttpStatus.BAD_REQUEST, "Head branch cannot be found."); } const { provinceId, districtId, subDistrictId, headOfficeId, ...rest } = body; return await prisma.branch.create({ include: { province: true, district: true, subDistrict: true, }, data: { ...rest, isHeadOffice: headOfficeId === null, province: { connect: provinceId ? { id: provinceId } : undefined }, district: { connect: districtId ? { id: districtId } : undefined }, subDistrict: { connect: subDistrictId ? { id: subDistrictId } : undefined }, headOffice: { connect: headOfficeId ? { id: headOfficeId } : undefined }, createdBy: req.user.name, updateBy: req.user.name, }, }); } @Patch("{branchId}") async editBranch( @Request() req: RequestWithUser, @Body() body: BranchUpdate, @Path() branchId: string, ) { if (body.subDistrictId || body.districtId || body.provinceId || body.headOfficeId) { const [province, district, subDistrict, branch] = await prisma.$transaction([ prisma.province.findFirst({ where: { id: body.provinceId || undefined } }), prisma.district.findFirst({ where: { id: body.districtId || undefined } }), prisma.subDistrict.findFirst({ where: { id: body.subDistrictId || undefined } }), prisma.branch.findFirst({ where: { id: body.headOfficeId || undefined } }), ]); if (body.provinceId && !province) throw new HttpError(HttpStatus.BAD_REQUEST, "Province cannot be found."); if (body.districtId && !district) throw new HttpError(HttpStatus.BAD_REQUEST, "District cannot be found."); if (body.subDistrictId && !subDistrict) throw new HttpError(HttpStatus.BAD_REQUEST, "Sub-district cannot be found."); if (body.headOfficeId && !branch) throw new HttpError(HttpStatus.BAD_REQUEST, "Head branch cannot be found."); } const { provinceId, districtId, subDistrictId, headOfficeId, ...rest } = body; const record = await prisma.branch.update({ include: { province: true, district: true, subDistrict: true }, data: { ...rest, isHeadOffice: headOfficeId === null, province: { connect: provinceId ? { id: provinceId } : undefined, disconnect: provinceId === null || undefined, }, district: { connect: districtId ? { id: districtId } : undefined, disconnect: districtId === null || undefined, }, subDistrict: { connect: subDistrictId ? { id: subDistrictId } : undefined, disconnect: subDistrictId === null || undefined, }, headOffice: { connect: headOfficeId ? { id: headOfficeId } : undefined, disconnect: headOfficeId === null || undefined, }, updateBy: req.user.name, }, where: { id: branchId }, }); if (!record) { throw new HttpError(HttpStatus.NOT_FOUND, "Branch cannot be found."); } return record; } @Delete("{branchId}") async deleteBranch(@Path() branchId: string) { const record = await prisma.branch.findFirst({ include: { province: true, district: true, subDistrict: true, }, where: { id: branchId }, }); if (!record) { throw new HttpError(HttpStatus.NOT_FOUND, "Branch cannot be found."); } if (record.status === Status.USED) { throw new HttpError(HttpStatus.FORBIDDEN, "Branch is in used."); } return await prisma.branch.delete({ where: { id: branchId } }); } }