diff --git a/pages/permohonan-temujanji/baru/index.vue b/pages/permohonan-temujanji/baru/index.vue index 0647685..a829885 100644 --- a/pages/permohonan-temujanji/baru/index.vue +++ b/pages/permohonan-temujanji/baru/index.vue @@ -426,26 +426,35 @@ const isFormValid = () => { ); }; -const simpan = () => { - $swal - .fire({ - title: "Adakah anda pasti?", - text: "Borang boleh dikemaskini selepas di simpan.", - icon: "warning", - showCancelButton: true, - confirmButtonText: "Ya, Hantar", - cancelButtonText: "Batal", - }) - .then((result) => { - if (result.isConfirmed) { - // Handle form submission - console.log({ +const simpan = async () => { + const isDraft = true; // Simpan means saving as draft + await submitData(isDraft); +}; + +const submitForm = async () => { + const isDraft = false; // Submit means final submission + await submitData(isDraft); +}; + +// Helper function to send the data to the API +const submitData = async (isDraft) => { + if (isFormValid()) { + try { + const response = await $fetch("/api/permohonan/create", { + method: "POST", + body: { namaPemohon: namaPemohon.value, pangkatPemohon: pangkatPemohon.value, noPegawaiPemohon: noPegawaiPemohon.value, - namaPenghantar: namaPenghantar.value, - pangkatPenghantar: pangkatPenghantar.value, - noPegawaiPenghantar: noPegawaiPenghantar.value, + namaPenghantar: isPenghantarSameAsPemohon.value + ? null + : namaPenghantar.value, + pangkatPenghantar: isPenghantarSameAsPemohon.value + ? null + : pangkatPenghantar.value, + noPegawaiPenghantar: isPenghantarSameAsPemohon.value + ? null + : noPegawaiPenghantar.value, ringkasanKenyataanKes: ringkasanKenyataanKes.value, bilangan: bilangan.value, barangList: barangList.value, @@ -453,67 +462,37 @@ const simpan = () => { noLaporanPolis: noLaporanPolis.value, tarikhTemujanji: tarikhTemujanji.value, slotMasa: slotMasa.value, - }); + isDraft: isDraft, + }, + }); - // Show success message - $swal.fire({ - title: "Berjaya!", - text: "Borang telah berjaya disimpan.", - icon: "success", - confirmButtonText: "OK", - }); - } - }); -}; - -const submitForm = () => { - $swal - .fire({ - title: "Adakah anda pasti?", - text: "Anda tidak boleh mengubah maklumat selepas borang dihantar.", - icon: "warning", - showCancelButton: true, - confirmButtonText: "Ya, Hantar", - cancelButtonText: "Batal", - }) - .then((result) => { - if (result.isConfirmed) { - if (isFormValid()) { - // Handle form submission - console.log({ - namaPemohon: namaPemohon.value, - pangkatPemohon: pangkatPemohon.value, - noPegawaiPemohon: noPegawaiPemohon.value, - namaPenghantar: namaPenghantar.value, - pangkatPenghantar: pangkatPenghantar.value, - noPegawaiPenghantar: noPegawaiPenghantar.value, - ringkasanKenyataanKes: ringkasanKenyataanKes.value, - bilangan: bilangan.value, - barangList: barangList.value, - noKertasSiasatan: noKertasSiasatan.value, - noLaporanPolis: noLaporanPolis.value, - tarikhTemujanji: tarikhTemujanji.value, - slotMasa: slotMasa.value, - }); - - // Show success message - $swal.fire({ - title: "Berjaya!", - text: "Borang telah berjaya dihantar.", - icon: "success", - confirmButtonText: "OK", - }); - } else { - // Show error message - $swal.fire({ - title: "Ralat!", - text: "Sila isi semua medan yang diperlukan dan tambah sekurang-kurangnya satu barang.", - icon: "error", - confirmButtonText: "OK", - }); - } + $swal.fire({ + title: "Berjaya!", + text: response.message, + icon: "success", + confirmButtonText: "OK", + }); + + // Redirect user based on action (draft or submission) + if (!isDraft) { + router.push("/permohonan-temujanji/success"); } + } catch (error) { + $swal.fire({ + title: "Ralat!", + text: error.message || "Something went wrong, please try again.", + icon: "error", + confirmButtonText: "OK", + }); + } + } else { + $swal.fire({ + title: "Ralat!", + text: "Sila isi semua medan yang diperlukan dan tambah sekurang-kurangnya satu barang.", + icon: "error", + confirmButtonText: "OK", }); + } }; const { $swal } = useNuxtApp(); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index d1a94ca..abba2f0 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -17,36 +17,40 @@ model audit { } model document { - documentID Int @id @default(autoincrement()) - userID Int? - documentName String? @db.VarChar(255) - documentURL String? @db.VarChar(255) - documentType String? @db.VarChar(255) - documentExtension String? @db.VarChar(255) - imageMIMEType String? @db.VarChar(255) - documentSize Int? - documentStatus String? @default("ACTIVE") @db.VarChar(255) - documentCreatedDate String? @db.VarChar(255) - documentModifiedDate String? @db.VarChar(255) - user user? @relation(fields: [userID], references: [userID], onDelete: NoAction, onUpdate: NoAction, map: "document_ibfk_1") - permohonan_report permohonan_report[] - permohonan_report_doc_support permohonan_report_doc_support[] + documentID Int @id @default(autoincrement()) + userID Int? + documentName String? @db.VarChar(255) + documentURL String? @db.VarChar(255) + documentType String? @db.VarChar(255) + documentExtension String? @db.VarChar(255) + imageMIMEType String? @db.VarChar(255) + documentSize Int? + documentStatus String? @default("ACTIVE") @db.VarChar(255) + documentCreatedDate String? @db.VarChar(255) + documentModifiedDate String? @db.VarChar(255) + user user? @relation(fields: [userID], references: [userID], onDelete: NoAction, onUpdate: NoAction, map: "document_ibfk_1") + permohonan_forensik_checking permohonan_forensik_checking[] + report report[] + report_doc_support report_doc_support[] @@index([userID], map: "userID") } model lookup { - lookupID Int @id @default(autoincrement()) - lookupOrder Int? - lookupTitle String? @db.VarChar(255) - lookupRefCode String? @db.VarChar(255) - lookupValue String? @db.VarChar(255) - lookupType String? @db.VarChar(255) - lookupStatus String? @db.VarChar(255) - lookupCreatedDate DateTime? @db.DateTime(0) - lookupModifiedDate DateTime? @db.DateTime(0) - permohonan permohonan[] - permohonan_penolakan permohonan_penolakan[] + lookupID Int @id @default(autoincrement()) + lookupOrder Int? + lookupTitle String? @db.VarChar(255) + lookupRefCode String? @db.VarChar(255) + lookupValue String? @db.VarChar(255) + lookupType String? @db.VarChar(255) + lookupStatus String? @db.VarChar(255) + lookupCreatedDate DateTime? @db.DateTime(0) + lookupModifiedDate DateTime? @db.DateTime(0) + permohonan permohonan[] + permohonan_jenis_barang permohonan_jenis_barang[] + permohonan_penolakan permohonan_penolakan[] + report_report_dapatanTolookup report[] @relation("report_dapatanTolookup") + report_report_jenis_barangTolookup report[] @relation("report_jenis_barangTolookup") } /// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments @@ -78,30 +82,30 @@ model penghantar { } model permohonan { - id Int @id @default(autoincrement()) - no_siri String @unique(map: "Permohonan_no_siri_key") @db.VarChar(255) + id Int @id @default(autoincrement()) + no_siri String @unique(map: "Permohonan_no_siri_key") @db.VarChar(255) pemohonID Int? penghantar_sama_dengan_pemohon Int? penghantarID Int? - status_permohonan String @db.VarChar(255) - ringkasan_kenyataan_kes String? @db.Text - bilangan String? @db.VarChar(255) + status_permohonan String @db.VarChar(255) + ringkasan_kenyataan_kes String? @db.Text + bilangan String? @db.VarChar(255) jenis_barang Int? - tanda_barang String? @db.VarChar(255) - keadaan_barang String? @db.VarChar(255) + tanda_barang String? @db.VarChar(255) + keadaan_barang String? @db.VarChar(255) kuantiti_barang Int? - jenis_barang_details String? @db.Text - no_laporan_polis String? @db.VarChar(255) - tarikh_temujanji DateTime? @db.DateTime(0) - create_at DateTime @db.DateTime(0) - penghantar penghantar? @relation(fields: [penghantarID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_ibfk_1") - pemohon pemohon? @relation(fields: [pemohonID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_ibfk_2") - lookup lookup? @relation(fields: [jenis_barang], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_ibfk_3") + jenis_barang_details String? @db.Text + no_laporan_polis String? @db.VarChar(255) + tarikh_temujanji DateTime? @db.DateTime(0) + create_at DateTime @db.DateTime(0) + penghantar penghantar? @relation(fields: [penghantarID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_ibfk_1") + pemohon pemohon? @relation(fields: [pemohonID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_ibfk_2") + lookup lookup? @relation(fields: [jenis_barang], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_ibfk_3") permohonan_assign_forensik permohonan_assign_forensik[] + permohonan_jenis_barang permohonan_jenis_barang[] permohonan_penerimaan permohonan_penerimaan[] - permohonan_report permohonan_report[] - permohonan_report_doc_support permohonan_report_doc_support[] permohonan_semakan permohonan_semakan[] + report report[] @@index([pemohonID], map: "idx_pemohon") @@index([penghantarID], map: "idx_penghantar") @@ -109,11 +113,12 @@ model permohonan { } model permohonan_assign_forensik { - assignID Int @id @default(autoincrement()) - permohonanID Int - pegawai_forensikID Int - permohonan permohonan @relation(fields: [permohonanID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_assign_forensik_ibfk_2") - user user @relation(fields: [pegawai_forensikID], references: [userID], onUpdate: Restrict, map: "permohonan_assign_forensik_ibfk_3") + assignID Int @id @default(autoincrement()) + permohonanID Int + pegawai_forensikID Int + permohonan permohonan @relation(fields: [permohonanID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_assign_forensik_ibfk_2") + user user @relation(fields: [pegawai_forensikID], references: [userID], onUpdate: Restrict, map: "permohonan_assign_forensik_ibfk_3") + permohonan_forensik_checking permohonan_forensik_checking[] @@index([pegawai_forensikID], map: "pegawai_forensikID") @@index([permohonanID], map: "permohonanID") @@ -151,35 +156,6 @@ model permohonan_penolakan { @@index([sebab_penolakan], map: "sebab_penolakan") } -/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments -model permohonan_report { - reportID Int @id @default(autoincrement()) - permohonanID Int - peralatan String @db.VarChar(255) - langkah_langkah Int - gambarID Int? - ulasan String? @db.Text - dapatan String @db.VarChar(255) - create_at DateTime? @db.DateTime(0) - create_by Int - permohonan permohonan @relation(fields: [permohonanID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_report_ibfk_1") - document document? @relation(fields: [gambarID], references: [documentID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_report_ibfk_2") - - @@index([gambarID], map: "gambarID") - @@index([permohonanID], map: "permohonanID") -} - -model permohonan_report_doc_support { - report_attachID Int @id @default(autoincrement()) - permohonanID Int - documentID Int - document document @relation(fields: [documentID], references: [documentID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_report_doc_support_ibfk_1") - permohonan permohonan @relation(fields: [permohonanID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_report_doc_support_ibfk_2") - - @@index([documentID], map: "documentID") - @@index([permohonanID], map: "permohonanID") -} - model permohonan_semakan { semakanID Int @id @default(autoincrement()) permohonanID Int @@ -226,6 +202,7 @@ model user { userModifiedDate DateTime? @db.DateTime(0) document document[] pemohon pemohon[] + permohonan_approval permohonan_approval[] permohonan_assign_forensik permohonan_assign_forensik[] permohonan_penerimaan permohonan_penerimaan[] permohonan_penolakan permohonan_penolakan[] @@ -244,3 +221,83 @@ model userrole { @@index([userRoleRoleID], map: "FK_userrole_role") @@index([userRoleUserID], map: "FK_userrole_user") } + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model permohonan_approval { + approvalID Int @id @default(autoincrement()) + permohonanID Int + approve_by Int + approval_status Int + ulasan String? @db.Text + approval_date DateTime @db.DateTime(0) + user user @relation(fields: [approve_by], references: [userID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_approval_ibfk_1") + + @@index([approve_by], map: "userID") +} + +/// This model or at least one of its fields has comments in the database, and requires an additional setup for migrations: Read more: https://pris.ly/d/database-comments +model permohonan_forensik_checking { + checkingID Int @id @default(autoincrement()) + assignID Int + gambar Int? + ulasan String? @db.Text + dapatan String @db.VarChar(255) + create_at DateTime @db.DateTime(0) + permohonan_assign_forensik permohonan_assign_forensik @relation(fields: [assignID], references: [assignID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_forensik_checking_ibfk_1") + document document? @relation(fields: [gambar], references: [documentID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_forensik_checking_ibfk_2") + + @@index([assignID], map: "assignID") + @@index([gambar], map: "gambar") +} + +model permohonan_jenis_barang { + barangID Int @id @default(autoincrement()) + permohonanID Int + jenis_barang Int + barang_status String @default("ACTIVE") @db.VarChar(255) + lookup lookup @relation(fields: [jenis_barang], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_jenis_barang_ibfk_1") + permohonan permohonan @relation(fields: [permohonanID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_jenis_barang_ibfk_2") + + @@index([jenis_barang], map: "jenis_barang") + @@index([permohonanID], map: "permohonanID") +} + +model permohonan_tanda_barang { + tandaID Int @id @default(autoincrement()) + tanda_name String @db.VarChar(255) + tanda_status String @default("ACTIVE") @db.VarChar(255) +} + +model report { + reportID Int @id @default(autoincrement()) + permohonanID Int + jenis_barang Int + peralatan String? @db.VarChar(255) + langkah_langkah Int? + gambarID Int? + ulasan String? @db.Text + dapatan Int? + create_at DateTime? @db.DateTime(0) + create_by Int + permohonan permohonan @relation(fields: [permohonanID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "report_ibfk_1") + document document? @relation(fields: [gambarID], references: [documentID], onDelete: NoAction, onUpdate: NoAction, map: "report_ibfk_2") + lookup_report_dapatanTolookup lookup? @relation("report_dapatanTolookup", fields: [dapatan], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "report_ibfk_3") + lookup_report_jenis_barangTolookup lookup @relation("report_jenis_barangTolookup", fields: [jenis_barang], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "report_ibfk_4") + report_doc_support report_doc_support[] + + @@index([dapatan], map: "dapatan") + @@index([gambarID], map: "gambarID") + @@index([jenis_barang], map: "jenis_barang") + @@index([permohonanID], map: "permohonanID") +} + +model report_doc_support { + report_attachID Int @id @default(autoincrement()) + reportID Int + documentID Int + document document @relation(fields: [documentID], references: [documentID], onDelete: NoAction, onUpdate: NoAction, map: "report_doc_support_ibfk_1") + report report @relation(fields: [reportID], references: [reportID], onDelete: NoAction, onUpdate: NoAction, map: "report_doc_support_ibfk_2") + + @@index([documentID], map: "documentID") + @@index([reportID], map: "reportID") +} diff --git a/server/api/lookup/index.js b/server/api/lookup/index.js new file mode 100644 index 0000000..a513dda --- /dev/null +++ b/server/api/lookup/index.js @@ -0,0 +1,35 @@ +export default defineEventHandler(async (event) => { + const { type } = getQuery(event); // Get lookup type from query params, e.g., jenis_barang, dapatan + + if (!type) { + return { + statusCode: 400, + message: "Lookup type is required", + }; + } + + try { + const lookups = await prisma.lookup.findMany({ + where: { + lookupTitle: type, + lookupStatus: "ACTIVE", + }, + select: { + lookupID: true, + lookupTitle: true, + lookupValue: true, + }, + }); + + return { + statusCode: 200, + data: lookups, + }; + } catch (error) { + return { + statusCode: 500, + message: "Error fetching lookup data", + error: error.message, + }; + } +}); diff --git a/server/api/permohonan/create.js b/server/api/permohonan/create.js new file mode 100644 index 0000000..a7801a4 --- /dev/null +++ b/server/api/permohonan/create.js @@ -0,0 +1,130 @@ +// File: server/api/permohonan/index.post.js + +export default defineEventHandler(async (event) => { + const body = await readBody(event); + + // Step 1: Validation for required fields + if ( + !body.namaPemohon || + !body.tarikhTemujanji || + !body.noLaporanPolis || + !body.slotMasa || + !body.barangList.length + ) { + return { + statusCode: 400, + message: + "Setiap medan mandatori yang bertanda * telah diisi. (Ralat CMN-E001)", + }; + } + + // Step 2: Validate appointment date must be in the future + const currentDate = new Date(); + const appointmentDate = new Date(body.tarikhTemujanji); + if (appointmentDate <= currentDate) { + return { + statusCode: 400, + message: + "Perlu memastikan tarikh janji temu yang dimasukkan adalah tarikh selepas tarikh semasa. (Ralat CMN-E002)", + }; + } + + // Step 3: Generate Case ID + const caseID = generateCaseID(); + + // Step 4: Determine status (Draft or Submitted) + const status = body.isDraft ? "Permohonan Draf" : "Permohonan Dihantar"; + + try { + // Step 5: Insert data into the permohonan table + const newPermohonan = await prisma.permohonan.create({ + data: { + no_siri: caseID, + pemohonID: body.pemohonID, + penghantarID: body.penghantarID || null, // If same as pemohon, this can be null + penghantar_sama_dengan_pemohon: body.penghantarSamaDenganPemohon + ? 1 + : 0, + status_permohonan: status, // Draf or Dihantar + ringkasan_kenyataan_kes: body.ringkasanKenyataanKes, + bilangan: body.bilangan?.toString(), + no_laporan_polis: body.noLaporanPolis, + tarikh_temujanji: new Date(body.tarikhTemujanji), + create_at: currentDate, + }, + }); + + // Step 6: Insert `barang` details into the `permohonan_jenis_barang` table + const barangList = body.barangList.map((barang) => ({ + permohonanID: newPermohonan.id, // Foreign key to permohonan + jenis_barang: barang.jenisBarang, // Foreign key to lookup(jenis_barang) + barang_status: "ACTIVE", // Static value for now + })); + await prisma.permohonan_jenis_barang.createMany({ data: barangList }); + + // Step 7: Insert data into the `report` table + const newReport = await prisma.report.create({ + data: { + permohonanID: newPermohonan.id, + jenis_barang: body.barangList[0].jenisBarang, // The first barang's jenis_barang + peralatan: body.peralatan || null, // Optional, based on frontend input + langkah_langkah: body.langkahLangkah || null, // Optional, based on frontend input + gambarID: body.gambarID || null, // Optional document ID, if any + ulasan: body.ulasan || null, // Optional notes + dapatan: body.dapatan || null, // Optional foreign key lookup(dapatan) + create_at: currentDate, + create_by: body.userID, // The user who created the report + }, + }); + + // Step 8: Send confirmation email (pseudocode) + sendEmail({ + case_id: caseID, + selected_appointment_date: body.tarikhTemujanji, + time_slot: body.slotMasa, + barang_list: body.barangList + .map((barang) => barang.jenisBarang) + .join(", "), + }); + + // Step 9: Return response depending on the action (draft or submit) + if (body.isDraft) { + return { + statusCode: 200, + message: "Rekod telah berjaya disimpan. (Status CMN-S001)", + data: { newPermohonan, newReport }, + }; + } else { + return { + statusCode: 200, + message: + "Permohonan pemeriksaan forensik telah dihantar. (Status FOR-S001)", + data: { newPermohonan, newReport }, + }; + } + } catch (error) { + console.log(error); + return { + statusCode: 500, + message: "Failed to create permohonan and report. Please try again.", + }; + } +}); + +// Helper function to generate unique case ID +function generateCaseID() { + const date = new Date(); + const year = date.getFullYear(); + const month = (date.getMonth() + 1).toString().padStart(2, "0"); + const day = date.getDate().toString().padStart(2, "0"); + const uniqueSerialNumber = Math.floor(Math.random() * 1000000) + .toString() + .padStart(6, "0"); + return `${year}${month}${day}-${uniqueSerialNumber}`; +} + +// Pseudocode function for sending email +function sendEmail(data) { + // Email logic goes here + console.log("Email sent with the following data: ", data); +}