"use server"; import { revalidatePath } from "next/cache"; import { z } from "zod"; import { getCurrentUser } from "@/data/auth"; import { countPemakaianGroupProduct, deleteGroupProduct, insertGroupProduct, updateGroupProduct, type GroupProductInput, } from "@/data/group-product"; import { logActionError, type DeleteState, type FormState, } from "@/lib/server-action"; type GroupProductField = keyof typeof groupProductSchema.shape; export type SimpanGroupProductState = FormState & { kdStrip?: string; }; export type HapusGroupProductState = DeleteState; // Batas atas = rentang kolom `int` MariaDB. const angka = z.coerce .number({ error: "Harus berupa angka" }) .int("Harus bilangan bulat") .min(0, "Tidak boleh negatif") .max(2_000_000_000, "Maksimal 2.000.000.000"); const groupProductSchema = z.object({ namaStrip: z .string() .trim() .min(1, "Nama wajib diisi") .max(50, "Nama maksimal 50 karakter"), murah1: angka, murah2: angka, sedang1: angka, sedang2: angka, mahal1: angka, mahal2: angka, benikMurah: angka, benikSedang: angka, benikMahal: angka, kelBrg: z.string().trim().max(1, "Kelompok barang maksimal 1 karakter"), kelJns: z.string().trim().max(1, "Kategori maksimal 1 karakter"), persenTiwul: z.coerce .number({ error: "Harus berupa angka" }) .min(0, "Tidak boleh negatif") .max(100, "Maksimal 100"), }); function emptyStringToNull(value: string): string | null { return value === "" ? null : value; } // Kolom angka dikosongkan berarti 0, kecuali persen tiwul yang default-nya 0.025. function angkaAtauDefault(value: string, def: string): string { return value === "" ? def : value; } export async function simpanGroupProduct( _prevState: SimpanGroupProductState, formData: FormData, ): Promise { const user = await getCurrentUser(); const fields = Object.keys(groupProductSchema.shape) as GroupProductField[]; const raw = Object.fromEntries( fields.map((field) => [field, String(formData.get(field) ?? "")]), ) as Record; const values: Record = { ...raw, murah1: angkaAtauDefault(raw.murah1, "0"), murah2: angkaAtauDefault(raw.murah2, "0"), sedang1: angkaAtauDefault(raw.sedang1, "0"), sedang2: angkaAtauDefault(raw.sedang2, "0"), mahal1: angkaAtauDefault(raw.mahal1, "0"), mahal2: angkaAtauDefault(raw.mahal2, "0"), benikMurah: angkaAtauDefault(raw.benikMurah, "0"), benikSedang: angkaAtauDefault(raw.benikSedang, "0"), benikMahal: angkaAtauDefault(raw.benikMahal, "0"), persenTiwul: angkaAtauDefault(raw.persenTiwul, "0.025"), }; const parsed = groupProductSchema.safeParse(values); if (!parsed.success) { return { ok: false, fieldErrors: z.flattenError(parsed.error).fieldErrors, values, }; } const input: GroupProductInput = { ...parsed.data, kelBrg: emptyStringToNull(parsed.data.kelBrg), }; const kdStrip = String(formData.get("kdStrip") ?? "").trim(); try { if (kdStrip === "") { const kdBaru = await insertGroupProduct(input); revalidatePath("/master/group-product"); return { ok: true, kdStrip: kdBaru }; } const updated = await updateGroupProduct(kdStrip, input); if (!updated) { return { ok: false, error: "Group product tidak ditemukan", values }; } revalidatePath("/master/group-product"); return { ok: true, kdStrip }; } catch (error) { logActionError( "simpanGroupProduct", { userId: user.id, kdStrip: kdStrip || "(baru)", nama: input.namaStrip }, error, ); return { ok: false, error: "Gagal menyimpan group product, coba simpan ulang", values, }; } } export async function hapusGroupProduct( _prevState: HapusGroupProductState, formData: FormData, ): Promise { const user = await getCurrentUser(); const kdStrip = String(formData.get("kdStrip") ?? "").trim(); if (kdStrip === "") { return { ok: false, error: "Kode group product tidak ada" }; } try { const dipakai = await countPemakaianGroupProduct(kdStrip); if (dipakai.barang > 0 || dipakai.subGroup > 0) { return { ok: false, error: `Group product masih dipakai ${dipakai.barang} barang dan ${dipakai.subGroup} sub group product, tidak bisa dihapus`, }; } const deleted = await deleteGroupProduct(kdStrip); if (!deleted) { return { ok: false, error: "Group product tidak ditemukan" }; } revalidatePath("/master/group-product"); return { ok: true }; } catch (error) { logActionError("hapusGroupProduct", { userId: user.id, kdStrip }, error); return { ok: false, error: "Gagal menghapus group product, coba hapus ulang", }; } }