import { Branch, Prisma, Status, User, UserType } from "@prisma/client"; import { Body, Controller, Delete, Get, 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 BranchUserBody = { user: string[] }; async function userBranchCodeGen(branch: Branch, user: User[]) { await prisma.$transaction( async (tx) => { for (const usr of user) { if (usr.code !== null) continue; const typ = usr.userType; const last = await tx.runningNo.upsert({ where: { key: `BR_USR_${branch.code.slice(4).padEnd(3, "0")}${typ !== "USER" ? typ.charAt(0).toLocaleUpperCase() : ""}`, }, create: { key: `BR_USR_${branch.code.slice(4).padEnd(3, "0")}${typ !== "USER" ? typ.charAt(0).toLocaleUpperCase() : ""}`, value: 1, }, update: { value: { increment: 1 } }, }); await prisma.user.update({ where: { id: usr.id }, data: { code: `${last.key.slice(7)}${last.value.toString().padStart(4, "0")}`, }, }); } }, { isolationLevel: Prisma.TransactionIsolationLevel.Serializable }, ); } @Route("api/v1/branch/{branchId}/user") @Tags("Branch User") @Security("keycloak") export class BranchUserController extends Controller { @Get() async getBranchUser( @Path() branchId: string, @Query() zipCode?: string, @Query() query: string = "", @Query() page: number = 1, @Query() pageSize: number = 30, ) { const where = { OR: [ { user: { firstName: { contains: query }, zipCode }, branchId }, { user: { firstNameEN: { contains: query }, zipCode }, branchId }, { user: { lastName: { contains: query }, zipCode }, branchId }, { user: { lastNameEN: { contains: query }, zipCode }, branchId }, { user: { email: { contains: query }, zipCode }, branchId }, { user: { telephoneNo: { contains: query }, zipCode }, branchId }, ], } satisfies Prisma.BranchUserWhereInput; const [result, total] = await prisma.$transaction([ prisma.branchUser.findMany({ orderBy: { user: { createdAt: "asc" } }, include: { user: { include: { province: true, district: true, subDistrict: true, }, }, }, where, take: pageSize, skip: (page - 1) * pageSize, }), prisma.branchUser.count({ where }), ]); return { result: result.map((v) => v.user), page, pageSize, total }; } @Post() async createBranchUser( @Request() req: RequestWithUser, @Path() branchId: string, @Body() body: BranchUserBody, ) { const [branch, user] = await prisma.$transaction([ prisma.branch.findUnique({ where: { id: branchId }, }), prisma.user.findMany({ include: { branch: true }, where: { id: { in: body.user } }, }), ]); if (!branch) { throw new HttpError( HttpStatus.BAD_REQUEST, "Branch cannot be found.", "missing_or_invalid_parameter", ); } if (user.length !== body.user.length) { throw new HttpError( HttpStatus.BAD_REQUEST, "One or more user cannot be found.", "missing_or_invalid_parameter", ); } await prisma.$transaction([ prisma.user.updateMany({ where: { id: { in: body.user }, status: Status.CREATED }, data: { status: Status.ACTIVE }, }), prisma.branchUser.createMany({ data: user .filter((a) => !a.branch.some((b) => b.branchId === branchId)) .map((v) => ({ branchId, userId: v.id, createdBy: req.user.name, updateBy: req.user.name, })), }), ]); await userBranchCodeGen(branch, user); } @Delete() async deleteBranchUser(@Path() branchId: string, @Body() body: BranchUserBody) { await prisma.$transaction( body.user.map((v) => prisma.branchUser.deleteMany({ where: { branchId, userId: v } })), ); await prisma.user.updateMany({ where: { branch: { none: {} }, }, data: { code: null }, }); } @Delete("{userId}") async deleteBranchUserById(@Path() branchId: string, @Path() userId: string) { await prisma.branchUser.deleteMany({ where: { branchId, userId }, }); await prisma.user.updateMany({ where: { id: userId, branch: { none: {} }, }, data: { code: null }, }); } } type UserBranchBody = { branch: string[] }; @Route("api/v1/user/{userId}/branch") @Tags("Branch User") @Security("keycloak") export class UserBranchController extends Controller { @Get() async getUserBranch( @Path() userId: string, @Query() zipCode?: string, @Query() query: string = "", @Query() page: number = 1, @Query() pageSize: number = 30, ) { const where = { OR: [ { branch: { name: { contains: query }, zipCode }, userId }, { branch: { nameEN: { contains: query }, zipCode }, userId }, ], } satisfies Prisma.BranchUserWhereInput; const [result, total] = await prisma.$transaction([ prisma.branchUser.findMany({ orderBy: { branch: { createdAt: "asc" } }, include: { branch: { include: { province: true, district: true, subDistrict: true, }, }, }, where, take: pageSize, skip: (page - 1) * pageSize, }), prisma.branchUser.count({ where }), ]); return { result: result.map((v) => v.branch), page, pageSize, total }; } @Post() async createUserBranch( @Request() req: RequestWithUser, @Path() userId: string, @Body() body: UserBranchBody, ) { const branch = await prisma.branch.findMany({ include: { user: true }, where: { id: { in: body.branch } }, }); if (branch.length !== body.branch.length) { throw new HttpError( HttpStatus.BAD_REQUEST, "One or more branch cannot be found.", "missing_or_invalid_parameter", ); } await prisma.branch.updateMany({ where: { id: { in: body.branch }, status: Status.CREATED }, data: { status: Status.ACTIVE }, }); await prisma.branchUser.createMany({ data: branch .filter((a) => !a.user.some((b) => b.userId === userId)) .map((v) => ({ branchId: v.id, userId, createdBy: req.user.name, updateBy: req.user.name, })), }); this.setStatus(HttpStatus.CREATED); } @Delete() async deleteUserBranch(@Path() userId: string, @Body() body: UserBranchBody) { await prisma.$transaction( body.branch.map((v) => prisma.branchUser.deleteMany({ where: { userId, branchId: v } })), ); await prisma.user.updateMany({ where: { branch: { none: {} }, }, data: { code: null }, }); } @Delete("{branchId}") async deleteUserBranchById(@Path() branchId: string, @Path() userId: string) { await prisma.branchUser.deleteMany({ where: { branchId, userId }, }); await prisma.user.updateMany({ where: { id: userId, branch: { none: {} }, }, data: { code: null }, }); } }