You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
4.2 KiB
TypeScript
149 lines
4.2 KiB
TypeScript
"use server";
|
|
|
|
import { revalidatePath } from "next/cache";
|
|
import { z } from "zod";
|
|
import { getCurrentUser } from "@/data/auth";
|
|
import {
|
|
SubGroupProductDitolakError,
|
|
countPemakaianSubGroupProduct,
|
|
deleteSubGroupProduct,
|
|
insertSubGroupProduct,
|
|
updateSubGroupProduct,
|
|
} from "@/data/sub-group-product";
|
|
import {
|
|
logActionError,
|
|
type DeleteState,
|
|
type FormState,
|
|
} from "@/lib/server-action";
|
|
|
|
type SubGroupProductField = keyof typeof subGroupProductSchema.shape;
|
|
export type SimpanSubGroupProductState = FormState<SubGroupProductField> & {
|
|
id?: number;
|
|
};
|
|
|
|
export type HapusSubGroupProductState = DeleteState;
|
|
|
|
const subGroupProductSchema = z.object({
|
|
kodeKedProduk: z
|
|
.string()
|
|
.trim()
|
|
.min(1, "Kode wajib diisi")
|
|
.max(1, "Kode maksimal 1 karakter"),
|
|
kodeStrip: z
|
|
.string()
|
|
.trim()
|
|
.min(1, "Group product wajib dipilih")
|
|
.max(2, "Kode group product maksimal 2 karakter"),
|
|
kedProduk: z
|
|
.string()
|
|
.trim()
|
|
.min(1, "Nama wajib diisi")
|
|
.max(50, "Nama maksimal 50 karakter"),
|
|
});
|
|
|
|
// Edit hanya mengubah nama; kode dikunci (lihat SubGroupProductUpdate).
|
|
const updateSchema = subGroupProductSchema.pick({ kedProduk: true });
|
|
|
|
export async function simpanSubGroupProduct(
|
|
_prevState: SimpanSubGroupProductState,
|
|
formData: FormData,
|
|
): Promise<SimpanSubGroupProductState> {
|
|
const user = await getCurrentUser();
|
|
|
|
const fields = Object.keys(
|
|
subGroupProductSchema.shape,
|
|
) as SubGroupProductField[];
|
|
const values = Object.fromEntries(
|
|
fields.map((field) => [field, String(formData.get(field) ?? "")]),
|
|
) as Record<SubGroupProductField, string>;
|
|
|
|
const idRaw = String(formData.get("id") ?? "").trim();
|
|
const id = idRaw === "" ? null : Number.parseInt(idRaw, 10);
|
|
if (id !== null && !Number.isSafeInteger(id)) {
|
|
return { ok: false, error: "Sub group product tidak valid", values };
|
|
}
|
|
|
|
try {
|
|
if (id === null) {
|
|
const parsed = subGroupProductSchema.safeParse(values);
|
|
if (!parsed.success) {
|
|
return {
|
|
ok: false,
|
|
fieldErrors: z.flattenError(parsed.error).fieldErrors,
|
|
values,
|
|
};
|
|
}
|
|
|
|
const idBaru = await insertSubGroupProduct(parsed.data);
|
|
revalidatePath("/master/sub-group-product");
|
|
return { ok: true, id: idBaru };
|
|
}
|
|
|
|
const parsed = updateSchema.safeParse(values);
|
|
if (!parsed.success) {
|
|
return {
|
|
ok: false,
|
|
fieldErrors: z.flattenError(parsed.error).fieldErrors,
|
|
values,
|
|
};
|
|
}
|
|
|
|
const updated = await updateSubGroupProduct(id, parsed.data);
|
|
if (!updated) {
|
|
return { ok: false, error: "Sub group product tidak ditemukan", values };
|
|
}
|
|
revalidatePath("/master/sub-group-product");
|
|
return { ok: true, id };
|
|
} catch (error) {
|
|
// Penolakan aturan bisnis adalah validasi biasa, bukan error tak terduga, jadi tidak di-log.
|
|
if (error instanceof SubGroupProductDitolakError) {
|
|
return { ok: false, error: error.message, values };
|
|
}
|
|
logActionError(
|
|
"simpanSubGroupProduct",
|
|
{ userId: user.id, id: id ?? "(baru)", ...values },
|
|
error,
|
|
);
|
|
return {
|
|
ok: false,
|
|
error: "Gagal menyimpan sub group product, coba simpan ulang",
|
|
values,
|
|
};
|
|
}
|
|
}
|
|
|
|
export async function hapusSubGroupProduct(
|
|
_prevState: HapusSubGroupProductState,
|
|
formData: FormData,
|
|
): Promise<HapusSubGroupProductState> {
|
|
const user = await getCurrentUser();
|
|
|
|
const id = Number.parseInt(String(formData.get("id") ?? ""), 10);
|
|
if (!Number.isSafeInteger(id)) {
|
|
return { ok: false, error: "Sub group product tidak valid" };
|
|
}
|
|
|
|
try {
|
|
const dipakai = await countPemakaianSubGroupProduct(id);
|
|
if (dipakai > 0) {
|
|
return {
|
|
ok: false,
|
|
error: `Sub group product masih dipakai ${dipakai} barang, tidak bisa dihapus`,
|
|
};
|
|
}
|
|
|
|
const deleted = await deleteSubGroupProduct(id);
|
|
if (!deleted) {
|
|
return { ok: false, error: "Sub group product tidak ditemukan" };
|
|
}
|
|
revalidatePath("/master/sub-group-product");
|
|
return { ok: true };
|
|
} catch (error) {
|
|
logActionError("hapusSubGroupProduct", { userId: user.id, id }, error);
|
|
return {
|
|
ok: false,
|
|
error: "Gagal menghapus sub group product, coba hapus ulang",
|
|
};
|
|
}
|
|
}
|