import { Prisma, Status } from "@prisma/client"; import { Body, Controller, Delete, Get, Put, 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) { 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.", "data_not_found"); } return record; } @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.", "missing_or_invalid_parameter", ); if (body.districtId && !district) throw new HttpError( HttpStatus.BAD_REQUEST, "District cannot be found.", "missing_or_invalid_parameter", ); if (body.subDistrictId && !subDistrict) throw new HttpError( HttpStatus.BAD_REQUEST, "Sub-district cannot be found.", "missing_or_invalid_parameter", ); if (body.headOfficeId && !branch) throw new HttpError( HttpStatus.BAD_REQUEST, "Head branch cannot be found.", "missing_or_invalid_parameter", ); } const { provinceId, districtId, subDistrictId, headOfficeId, ...rest } = body; const record = await prisma.branch.create({ include: { province: true, district: true, subDistrict: true, }, data: { ...rest, isHeadOffice: !headOfficeId, 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, }, }); this.setStatus(HttpStatus.CREATED); return record; } @Put("{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.", "missing_or_invalid_parameter", ); if (body.districtId && !district) throw new HttpError( HttpStatus.BAD_REQUEST, "District cannot be found.", "missing_or_invalid_parameter", ); if (body.subDistrictId && !subDistrict) throw new HttpError( HttpStatus.BAD_REQUEST, "Sub-district cannot be found.", "missing_or_invalid_parameter", ); if (body.headOfficeId && !branch) throw new HttpError( HttpStatus.BAD_REQUEST, "Head branch cannot be found.", "missing_or_invalid_parameter", ); } const { provinceId, districtId, subDistrictId, headOfficeId, ...rest } = body; const record = await prisma.branch.update({ include: { province: true, district: true, subDistrict: true }, data: { ...rest, isHeadOffice: headOfficeId !== undefined ? headOfficeId === null : undefined, 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.", "data_not_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.", "data_not_found"); } if (record.status === Status.USED) { throw new HttpError(HttpStatus.FORBIDDEN, "Branch is in used.", "data_exists"); } return await prisma.branch.delete({ include: { province: true, district: true, subDistrict: true, }, where: { id: branchId }, }); } }