feat: add address fields

This commit is contained in:
Methapon Metanipat 2024-09-11 15:06:27 +07:00
parent 730ebd6907
commit a7cafd25d0
8 changed files with 209 additions and 206 deletions

View file

@ -0,0 +1,40 @@
/*
Warnings:
- You are about to drop the column `zipCode` on the `Branch` table. All the data in the column will be lost.
- You are about to drop the column `zipCode` on the `User` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE "Branch" DROP COLUMN "zipCode",
ADD COLUMN "moo" TEXT,
ADD COLUMN "mooEN" TEXT,
ADD COLUMN "soi" TEXT,
ADD COLUMN "soiEN" TEXT,
ADD COLUMN "street" TEXT,
ADD COLUMN "streetEN" TEXT;
-- AlterTable
ALTER TABLE "CustomerBranch" ADD COLUMN "moo" TEXT,
ADD COLUMN "mooEN" TEXT,
ADD COLUMN "soi" TEXT,
ADD COLUMN "soiEN" TEXT,
ADD COLUMN "street" TEXT,
ADD COLUMN "streetEN" TEXT;
-- AlterTable
ALTER TABLE "Employee" ADD COLUMN "moo" TEXT,
ADD COLUMN "mooEN" TEXT,
ADD COLUMN "soi" TEXT,
ADD COLUMN "soiEN" TEXT,
ADD COLUMN "street" TEXT,
ADD COLUMN "streetEN" TEXT;
-- AlterTable
ALTER TABLE "User" DROP COLUMN "zipCode",
ADD COLUMN "moo" TEXT,
ADD COLUMN "mooEN" TEXT,
ADD COLUMN "soi" TEXT,
ADD COLUMN "soiEN" TEXT,
ADD COLUMN "street" TEXT,
ADD COLUMN "streetEN" TEXT;

View file

@ -190,10 +190,18 @@ model Branch {
taxNo String
name String
nameEN String
address String
addressEN String
telephoneNo String
address String
addressEN String
soi String?
soiEN String?
moo String?
mooEN String?
street String?
streetEN String?
province Province? @relation(fields: [provinceId], references: [id], onDelete: SetNull)
provinceId String?
@ -203,8 +211,6 @@ model Branch {
subDistrict SubDistrict? @relation(fields: [subDistrictId], references: [id], onDelete: SetNull)
subDistrictId String?
zipCode String
email String
contactName String?
lineId String?
@ -304,6 +310,13 @@ model User {
address String
addressEN String
soi String?
soiEN String?
moo String?
mooEN String?
street String?
streetEN String?
province Province? @relation(fields: [provinceId], references: [id], onDelete: SetNull)
provinceId String?
@ -313,8 +326,6 @@ model User {
subDistrict SubDistrict? @relation(fields: [subDistrictId], references: [id], onDelete: SetNull)
subDistrictId String?
zipCode String
email String
telephoneNo String
@ -329,6 +340,10 @@ model User {
userType UserType
userRole String
// citizenId String?
// citizenIssue DateTime? @db.Date
// citizenExpire DateTime? @db.Date
discountCondition String?
licenseNo String?
@ -451,6 +466,13 @@ model CustomerBranch {
address String
addressEN String
soi String?
soiEN String?
moo String?
mooEN String?
street String?
streetEN String?
province Province? @relation(fields: [provinceId], references: [id], onDelete: SetNull)
provinceId String?
@ -509,6 +531,13 @@ model Employee {
address String?
addressEN String?
soi String?
soiEN String?
moo String?
mooEN String?
street String?
streetEN String?
province Province? @relation(fields: [provinceId], references: [id], onDelete: SetNull)
provinceId String?

View file

@ -51,7 +51,6 @@ const APP_PORT = +(process.env.APP_PORT || 3000);
gender: "",
address: "",
addressEN: "",
zipCode: "",
userType: "USER",
userRole: "system",
telephoneNo: "",

View file

@ -25,8 +25,8 @@ import {
createPermCondition,
} from "../services/permission";
import { filterStatus } from "../services/prisma";
import { connectOrDisconnect, connectOrNot } from "../utils/relation";
import { notFoundError } from "../utils/error";
import { connectOrDisconnect, connectOrNot, whereAddressQuery } from "../utils/relation";
import { notFoundError, relationError } from "../utils/error";
if (!process.env.MINIO_BUCKET) {
throw Error("Require MinIO bucket.");
@ -46,7 +46,12 @@ type BranchCreate = {
name: string;
addressEN: string;
address: string;
zipCode: string;
soi?: string | null;
soiEN?: string | null;
moo?: string | null;
mooEN?: string | null;
street?: string | null;
streetEN?: string | null;
email: string;
contactName?: string | null;
webUrl?: string | null;
@ -80,7 +85,12 @@ type BranchUpdate = {
name?: string;
addressEN?: string;
address?: string;
zipCode?: string;
soi?: string | null;
soiEN?: string | null;
moo?: string | null;
mooEN?: string | null;
street?: string | null;
streetEN?: string | null;
email?: string;
telephoneNo?: string;
contactName?: string;
@ -202,7 +212,6 @@ export class BranchController extends Controller {
@Security("keycloak")
async getBranch(
@Request() req: RequestWithUser,
@Query() zipCode?: string,
@Query() filter?: "head" | "sub",
@Query() headOfficeId?: string,
@Query() includeHead?: boolean,
@ -215,7 +224,6 @@ export class BranchController extends Controller {
const where = {
AND: {
...filterStatus(status),
zipCode,
headOfficeId: headOfficeId ?? (filter === "head" || tree ? null : undefined),
NOT: { headOfficeId: filter === "sub" && !headOfficeId ? null : undefined },
OR: permissionCond(req.user, true),
@ -225,6 +233,20 @@ export class BranchController extends Controller {
{ name: { contains: query } },
{ email: { contains: query } },
{ telephoneNo: { contains: query } },
...whereAddressQuery(query),
{
branch: {
some: {
OR: [
{ nameEN: { contains: query } },
{ name: { contains: query } },
{ email: { contains: query } },
{ telephoneNo: { contains: query } },
...whereAddressQuery(query),
],
},
},
},
],
} satisfies Prisma.BranchWhereInput;
@ -247,6 +269,15 @@ export class BranchController extends Controller {
: false,
branch: tree
? {
where: {
OR: [
{ nameEN: { contains: query } },
{ name: { contains: query } },
{ email: { contains: query } },
{ telephoneNo: { contains: query } },
...whereAddressQuery(query),
],
},
include: {
province: true,
district: true,
@ -312,30 +343,10 @@ export class BranchController extends Controller {
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.",
"relationProvinceNotFound",
);
if (body.districtId && !district)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"District cannot be found.",
"relationDistrictNotFound",
);
if (body.subDistrictId && !subDistrict)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"Sub-district cannot be found.",
"relationSubDistrictNotFound",
);
if (body.headOfficeId && !head)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"Headquaters cannot be found.",
"relationHQNotFound",
);
if (body.provinceId && !province) throw relationError("Province");
if (body.districtId && !district) throw relationError("District");
if (body.subDistrictId && !subDistrict) throw relationError("SubDistrict");
if (body.headOfficeId && !head) throw relationError("HQ");
const { provinceId, districtId, subDistrictId, headOfficeId, bank, contact, code, ...rest } =
body;
@ -447,30 +458,10 @@ export class BranchController extends Controller {
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.",
"relationProvinceNotFound",
);
if (body.districtId && !district)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"District cannot be found.",
"relationDistrictNotFound",
);
if (body.subDistrictId && !subDistrict)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"Sub-district cannot be found.",
"relationSubDistrictNotFound",
);
if (body.headOfficeId && !branch)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"Headquaters cannot be found.",
"relationHQNotFound",
);
if (body.provinceId && !province) throw relationError("Province");
if (body.districtId && !district) throw relationError("District");
if (body.subDistrictId && !subDistrict) throw relationError("SubDistrict");
if (body.headOfficeId && !branch) throw relationError("HQ");
}
const { provinceId, districtId, subDistrictId, headOfficeId, bank, contact, ...rest } = body;

View file

@ -98,10 +98,11 @@ export class UserBranchController extends Controller {
@Query() pageSize: number = 30,
) {
const where = {
OR: [
{ branch: { name: { contains: query }, zipCode }, userId },
{ branch: { nameEN: { contains: query }, zipCode }, userId },
],
AND: {
branch: { subDistrict: { zipCode } },
userId,
},
OR: [{ branch: { name: { contains: query } } }, { branch: { nameEN: { contains: query } } }],
} satisfies Prisma.BranchUserWhereInput;
const [result, total] = await prisma.$transaction([
@ -147,13 +148,17 @@ export class BranchUserController extends Controller {
@Query() pageSize: number = 30,
) {
const where = {
AND: {
user: { subDistrict: { zipCode } },
branchId,
},
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 },
{ user: { firstName: { contains: query } } },
{ user: { firstNameEN: { contains: query } } },
{ user: { lastName: { contains: query } } },
{ user: { lastNameEN: { contains: query } } },
{ user: { email: { contains: query } } },
{ user: { telephoneNo: { contains: query } } },
],
} satisfies Prisma.BranchUserWhereInput;

View file

@ -36,7 +36,7 @@ import {
createPermCheck,
createPermCondition,
} from "../services/permission";
import { connectOrDisconnect, connectOrNot } from "../utils/relation";
import { connectOrDisconnect, connectOrNot, whereAddressQuery } from "../utils/relation";
if (!process.env.MINIO_BUCKET) {
throw Error("Require MinIO bucket.");
@ -84,7 +84,12 @@ type UserCreate = {
address: string;
addressEN: string;
zipCode: string;
soi?: string | null;
soiEN?: string | null;
moo?: string | null;
mooEN?: string | null;
street?: string | null;
streetEN?: string | null;
email: string;
telephoneNo: string;
@ -131,7 +136,12 @@ type UserUpdate = {
address?: string;
addressEN?: string;
zipCode?: string;
soi?: string | null;
soiEN?: string | null;
moo?: string | null;
mooEN?: string | null;
street?: string | null;
streetEN?: string | null;
email?: string;
telephoneNo?: string;
@ -223,7 +233,6 @@ export class UserController extends Controller {
async getUser(
@Request() req: RequestWithUser,
@Query() userType?: UserType,
@Query() zipCode?: string,
@Query() includeBranch: boolean = false,
@Query() query: string = "",
@Query() page: number = 1,
@ -238,10 +247,10 @@ export class UserController extends Controller {
{ lastNameEN: { contains: query } },
{ email: { contains: query } },
{ telephoneNo: { contains: query } },
...whereAddressQuery(query),
],
AND: {
userRole: { not: "system" },
zipCode,
userType,
...filterStatus(status),
branch: isSystem(req.user)

View file

@ -17,10 +17,16 @@ 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";
import minio, { deleteFolder } from "../services/minio";
import { isSystem } from "../utils/keycloak";
import { branchRelationPermInclude, createPermCheck } from "../services/permission";
import {
branchRelationPermInclude,
createPermCheck,
createPermCondition,
} from "../services/permission";
import { filterStatus } from "../services/prisma";
import { connectOrDisconnect, connectOrNot, whereAddressQuery } from "../utils/relation";
import { notFoundError, relationError } from "../utils/error";
if (!process.env.MINIO_BUCKET) {
throw Error("Require MinIO bucket.");
@ -42,6 +48,7 @@ function globalAllow(user: RequestWithUser["user"]) {
return allowList.some((v) => user.roles?.includes(v));
}
const permissionCond = createPermCondition(globalAllow);
const permissionCheck = createPermCheck(globalAllow);
function imageLocation(id: string) {
@ -74,6 +81,12 @@ export type CustomerBranchCreate = (
workplaceEN: string;
address: string;
addressEN: string;
soi?: string | null;
soiEN?: string | null;
moo?: string | null;
mooEN?: string | null;
street?: string | null;
streetEN?: string | null;
email: string;
contactName: string;
@ -116,6 +129,12 @@ export type CustomerBranchUpdate = (
workplaceEN: string;
address: string;
addressEN: string;
soi?: string | null;
soiEN?: string | null;
moo?: string | null;
mooEN?: string | null;
street?: string | null;
streetEN?: string | null;
email?: string;
contactName?: string;
@ -158,14 +177,7 @@ export class CustomerBranchController extends Controller {
{ registerNameEN: { contains: query } },
{ email: { contains: query } },
{ code: { contains: query } },
{ address: { contains: query } },
{ addressEN: { contains: query } },
{ province: { name: { contains: query } } },
{ province: { nameEN: { contains: query } } },
{ district: { name: { contains: query } } },
{ district: { nameEN: { contains: query } } },
{ subDistrict: { name: { contains: query } } },
{ subDistrict: { nameEN: { contains: query } } },
...whereAddressQuery(query),
{
customer: {
OR: [
@ -183,26 +195,7 @@ export class CustomerBranchController extends Controller {
? undefined
: {
registeredBranch: {
OR: [
{
user: { some: { userId: req.user.sub } },
},
{
branch: globalAllow(req.user)
? { some: { user: { some: { userId: req.user.sub } } } }
: undefined,
},
{
headOffice: globalAllow(req.user)
? { branch: { some: { user: { some: { userId: req.user.sub } } } } }
: undefined,
},
{
headOffice: globalAllow(req.user)
? { user: { some: { userId: req.user.sub } } }
: undefined,
},
],
OR: permissionCond(req.user),
},
},
customerId,
@ -248,9 +241,7 @@ export class CustomerBranchController extends Controller {
where: { id: branchId },
});
if (!record) {
throw new HttpError(HttpStatus.NOT_FOUND, "Branch cannot be found.", "branchNotFound");
}
if (!record) throw notFoundError("Branch");
return record;
}
@ -266,14 +257,6 @@ export class CustomerBranchController extends Controller {
@Query() page: number = 1,
@Query() pageSize: number = 30,
) {
const filterStatus = (val?: Status) => {
if (!val) return {};
return val !== Status.CREATED && val !== Status.ACTIVE
? { status: val }
: { OR: [{ status: Status.CREATED }, { status: Status.ACTIVE }] };
};
const where = {
OR: [
{ firstName: { contains: query } },
@ -281,6 +264,7 @@ export class CustomerBranchController extends Controller {
{ lastName: { contains: query } },
{ lastNameEN: { contains: query } },
{ passportNumber: { contains: query } },
...whereAddressQuery(query),
],
AND: {
...filterStatus(status),
@ -344,32 +328,14 @@ export class CustomerBranchController extends Controller {
},
}),
]);
if (body.provinceId && !province)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"Province cannot be found.",
"relationProvinceNotFound",
);
if (body.districtId && !district)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"District cannot be found.",
"relationDistrictNotFound",
);
if (body.subDistrictId && !subDistrict)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"Sub-district cannot be found.",
"relationSubDistrictNotFound",
);
if (!customer)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"Customer cannot be found.",
"relationCustomerNotFound",
);
if (body.provinceId && !province) throw relationError("Province");
if (body.districtId && !district) throw relationError("District");
if (body.subDistrictId && !subDistrict) throw relationError("SubDistrict");
if (!customer) throw relationError("Customer");
await permissionCheck(req.user, customer.registeredBranch);
let company = await permissionCheck(req.user, customer.registeredBranch).then(
(v) => (v.headOffice || v).code,
);
const { provinceId, districtId, subDistrictId, customerId, ...rest } = body;
@ -381,11 +347,11 @@ export class CustomerBranchController extends Controller {
let runningKey = "";
if (headofficeCode) {
runningKey = `CUSTOMER_BRANCH_${headofficeCode}`;
runningKey = `CUSTOMER_BRANCH_${company}_${headofficeCode}`;
} else if ("citizenId" in body) {
runningKey = `CUSTOMER_BRANCH_${body.citizenId}`;
runningKey = `CUSTOMER_BRANCH_${company}_${body.citizenId}`;
} else {
runningKey = `CUSTOMER_BRANCH_${body.legalPersonNo}`;
runningKey = `CUSTOMER_BRANCH_${company}_${body.legalPersonNo}`;
}
const last = await tx.runningNo.upsert({
@ -478,30 +444,10 @@ export class CustomerBranchController extends Controller {
},
}),
]);
if (body.provinceId && !province)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"Province cannot be found.",
"relationProvinceNotFound",
);
if (body.districtId && !district)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"District cannot be found.",
"relationDistrictNotFound",
);
if (body.subDistrictId && !subDistrict)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"Sub-district cannot be found.",
"relationSubDistrictNotFound",
);
if (!customer)
throw new HttpError(
HttpStatus.BAD_REQUEST,
"Customer cannot be found.",
"relationCustomerNotFound",
);
if (body.provinceId && !province) throw relationError("Province");
if (body.districtId && !district) throw relationError("District");
if (body.subDistrictId && !subDistrict) throw relationError("SubDistrict");
if (!customer) throw relationError("Customer");
await permissionCheck(req.user, customer.registeredBranch);
}
@ -519,19 +465,10 @@ export class CustomerBranchController extends Controller {
data: {
...rest,
statusOrder: +(rest.status === "INACTIVE"),
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,
},
customer: connectOrNot(customerId),
province: connectOrDisconnect(provinceId),
district: connectOrDisconnect(districtId),
subDistrict: connectOrDisconnect(subDistrictId),
updatedBy: { connect: { id: req.user.sub } },
},
});
@ -553,13 +490,7 @@ export class CustomerBranchController extends Controller {
},
});
if (!record) {
throw new HttpError(
HttpStatus.NOT_FOUND,
"Customer branch cannot be found.",
"customerBranchNotFound",
);
}
if (!record) throw notFoundError("Customer Branch");
await permissionCheck(req.user, record.customer.registeredBranch);
@ -577,22 +508,7 @@ export class CustomerBranchController extends Controller {
where: { id: branchId },
})
.then((v) => {
new Promise<string[]>((resolve, reject) => {
const item: string[] = [];
const stream = minio.listObjectsV2(
MINIO_BUCKET,
`${attachmentLocation(record.customerId, branchId)}/`,
);
stream.on("data", (v) => v && v.name && item.push(v.name));
stream.on("end", () => resolve(item));
stream.on("error", () => reject(new Error("MinIO error.")));
}).then((list) => {
list.map(async (v) => {
await minio.removeObject(MINIO_BUCKET, v, { forceDelete: true });
});
});
deleteFolder(MINIO_BUCKET, `${attachmentLocation(record.customerId, branchId)}/`);
return v;
});
}

View file

@ -24,7 +24,7 @@ import {
createPermCheck,
createPermCondition,
} from "../services/permission";
import { connectOrDisconnect, connectOrNot } from "../utils/relation";
import { connectOrDisconnect, connectOrNot, whereAddressQuery } from "../utils/relation";
import { notFoundError, relationError } from "../utils/error";
import { deleteFile, fileLocation, getFile, listFile, setFile } from "../utils/minio";
@ -70,6 +70,12 @@ type EmployeeCreate = {
addressEN: string;
address: string;
soi?: string | null;
soiEN?: string | null;
moo?: string | null;
mooEN?: string | null;
street?: string | null;
streetEN?: string | null;
passportType: string;
passportNumber: string;
@ -156,6 +162,12 @@ type EmployeeUpdate = {
addressEN?: string;
address?: string;
soi?: string | null;
soiEN?: string | null;
moo?: string | null;
mooEN?: string | null;
street?: string | null;
streetEN?: string | null;
passportType?: string;
passportNumber?: string;
@ -253,6 +265,7 @@ export class EmployeeController extends Controller {
{ firstNameEN: { contains: query } },
{ lastName: { contains: query } },
{ lastNameEN: { contains: query } },
...whereAddressQuery(query),
],
AND: {
...filterStatus(status),
@ -294,6 +307,7 @@ export class EmployeeController extends Controller {
{ lastName: { contains: query } },
{ lastNameEN: { contains: query } },
{ passportNumber: { contains: query } },
...whereAddressQuery(query),
],
AND: {
...filterStatus(status),