refactor(create): remove realisasiAwal, simplify to anggaran-only input
Refactoring: - Remove realisasiAwal field from ItemForm type - Remove NumberInput for realisasi awal from UI - Remove realisasiAwal column from preview table - Simplify state management (no realisasiAwal mapping) - API create: Create items with totalRealisasi=0 (no auto-create realisasi) Rationale: - Cleaner separation: Anggaran dan Realisasi adalah entitas terpisah - User create item untuk ANGGARAN dulu - Setelah item dibuat, user bisa add MULTIPLE REALISASI dengan: * Uraian yang jelas untuk setiap realisasi * Tanggal yang spesifik * Keterangan detail * Bukti file attachment - Follows the original schema design more closely Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
This commit is contained in:
@@ -5,12 +5,11 @@ import { toast } from "react-toastify";
|
||||
import { proxy } from "valtio";
|
||||
import { z } from "zod";
|
||||
|
||||
// --- Zod Schema untuk APBDes Item (dengan realisasiAwal opsional) ---
|
||||
// --- Zod Schema untuk APBDes Item (tanpa field kalkulasi) ---
|
||||
const ApbdesItemSchema = z.object({
|
||||
kode: z.string().min(1, "Kode wajib diisi"),
|
||||
uraian: z.string().min(1, "Uraian wajib diisi"),
|
||||
anggaran: z.number().min(0, "Anggaran tidak boleh negatif"),
|
||||
realisasiAwal: z.number().min(0).optional(), // Realisasi pertama saat create
|
||||
level: z.number().int().min(1).max(3),
|
||||
tipe: z.enum(['pendapatan', 'belanja', 'pembiayaan']).nullable().optional(),
|
||||
});
|
||||
@@ -92,21 +91,7 @@ const apbdes = proxy({
|
||||
|
||||
try {
|
||||
this.loading = true;
|
||||
|
||||
// Extract realisasiAwal dari items
|
||||
const itemsWithRealisasi = this.form.items.map(item => ({
|
||||
kode: item.kode,
|
||||
uraian: item.uraian,
|
||||
anggaran: item.anggaran,
|
||||
level: item.level,
|
||||
tipe: item.tipe,
|
||||
realisasiAwal: item.realisasiAwal || 0,
|
||||
}));
|
||||
|
||||
const res = await ApiFetch.api.landingpage.apbdes["create"].post({
|
||||
...parsed.data,
|
||||
items: itemsWithRealisasi,
|
||||
});
|
||||
const res = await ApiFetch.api.landingpage.apbdes["create"].post(parsed.data);
|
||||
|
||||
if (res.data?.success) {
|
||||
toast.success("APBDes berhasil dibuat");
|
||||
|
||||
@@ -33,7 +33,6 @@ type ItemForm = {
|
||||
kode: string;
|
||||
uraian: string;
|
||||
anggaran: number;
|
||||
realisasiAwal?: number; // Realisasi pertama saat create
|
||||
level: number;
|
||||
tipe: 'pendapatan' | 'belanja' | 'pembiayaan';
|
||||
};
|
||||
@@ -61,7 +60,6 @@ function CreateAPBDes() {
|
||||
kode: '',
|
||||
uraian: '',
|
||||
anggaran: 0,
|
||||
realisasiAwal: 0,
|
||||
level: 1,
|
||||
tipe: 'pendapatan',
|
||||
});
|
||||
@@ -80,7 +78,6 @@ function CreateAPBDes() {
|
||||
kode: '',
|
||||
uraian: '',
|
||||
anggaran: 0,
|
||||
realisasiAwal: 0,
|
||||
level: 1,
|
||||
tipe: 'pendapatan',
|
||||
});
|
||||
@@ -127,7 +124,7 @@ function CreateAPBDes() {
|
||||
|
||||
// Tambahkan item ke state
|
||||
const handleAddItem = () => {
|
||||
const { kode, uraian, anggaran, realisasiAwal, level, tipe } = newItem;
|
||||
const { kode, uraian, anggaran, level, tipe } = newItem;
|
||||
if (!kode || !uraian) {
|
||||
return toast.warn("Kode dan uraian wajib diisi");
|
||||
}
|
||||
@@ -138,7 +135,6 @@ function CreateAPBDes() {
|
||||
kode,
|
||||
uraian,
|
||||
anggaran,
|
||||
realisasiAwal: realisasiAwal || 0,
|
||||
level,
|
||||
tipe: finalTipe,
|
||||
});
|
||||
@@ -148,7 +144,6 @@ function CreateAPBDes() {
|
||||
kode: '',
|
||||
uraian: '',
|
||||
anggaran: 0,
|
||||
realisasiAwal: 0,
|
||||
level: 1,
|
||||
tipe: 'pendapatan',
|
||||
});
|
||||
@@ -423,14 +418,6 @@ function CreateAPBDes() {
|
||||
thousandSeparator
|
||||
min={0}
|
||||
/>
|
||||
<NumberInput
|
||||
label="Realisasi Awal (Rp) - Opsional"
|
||||
value={newItem.realisasiAwal}
|
||||
onChange={(val) => setNewItem({ ...newItem, realisasiAwal: Number(val) || 0 })}
|
||||
thousandSeparator
|
||||
min={0}
|
||||
description="Isi jika sudah ada realisasi saat create"
|
||||
/>
|
||||
</Group>
|
||||
<Button
|
||||
leftSection={<IconPlus size={16} />}
|
||||
@@ -452,7 +439,6 @@ function CreateAPBDes() {
|
||||
<th>Kode</th>
|
||||
<th>Uraian</th>
|
||||
<th>Anggaran</th>
|
||||
<th>Realisasi Awal</th>
|
||||
<th>Level</th>
|
||||
<th>Tipe</th>
|
||||
<th style={{ width: 50 }}>Aksi</th>
|
||||
@@ -464,7 +450,6 @@ function CreateAPBDes() {
|
||||
<td><Text size="sm" fw={500}>{item.kode}</Text></td>
|
||||
<td>{item.uraian}</td>
|
||||
<td>{item.anggaran.toLocaleString('id-ID')}</td>
|
||||
<td>{(item.realisasiAwal || 0).toLocaleString('id-ID')}</td>
|
||||
<td>
|
||||
<Badge size="sm" color={item.level === 1 ? 'blue' : item.level === 2 ? 'green' : 'grape'}>
|
||||
L{item.level}
|
||||
|
||||
@@ -10,7 +10,6 @@ type APBDesItemInput = {
|
||||
anggaran: number;
|
||||
level: number;
|
||||
tipe?: string | null;
|
||||
realisasiAwal?: number; // Realisasi pertama saat create
|
||||
};
|
||||
|
||||
type FormCreate = {
|
||||
@@ -56,15 +55,14 @@ export default async function apbdesCreate(context: Context) {
|
||||
},
|
||||
});
|
||||
|
||||
// Create items dengan auto-calculate totalRealisasi, selisih, persentase
|
||||
// Create items dengan auto-calculate totalRealisasi=0, selisih, persentase
|
||||
const items = await Promise.all(
|
||||
body.items.map(async item => {
|
||||
const anggaran = item.anggaran;
|
||||
const realisasiAwal = item.realisasiAwal || 0;
|
||||
|
||||
// Jika ada realisasiAwal, buat realisasi item pertama
|
||||
let totalRealisasi = realisasiAwal;
|
||||
|
||||
const totalRealisasi = 0; // Belum ada realisasi saat create
|
||||
const selisih = totalRealisasi - anggaran;
|
||||
const persentase = anggaran > 0 ? (totalRealisasi / anggaran) * 100 : 0;
|
||||
|
||||
const itemData = {
|
||||
kode: item.kode,
|
||||
uraian: item.uraian,
|
||||
@@ -72,29 +70,15 @@ export default async function apbdesCreate(context: Context) {
|
||||
level: item.level,
|
||||
tipe: item.tipe || null,
|
||||
totalRealisasi,
|
||||
selisih: totalRealisasi - anggaran,
|
||||
persentase: anggaran > 0 ? (totalRealisasi / anggaran) * 100 : 0,
|
||||
selisih,
|
||||
persentase,
|
||||
apbdesId: apbdes.id,
|
||||
};
|
||||
|
||||
const createdItem = await prisma.aPBDesItem.create({
|
||||
return prisma.aPBDesItem.create({
|
||||
data: itemData,
|
||||
select: { id: true, kode: true },
|
||||
});
|
||||
|
||||
// Jika ada realisasiAwal, buat realisasi item pertama
|
||||
if (realisasiAwal > 0) {
|
||||
await prisma.realisasiItem.create({
|
||||
data: {
|
||||
apbdesItemId: createdItem.id,
|
||||
jumlah: realisasiAwal,
|
||||
tanggal: new Date(),
|
||||
keterangan: 'Realisasi awal saat create APBDes',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
return createdItem;
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user