From 20d9598a4eb2c711db34fe24c6f442f29dd978fb Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:37:40 +0700 Subject: [PATCH 01/11] feat: add customer branch controller --- src/controllers/customer-branch-controller.ts | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/controllers/customer-branch-controller.ts diff --git a/src/controllers/customer-branch-controller.ts b/src/controllers/customer-branch-controller.ts new file mode 100644 index 0000000..f83a434 --- /dev/null +++ b/src/controllers/customer-branch-controller.ts @@ -0,0 +1,35 @@ +import { Prisma, Status } from "@prisma/client"; +import { + Body, + Controller, + Delete, + Get, + Path, + Post, + Put, + Query, + Request, + Route, + Security, + Tags, +} from "tsoa"; +import { RequestWithUser } from "../interfaces/user"; +import prisma from "../db"; +import HttpStatus from "../interfaces/http-status"; +import HttpError from "../interfaces/http-error"; +import minio from "../services/minio"; + +if (!process.env.MINIO_BUCKET) { + throw Error("Require MinIO bucket."); +} + +const MINIO_BUCKET = process.env.MINIO_BUCKET; + +function imageLocation(id: string) { + return `employee/profile-img-${id}`; +} +@Route("api/customer-branch") +@Tags("Customer Branch") +@Security("keycloak") +export class CustomerBranchController extends Controller { +} From a90400b34864df87f0ef53058af9974a678f381e Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 11:42:03 +0700 Subject: [PATCH 02/11] feat: add type for create and edit --- src/controllers/customer-branch-controller.ts | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/src/controllers/customer-branch-controller.ts b/src/controllers/customer-branch-controller.ts index f83a434..4c1cca9 100644 --- a/src/controllers/customer-branch-controller.ts +++ b/src/controllers/customer-branch-controller.ts @@ -28,6 +28,67 @@ const MINIO_BUCKET = process.env.MINIO_BUCKET; function imageLocation(id: string) { return `employee/profile-img-${id}`; } + +type CustomerBranchCreate = { + customerId: string; + + code: string; + status?: Status; + + branchNo: string; + legalPersonNo: string; + + taxNo: string; + name: string; + nameEN: string; + addressEN: string; + address: string; + zipCode: string; + email: string; + telephoneNo: string; + longitude: string; + latitude: string; + + registerName: string; + registerDate: Date; + authorizedCapital: string; + + subDistrictId?: string | null; + districtId?: string | null; + provinceId?: string | null; + headOfficeId?: string | null; +}; + +type CustomerBranchUpdate = { + customerId?: string; + + code?: string; + status?: "ACTIVE" | "INACTIVE"; + + branchNo?: string; + legalPersonNo?: string; + + taxNo?: string; + name?: string; + nameEN?: string; + addressEN?: string; + address?: string; + zipCode?: string; + email?: string; + telephoneNo?: string; + longitude?: string; + latitude?: string; + + registerName?: string; + registerDate?: Date; + authorizedCapital?: string; + + subDistrictId?: string | null; + districtId?: string | null; + provinceId?: string | null; + headOfficeId?: string | null; +}; + @Route("api/customer-branch") @Tags("Customer Branch") @Security("keycloak") From fd37eb65203157c18c85ecd25aa9c68252976a3a Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 13:51:36 +0700 Subject: [PATCH 03/11] feat: create customer branch endpoint --- src/controllers/customer-branch-controller.ts | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/src/controllers/customer-branch-controller.ts b/src/controllers/customer-branch-controller.ts index 4c1cca9..2a8b48d 100644 --- a/src/controllers/customer-branch-controller.ts +++ b/src/controllers/customer-branch-controller.ts @@ -93,4 +93,67 @@ type CustomerBranchUpdate = { @Tags("Customer Branch") @Security("keycloak") export class CustomerBranchController extends Controller { + @Post() + async create(@Request() req: RequestWithUser, @Body() body: CustomerBranchCreate) { + if (body.provinceId || body.districtId || body.subDistrictId || body.customerId) { + const [province, district, subDistrict, customer] = 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.customer.findFirst({ where: { id: body.customerId || 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.customerId && !customer) + throw new HttpError( + HttpStatus.BAD_REQUEST, + "Customer cannot be found.", + "missing_or_invalid_parameter", + ); + } + + const { provinceId, districtId, subDistrictId, customerId, ...rest } = body; + + const record = await prisma.customerBranch.create({ + include: { + province: true, + district: true, + subDistrict: true, + }, + data: { + ...rest, + customer: { connect: { id: customerId } }, + province: { connect: provinceId ? { id: provinceId } : undefined }, + district: { connect: districtId ? { id: districtId } : undefined }, + subDistrict: { connect: subDistrictId ? { id: subDistrictId } : undefined }, + createdBy: req.user.name, + updateBy: req.user.name, + }, + }); + + await prisma.customer.update({ + where: { id: customerId, status: Status.CREATED }, + data: { status: Status.ACTIVE }, + }); + + this.setStatus(HttpStatus.CREATED); + + return record; + } } From 6adc96135254702c1bd175ddf5ccd4406a963f8e Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:15:38 +0700 Subject: [PATCH 04/11] feat: edit customer branch endpoint --- src/controllers/customer-branch-controller.ts | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/src/controllers/customer-branch-controller.ts b/src/controllers/customer-branch-controller.ts index 2a8b48d..06682e0 100644 --- a/src/controllers/customer-branch-controller.ts +++ b/src/controllers/customer-branch-controller.ts @@ -156,4 +156,77 @@ export class CustomerBranchController extends Controller { return record; } + + @Put("{branchId}") + async editById( + @Request() req: RequestWithUser, + @Body() body: CustomerBranchUpdate, + @Path() branchId: string, + ) { + if (body.provinceId || body.districtId || body.subDistrictId || body.customerId) { + const [province, district, subDistrict, customer] = 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.customer.findFirst({ where: { id: body.customerId || 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.customerId && !customer) + throw new HttpError( + HttpStatus.BAD_REQUEST, + "Customer cannot be found.", + "missing_or_invalid_parameter", + ); + } + + const { provinceId, districtId, subDistrictId, customerId, ...rest } = body; + + const record = await prisma.customerBranch.update({ + where: { id: branchId }, + include: { + province: true, + district: true, + subDistrict: true, + }, + data: { + ...rest, + customer: { connect: customerId ? { id: customerId } : 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, + }, + createdBy: req.user.name, + updateBy: req.user.name, + }, + }); + + this.setStatus(HttpStatus.CREATED); + + return record; + } } From d43ac9f54e75f2af6eb1530951c9a1d1739dec20 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:27:38 +0700 Subject: [PATCH 05/11] fix: input type not matched with db --- src/controllers/customer-branch-controller.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/controllers/customer-branch-controller.ts b/src/controllers/customer-branch-controller.ts index 06682e0..ce26649 100644 --- a/src/controllers/customer-branch-controller.ts +++ b/src/controllers/customer-branch-controller.ts @@ -32,7 +32,6 @@ function imageLocation(id: string) { type CustomerBranchCreate = { customerId: string; - code: string; status?: Status; branchNo: string; @@ -56,13 +55,11 @@ type CustomerBranchCreate = { subDistrictId?: string | null; districtId?: string | null; provinceId?: string | null; - headOfficeId?: string | null; }; type CustomerBranchUpdate = { customerId?: string; - code?: string; status?: "ACTIVE" | "INACTIVE"; branchNo?: string; @@ -86,7 +83,6 @@ type CustomerBranchUpdate = { subDistrictId?: string | null; districtId?: string | null; provinceId?: string | null; - headOfficeId?: string | null; }; @Route("api/customer-branch") From 58611f8589b9f394aeb252ef6fa69df63e510dd3 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:28:25 +0700 Subject: [PATCH 06/11] fix: error when trying to update --- src/controllers/customer-branch-controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/customer-branch-controller.ts b/src/controllers/customer-branch-controller.ts index ce26649..642d63d 100644 --- a/src/controllers/customer-branch-controller.ts +++ b/src/controllers/customer-branch-controller.ts @@ -143,7 +143,7 @@ export class CustomerBranchController extends Controller { }, }); - await prisma.customer.update({ + await prisma.customer.updateMany({ where: { id: customerId, status: Status.CREATED }, data: { status: Status.ACTIVE }, }); From 011d53d65572cfcc7ef205efe0cfd743aecab698 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:43:21 +0700 Subject: [PATCH 07/11] fix: error on not exist --- src/controllers/customer-branch-controller.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/controllers/customer-branch-controller.ts b/src/controllers/customer-branch-controller.ts index 642d63d..4312eb6 100644 --- a/src/controllers/customer-branch-controller.ts +++ b/src/controllers/customer-branch-controller.ts @@ -194,6 +194,10 @@ export class CustomerBranchController extends Controller { const { provinceId, districtId, subDistrictId, customerId, ...rest } = body; + if (!(await prisma.customerBranch.findUnique({ where: { id: branchId } }))) { + throw new HttpError(HttpStatus.NOT_FOUND, "Branch cannot be found.", "data_not_found"); + } + const record = await prisma.customerBranch.update({ where: { id: branchId }, include: { From 910c8b50e44df26a7b334990e6d66fec31b39df8 Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 14:55:24 +0700 Subject: [PATCH 08/11] feat: list customer branch --- src/controllers/customer-branch-controller.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/controllers/customer-branch-controller.ts b/src/controllers/customer-branch-controller.ts index 4312eb6..e13984c 100644 --- a/src/controllers/customer-branch-controller.ts +++ b/src/controllers/customer-branch-controller.ts @@ -89,6 +89,38 @@ type CustomerBranchUpdate = { @Tags("Customer Branch") @Security("keycloak") export class CustomerBranchController extends Controller { + @Get() + async list( + @Query() zipCode?: string, + @Query() query: string = "", + @Query() page: number = 1, + @Query() pageSize: number = 30, + ) { + const where = { + OR: [ + { nameEN: { contains: query }, zipCode }, + { name: { contains: query }, zipCode }, + { email: { contains: query }, zipCode }, + ], + } satisfies Prisma.BranchWhereInput; + + const [result, total] = await prisma.$transaction([ + prisma.customerBranch.findMany({ + include: { + province: true, + district: true, + subDistrict: true, + }, + where, + take: pageSize, + skip: (page - 1) * pageSize, + }), + prisma.customerBranch.count({ where }), + ]); + + return { result, page, pageSize, total }; + } + @Post() async create(@Request() req: RequestWithUser, @Body() body: CustomerBranchCreate) { if (body.provinceId || body.districtId || body.subDistrictId || body.customerId) { From 620a57c6c635519f2f9ff913fa022fef5afe27fa Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:07:29 +0700 Subject: [PATCH 09/11] feat: get employee of customer branch --- src/controllers/customer-branch-controller.ts | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/controllers/customer-branch-controller.ts b/src/controllers/customer-branch-controller.ts index e13984c..8ece315 100644 --- a/src/controllers/customer-branch-controller.ts +++ b/src/controllers/customer-branch-controller.ts @@ -121,6 +121,56 @@ export class CustomerBranchController extends Controller { return { result, page, pageSize, total }; } + @Get("{branchId}/employee") + async listEmployee( + @Path() branchId: string, + @Query() zipCode?: string, + @Query() query: string = "", + @Query() page: number = 1, + @Query() pageSize: number = 30, + ) { + const where = { + AND: { customerBranchId: branchId }, + OR: [ + { firstName: { contains: query }, zipCode }, + { firstNameEN: { contains: query }, zipCode }, + { lastName: { contains: query }, zipCode }, + { lastNameEN: { contains: query }, zipCode }, + { email: { contains: query }, zipCode }, + ], + } satisfies Prisma.EmployeeWhereInput; + + const [result, total] = await prisma.$transaction([ + prisma.employee.findMany({ + include: { + province: true, + district: true, + subDistrict: true, + }, + where, + take: pageSize, + skip: (page - 1) * pageSize, + }), + prisma.employee.count({ where }), + ]); + + return { + result: await Promise.all( + result.map(async (v) => ({ + ...v, + profileImageUrl: await minio.presignedGetObject( + MINIO_BUCKET, + imageLocation(v.id), + 12 * 60 * 60, + ), + })), + ), + page, + pageSize, + total, + }; + } + @Post() async create(@Request() req: RequestWithUser, @Body() body: CustomerBranchCreate) { if (body.provinceId || body.districtId || body.subDistrictId || body.customerId) { From 3f43ad1b9bbf7e3fd865b1761c0f4f19736100cc Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:09:44 +0700 Subject: [PATCH 10/11] feat: get customer branch by id --- src/controllers/customer-branch-controller.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/controllers/customer-branch-controller.ts b/src/controllers/customer-branch-controller.ts index 8ece315..5b6b7b6 100644 --- a/src/controllers/customer-branch-controller.ts +++ b/src/controllers/customer-branch-controller.ts @@ -121,6 +121,24 @@ export class CustomerBranchController extends Controller { return { result, page, pageSize, total }; } + @Get("{branchId}") + async getById(@Path() branchId: string) { + const record = await prisma.customerBranch.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; + } + @Get("{branchId}/employee") async listEmployee( @Path() branchId: string, From c0e59ccb703781bff5f2773de11ed212fbb90bbf Mon Sep 17 00:00:00 2001 From: Methapon2001 <61303214+Methapon2001@users.noreply.github.com> Date: Fri, 5 Apr 2024 15:13:33 +0700 Subject: [PATCH 11/11] feat: delete customer branch --- src/controllers/customer-branch-controller.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/controllers/customer-branch-controller.ts b/src/controllers/customer-branch-controller.ts index 5b6b7b6..303d9f8 100644 --- a/src/controllers/customer-branch-controller.ts +++ b/src/controllers/customer-branch-controller.ts @@ -329,4 +329,23 @@ export class CustomerBranchController extends Controller { return record; } + + @Delete("{branchId}") + async delete(@Path() branchId: string) { + const record = await prisma.customerBranch.findFirst({ where: { id: branchId } }); + + if (!record) { + throw new HttpError( + HttpStatus.NOT_FOUND, + "Customer branch cannot be found.", + "data_not_found", + ); + } + + if (record.status !== Status.CREATED) { + throw new HttpError(HttpStatus.FORBIDDEN, "Customer branch is in used.", "data_in_used"); + } + + return await prisma.customerBranch.delete({ where: { id: branchId } }); + } }