summaryrefslogtreecommitdiff
path: root/lib/material/services.ts
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-09-01 10:22:55 +0000
committerjoonhoekim <26rote@gmail.com>2025-09-01 10:22:55 +0000
commitf72142f6cc46c7be5bf90803d365c2ecd144c53d (patch)
tree6cfefba8edc8573bc99bee14ae7ed95914692430 /lib/material/services.ts
parent20ba04d8588a7dfa6f65b1c080d6373631449f59 (diff)
(김준회) MDG 자재마스터 정보 조회 기능 및 메뉴 추가, 회원가입시 공급품목 선택 기능 추가
Diffstat (limited to 'lib/material/services.ts')
-rw-r--r--lib/material/services.ts224
1 files changed, 224 insertions, 0 deletions
diff --git a/lib/material/services.ts b/lib/material/services.ts
new file mode 100644
index 00000000..e050d8f8
--- /dev/null
+++ b/lib/material/services.ts
@@ -0,0 +1,224 @@
+'use server'
+
+import { and, asc, desc, ilike, or, sql, eq } from 'drizzle-orm';
+import db from '@/db/db';
+import { filterColumns } from "@/lib/filter-columns";
+import {
+ MATERIAL_MASTER_PART_MATL,
+ MATERIAL_MASTER_PART_MATL_CHARASGN,
+ MATERIAL_MASTER_PART_MATL_CLASSASGN,
+ MATERIAL_MASTER_PART_MATL_DESC,
+ MATERIAL_MASTER_PART_MATL_UNIT
+} from "@/db/schema/MDG/mdg";
+
+// 자재마스터 테이블의 컬럼 타입 정의
+type MaterialColumn = keyof typeof MATERIAL_MASTER_PART_MATL.$inferSelect;
+
+export interface GetMaterialsInput {
+ page: number;
+ perPage: number;
+ search?: string;
+ sort: Array<{
+ id: MaterialColumn;
+ desc: boolean;
+ }>;
+ filters?: any[];
+ joinOperator: 'and' | 'or';
+}
+
+/**
+ * 자재마스터 목록을 조회합니다.
+ * 필수 컬럼: MATKL(자재그룹), MATNR(자재코드), ZZNAME(자재명), ZZPJT(프로젝트), createdAt, updatedAt
+ */
+export async function getMaterials(input: GetMaterialsInput) {
+ const safePerPage = Math.min(input.perPage, 100);
+
+ try {
+ const offset = (input.page - 1) * safePerPage;
+
+ // 고급 필터링
+ const advancedWhere = filterColumns({
+ table: MATERIAL_MASTER_PART_MATL,
+ filters: (input.filters || []) as any,
+ joinOperator: input.joinOperator,
+ });
+
+ // 전역 검색 - 주요 컬럼들에 대해 검색
+ let globalWhere;
+ if (input.search) {
+ const s = `%${input.search}%`;
+ globalWhere = or(
+ ilike(MATERIAL_MASTER_PART_MATL.MATKL, s), // 자재그룹코드
+ ilike(MATERIAL_MASTER_PART_MATL.MATNR, s), // 자재코드
+ ilike(MATERIAL_MASTER_PART_MATL.ZZNAME, s), // 자재명
+ ilike(MATERIAL_MASTER_PART_MATL.ZZPJT, s), // 프로젝트
+ );
+ }
+
+ const finalWhere = and(advancedWhere, globalWhere);
+
+ // 정렬 처리 - 타입 안전하게 처리
+ const orderBy = input.sort.length > 0
+ ? input.sort.map((item) => {
+ const column = MATERIAL_MASTER_PART_MATL[item.id];
+ return item.desc ? desc(column) : asc(column);
+ })
+ : [desc(MATERIAL_MASTER_PART_MATL.createdAt)];
+
+ // 데이터 조회 - 필요한 컬럼만 선택
+ const { data, total } = await db.transaction(async (tx) => {
+ const data = await tx
+ .select({
+ id: MATERIAL_MASTER_PART_MATL.id,
+ MATKL: MATERIAL_MASTER_PART_MATL.MATKL, // 자재그룹(=자재그룹코드)
+ MATNR: MATERIAL_MASTER_PART_MATL.MATNR, // 자재코드(=자재번호)
+ ZZNAME: MATERIAL_MASTER_PART_MATL.ZZNAME, // 자재명(=자재그룹명)
+ ZZPJT: MATERIAL_MASTER_PART_MATL.ZZPJT, // 프로젝트
+ createdAt: MATERIAL_MASTER_PART_MATL.createdAt,
+ updatedAt: MATERIAL_MASTER_PART_MATL.updatedAt,
+ })
+ .from(MATERIAL_MASTER_PART_MATL)
+ .where(finalWhere)
+ .orderBy(...orderBy)
+ .offset(offset)
+ .limit(safePerPage);
+
+ const totalResult = await tx
+ .select({
+ count: sql<number>`count(*)`
+ })
+ .from(MATERIAL_MASTER_PART_MATL)
+ .where(finalWhere);
+
+ const total = Number(totalResult[0]?.count) || 0;
+ return { data, total };
+ });
+
+ const pageCount = Math.ceil(total / safePerPage);
+ return { data, pageCount };
+ } catch (err) {
+ console.error('Error in getMaterials:', err);
+ return { data: [], pageCount: 0 };
+ }
+}
+
+/**
+ * 무한 스크롤을 위한 자재마스터 조회 (페이지네이션 없음)
+ */
+export interface GetMaterialsInfiniteInput extends Omit<GetMaterialsInput, 'page' | 'perPage'> {
+ limit?: number; // 무한 스크롤용 추가 옵션
+}
+
+export async function getMaterialsInfinite(input: GetMaterialsInfiniteInput) {
+ try {
+ // 고급 필터링
+ const advancedWhere = filterColumns({
+ table: MATERIAL_MASTER_PART_MATL,
+ filters: (input.filters || []) as any,
+ joinOperator: input.joinOperator || "and",
+ });
+
+ // 전역 검색
+ let globalWhere;
+ if (input.search) {
+ const s = `%${input.search}%`;
+ globalWhere = or(
+ ilike(MATERIAL_MASTER_PART_MATL.MATKL, s),
+ ilike(MATERIAL_MASTER_PART_MATL.MATNR, s),
+ ilike(MATERIAL_MASTER_PART_MATL.ZZNAME, s),
+ ilike(MATERIAL_MASTER_PART_MATL.ZZPJT, s),
+ );
+ }
+
+ const finalWhere = and(advancedWhere, globalWhere);
+
+ // 정렬 처리 - 타입 안전하게 처리
+ const orderBy = input.sort.length > 0
+ ? input.sort.map((item) => {
+ const column = MATERIAL_MASTER_PART_MATL[item.id];
+ return item.desc ? desc(column) : asc(column);
+ })
+ : [desc(MATERIAL_MASTER_PART_MATL.createdAt)];
+
+ // 전체 데이터 조회 (클라이언트에서 가상화 처리)
+ const data = await db
+ .select({
+ id: MATERIAL_MASTER_PART_MATL.id,
+ MATKL: MATERIAL_MASTER_PART_MATL.MATKL,
+ MATNR: MATERIAL_MASTER_PART_MATL.MATNR,
+ ZZNAME: MATERIAL_MASTER_PART_MATL.ZZNAME,
+ ZZPJT: MATERIAL_MASTER_PART_MATL.ZZPJT,
+ createdAt: MATERIAL_MASTER_PART_MATL.createdAt,
+ updatedAt: MATERIAL_MASTER_PART_MATL.updatedAt,
+ })
+ .from(MATERIAL_MASTER_PART_MATL)
+ .where(finalWhere)
+ .orderBy(...orderBy);
+
+ return { data };
+ } catch (err) {
+ console.error('Error in getMaterialsInfinite:', err);
+ return { data: [] };
+ }
+}
+
+/**
+ * 자재마스터 상세 정보를 조회합니다 (모든 관련 테이블 포함)
+ */
+export async function getMaterialDetail(matnr: string) {
+ try {
+ // 메인 자재 정보 조회
+ const material = await db
+ .select()
+ .from(MATERIAL_MASTER_PART_MATL)
+ .where(eq(MATERIAL_MASTER_PART_MATL.MATNR, matnr))
+ .limit(1);
+
+ if (material.length === 0) {
+ return null;
+ }
+
+ // 관련 테이블들 조회
+ const [
+ characteristics,
+ classifications,
+ descriptions,
+ units
+ ] = await Promise.all([
+ // CHARASGN - 특성 할당
+ db
+ .select()
+ .from(MATERIAL_MASTER_PART_MATL_CHARASGN)
+ .where(eq(MATERIAL_MASTER_PART_MATL_CHARASGN.MATNR, matnr)),
+
+ // CLASSASGN - 클래스 할당
+ db
+ .select()
+ .from(MATERIAL_MASTER_PART_MATL_CLASSASGN)
+ .where(eq(MATERIAL_MASTER_PART_MATL_CLASSASGN.MATNR, matnr)),
+
+ // DESC - 설명
+ db
+ .select()
+ .from(MATERIAL_MASTER_PART_MATL_DESC)
+ .where(eq(MATERIAL_MASTER_PART_MATL_DESC.MATNR, matnr)),
+
+ // UNIT - 단위
+ db
+ .select()
+ .from(MATERIAL_MASTER_PART_MATL_UNIT)
+ .where(eq(MATERIAL_MASTER_PART_MATL_UNIT.MATNR, matnr))
+ ]);
+
+ return {
+ material: material[0],
+ characteristics,
+ classifications,
+ descriptions,
+ units
+ };
+ } catch (err) {
+ console.error('Error in getMaterialDetail:', err);
+ return null;
+ }
+} \ No newline at end of file