From 9d17b442e2c9948ef7a1499c374249410ea15dff Mon Sep 17 00:00:00 2001 From: bagasbanuna Date: Wed, 10 Dec 2025 17:28:59 +0800 Subject: [PATCH 1/3] Fix api APP Informastion untuk QC ( Ayu ) Fix: - modified: src/app/api/mobile/admin/master/business-field/[id]/route.ts - modified: src/app/api/mobile/admin/master/business-field/route.ts ### No Issue --- .../admin/master/business-field/[id]/route.ts | 83 ++++++-- .../admin/master/business-field/route.ts | 194 ++++++++++++++++-- 2 files changed, 244 insertions(+), 33 deletions(-) diff --git a/src/app/api/mobile/admin/master/business-field/[id]/route.ts b/src/app/api/mobile/admin/master/business-field/[id]/route.ts index 9cc26fdf..88eeb137 100644 --- a/src/app/api/mobile/admin/master/business-field/[id]/route.ts +++ b/src/app/api/mobile/admin/master/business-field/[id]/route.ts @@ -4,19 +4,55 @@ import { prisma } from "@/lib"; export { GET, PUT }; async function GET(request: Request, { params }: { params: { id: string } }) { + let fixData; try { const { id } = params; - const data = await prisma.masterBidangBisnis.findUnique({ - where: { - id: id, - }, - }); + const { searchParams } = new URL(request.url); + const category = searchParams.get("category"); + const subBidangId = searchParams.get("subBidangId"); + + if (category === "all") { + const bidang = await prisma.masterBidangBisnis.findUnique({ + where: { + id: id, + }, + }); + const subBidang = await prisma.masterSubBidangBisnis.findMany({ + orderBy: { + updatedAt: "desc", + }, + where: { + masterBidangBisnisId: id, + }, + }); + + fixData = { + bidang, + subBidang, + }; + } else if (category === "bidang") { + const bidang = await prisma.masterBidangBisnis.findUnique({ + where: { + id: id, + }, + }); + + fixData = bidang; + } else if (category === "sub-bidang") { + const subBidang = await prisma.masterSubBidangBisnis.findUnique({ + where: { + id: subBidangId as any, + }, + }); + + fixData = subBidang; + } return NextResponse.json({ status: 200, success: true, message: "Berhasil mendapatkan data", - data: data, + data: fixData, }); } catch (error) { console.error("Error Get Master Bank >>", error); @@ -32,17 +68,34 @@ async function GET(request: Request, { params }: { params: { id: string } }) { async function PUT(request: Request, { params }: { params: { id: string } }) { const { id } = params; const { data } = await request.json(); + const { searchParams } = new URL(request.url); + const category = searchParams.get("category"); + + console.log("category", category); + console.log("data", data); try { - const updateData = await prisma.masterBidangBisnis.update({ - where: { - id: id, - }, - data: { - name: data.name, - active: data.active, - }, - }); + if (category === "bidang") { + const updateData = await prisma.masterBidangBisnis.update({ + where: { + id: id, + }, + data: { + name: data.name, + active: data.active, + }, + }); + } else if (category === "sub-bidang") { + const updateData = await prisma.masterSubBidangBisnis.update({ + where: { + id: id, + }, + data: { + name: data.name, + isActive: data.isActive, + }, + }); + } return NextResponse.json({ status: 200, diff --git a/src/app/api/mobile/admin/master/business-field/route.ts b/src/app/api/mobile/admin/master/business-field/route.ts index 52a6dfa1..70d50498 100644 --- a/src/app/api/mobile/admin/master/business-field/route.ts +++ b/src/app/api/mobile/admin/master/business-field/route.ts @@ -1,5 +1,7 @@ import { NextResponse } from "next/server"; import { prisma } from "@/lib"; +import _ from "lodash"; +import { Prisma } from "@prisma/client"; export { GET, POST }; @@ -31,35 +33,191 @@ async function GET(request: Request) { } } +type BidangInput = { + name: string; +}; + +type SubBidangInput = { + name: string; +}; + +type RequestBody = { + data: { + bidang: BidangInput; + subBidang: SubBidangInput[]; + }; +}; + +/* --------------------------- + POST handler + - body: { bidang: { name }, subBidang: [{ name }, ...] } + - buat masterBidangBisnis (id incremental dari count + 1) + - generate id untuk tiap subBidang, cek unik, dan createMany via transaction + --------------------------- */ async function POST(request: Request) { - const { data } = await request.json(); try { - const count = await prisma.masterBidangBisnis.count(); - const createNewId = count + 1; + const { data } = (await request.json()) as RequestBody; - const slugName = data.name.toLowerCase().replace(/\s+/g, "_"); + console.log("body >>", data.bidang.name); - const create = await prisma.masterBidangBisnis.create({ - data: { - id: createNewId.toString(), - name: data.name, - slug: slugName, - }, + if (!data.bidang.name || !Array.isArray(data.subBidang)) { + return NextResponse.json( + { + status: 400, + success: false, + message: + "Invalid payload. Expect { bidang: { name }, subBidang: [] }", + }, + { status: 400 } + ); + } + + // run in transaction to avoid race conditions + const result = await prisma.$transaction(async (tx) => { + // ambil last id numerik dengan cast (Postgres) + const rows = await tx.$queryRaw<{ id: string }[]>` + SELECT id FROM "MasterBidangBisnis" ORDER BY (id::int) DESC LIMIT 1; + `; + const lastId = rows[0]?.id ?? null; + const bidangId = lastId ? String(Number(lastId) + 1) : "1"; + console.log("bidangId >>", bidangId); + + const slugName = data.bidang.name.toLowerCase().replace(/\s+/g, "_"); + + const createdBidang = await tx.masterBidangBisnis.create({ + data: { + id: bidangId, + name: data.bidang.name, + slug: slugName, + }, + }); + + // 2) hitung existing sub bidang untuk bidang ini + const existingSubCount = await tx.masterSubBidangBisnis.count({ + where: { masterBidangBisnisId: createdBidang.id }, + }); + + console.log("existingSubCount >>", existingSubCount); + + // 3) generate unique ids satu-per-satu (cek ke DB via tx) + const subBidangToCreate: { + id: string; + name: string; + masterBidangBisnisId: string; + }[] = []; + + for (let i = 0; i < data.subBidang.length; i++) { + const seqNumber = existingSubCount + i + 1; // 1-based + const uniqueId = await generateUniqueSubBidangId( + data.bidang.name, + seqNumber, + tx + ); + + // push object to array + subBidangToCreate.push({ + id: uniqueId, + name: data.subBidang[i].name, + masterBidangBisnisId: createdBidang.id, + }); + } + + // 4) createMany (batched) -- note: createMany doesn't return created rows + if (subBidangToCreate.length > 0) { + await tx.masterSubBidangBisnis.createMany({ + data: subBidangToCreate, + skipDuplicates: false, // kita sudah memastikan unik, so false + }); + } + + return { createdBidang, subBidang: subBidangToCreate }; }); return NextResponse.json({ status: 200, success: true, - message: "Berhasil menambahkan data", - data: create, + message: "Berhasil menambahkan bidang dan sub bidang", + data: result, }); } catch (error) { console.error("Error Post Master Business Field >>", error); - return NextResponse.json({ - status: 500, - success: false, - message: "API Error Post Data", - reason: (error as Error).message, - }); + const msg = error instanceof Error ? error.message : String(error); + return NextResponse.json( + { + status: 500, + success: false, + message: "API Error Post Data", + reason: msg, + }, + { status: 500 } + ); } } + +/* --------------------------- + Helper: generate base code + - mengabaikan stop words: 'dan', 'atau', '&' + - ambil dua kata pertama yang tersisa + - ambil 3 huruf pertama tiap kata (jika ada) + --------------------------- */ +function generateBaseCode(name: string) { + const stopWords = new Set(["dan", "atau", "&"]); + // keep only letters and spaces, normalize spaces + const cleaned = name + .normalize("NFD") + .replace(/[\u0300-\u036f]/g, "") // remove diacritics + .replace(/[^a-zA-Z\s&]/g, " ") + .replace(/\s+/g, " ") + .trim() + .toLowerCase(); + + const words = cleaned + .split(" ") + .filter((w) => w.length > 0 && !stopWords.has(w)); + + const primary = (words[0] ?? "xxx").substring(0, 3).toUpperCase(); + const secondary = words[1] ? words[1].substring(0, 3).toUpperCase() : ""; + + return { primary, secondary }; +} + +function padNumber(n: number) { + return String(n).padStart(2, "0"); +} + +/* --------------------------- + generateUniqueSubBidangId + - cek urutan strategi: + 1) PRIMARY- + 2) PRIMARY-SECONDARY- (jika secondary ada) + 3) PRIMARYSECONDARY- (jika secondary ada) + 4) fallback: PRIMARY + last4Timestamp - + - menggunakan tx (Prisma.TransactionClient) untuk cek di DB + --------------------------- */ +async function generateUniqueSubBidangId( + bidangName: string, + number: number, + tx: Prisma.TransactionClient +): Promise { + const { primary, secondary } = generateBaseCode(bidangName); + const num = padNumber(number); + + const candidates: string[] = []; + candidates.push(`${primary}-${num}`); + if (secondary) candidates.push(`${primary}-${secondary}-${num}`); + if (secondary) candidates.push(`${primary}${secondary}-${num}`); + // final fallback + candidates.push(`${primary}${String(Date.now()).slice(-4)}-${num}`); + + for (const id of candidates) { + // findUnique requires unique field; assuming `id` is the PK/unique + const found = await tx.masterSubBidangBisnis.findUnique({ + where: { id }, + select: { id: true }, + }); + if (!found) return id; + } + + // theoretically unreachable, but return a final deterministic fallback + return `${primary}-${String(Math.floor(Math.random() * 9000) + 1000)}-${num}`; +} From 7ab25655f286304a7dc1c154476d24a97dc1a727 Mon Sep 17 00:00:00 2001 From: bagasbanuna Date: Wed, 10 Dec 2025 17:30:39 +0800 Subject: [PATCH 2/3] chore(release): 1.5.26 --- CHANGELOG.md | 2 ++ package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ba625cd5..990816a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines. +## [1.5.26](https://wibugit.wibudev.com/wibu/hipmi/compare/v1.5.25...v1.5.26) (2025-12-10) + ## [1.5.25](https://wibugit.wibudev.com/wibu/hipmi/compare/v1.5.24...v1.5.25) (2025-12-09) ## [1.5.24](https://wibugit.wibudev.com/wibu/hipmi/compare/v1.5.22...v1.5.24) (2025-12-08) diff --git a/package.json b/package.json index fc6d2eeb..a4fef616 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hipmi", - "version": "1.5.25", + "version": "1.5.26", "private": true, "prisma": { "seed": "bun prisma/seed.ts" From f06482a1594addb678003f6ec0f713fddd752b0f Mon Sep 17 00:00:00 2001 From: bagasbanuna Date: Wed, 10 Dec 2025 17:31:23 +0800 Subject: [PATCH 3/3] fix version --- src/app/api/mobile/admin/master/business-field/route.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/app/api/mobile/admin/master/business-field/route.ts b/src/app/api/mobile/admin/master/business-field/route.ts index 70d50498..f428f879 100644 --- a/src/app/api/mobile/admin/master/business-field/route.ts +++ b/src/app/api/mobile/admin/master/business-field/route.ts @@ -58,8 +58,6 @@ async function POST(request: Request) { try { const { data } = (await request.json()) as RequestBody; - console.log("body >>", data.bidang.name); - if (!data.bidang.name || !Array.isArray(data.subBidang)) { return NextResponse.json( { @@ -80,7 +78,6 @@ async function POST(request: Request) { `; const lastId = rows[0]?.id ?? null; const bidangId = lastId ? String(Number(lastId) + 1) : "1"; - console.log("bidangId >>", bidangId); const slugName = data.bidang.name.toLowerCase().replace(/\s+/g, "_"); @@ -97,8 +94,6 @@ async function POST(request: Request) { where: { masterBidangBisnisId: createdBidang.id }, }); - console.log("existingSubCount >>", existingSubCount); - // 3) generate unique ids satu-per-satu (cek ke DB via tx) const subBidangToCreate: { id: string;