feat: add property management endpoint

This commit is contained in:
Methapon2001 2025-03-10 15:12:30 +07:00
parent e6903af8ce
commit 140cb59ebb
3 changed files with 206 additions and 0 deletions

View file

@ -318,6 +318,7 @@ model Branch {
workflowTemplate WorkflowTemplate[]
taskOrder TaskOrder[]
notification Notification[]
property Property[]
}
model BranchBank {
@ -1004,6 +1005,23 @@ model Institution {
taskOrder TaskOrder[]
}
model Property {
id String @id @default(cuid())
registeredBranch Branch @relation(fields: [registeredBranchId], references: [id])
registeredBranchId String
name String
nameEN String
type Json
status Status @default(CREATED)
statusOrder Int @default(0)
createdAt DateTime @default(now())
}
model WorkflowTemplate {
id String @id @default(cuid())
name String

View file

@ -0,0 +1,187 @@
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 { Prisma, Status } from "@prisma/client";
import {
branchRelationPermInclude,
createPermCheck,
createPermCondition,
} from "../services/permission";
import HttpError from "../interfaces/http-error";
import HttpStatus from "../interfaces/http-status";
import { notFoundError } from "../utils/error";
import { filterStatus } from "../services/prisma";
import { queryOrNot } from "../utils/relation";
type PropertyPayload = {
name: string;
nameEN: string;
type: Record<string, any>;
registeredBranchId?: string;
status?: Status;
};
const permissionCondCompany = createPermCondition((_) => true);
const permissionCheckCompany = createPermCheck((_) => true);
@Route("api/v1/properties")
@Tags("Properties")
@Security("keycloak")
export class PropertiesController extends Controller {
@Get()
async getProperties(
@Request() req: RequestWithUser,
@Query() page: number = 1,
@Query() pageSize: number = 30,
@Query() status?: Status,
@Query() query = "",
@Query() activeOnly?: boolean,
) {
const where = {
OR: queryOrNot(query, [{ name: { contains: query } }, { nameEN: { contains: query } }]),
AND: {
...filterStatus(activeOnly ? Status.ACTIVE : status),
registeredBranch: {
OR: permissionCondCompany(req.user, { activeOnly: true }),
},
},
} satisfies Prisma.PropertyWhereInput;
const [result, total] = await prisma.$transaction([
prisma.property.findMany({
where,
orderBy: [{ statusOrder: "asc" }, { createdAt: "asc" }],
take: pageSize,
skip: (page - 1) * pageSize,
}),
prisma.property.count({ where }),
]);
return {
result,
page,
pageSize,
total,
};
}
@Get("{propertyId}")
async getPropertyById(@Request() _req: RequestWithUser, @Path() propertyId: string) {
const record = await prisma.property.findFirst({
where: { id: propertyId },
orderBy: { createdAt: "asc" },
});
if (!record) throw notFoundError("Property");
return record;
}
@Post()
async createProperty(@Request() req: RequestWithUser, @Body() body: PropertyPayload) {
const where = {
OR: [{ name: { contains: body.name } }, { nameEN: { contains: body.nameEN } }],
AND: {
registeredBranch: {
OR: permissionCondCompany(req.user),
},
},
} satisfies Prisma.PropertyWhereInput;
const exists = await prisma.property.findFirst({ where });
if (exists) {
throw new HttpError(
HttpStatus.BAD_REQUEST,
"Property with this name already exists",
"samePropertyNameExists",
);
}
const userAffiliatedBranch = await prisma.branch.findFirst({
include: branchRelationPermInclude(req.user),
where: body.registeredBranchId
? { id: body.registeredBranchId }
: {
user: { some: { userId: req.user.sub } },
},
});
if (!userAffiliatedBranch) {
throw new HttpError(
HttpStatus.BAD_REQUEST,
"You must be affilated with at least one branch or specify branch to be registered (System permission required).",
"reqMinAffilatedBranch",
);
}
await permissionCheckCompany(req.user, userAffiliatedBranch);
return await prisma.property.create({
data: {
...body,
statusOrder: +(body.status === "INACTIVE"),
registeredBranchId: userAffiliatedBranch.id,
},
});
}
@Put("{propertyId}")
async updatePropertyById(
@Request() req: RequestWithUser,
@Path() propertyId: string,
@Body() body: PropertyPayload,
) {
const record = await prisma.property.findUnique({
where: { id: propertyId },
include: {
registeredBranch: {
include: branchRelationPermInclude(req.user),
},
},
});
if (!record) throw notFoundError("Property");
await permissionCheckCompany(req.user, record.registeredBranch);
return await prisma.property.update({
where: { id: propertyId },
data: {
...body,
statusOrder: +(body.status === "INACTIVE"),
},
});
}
@Delete("{propertyId}")
async deletePropertyById(@Request() req: RequestWithUser, @Path() propertyId: string) {
const record = await prisma.property.findUnique({
where: { id: propertyId },
include: {
registeredBranch: {
include: branchRelationPermInclude(req.user),
},
},
});
if (!record) throw notFoundError("Property");
await permissionCheckCompany(req.user, record.registeredBranch);
return await prisma.property.delete({
where: { id: propertyId },
});
}
}

View file

@ -41,6 +41,7 @@
{ "name": "Employee Other Info" },
{ "name": "Institution" },
{ "name": "Workflow" },
{ "name": "Property" },
{ "name": "Product Group" },
{ "name": "Product" },
{ "name": "Work" },