upd:
dashboard admin Deskripsi: - list pelayanan surat - detail pelayanan surat - terima pelayanan surat - menolak pelayanan surat - menyelesaikan pelayanan surat - tambah surat > databse No Issues
This commit is contained in:
24
src/server/lib/create-surat.ts
Normal file
24
src/server/lib/create-surat.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { prisma } from "./prisma"
|
||||
|
||||
export async function createSurat({ idPengajuan, idCategory, idWarga, noSurat }: { idPengajuan: string, idCategory: string, idWarga: string, noSurat: string }) {
|
||||
try {
|
||||
const surat = await prisma.suratPelayanan.create({
|
||||
data: {
|
||||
idPengajuanLayanan: idPengajuan,
|
||||
idCategory,
|
||||
idWarga,
|
||||
noSurat,
|
||||
}
|
||||
})
|
||||
|
||||
if (!surat.id) {
|
||||
return { success: false, message: 'gagal membuat surat' }
|
||||
}
|
||||
|
||||
return { success: true, message: 'surat sudah dibuat' }
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
return { success: false, message: 'gagal membuat surat' }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
import Elysia, { t } from "elysia"
|
||||
import type { StatusPengaduan } from "generated/prisma"
|
||||
import { createSurat } from "../lib/create-surat"
|
||||
import { getLastUpdated } from "../lib/get-last-updated"
|
||||
import { generateNoPengajuanSurat } from "../lib/no-pengajuan-surat"
|
||||
import { normalizePhoneNumber } from "../lib/normalizePhone"
|
||||
import { prisma } from "../lib/prisma"
|
||||
@@ -102,28 +104,179 @@ const PelayananRoute = new Elysia({
|
||||
|
||||
|
||||
// --- PELAYANAN SURAT ---
|
||||
.get("/", async () => {
|
||||
.get("/", async ({ query }) => {
|
||||
const { phone } = query
|
||||
const data = await prisma.pelayananAjuan.findMany({
|
||||
orderBy: {
|
||||
createdAt: "asc"
|
||||
},
|
||||
where: {
|
||||
isActive: true
|
||||
isActive: true,
|
||||
Warga: {
|
||||
phone
|
||||
}
|
||||
}
|
||||
})
|
||||
return data
|
||||
}, {
|
||||
query: t.Object({
|
||||
phone: t.String({ minLength: 1, error: "phone harus diisi" }),
|
||||
}),
|
||||
detail: {
|
||||
summary: "List Ajuan Pelayanan Surat",
|
||||
summary: "List Ajuan Pelayanan Surat by Phone",
|
||||
description: `tool untuk mendapatkan list ajuan pelayanan surat`,
|
||||
tags: ["mcp"]
|
||||
}
|
||||
})
|
||||
.get("/detail", async ({ query }) => {
|
||||
const { id } = query
|
||||
const data = await prisma.pelayananAjuan.findUnique({
|
||||
|
||||
const data = await prisma.pelayananAjuan.findFirst({
|
||||
where: {
|
||||
id,
|
||||
OR: [
|
||||
{
|
||||
noPengajuan: id
|
||||
},
|
||||
{
|
||||
id: id
|
||||
}
|
||||
]
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
noPengajuan: true,
|
||||
status: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
CategoryPelayanan: {
|
||||
select: {
|
||||
name: true,
|
||||
dataText: true,
|
||||
syaratDokumen: true,
|
||||
}
|
||||
},
|
||||
Warga: {
|
||||
select: {
|
||||
name: true,
|
||||
phone: true,
|
||||
_count: {
|
||||
select: {
|
||||
Pengaduan: true,
|
||||
PelayananAjuan: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
})
|
||||
return data
|
||||
|
||||
const dataSyarat = await prisma.syaratDokumenPelayanan.findMany({
|
||||
where: {
|
||||
idPengajuanLayanan: data?.id,
|
||||
isActive: true
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
jenis: true,
|
||||
value: true,
|
||||
}
|
||||
})
|
||||
|
||||
const dataText = await prisma.dataTextPelayanan.findMany({
|
||||
where: {
|
||||
idPengajuanLayanan: data?.id,
|
||||
isActive: true
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
value: true,
|
||||
jenis: true,
|
||||
}
|
||||
})
|
||||
const syaratDokumen = (data?.CategoryPelayanan?.syaratDokumen ?? []) as {
|
||||
name: string;
|
||||
desc: string;
|
||||
}[];
|
||||
|
||||
const dataSyaratFix = dataSyarat.map((item) => {
|
||||
const desc = syaratDokumen.find((v) => v.name == item.jenis)?.desc
|
||||
return {
|
||||
id: item.id,
|
||||
jenis: desc,
|
||||
value: item.value,
|
||||
}
|
||||
})
|
||||
|
||||
const dataTextFix = dataText.map((item) => {
|
||||
const desc = data?.CategoryPelayanan?.dataText.find((v) => v == item.jenis)
|
||||
return {
|
||||
id: item.id,
|
||||
jenis: item.jenis,
|
||||
value: item.value,
|
||||
}
|
||||
})
|
||||
|
||||
const dataHistory = await prisma.historyPelayanan.findMany({
|
||||
where: {
|
||||
idPengajuanLayanan: data?.id,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
deskripsi: true,
|
||||
status: true,
|
||||
createdAt: true,
|
||||
idUser: true,
|
||||
User: {
|
||||
select: {
|
||||
name: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const dataHistoryFix = dataHistory.map((item) => {
|
||||
return {
|
||||
id: item.id,
|
||||
deskripsi: item.deskripsi,
|
||||
status: item.status,
|
||||
createdAt: item.createdAt.toLocaleString("id-ID", {
|
||||
day: "2-digit",
|
||||
month: "short",
|
||||
year: "numeric",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12: false
|
||||
}),
|
||||
idUser: item.idUser,
|
||||
nameUser: item.User?.name,
|
||||
}
|
||||
})
|
||||
|
||||
const warga = {
|
||||
name: data?.Warga?.name,
|
||||
phone: data?.Warga?.phone,
|
||||
pengaduan: data?.Warga?._count.Pengaduan,
|
||||
pelayanan: data?.Warga?._count.PelayananAjuan,
|
||||
}
|
||||
|
||||
const dataPengajuan = {
|
||||
id: data?.id,
|
||||
noPengajuan: data?.noPengajuan,
|
||||
category: data?.CategoryPelayanan.name,
|
||||
status: data?.status,
|
||||
createdAt: data?.createdAt,
|
||||
updatedAt: data?.updatedAt,
|
||||
}
|
||||
|
||||
const datafix = {
|
||||
pengajuan: dataPengajuan,
|
||||
history: dataHistoryFix,
|
||||
warga: warga,
|
||||
syaratDokumen: dataSyaratFix,
|
||||
dataText: dataTextFix,
|
||||
}
|
||||
|
||||
return datafix
|
||||
}, {
|
||||
query: t.Object({
|
||||
id: t.String({ minLength: 1, error: "id harus diisi" }),
|
||||
@@ -135,20 +288,20 @@ const PelayananRoute = new Elysia({
|
||||
}
|
||||
})
|
||||
.post("/create", async ({ body }) => {
|
||||
const { idCategory, idWarga, phone, dataText, syaratDokumen } = body
|
||||
const { kategoriId, wargaId, noTelepon, dataText, syaratDokumen } = body
|
||||
const noPengajuan = await generateNoPengajuanSurat()
|
||||
let idCategoryFix = idCategory
|
||||
let idWargaFix = idWarga
|
||||
let idCategoryFix = kategoriId
|
||||
let idWargaFix = wargaId
|
||||
const category = await prisma.categoryPelayanan.findUnique({
|
||||
where: {
|
||||
id: idCategory,
|
||||
id: kategoriId,
|
||||
}
|
||||
})
|
||||
|
||||
if (!category) {
|
||||
const cariCategory = await prisma.categoryPelayanan.findFirst({
|
||||
where: {
|
||||
name: idCategory,
|
||||
name: kategoriId,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -162,12 +315,12 @@ const PelayananRoute = new Elysia({
|
||||
|
||||
const warga = await prisma.warga.findUnique({
|
||||
where: {
|
||||
id: idWarga,
|
||||
id: wargaId,
|
||||
}
|
||||
})
|
||||
|
||||
if (!warga) {
|
||||
const nomorHP = normalizePhoneNumber({ phone })
|
||||
const nomorHP = normalizePhoneNumber({ phone: noTelepon })
|
||||
const cariWarga = await prisma.warga.findFirst({
|
||||
where: {
|
||||
phone: nomorHP,
|
||||
@@ -177,7 +330,7 @@ const PelayananRoute = new Elysia({
|
||||
if (!cariWarga) {
|
||||
const wargaCreate = await prisma.warga.create({
|
||||
data: {
|
||||
name: idWarga,
|
||||
name: wargaId,
|
||||
phone: nomorHP,
|
||||
},
|
||||
select: {
|
||||
@@ -203,7 +356,7 @@ const PelayananRoute = new Elysia({
|
||||
})
|
||||
|
||||
if (!pengaduan.id) {
|
||||
throw new Error("gagal membuat pengajuan surat")
|
||||
return { success: false, message: 'gagal membuat pengajuan surat' }
|
||||
}
|
||||
|
||||
let dataInsertSyaratDokumen = []
|
||||
@@ -246,17 +399,81 @@ const PelayananRoute = new Elysia({
|
||||
return { success: true, message: 'pengajuan surat sudah dibuat' }
|
||||
}, {
|
||||
body: t.Object({
|
||||
idCategory: t.String({ minLength: 1, error: "idCategory harus diisi" }),
|
||||
idWarga: t.String({ minLength: 1, error: "idWarga harus diisi" }),
|
||||
phone: t.String({ minLength: 1, error: "phone harus diisi" }),
|
||||
dataText: t.Array(t.Object({
|
||||
jenis: t.String({ minLength: 1, error: "jenis harus diisi" }),
|
||||
value: t.String({ minLength: 1, error: "value harus diisi" }),
|
||||
})),
|
||||
syaratDokumen: t.Array(t.Object({
|
||||
jenis: t.String({ minLength: 1, error: "jenis harus diisi" }),
|
||||
value: t.String({ minLength: 1, error: "value harus diisi" }),
|
||||
})),
|
||||
kategoriId: t.String({
|
||||
minLength: 1,
|
||||
description: "ID atau nama kategori pelayanan surat yang dipilih. Jika berupa nama, sistem akan mencocokkan secara otomatis.",
|
||||
examples: ["skusaha"],
|
||||
error: "ID kategori harus diisi"
|
||||
}),
|
||||
|
||||
wargaId: t.String({
|
||||
minLength: 1,
|
||||
description: "ID warga atau nama warga. Jika ID tidak ditemukan, sistem akan mencari berdasarkan nama.",
|
||||
examples: ["Budi Santoso"],
|
||||
error: "ID warga harus diisi"
|
||||
}),
|
||||
|
||||
noTelepon: t.String({
|
||||
minLength: 8,
|
||||
description: "Nomor HP warga yang akan dinormalisasi. Jika data warga tidak ditemukan berdasarkan idWarga, pencarian dilakukan via nomor ini.",
|
||||
examples: ["081234567890"],
|
||||
error: "Nomor telepon harus diisi"
|
||||
}),
|
||||
|
||||
dataText: t.Array(
|
||||
t.Object({
|
||||
jenis: t.String({
|
||||
minLength: 1,
|
||||
description: "Jenis field yang dibutuhkan oleh kategori pelayanan. Biasanya dinamis.",
|
||||
examples: ["nama", "alamat", "pekerjaan", "keperluan"],
|
||||
error: "jenis harus diisi"
|
||||
}),
|
||||
value: t.String({
|
||||
minLength: 1,
|
||||
description: "Isi atau nilai dari jenis field terkait.",
|
||||
examples: ["Budi Santoso", "Jl. Mawar No. 10", "Karyawan Swasta"],
|
||||
error: "value harus diisi"
|
||||
}),
|
||||
}),
|
||||
{
|
||||
description: "Kumpulan data text dinamis sesuai kategori layanan.",
|
||||
examples: [
|
||||
[
|
||||
{ jenis: "jenis usaha", value: "usaha makanan" },
|
||||
{ jenis: "alamat usaha", value: "Jl. Melati No. 21" },
|
||||
]
|
||||
],
|
||||
error: "dataText harus berupa array"
|
||||
}
|
||||
),
|
||||
|
||||
syaratDokumen: t.Array(
|
||||
t.Object({
|
||||
jenis: t.String({
|
||||
minLength: 1,
|
||||
description: "Jenis dokumen persyaratan yang diminta oleh kategori layanan.",
|
||||
examples: ["ktp", "kk", "surat_pengantar_rt"],
|
||||
error: "jenis harus diisi"
|
||||
}),
|
||||
value: t.String({
|
||||
minLength: 1,
|
||||
description: "Nama file atau identifier file dokumen yang diupload.",
|
||||
examples: ["ktp_budi.png", "kk_budi.png"],
|
||||
error: "value harus diisi"
|
||||
}),
|
||||
}),
|
||||
{
|
||||
description: "Kumpulan dokumen yang wajib diupload sesuai persyaratan layanan.",
|
||||
examples: [
|
||||
[
|
||||
{ jenis: "pengantar kelian", value: "pengantar_kelurahan_budi.png" },
|
||||
{ jenis: "ktp/kk", value: "kk_budi.png" },
|
||||
{ jenis: "foto lokasi", value: "foto_lokasi_budi.png" }
|
||||
]
|
||||
],
|
||||
error: "syaratDokumen harus berupa array"
|
||||
}
|
||||
),
|
||||
}),
|
||||
detail: {
|
||||
summary: "Create Pengajuan Pelayanan Surat",
|
||||
@@ -265,7 +482,9 @@ const PelayananRoute = new Elysia({
|
||||
}
|
||||
})
|
||||
.post("/update-status", async ({ body }) => {
|
||||
const { id, status, keterangan, idUser } = body
|
||||
const { id, status, keterangan, idUser, noSurat } = body
|
||||
let deskripsi = ""
|
||||
|
||||
|
||||
const pengajuan = await prisma.pelayananAjuan.update({
|
||||
where: {
|
||||
@@ -273,28 +492,48 @@ const PelayananRoute = new Elysia({
|
||||
},
|
||||
data: {
|
||||
status: status as StatusPengaduan,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
idCategory: true,
|
||||
idWarga: true,
|
||||
}
|
||||
})
|
||||
|
||||
if (!pengajuan) {
|
||||
throw new Error("gagal membuat pengajuan")
|
||||
return { success: false, message: 'gagal update status pengajuan surat' }
|
||||
}
|
||||
|
||||
if (status === "diterima") {
|
||||
deskripsi = "Pengajuan surat diterima"
|
||||
} else if (status === "ditolak") {
|
||||
deskripsi = "Pengajuan surat ditolak dengan keterangan " + keterangan
|
||||
} else if (status === "selesai") {
|
||||
deskripsi = "Pengajuan surat disetujui"
|
||||
}
|
||||
|
||||
await prisma.historyPelayanan.create({
|
||||
data: {
|
||||
idPengajuanLayanan: pengajuan.id,
|
||||
deskripsi: "Pengajuan surat diperbarui",
|
||||
deskripsi: deskripsi,
|
||||
status: status as StatusPengaduan,
|
||||
idUser,
|
||||
keteranganAlasan: keterangan,
|
||||
}
|
||||
})
|
||||
|
||||
if (status === "selesai") {
|
||||
await createSurat({ idPengajuan: pengajuan.id, idCategory: pengajuan.idCategory, idWarga: pengajuan.idWarga, noSurat })
|
||||
}
|
||||
|
||||
return { success: true, message: 'pengajuan surat sudah diperbarui' }
|
||||
}, {
|
||||
body: t.Object({
|
||||
id: t.String({ minLength: 1, error: "id harus diisi" }),
|
||||
status: t.String({ minLength: 1, error: "status harus diisi" }),
|
||||
keterangan: t.String({ minLength: 1, error: "keterangan harus diisi" }),
|
||||
idUser: t.String({ minLength: 1, error: "idUser harus diisi" }),
|
||||
keterangan: t.String({ optional: true }),
|
||||
idUser: t.String({ optional: true }),
|
||||
noSurat: t.String({ optional: true }),
|
||||
}),
|
||||
detail: {
|
||||
summary: "Update Status Pengajuan Pelayanan Surat",
|
||||
@@ -302,5 +541,128 @@ const PelayananRoute = new Elysia({
|
||||
tags: ["mcp"]
|
||||
}
|
||||
})
|
||||
.get("/list", async ({ query }) => {
|
||||
const { take, page, search, status } = query
|
||||
const skip = !page ? 0 : (Number(page) - 1) * (!take ? 10 : Number(take))
|
||||
|
||||
let where: any = {
|
||||
isActive: true,
|
||||
OR: [
|
||||
{
|
||||
CategoryPelayanan: {
|
||||
name: {
|
||||
contains: search ?? "",
|
||||
mode: "insensitive"
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
noPengajuan: {
|
||||
contains: search ?? "",
|
||||
mode: "insensitive"
|
||||
},
|
||||
},
|
||||
{
|
||||
Warga: {
|
||||
phone: {
|
||||
contains: search ?? "",
|
||||
mode: "insensitive"
|
||||
},
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
if (status && status !== "semua") {
|
||||
where = {
|
||||
...where,
|
||||
status: status
|
||||
}
|
||||
}
|
||||
|
||||
const data = await prisma.pelayananAjuan.findMany({
|
||||
skip,
|
||||
take: !take ? 10 : Number(take),
|
||||
orderBy: {
|
||||
createdAt: "desc"
|
||||
},
|
||||
where,
|
||||
select: {
|
||||
id: true,
|
||||
noPengajuan: true,
|
||||
status: true,
|
||||
createdAt: true,
|
||||
updatedAt: true,
|
||||
CategoryPelayanan: {
|
||||
select: {
|
||||
name: true
|
||||
}
|
||||
},
|
||||
Warga: {
|
||||
select: {
|
||||
name: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const dataFix = data.map((item) => {
|
||||
return {
|
||||
noPengajuan: item.noPengajuan,
|
||||
id: item.id,
|
||||
category: item.CategoryPelayanan.name,
|
||||
warga: item.Warga.name,
|
||||
status: item.status,
|
||||
createdAt: item.createdAt.toLocaleDateString("id-ID", { day: "numeric", month: "long", year: "numeric" }),
|
||||
updatedAt: 'terakhir diperbarui ' + getLastUpdated(item.updatedAt),
|
||||
}
|
||||
})
|
||||
|
||||
return dataFix
|
||||
}, {
|
||||
query: t.Object({
|
||||
take: t.String({ optional: true }),
|
||||
page: t.String({ optional: true }),
|
||||
search: t.String({ optional: true }),
|
||||
status: t.String({ optional: true }),
|
||||
}),
|
||||
detail: {
|
||||
summary: "List Pengajuan Pelayanan Surat Warga",
|
||||
description: `tool untuk mendapatkan list pengajuan pelayanan surat warga`,
|
||||
}
|
||||
})
|
||||
.get("/count", async ({ query }) => {
|
||||
const counts = await prisma.pelayananAjuan.groupBy({
|
||||
by: ['status'],
|
||||
where: {
|
||||
isActive: true,
|
||||
},
|
||||
_count: {
|
||||
status: true,
|
||||
},
|
||||
});
|
||||
|
||||
const grouped = Object.fromEntries(
|
||||
counts.map(c => [c.status, c._count.status])
|
||||
);
|
||||
|
||||
const total = await prisma.pelayananAjuan.count({
|
||||
where: { isActive: true },
|
||||
});
|
||||
|
||||
return {
|
||||
antrian: grouped?.antrian || 0,
|
||||
diterima: grouped?.diterima || 0,
|
||||
dikerjakan: grouped?.dikerjakan || 0,
|
||||
ditolak: grouped?.ditolak || 0,
|
||||
selesai: grouped?.selesai || 0,
|
||||
semua: total,
|
||||
};
|
||||
}, {
|
||||
detail: {
|
||||
summary: "Jumlah Pengajuan Pelayanan Surat Warga",
|
||||
description: `tool untuk mendapatkan jumlah pengajuan pelayanan surat warga`,
|
||||
}
|
||||
})
|
||||
|
||||
export default PelayananRoute
|
||||
|
||||
@@ -278,7 +278,7 @@ Respon:
|
||||
})
|
||||
|
||||
if (!pengaduan) {
|
||||
throw new Error("gagal membuat pengaduan")
|
||||
return { success: false, message: 'gagal update status pengaduan' }
|
||||
}
|
||||
|
||||
if (status === "diterima") {
|
||||
|
||||
Reference in New Issue
Block a user